@chatpanel/events 0.278.0 → 0.295.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/sideline.js CHANGED
@@ -1,19 +1,21 @@
1
- import{approxTokens as x,queryTerms as S}from"./sources-retrieval.js";const M=Object.freeze(["sideline","breakout"]),I="bringback",h="thread";import{SIDELINE_SLASH_ITEMS as R}from"./slash-commands.js";function w(t){const e=/^\/(sideline|breakout)\b\s*([\s\S]*)$/i.exec(String(t||"").trim());if(!e)return null;let s=e[2].trim(),n=null;const r=/^@(?:(team|agent|cli|model):)?(?:"([^"]+)"|([^\s]+))\s*/i.exec(s);return r&&(n={kind:r[1]?r[1].toLowerCase():null,name:(r[2]||r[3]||"").trim()},s=s.slice(r[0].length).trim()),{question:s,target:n}}function L(t){const e=/^\/bringback\b\s*(full|brief)?\s*$/i.exec(String(t||"").trim());return e?{mode:e[1]?e[1].toLowerCase():"brief"}:null}function j(t,{teams:e=[],agents:s=[],clis:n=[],models:r=[]}={}){if(!t?.name)return null;const a=t.name.toLowerCase(),o=i=>String(i||"").toLowerCase()===a,c=[["team",e,i=>o(i.name)||o(i.id)],["agent",s,i=>o(i.name)||o(i.id)],["cli",n,i=>o(i.id)||o(i.label)||o(i.name)],["model",r,i=>o(i.id)||o(i.label)||o(i.model)||o(i.name)]];for(const[i,l,u]of c){if(t.kind&&t.kind!==i)continue;const f=(l||[]).find(d=>d&&u(d));if(f)return{kind:i,ref:f}}return null}function $(t=[]){return(t||[]).filter(e=>e&&(e.role==="user"||e.role==="assistant"))}const b=Object.freeze({chat:"message",sideline:"message",note:"section",meeting:"segment",run:"post",text:"part"});function g(t=""){const e=[];let s=null;const n=()=>{s&&s.text.trim()&&e.push({label:s.label,text:s.text.trim()}),s=null};for(const r of String(t||"").split(`
2
- `)){const a=/^(#{1,6})\s+(.*)$/.exec(r);if(a){n(),s={label:a[2].trim().slice(0,80)||"section",text:""};continue}if(!r.trim()){s&&!s.label?n():s&&(s.text+=`
3
- `);continue}s||(s={label:"",text:""}),s.text+=(s.text?`
4
- `:"")+r}return n(),e.map((r,a)=>({n:a+1,label:r.label||`paragraph ${a+1}`,text:r.text}))}function p(t){if(!t)return{kind:"text",title:"",units:[],focus:"",sources:[]};if(Array.isArray(t.units))return{kind:t.kind||"text",title:t.title||"",units:t.units,focus:t.focus||"",sources:t.sources||[]};const e=t.body||t,n=!!(t.sidelineOf||t.meta?.sidelineOf)?"sideline":t.kind||(Array.isArray(e.messages)?"chat":e.markdown!=null?"note":Array.isArray(e.segments)?"meeting":"text"),r=t.title||"",a=(e.attachments||[]).filter(o=>o&&o.kind!=="image"&&(o.title||o.url));if(n==="chat"||n==="sideline"){const o=$(e.messages||[]),c=[...o].reverse().find(l=>l.role==="user"),i=(e.messages||[]).flatMap(l=>(l.attachments||[]).filter(u=>u&&u.kind!=="image"&&u.kind!=="sideline"&&(u.title||u.url)));return{kind:n,title:r,sources:[...a,...i],units:o.map((l,u)=>({n:u+1,label:l.role,text:String(l.content||"")})),focus:String(c?.content||"")}}if(n==="note")return{kind:n,title:r,sources:a,units:g(e.markdown??e.text??""),focus:""};if(n==="meeting"){const o=Array.isArray(e.segments)?e.segments:[],c=o.length?o.map((i,l)=>({n:l+1,label:i.speaker||i.who||"speaker",text:String(i.text||"")})):g(e.summary?`# Summary
1
+ import{approxTokens as y,queryTerms as k}from"./sources-retrieval.js";const I=Object.freeze(["sideline","breakout"]),L="bringback",m="thread";import{SIDELINE_SLASH_ITEMS as W}from"./slash-commands.js";function O(t){const e=/^\/(sideline|breakout)\b\s*([\s\S]*)$/i.exec(String(t||"").trim());if(!e)return null;let i=e[2].trim(),n=null;const r=/^@(?:(team|agent|cli|model):)?(?:"([^"]+)"|([^\s]+))\s*/i.exec(i);return r&&(n={kind:r[1]?r[1].toLowerCase():null,name:(r[2]||r[3]||"").trim()},i=i.slice(r[0].length).trim()),{question:i,target:n}}function j(t){const e=/^\/bringback\b\s*(full|brief)?\s*$/i.exec(String(t||"").trim());return e?{mode:e[1]?e[1].toLowerCase():"brief"}:null}function C(t,{teams:e=[],agents:i=[],clis:n=[],models:r=[]}={}){if(!t?.name)return null;const a=t.name.toLowerCase(),o=s=>String(s||"").toLowerCase()===a,l=[["team",e,s=>o(s.name)||o(s.id)],["agent",i,s=>o(s.name)||o(s.id)],["cli",n,s=>o(s.id)||o(s.label)||o(s.name)],["model",r,s=>o(s.id)||o(s.label)||o(s.model)||o(s.name)]];for(const[s,u,c]of l){if(t.kind&&t.kind!==s)continue;const h=(u||[]).find(d=>d&&c(d));if(h)return{kind:s,ref:h}}return null}function N(t=[]){return(t||[]).filter(e=>e&&(e.role==="user"||e.role==="assistant"))}const p=Object.freeze({chat:"message",sideline:"message",note:"section",meeting:"segment",run:"post",text:"part"});function x(t=""){const e=[];let i=null;const n=()=>{i&&i.text.trim()&&e.push({label:i.label,text:i.text.trim()}),i=null};for(const r of String(t||"").split(`
2
+ `)){const a=/^(#{1,6})\s+(.*)$/.exec(r);if(a){n(),i={label:a[2].trim().slice(0,80)||"section",text:""};continue}if(!r.trim()){i&&!i.label?n():i&&(i.text+=`
3
+ `);continue}i||(i={label:"",text:""}),i.text+=(i.text?`
4
+ `:"")+r}return n(),e.map((r,a)=>({n:a+1,label:r.label||`paragraph ${a+1}`,text:r.text}))}function g(t){if(!t)return{kind:"text",title:"",units:[],focus:"",sources:[]};if(Array.isArray(t.units))return{kind:t.kind||"text",title:t.title||"",units:t.units,focus:t.focus||"",sources:t.sources||[]};const e=t.body||t,n=!!(t.sidelineOf||t.meta?.sidelineOf)?"sideline":t.kind||(Array.isArray(e.messages)?"chat":e.markdown!=null?"note":Array.isArray(e.segments)?"meeting":"text"),r=t.title||"",a=(e.attachments||[]).filter(o=>o&&o.kind!=="image"&&(o.title||o.url));if(n==="chat"||n==="sideline"){const o=N(e.messages||[]),l=[...o].reverse().find(u=>u.role==="user"),s=(e.messages||[]).flatMap(u=>(u.attachments||[]).filter(c=>c&&c.kind!=="image"&&c.kind!=="sideline"&&(c.title||c.url)));return{kind:n,title:r,sources:[...a,...s],units:o.map((u,c)=>({n:c+1,label:u.role,text:String(u.content||"")})),focus:String(l?.content||"")}}if(n==="note")return{kind:n,title:r,sources:a,units:x(e.markdown??e.text??""),focus:""};if(n==="meeting"){const o=Array.isArray(e.segments)?e.segments:[],l=o.length?o.map((s,u)=>({n:u+1,label:s.speaker||s.who||"speaker",text:String(s.text||"")})):x(e.summary?`# Summary
5
5
  ${e.summary}
6
6
 
7
- ${e.text||e.transcript||""}`:e.text||e.transcript||"");return{kind:n,title:r,sources:a,units:c,focus:String(e.summary||"").slice(0,240)}}if(n==="run"||Array.isArray(e.posts)){const o=e.posts||e.steps||[];return{kind:"run",title:r,sources:a,units:o.map((c,i)=>({n:i+1,label:c.actor||c.by||c.role||"post",text:String(c.text||c.content||"")})),focus:String(e.goal||e.request||"")}}return{kind:"text",title:r,sources:a,units:g(e.text||e.markdown||""),focus:""}}function O(t={}){const e=t.units?t:p(t.messages?{kind:"chat",title:t.title,body:{messages:t.messages,attachments:t.sources}}:t),s=b[e.kind]||"part",n=e.kind==="note"?"Main note":e.kind==="meeting"?"Meeting":e.kind==="run"?"Team run":"Main thread",r=String(e.focus||"").replace(/\s+/g," ").trim().slice(0,240),a=(e.sources||[]).map(c=>c?.title||c?.url).filter(Boolean).slice(0,6);return[`${n}${e.title?`: "${e.title}"`:""} — ${e.units.length} ${s}${e.units.length===1?"":"s"}, ~${x(e.units.map(c=>c.text).join(" "))} tokens.`,r?e.kind==="meeting"?`Summary: "${r}${r.length===240?"…":""}"`:`It is currently working on: "${r}${r.length===240?"…":""}"`:"",a.length?`Attached there: ${a.join(" · ")}.`:"",`Its content is NOT in this conversation. Call \`${h}\` to search it or read a range of ${s}s when the question depends on it — and only then.`].filter(Boolean).join(`
8
- `)}const N=Object.freeze({name:h,annotations:{readOnlyHint:!0,idempotentHint:!0},description:"Search or read what this sideline branched from — the main thread, note, meeting or run. Its content is not in this conversation; use this when the question depends on what was said or found there.",parameters:{type:"object",properties:{action:{type:"string",enum:["search","read","latest"],description:"search: parts matching a query (numbered). read: parts from..to by number. latest: the last n parts."},query:{type:"string",description:"For search: what you are looking for."},from:{type:"integer",description:"For read: first part number (1 = oldest)."},to:{type:"integer",description:"For read: last part number (inclusive)."},n:{type:"integer",description:"For latest: how many (default 4)."}},required:["action"],additionalProperties:!1}}),y=320;function A(t,e){const s=String(t||"").replace(/\s+/g," ").trim();if(s.length<=y)return s;const n=s.toLowerCase();let r=-1;for(const o of e)if(r=n.indexOf(o),r>=0)break;const a=Math.max(0,r-80);return`${a?"…":""}${s.slice(a,a+y)}…`}function q(t={},e={}){const s=t.units?t:p(t.messages?{kind:"chat",body:{messages:t.messages}}:t),n=s.units.map(o=>({n:o.n,role:o.label,text:String(o.text||"")})),r=String(e?.action||"latest");if(r==="search"){const o=S(e?.query);if(!o.length)return{error:"search needs a query."};const c=n.map(i=>({...i,score:o.reduce((l,u)=>l+(i.text.toLowerCase().includes(u)?Math.min(3,u.length/4):0),0)})).filter(i=>i.score>0).sort((i,l)=>l.score-i.score||i.n-l.n).slice(0,6).sort((i,l)=>i.n-l.n).map(i=>({n:i.n,role:i.role,snippet:A(i.text,o)}));return{of:n.length,hits:c,note:c.length?'Read a range with action "read" for the full text.':"Nothing there mentions that."}}if(r==="read"){const o=Math.max(1,Number(e?.from)||1),c=Math.min(n.length,Number(e?.to)||o);if(o>n.length)return{error:`There are ${n.length} ${b[s.kind]||"part"}s.`};const i=n.filter(d=>d.n>=o&&d.n<=c);let l=2e3*4;const u=[];let f=!1;for(const d of i){if(l<=0){f=!0;break}const m=d.text.length>l?`${d.text.slice(0,l)}…`:d.text;m.length<d.text.length&&(f=!0),l-=m.length,u.push({n:d.n,role:d.role,text:m})}return{of:n.length,from:o,to:c,messages:u,truncated:f}}const a=Math.max(1,Math.min(12,Number(e?.n)||4));return{of:n.length,messages:n.slice(-a).map(o=>({n:o.n,role:o.role,text:o.text.length>1600?`${o.text.slice(0,1600)}…`:o.text}))}}function C(t={}){const e=t.units?t:p(t.messages?{kind:"chat",title:t.title,body:{messages:t.messages,attachments:t.sources}}:t),s=O(e);return{specs:[{...N}],system:s,systemParts:{thread:x(s)},async execute(n,r){if(n!==h)return JSON.stringify({error:`Unknown tool: ${n}`});const a=typeof r=="string"?JSON.parse(r||"{}"):r||{};return JSON.stringify(q(e,a))}}}function _({title:t="",turns:e=[]}={}){const s=(e||[]).filter(n=>n&&(n.role==="user"||n.role==="assistant")).map(n=>`${n.role==="user"?"Asked":"Answered"}: ${String(n.content||"").trim()}`).join(`
7
+ ${e.text||e.transcript||""}`:e.text||e.transcript||"");return{kind:n,title:r,sources:a,units:l,focus:String(e.summary||"").slice(0,240)}}if(n==="run"||Array.isArray(e.posts)){const o=e.posts||e.steps||[];return{kind:"run",title:r,sources:a,units:o.map((l,s)=>({n:s+1,label:l.actor||l.by||l.role||"post",text:String(l.text||l.content||"")})),focus:String(e.goal||e.request||"")}}return{kind:"text",title:r,sources:a,units:x(e.text||e.markdown||""),focus:""}}function A(t={}){const e=t.units?t:g(t.messages?{kind:"chat",title:t.title,body:{messages:t.messages,attachments:t.sources}}:t),i=p[e.kind]||"part",n=e.kind==="note"?"Main note":e.kind==="meeting"?"Meeting":e.kind==="run"?"Team run":"Main thread",r=String(e.focus||"").replace(/\s+/g," ").trim().slice(0,240),a=(e.sources||[]).map(l=>l?.title||l?.url).filter(Boolean).slice(0,6);return[`${n}${e.title?`: "${e.title}"`:""} — ${e.units.length} ${i}${e.units.length===1?"":"s"}, ~${y(e.units.map(l=>l.text).join(" "))} tokens.`,r?e.kind==="meeting"?`Summary: "${r}${r.length===240?"…":""}"`:`It is currently working on: "${r}${r.length===240?"…":""}"`:"",a.length?`Attached there: ${a.join(" · ")}.`:"",`Its content is NOT in this conversation. Call \`${m}\` to search it or read a range of ${i}s when the question depends on it — and only then.`].filter(Boolean).join(`
8
+ `)}const q=Object.freeze({name:m,annotations:{readOnlyHint:!0,idempotentHint:!0},description:"Search or read what this sideline branched from — the main thread, note, meeting or run. Its content is not in this conversation; use this when the question depends on what was said or found there.",parameters:{type:"object",properties:{action:{type:"string",enum:["search","read","latest"],description:"search: parts matching a query (numbered). read: parts from..to by number. latest: the last n parts."},query:{type:"string",description:"For search: what you are looking for."},from:{type:"integer",description:"For read: first part number (1 = oldest)."},to:{type:"integer",description:"For read: last part number (inclusive)."},n:{type:"integer",description:"For latest: how many (default 4)."}},required:["action"],additionalProperties:!1}}),S=320;function T(t,e){const i=String(t||"").replace(/\s+/g," ").trim();if(i.length<=S)return i;const n=i.toLowerCase();let r=-1;for(const o of e)if(r=n.indexOf(o),r>=0)break;const a=Math.max(0,r-80);return`${a?"…":""}${i.slice(a,a+S)}…`}function $(t={},e={}){const i=t.units?t:g(t.messages?{kind:"chat",body:{messages:t.messages}}:t),n=i.units.map(o=>({n:o.n,role:o.label,text:String(o.text||"")})),r=String(e?.action||"latest");if(r==="search"){const o=k(e?.query);if(!o.length)return{error:"search needs a query."};const l=n.map(s=>({...s,score:o.reduce((u,c)=>u+(s.text.toLowerCase().includes(c)?Math.min(3,c.length/4):0),0)})).filter(s=>s.score>0).sort((s,u)=>u.score-s.score||s.n-u.n).slice(0,6).sort((s,u)=>s.n-u.n).map(s=>({n:s.n,role:s.role,snippet:T(s.text,o)}));return{of:n.length,hits:l,note:l.length?'Read a range with action "read" for the full text.':"Nothing there mentions that."}}if(r==="read"){const o=Math.max(1,Number(e?.from)||1),l=Math.min(n.length,Number(e?.to)||o);if(o>n.length)return{error:`There are ${n.length} ${p[i.kind]||"part"}s.`};const s=n.filter(d=>d.n>=o&&d.n<=l);let u=2e3*4;const c=[];let h=!1;for(const d of s){if(u<=0){h=!0;break}const f=d.text.length>u?`${d.text.slice(0,u)}…`:d.text;f.length<d.text.length&&(h=!0),u-=f.length,c.push({n:d.n,role:d.role,text:f})}return{of:n.length,from:o,to:l,messages:c,truncated:h}}const a=Math.max(1,Math.min(12,Number(e?.n)||4));return{of:n.length,messages:n.slice(-a).map(o=>({n:o.n,role:o.role,text:o.text.length>1600?`${o.text.slice(0,1600)}…`:o.text}))}}function _(t={},e="",{maxChars:i=2400}={}){const n=t.units?t:g(t.messages?{kind:"chat",title:t.title,body:{messages:t.messages}}:t),r=n.units.filter(c=>String(c.text||"").trim());if(!r.length)return"";const a=r.slice(-2).reverse().map(c=>c.n);if(k(e).length)for(const c of $(n,{action:"search",query:e}).hits||[])a.push(c.n);const o=new Map(r.map(c=>[c.n,c])),l=[];let s=0;for(const c of[...new Set(a)]){const h=o.get(c);if(!h)continue;const d=i-s;if(d<160)break;const f=String(h.text).replace(/\s+\n/g,`
9
+ `).trim(),b=f.length>d?`${f.slice(0,d-1)}…`:f;l.push({n:c,label:h.label,text:b}),s+=b.length}l.sort((c,h)=>c.n-h.n);const u=p[n.kind]||"part";return[`From the main thread${n.title?` "${n.title}"`:""} — ${l.length} of its ${r.length} ${u}${r.length===1?"":"s"}: the latest, and what mentions this question. Answer the side question with this in mind${r.length>l.length?`; \`${m}\` reads the rest`:""}.`,...l.map(c=>`[${c.n}] ${c.label}: ${c.text}`)].join(`
10
+ `)}function v(t={}){const e=t.units?t:g(t.messages?{kind:"chat",title:t.title,body:{messages:t.messages,attachments:t.sources}}:t),i=A(e);return{specs:[{...q}],system:i,systemParts:{thread:y(i)},async execute(n,r){if(n!==m)return JSON.stringify({error:`Unknown tool: ${n}`});const a=typeof r=="string"?JSON.parse(r||"{}"):r||{};return JSON.stringify($(e,a))}}}function P({title:t="",turns:e=[]}={}){const i=(e||[]).filter(n=>n&&(n.role==="user"||n.role==="assistant")).map(n=>`${n.role==="user"?"Asked":"Answered"}: ${String(n.content||"").trim()}`).join(`
9
11
 
10
- `);return[`This was a side conversation${t?` about "${t}"`:""}, held apart from a main thread that is still being worked on. Write the brief the main thread should receive.`,"Rules: at most 120 words. State what was asked, the answer, any decision or recommendation, and anything still open. Plain prose or up to four short bullets. No preamble, no headings, no restating the main thread.","",s].join(`
11
- `)}function P({sideline:t,mode:e="brief",brief:s="",now:n=Date.now,newId:r=()=>`sl_${Math.random().toString(36).slice(2,10)}`}={}){const a=(t?.turns||[]).filter(l=>l&&(l.role==="user"||l.role==="assistant")),o=a.map(l=>`${l.role==="user"?"Asked":"Answered"}: ${String(l.content||"").trim()}`).join(`
12
+ `);return[`This was a side conversation${t?` about "${t}"`:""}, held apart from a main thread that is still being worked on. Write the brief the main thread should receive.`,"Rules: at most 120 words. State what was asked, the answer, any decision or recommendation, and anything still open. Plain prose or up to four short bullets. No preamble, no headings, no restating the main thread.","",i].join(`
13
+ `)}function B({sideline:t,mode:e="brief",brief:i="",now:n=Date.now,newId:r=()=>`sl_${Math.random().toString(36).slice(2,10)}`}={}){const a=(t?.turns||[]).filter(u=>u&&(u.role==="user"||u.role==="assistant")),o=a.map(u=>`${u.role==="user"?"Asked":"Answered"}: ${String(u.content||"").trim()}`).join(`
12
14
 
13
- `),c=e==="full"?o:String(s||"").trim()||o,i=`From Sideline ${t?.index||1}${t?.model?` · ${t.model}`:""}`;return{id:r(),role:"note",kind:"sideline",ts:n(),content:c,sideline:{id:t?.id||null,index:t?.index||1,model:t?.model||"",turns:a.length,mode:e,broughtBackAt:n()},attachments:[{kind:"sideline",title:i,text:c}]}}function v(t=[]){const e=Array.isArray(t)?t:[];if(!e.some(r=>r?.role==="note"))return e;const s=[];let n=[];for(const r of e){if(r?.role==="note"){n.push(...r.attachments||[]);continue}if(r?.role==="user"&&n.length){s.push({...r,attachments:[...n,...r.attachments||[]]}),n=[];continue}s.push(r)}return s}function B(t=[]){return(t||[]).reduce((e,s)=>Math.max(e,Number(s?.index)||0),0)+1}function D(t,e){const s=[];let n=t,r=0;for(;n&&(n.sideline||n.meta?.sideline)&&r++<16;)s.unshift((n.sideline||n.meta?.sideline)?.index||1),n=e?.(n)||null;return s.join(".")}function J(t,e){if(t==="note"){const s=e.attachments?.[0]?.title||`From Sideline ${e.sideline?.index||1}`,n=String(e.content||"").trim().split(`
15
+ `),l=e==="full"?o:String(i||"").trim()||o,s=`From Sideline ${t?.index||1}${t?.model?` · ${t.model}`:""}`;return{id:r(),role:"note",kind:"sideline",ts:n(),content:l,sideline:{id:t?.id||null,index:t?.index||1,model:t?.model||"",turns:a.length,mode:e,broughtBackAt:n()},attachments:[{kind:"sideline",title:s,text:l}]}}function D(t=[]){const e=Array.isArray(t)?t:[];if(!e.some(r=>r?.role==="note"))return e;const i=[];let n=[];for(const r of e){if(r?.role==="note"){n.push(...r.attachments||[]);continue}if(r?.role==="user"&&n.length){i.push({...r,attachments:[...n,...r.attachments||[]]}),n=[];continue}i.push(r)}return i}function J(t=[]){return(t||[]).reduce((e,i)=>Math.max(e,Number(i?.index)||0),0)+1}function F(t,e){const i=[];let n=t,r=0;for(;n&&(n.sideline||n.meta?.sideline)&&r++<16;)i.unshift((n.sideline||n.meta?.sideline)?.index||1),n=e?.(n)||null;return i.join(".")}function U(t,e){if(t==="note"){const i=e.attachments?.[0]?.title||`From Sideline ${e.sideline?.index||1}`,n=String(e.content||"").trim().split(`
14
16
  `).map(r=>`> ${r}`).join(`
15
17
  `);return{kind:"markdown",markdown:`
16
18
 
17
- > **${s}**
19
+ > **${i}**
18
20
  ${n}
19
- `}}return{kind:"message",message:e}}const k="sideline",T=Object.freeze({name:k,annotations:{readOnlyHint:!1,idempotentHint:!1},description:"Open a SIDELINE — a separate conversation about one question, apart from this one — and get its brief back. Use it to fork a sub-question to a team, an agent or another model without cluttering this thread; the sideline can search or read this thread with its own `thread` tool. Returns the brief (or the full text) when it is done.",parameters:{type:"object",properties:{question:{type:"string",description:"The question or task for the sideline, self-contained."},target:{type:"string",description:"Optional: who answers — a team name, an agent name, a CLI agent or a model id. Omit for the same model as this conversation."},bring:{type:"string",enum:["brief","full"],description:"What comes back: a brief (default) or the full exchange."}},required:["question"],additionalProperties:!1}});function U({run:t,depth:e=0,maxDepth:s=3}={}){if(typeof t!="function")throw new Error("sidelineToolProvider: run required");return{id:"sideline",specs:[{...T}],system:"You may fork a sub-question into a `sideline` (a team, an agent or a model works on it apart from this thread and you get the brief back). Use it for work that would otherwise clutter this thread; do not use it for a question you can answer directly.",async execute(n,r){if(n!==k)return JSON.stringify({error:`Unknown tool: ${n}`});const a=typeof r=="string"?JSON.parse(r||"{}"):r||{},o=String(a.question||"").trim();if(!o)return JSON.stringify({error:"question is required."});if(e>=s)return JSON.stringify({error:`Sidelines nest at most ${s} deep; answer this one here.`});const c=a.target&&w(`/sideline @${/\s/.test(String(a.target))?`"${a.target}"`:a.target} x`)?.target||null;try{const i=await t({question:o,target:c,bring:a.bring==="full"?"full":"brief"});return JSON.stringify({sideline:i?.index!=null?`Sideline ${i.index}`:"sideline",id:i?.id||null,model:i?.model||"",brief:String(i?.brief||"")})}catch(i){return JSON.stringify({error:`The sideline failed: ${i?.message||i}`})}}}}export{I as BRINGBACK_COMMAND,M as SIDELINE_COMMANDS,R as SIDELINE_SLASH_ITEMS,k as SIDELINE_TOOL_NAME,T as SIDELINE_TOOL_SPEC,h as THREAD_TOOL_NAME,N as THREAD_TOOL_SPEC,_ as briefPrompt,J as foldBackFor,P as foldBackNote,v as foldNotes,B as nextSidelineIndex,g as noteUnits,L as parseBringBack,w as parseSideline,q as readThread,j as resolveSidelineTarget,D as sidelinePath,U as sidelineToolProvider,p as sourceOf,O as threadManifest,C as threadToolProvider};
21
+ `}}return{kind:"message",message:e}}const w="sideline",E=Object.freeze({name:w,annotations:{readOnlyHint:!1,idempotentHint:!1},description:"Open a SIDELINE — a separate conversation about one question, apart from this one — and get its brief back. Use it to fork a sub-question to a team, an agent or another model without cluttering this thread; the sideline can search or read this thread with its own `thread` tool. Returns the brief (or the full text) when it is done.",parameters:{type:"object",properties:{question:{type:"string",description:"The question or task for the sideline, self-contained."},target:{type:"string",description:"Optional: who answers — a team name, an agent name, a CLI agent or a model id. Omit for the same model as this conversation."},bring:{type:"string",enum:["brief","full"],description:"What comes back: a brief (default) or the full exchange."}},required:["question"],additionalProperties:!1}});function H({run:t,depth:e=0,maxDepth:i=3}={}){if(typeof t!="function")throw new Error("sidelineToolProvider: run required");return{id:"sideline",specs:[{...E}],system:"You may fork a sub-question into a `sideline` (a team, an agent or a model works on it apart from this thread and you get the brief back). Use it for work that would otherwise clutter this thread; do not use it for a question you can answer directly.",async execute(n,r){if(n!==w)return JSON.stringify({error:`Unknown tool: ${n}`});const a=typeof r=="string"?JSON.parse(r||"{}"):r||{},o=String(a.question||"").trim();if(!o)return JSON.stringify({error:"question is required."});if(e>=i)return JSON.stringify({error:`Sidelines nest at most ${i} deep; answer this one here.`});const l=a.target&&O(`/sideline @${/\s/.test(String(a.target))?`"${a.target}"`:a.target} x`)?.target||null;try{const s=await t({question:o,target:l,bring:a.bring==="full"?"full":"brief"});return JSON.stringify({sideline:s?.index!=null?`Sideline ${s.index}`:"sideline",id:s?.id||null,model:s?.model||"",brief:String(s?.brief||"")})}catch(s){return JSON.stringify({error:`The sideline failed: ${s?.message||s}`})}}}}export{L as BRINGBACK_COMMAND,I as SIDELINE_COMMANDS,W as SIDELINE_SLASH_ITEMS,w as SIDELINE_TOOL_NAME,E as SIDELINE_TOOL_SPEC,m as THREAD_TOOL_NAME,q as THREAD_TOOL_SPEC,P as briefPrompt,U as foldBackFor,B as foldBackNote,D as foldNotes,J as nextSidelineIndex,x as noteUnits,j as parseBringBack,O as parseSideline,$ as readThread,C as resolveSidelineTarget,_ as sidelineExcerpt,F as sidelinePath,H as sidelineToolProvider,g as sourceOf,A as threadManifest,v as threadToolProvider};
package/site-pages.js ADDED
@@ -0,0 +1 @@
1
+ const i=Object.freeze([{name:"Hacker News",re:/\b[Hh]acker\s?[Nn]ews\b|\bHN\b/,url:"https://news.ycombinator.com/"},{name:"Lobsters",re:/\blobste\.rs\b|\blobsters\b/i,url:"https://lobste.rs/"}]),a=/\b(?:what(?:'s| is| are)|anything|something)\s+(?:new|up|happening|going on|trending|hot|interesting|good|on|there|the (?:latest|top|news|headlines))\b|\b(?:news|headlines|top (?:stories|posts|links)|front ?page|latest|today'?s stories|trending|stories|posts)\b/i;function h(t,{max:o=1}={}){const n=String(t||""),s=[];for(const e of i){if(!e.re.test(n))continue;const r=n.replace(new RegExp(e.re.source,`g${e.re.flags.replace("g","")}`)," ");if(a.test(r)&&s.push({name:e.name,url:e.url}),s.length>=o)break}return s}function b(t){return`The ${t} front page is above. Answer from it: name the top stories by their titles, in the order the page lists them, with a few words on what each is about where the title does not say. Use only the page text above.`}export{i as FRONT_PAGES,b as frontPageInstruction,h as frontPagesAskedAbout};
package/weather-tool.js CHANGED
@@ -1 +1 @@
1
- import{getWeather as a}from"./weather.js";const l="weather",i="For weather, call `weather` FIRST — it answers the whole question in one request. Only fall back to web_search if it tells you to. Report the location it says it resolved, because a bare town name can geocode to the wrong place.";function c({fetchJson:o}={}){if(typeof o!="function")throw new Error("weatherToolProvider: fetchJson required");return{specs:[{name:"weather",annotations:{readOnlyHint:!0,idempotentHint:!0,openWorldHint:!0},description:"Current conditions and a short forecast for one place, in a single request. Use this for any weather question instead of searching. Returns the location it actually resolved to — say which place the answer is for.",parameters:{type:"object",properties:{location:{type:"string",description:'A place, as the user said it. Add a state or country only if THEY did — "Fairview, OR" if they said so, plain "Fairview" if they did not.'}},required:["location"],additionalProperties:!1}}],system:i,async execute(r,n){if(r!=="weather")return JSON.stringify({error:`Unknown tool: ${r}`});const e=String(n?.location||"").trim();if(!e)return"No location provided to weather.";const t=await a(e,{fetchJson:o});return t.ok?{text:t.text,note:"ChatPanel · wttr.in"}:`The weather service could not answer for "${e}" (${t.reason}). Now call web_search for "weather in ${e}" and answer from the results — do not tell the user a tool failed.`}}}export{l as WEATHER_TOOL_NAME,i as WEATHER_TOOL_SYSTEM,c as weatherToolProvider};
1
+ import{getWeather as s,isHere as l}from"./weather.js";const d="weather",c="For weather, call `weather` FIRST — it answers the whole question in one request. Only fall back to web_search if it tells you to. Report the location it says it resolved, because a bare town name can geocode to the wrong place.";function w({fetchJson:t}={}){if(typeof t!="function")throw new Error("weatherToolProvider: fetchJson required");return{specs:[{name:"weather",annotations:{readOnlyHint:!0,idempotentHint:!0,openWorldHint:!0},description:"Current conditions and a short forecast for one place, in a single request. Use this for any weather question instead of searching. Returns the location it actually resolved to — say which place the answer is for.",parameters:{type:"object",properties:{location:{type:"string",description:'A place, as the user said it. Add a state or country only if THEY did — "Fairview, OR" if they said so, plain "Fairview" if they did not.'}},required:["location"],additionalProperties:!1}}],system:c,async execute(o,i){if(o!=="weather")return JSON.stringify({error:`Unknown tool: ${o}`});const r=String(i?.location||"").trim(),a=l(r)?"":r,e=await s(a,{fetchJson:t});if(!e.ok){const n=a||"my area";return`The weather service could not answer for "${n}" (${e.reason}). Now call web_search for "weather in ${n}" and answer from the results — do not tell the user a tool failed.`}return{text:e.text,note:"ChatPanel · wttr.in"}}}}export{d as WEATHER_TOOL_NAME,c as WEATHER_TOOL_SYSTEM,w as weatherToolProvider};
package/weather.js CHANGED
@@ -1,2 +1,2 @@
1
- const f="https://wttr.in",L=7e3;class m extends Error{constructor(r,n){super(n),this.name="WeatherError",this.code=r}}function d(e,{host:r=f}={}){const n=String(e??"").trim();if(!n)throw new m("NO_LOCATION","a location is required");if(n.length>120)throw new m("BAD_LOCATION","location is too long to be one");return`${r}/${encodeURIComponent(n)}?format=j1`}const s=e=>{const r=Number(e);return Number.isFinite(r)?r:null},l=e=>String(e??"").trim(),h=e=>Array.isArray(e)?l(e[0]?.value):l(e);function w(e,{query:r=""}={}){if(!e||typeof e!="object")return null;const n=Array.isArray(e.current_condition)?e.current_condition[0]:null;if(!n)return null;const t=s(n.temp_C),a=s(n.temp_F);if(t===null&&a===null)return null;const i=Array.isArray(e.nearest_area)?e.nearest_area[0]:null,o=i?{name:h(i.areaName),region:h(i.region),country:h(i.country),lat:s(i.latitude),lon:s(i.longitude)}:null,c=(Array.isArray(e.weather)?e.weather:[]).slice(0,3).map(u=>({date:l(u.date),maxC:s(u.maxtempC),maxF:s(u.maxtempF),minC:s(u.mintempC),minF:s(u.mintempF),sunrise:l(u.astronomy?.[0]?.sunrise),sunset:l(u.astronomy?.[0]?.sunset),condition:h(u.hourly?.[4]?.weatherDesc)||h(u.hourly?.[0]?.weatherDesc),chanceOfRain:s(u.hourly?.[4]?.chanceofrain)}));return{query:l(r),area:o,now:{tempC:t,tempF:a,feelsLikeC:s(n.FeelsLikeC),feelsLikeF:s(n.FeelsLikeF),condition:h(n.weatherDesc),humidity:s(n.humidity),windKph:s(n.windspeedKmph),windMph:s(n.windspeedMiles),windDir:l(n.winddir16Point),precipMm:s(n.precipMM),uv:s(n.uvIndex),observedAt:l(n.localObsDateTime)},days:c}}function y(e,r=""){if(!e)return r;const n=[e.name,e.region,e.country].map(l).filter(Boolean),t=new Set;return n.filter(i=>{const o=i.toLowerCase();return t.has(o)?!1:(t.add(o),!0)}).join(", ")||r}function $(e){const r=l(e);return r?!/[,]/.test(r)&&r.split(/\s+/).length<=2:!1}const C=e=>Math.round(e*9/5+32),p=(e,r)=>{const n=e===null&&r!==null?Math.round((r-32)*5/9):e,t=r===null&&e!==null?C(e):r;return n===null&&t===null?"":n===null?`${t}°F`:t===null?`${n}°C`:`${t}°F / ${n}°C`};function g(e){if(!e)return"";const r=y(e.area,e.query),n=[];n.push(`Weather for ${r}${e.query&&r.toLowerCase()!==e.query.toLowerCase()?` (asked: "${e.query}")`:""}`);const t=e.now,a=[`Now: ${p(t.tempC,t.tempF)}`];(t.feelsLikeC!==null||t.feelsLikeF!==null)&&a.push(`feels like ${p(t.feelsLikeC,t.feelsLikeF)}`),t.condition&&a.push(t.condition.toLowerCase()),n.push(a.join(", "));const i=[];t.humidity!==null&&i.push(`humidity ${t.humidity}%`),(t.windMph!==null||t.windKph!==null)&&i.push(`wind ${t.windMph!==null?`${t.windMph} mph`:`${t.windKph} km/h`}${t.windDir?` ${t.windDir}`:""}`),t.precipMm!==null&&i.push(`precip ${t.precipMm} mm`),t.uv!==null&&i.push(`UV ${t.uv}`),i.length&&n.push(i.join(" · "));for(const o of e.days){const c=`${p(o.maxC,o.maxF)} high / ${p(o.minC,o.minF)} low`,u=o.chanceOfRain!==null?`, ${o.chanceOfRain}% rain`:"";n.push(`${o.date}: ${c}${o.condition?`, ${o.condition.toLowerCase()}`:""}${u}`)}return t.observedAt&&n.push(`Observed ${t.observedAt} local. Source: wttr.in`),$(e.query)&&n.push("The place name was ambiguous — TELL THE USER which location this is for, and offer to re-check with a state or country if it is the wrong one."),n.join(`
2
- `)}async function x(e,{fetchJson:r,timeoutMs:n=7e3,host:t=f}={}){let a;try{a=d(e,{host:t})}catch(c){return{ok:!1,reason:c.message}}if(typeof r!="function")return{ok:!1,reason:"no fetch was provided"};let i;try{i=await r(a,{timeoutMs:n})}catch(c){return{ok:!1,reason:c?.message||"the weather service did not answer"}}const o=w(i,{query:e});return o?{ok:!0,weather:o,text:g(o)}:{ok:!1,reason:"the weather service returned nothing usable"}}export{f as WEATHER_HOST,L as WEATHER_TIMEOUT_MS,m as WeatherError,y as areaLabel,g as formatWeather,x as getWeather,$ as isAmbiguousLocation,w as parseWeather,d as weatherUrl};
1
+ const m="https://wttr.in",F=7e3;class d extends Error{constructor(r,n){super(n),this.name="WeatherError",this.code=r}}function w(e,{host:r=m}={}){const n=String(e??"").trim();if(y(n))return`${r}/?format=j1`;if(n.length>120)throw new d("BAD_LOCATION","location is too long to be one");return`${r}/${encodeURIComponent(n)}?format=j1`}const f=/^(?:(?:right )?here|near me|nearby|around (?:here|me)|my (?:location|area|city|town|place)|(?:my )?current location|where i am|local(?:ly)?|outside|(?:right )?now|currently|today|tonight|tomorrow|(?:this|next|the) (?:morning|afternoon|evening|night|week|weekend)|(?:this |next |on )?(?:mon|tues|wednes|thurs|fri|satur|sun)day)$/i;function y(e){const r=String(e??"").trim().replace(/[?.!,]+$/,"").replace(/\s+/g," ");return!r||f.test(r)||r.split(/\s*(?:,|\band\b|\bor\b)\s*/).every(n=>f.test(n))}const s=e=>{const r=Number(e);return Number.isFinite(r)?r:null},l=e=>String(e??"").trim(),h=e=>Array.isArray(e)?l(e[0]?.value):l(e);function $(e,{query:r=""}={}){if(!e||typeof e!="object")return null;const n=Array.isArray(e.current_condition)?e.current_condition[0]:null;if(!n)return null;const t=s(n.temp_C),u=s(n.temp_F);if(t===null&&u===null)return null;const i=Array.isArray(e.nearest_area)?e.nearest_area[0]:null,o=i?{name:h(i.areaName),region:h(i.region),country:h(i.country),lat:s(i.latitude),lon:s(i.longitude)}:null,c=(Array.isArray(e.weather)?e.weather:[]).slice(0,3).map(a=>({date:l(a.date),maxC:s(a.maxtempC),maxF:s(a.maxtempF),minC:s(a.mintempC),minF:s(a.mintempF),sunrise:l(a.astronomy?.[0]?.sunrise),sunset:l(a.astronomy?.[0]?.sunset),condition:h(a.hourly?.[4]?.weatherDesc)||h(a.hourly?.[0]?.weatherDesc),chanceOfRain:s(a.hourly?.[4]?.chanceofrain)}));return{query:l(r),area:o,now:{tempC:t,tempF:u,feelsLikeC:s(n.FeelsLikeC),feelsLikeF:s(n.FeelsLikeF),condition:h(n.weatherDesc),humidity:s(n.humidity),windKph:s(n.windspeedKmph),windMph:s(n.windspeedMiles),windDir:l(n.winddir16Point),precipMm:s(n.precipMM),uv:s(n.uvIndex),observedAt:l(n.localObsDateTime)},days:c}}function g(e,r=""){if(!e)return r;const n=[e.name,e.region,e.country].map(l).filter(Boolean),t=new Set;return n.filter(i=>{const o=i.toLowerCase();return t.has(o)?!1:(t.add(o),!0)}).join(", ")||r}function C(e){const r=l(e);return r?!/[,]/.test(r)&&r.split(/\s+/).length<=2:!1}const x=e=>Math.round(e*9/5+32),p=(e,r)=>{const n=e===null&&r!==null?Math.round((r-32)*5/9):e,t=r===null&&e!==null?x(e):r;return n===null&&t===null?"":n===null?`${t}°F`:t===null?`${n}°C`:`${t}°F / ${n}°C`};function k(e){if(!e)return"";const r=g(e.area,e.query),n=[];n.push(`Weather for ${r}${e.query&&r.toLowerCase()!==e.query.toLowerCase()?` (asked: "${e.query}")`:""}`);const t=e.now,u=[`Now: ${p(t.tempC,t.tempF)}`];(t.feelsLikeC!==null||t.feelsLikeF!==null)&&u.push(`feels like ${p(t.feelsLikeC,t.feelsLikeF)}`),t.condition&&u.push(t.condition.toLowerCase()),n.push(u.join(", "));const i=[];t.humidity!==null&&i.push(`humidity ${t.humidity}%`),(t.windMph!==null||t.windKph!==null)&&i.push(`wind ${t.windMph!==null?`${t.windMph} mph`:`${t.windKph} km/h`}${t.windDir?` ${t.windDir}`:""}`),t.precipMm!==null&&i.push(`precip ${t.precipMm} mm`),t.uv!==null&&i.push(`UV ${t.uv}`),i.length&&n.push(i.join(" · "));for(const o of e.days){const c=`${p(o.maxC,o.maxF)} high / ${p(o.minC,o.minF)} low`,a=o.chanceOfRain!==null?`, ${o.chanceOfRain}% rain`:"";n.push(`${o.date}: ${c}${o.condition?`, ${o.condition.toLowerCase()}`:""}${a}`)}return t.observedAt&&n.push(`Observed ${t.observedAt} local. Source: wttr.in`),C(e.query)&&n.push("The place name was ambiguous — TELL THE USER which location this is for, and offer to re-check with a state or country if it is the wrong one."),n.join(`
2
+ `)}async function L(e,{fetchJson:r,timeoutMs:n=7e3,host:t=m}={}){let u;try{u=w(e,{host:t})}catch(c){return{ok:!1,reason:c.message}}if(typeof r!="function")return{ok:!1,reason:"no fetch was provided"};let i;try{i=await r(u,{timeoutMs:n})}catch(c){return{ok:!1,reason:c?.message||"the weather service did not answer"}}const o=$(i,{query:e});return o?{ok:!0,weather:o,text:k(o)}:{ok:!1,reason:"the weather service returned nothing usable"}}export{m as WEATHER_HOST,F as WEATHER_TIMEOUT_MS,d as WeatherError,g as areaLabel,k as formatWeather,L as getWeather,C as isAmbiguousLocation,y as isHere,$ as parseWeather,w as weatherUrl};