@chatpanel/events 0.295.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.
- package/agent-card-view.js +1 -1
- package/agent-permission.js +2 -2
- package/agent-session-open.js +1 -0
- package/agent-thread.js +5 -0
- package/attached-paths.js +1 -1
- package/browser-relay.js +1 -1
- package/client-prefs.js +1 -1
- package/clock.js +1 -0
- package/compaction.js +4 -4
- package/context-select.js +2 -0
- package/context-window.js +1 -1
- package/dialect-a2a.js +1 -1
- package/dialect-claude.js +1 -1
- package/digest.js +7 -0
- package/fetched.js +2 -2
- package/find-tool.js +1 -1
- package/harness-cards.js +1 -1
- package/history-search.js +6 -6
- package/identity.js +1 -0
- package/index.js +1 -1
- package/link-connect.js +1 -1
- package/link-protocol.js +1 -1
- package/link-routes.js +2 -0
- package/memory.js +2 -2
- package/model-candidates.js +1 -1
- package/note-tool.js +2 -2
- package/own-instructions.js +5 -0
- package/package.json +23 -1
- package/prefetch.js +4 -2
- package/provider-presets.js +1 -1
- package/research.js +7 -7
- package/retrieval-plan.js +1 -0
- package/sandbox-policy.js +1 -1
- package/search-modes.js +6 -6
- package/service-standby.js +1 -0
- package/settings-registry.js +1 -1
- package/stitch.js +16 -14
- package/thread-send.js +1 -0
- package/tool-group-data.js +1 -1
- package/tool-hints.js +4 -4
- package/tool-hub.js +4 -4
- package/tool-need.js +3 -3
- package/tool-result.js +2 -2
- package/turn-loop.js +4 -4
- package/vault.js +1 -1
- package/voice-intents.js +2 -2
- package/voice-sample.js +1 -1
- package/weather-tool.js +10 -1
- package/weather.js +2 -2
package/note-tool.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
const N=[{name:"note",description:"WRITE to the user'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||""),
|
|
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.
|
|
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",
|
|
@@ -126,6 +129,7 @@
|
|
|
126
129
|
"./note-merge.js": "./note-merge.js",
|
|
127
130
|
"./link-connect.js": "./link-connect.js",
|
|
128
131
|
"./link-sync.js": "./link-sync.js",
|
|
132
|
+
"./link-routes.js": "./link-routes.js",
|
|
129
133
|
"./qr.js": "./qr.js",
|
|
130
134
|
"./record-entities.js": "./record-entities.js",
|
|
131
135
|
"./decide-by-model.js": "./decide-by-model.js",
|
|
@@ -192,6 +196,7 @@
|
|
|
192
196
|
"./sync-plan.js": "./sync-plan.js",
|
|
193
197
|
"./synthesis.js": "./synthesis.js",
|
|
194
198
|
"./tags.js": "./tags.js",
|
|
199
|
+
"./thread-send.js": "./thread-send.js",
|
|
195
200
|
"./team-board.js": "./team-board.js",
|
|
196
201
|
"./board-tool.js": "./board-tool.js",
|
|
197
202
|
"./team-cache.js": "./team-cache.js",
|
|
@@ -266,6 +271,7 @@
|
|
|
266
271
|
"./kokoro-text.js": "./kokoro-text.js",
|
|
267
272
|
"./weather-tool.js": "./weather-tool.js",
|
|
268
273
|
"./weather.js": "./weather.js",
|
|
274
|
+
"./clock.js": "./clock.js",
|
|
269
275
|
"./web-search-tool.js": "./web-search-tool.js",
|
|
270
276
|
"./web-search.js": "./web-search.js",
|
|
271
277
|
"./widget.js": "./widget.js",
|
|
@@ -276,6 +282,11 @@
|
|
|
276
282
|
"./fetched.js": "./fetched.js",
|
|
277
283
|
"./context-window.js": "./context-window.js",
|
|
278
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",
|
|
279
290
|
"./site-policy.js": "./site-policy.js",
|
|
280
291
|
"./read-document.js": "./read-document.js",
|
|
281
292
|
"./serp-anchors.js": "./serp-anchors.js",
|
|
@@ -298,6 +309,8 @@
|
|
|
298
309
|
"a2a-task.js",
|
|
299
310
|
"agent-dialects.js",
|
|
300
311
|
"agent-portability.js",
|
|
312
|
+
"agent-session-open.js",
|
|
313
|
+
"agent-thread.js",
|
|
301
314
|
"attribution.js",
|
|
302
315
|
"backup-envelope.js",
|
|
303
316
|
"blob-envelope.js",
|
|
@@ -313,6 +326,7 @@
|
|
|
313
326
|
"capability-adapters.js",
|
|
314
327
|
"open-decision.js",
|
|
315
328
|
"runtime-in-process.js",
|
|
329
|
+
"service-standby.js",
|
|
316
330
|
"capability-providers.js",
|
|
317
331
|
"capability-tools.js",
|
|
318
332
|
"fast-path.js",
|
|
@@ -408,6 +422,7 @@
|
|
|
408
422
|
"note-merge.js",
|
|
409
423
|
"link-connect.js",
|
|
410
424
|
"link-sync.js",
|
|
425
|
+
"link-routes.js",
|
|
411
426
|
"qr.js",
|
|
412
427
|
"record-entities.js",
|
|
413
428
|
"decide-by-model.js",
|
|
@@ -435,6 +450,11 @@
|
|
|
435
450
|
"fetched.js",
|
|
436
451
|
"context-window.js",
|
|
437
452
|
"compaction.js",
|
|
453
|
+
"context-select.js",
|
|
454
|
+
"own-instructions.js",
|
|
455
|
+
"digest.js",
|
|
456
|
+
"retrieval-plan.js",
|
|
457
|
+
"identity.js",
|
|
438
458
|
"promotion.js",
|
|
439
459
|
"queue.js",
|
|
440
460
|
"reach.js",
|
|
@@ -481,6 +501,7 @@
|
|
|
481
501
|
"sync-plan.js",
|
|
482
502
|
"synthesis.js",
|
|
483
503
|
"tags.js",
|
|
504
|
+
"thread-send.js",
|
|
484
505
|
"team-board.js",
|
|
485
506
|
"board-tool.js",
|
|
486
507
|
"team-cache.js",
|
|
@@ -555,6 +576,7 @@
|
|
|
555
576
|
"kokoro-text.js",
|
|
556
577
|
"weather-tool.js",
|
|
557
578
|
"weather.js",
|
|
579
|
+
"clock.js",
|
|
558
580
|
"web-search-tool.js",
|
|
559
581
|
"web-search.js",
|
|
560
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
|
-
${
|
|
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};
|
package/provider-presets.js
CHANGED
|
@@ -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};
|
package/research.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import{lexicalPlan as
|
|
1
|
+
import{lexicalPlan as oe}from"./recall.js";import{namesIn as re}from"./search-modes.js";import{recall as ie}from"./memory.js";import{splitForWindow as ae,partChars as q,partPrompt as le,mapParts as ce,reduceNotes as de}from"./stitch.js";import{normalizeCorrections as he}from"./search-modes.js";import{defineSchema as z,describeSchema as B,parseStructured as G}from"./structured.js";import{withoutOwnInstructions as H}from"./own-instructions.js";import{isSmallWindow as ue}from"./context-window.js";const F=Object.freeze({rounds:2,records:3,chunks:10,chunkChars:2800,parts:16,ms:6e4}),W=[["meeting",/\b(meetings?|calls?|standups?|syncs?|1:1s?|one[- ]on[- ]ones?)\b/i],["note",/\bnotes?\b/i],["chat",/\b(chats?|conversations?)\b/i]],K=/\b(last|latest|most recent|recent|newest)\b/i,Q=/\b(first|earliest|oldest)\b/i,me=/\b(how many|how often|number of|count)\b/i,pe=/\b(list|which|all (?:my|the)|every)\b/i,J=/\b(summari[sz]e|summary|what (?:was|is) it about|what was (?:discussed|said)|details?|in detail|tell me more|go deeper|deeper|explain|what did (?:we|they|he|she|i) (?:say|discuss|decide|talk about))\b/i,V=/^(?:meet|meets|met|meeting|talk|talked|speak|spoke|chat|chatted|most|often|frequent|frequently|common|top|people|attendees?|participants?|contacts?|shows?|attends?|joins?|busiest|months?|weeks?|days?|monthly|weekly|daily|per|each|every|count|many|much)$/i,Y=/\b(?:who (?:do|did|have) i (?:meet|met|talk(?:ed)?|speak|spoke|chat(?:ted)?)(?: with| to)?(?: the)? most(?: often)?|most (?:frequent|common|met) (?:people|attendees|participants|contacts)|top (?:people|attendees|participants|contacts)|who (?:shows up|attends|joins) (?:the )?most)\b/i,X=/\b(?:per|by|each|every|a) (month|week|day)\b|\b(monthly|weekly|daily)\b|\bwhich (month|week|day)\b|\bbusiest (month|week|day)\b/i,fe=/\b(who (?:else )?(?:was|were) (?:in|at|on|there)|who (?:joined|attended|spoke|was there)|attendees?|participants?|who (?:else )?(?:is|are) in)\b/i,we=/\b(even later|later than that|more recent|after that|newer)\b/i,ge=/\b(even earlier|earlier than that|before that|older)\b/i,be=/^\s*(?:no\b|nope\b|not that\b|it\b|that\b|this\b|and\b|also\b|what about\b|how about\b|what was it\b|summari[sz]e\b|more\b|even\b)/i,ye=/\b(\d{4}-\d{2}-\d{2}|(?:jan|feb|mar|apr|may|jun|jul|aug|sep|sept|oct|nov|dec)[a-z]*\.? \d{1,2}(?:st|nd|rd|th)?,? \d{4}|\d{1,2}(?:st|nd|rd|th)? (?:jan|feb|mar|apr|may|jun|jul|aug|sep|sept|oct|nov|dec)[a-z]* \d{4})\b/i;function ke(n){const s=ye.exec(String(n||""));if(!s)return 0;const d=Date.parse(s[1].replace(/(\d)(st|nd|rd|th)/i,"$1").replace(/\bsept\b/i,"sep"));return Number.isFinite(d)?d:0}function $e(n,{previous:s=null,knownNames:d=[],now:a=Date.now()}={}){const r=String(n||""),c=r.toLowerCase(),o=oe(r,{now:a}),p=d.filter(m=>m&&new RegExp(`\\b${String(m).toLowerCase().replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}\\b`).test(c)),k=[...new Set([...re(r),...p])],u=W.find(([,m])=>m.test(r))?.[0]||"",x=new Set(k.flatMap(m=>m.toLowerCase().split(/\s+/))),e={intent:Y.test(r)||X.test(r)?"group":fe.test(r)?"people":me.test(r)?"count":K.test(r)?"latest":Q.test(r)?"earliest":pe.test(r)?"list":J.test(r)?"detail":"find",kind:u,names:k,terms:o.terms.filter(m=>!x.has(m)&&!W.some(([,L])=>L.test(m))&&!K.test(m)&&!Q.test(m)),sort:"relevance",limit:8,since:o.sinceAt||0,after:0,before:0,readFull:J.test(r),followUp:!1,target:null,group:""};if(e.intent==="group"){const m=X.exec(r),L=m?(m[1]||m[2]||m[3]||m[4]||"").toLowerCase().replace(/ly$/,"").replace(/^dai$/,"day"):"";e.group=Y.test(r)?"person":L,e.group==="person"&&(e.kind=e.kind||"meeting"),e.terms=e.terms.filter($=>!V.test($)),e.limit=5}e.intent==="latest"&&(e.sort="newest",e.limit=5),e.intent==="earliest"&&(e.sort="oldest",e.limit=5),e.intent==="list"&&(e.limit=12),e.intent==="people"&&(e.sort="newest",e.limit=3,e.readFull=!0,e.kind=e.kind||"meeting");const b=s?.plan;if(b&&(be.test(r)||/\b(?:the|that|this) (?:meeting|call|chat|note)\b/i.test(r)||!k.length&&!u&&r.trim().split(/\s+/).length<=6)){e.followUp=!0,e.kind=e.kind||b.kind,e.names=e.names.length?e.names:b.names,e.terms=e.terms.length?e.terms:b.terms;const m=ke(s.answer);we.test(r)?(e.intent="latest",e.sort="newest",e.after=m?m+864e5:b.after,e.limit=5):ge.test(r)?(e.intent="earliest",e.sort="newest",e.before=m||b.before,e.limit=5):e.intent==="people"?e.target=s.top||null:e.readFull||/\b(it|that|this)\b/i.test(r)?(e.intent="detail",e.readFull=!0,e.target=s.top||null,e.sort=b.sort):(e.intent=b.intent,e.sort=b.sort)}return(e.intent==="latest"||e.intent==="earliest")&&(e.readFull=e.readFull||!1),e}function Se(n,s,d){if(n.length<=d)return n;const a=[...s.names||[],...s.terms||[]].map(c=>String(c).toLowerCase()).filter(c=>c.length>2),r=n.filter(c=>a.some(o=>c.text.toLowerCase().includes(o)));return[...r,...n.filter(c=>!r.includes(c))].slice(0,d).sort((c,o)=>c.at-o.at)}function xe(n,s,{chunkChars:d=F.chunkChars,max:a=F.chunks}={}){const r=String(n||""),c=[];for(let u=0;u<r.length;u+=d)c.push({at:u,text:r.slice(u,u+d)});const o=[...s.names||[],...s.terms||[]].map(u=>String(u).toLowerCase()).filter(u=>u.length>2);if(!o.length||c.length<=a)return c.slice(0,a);const p=c.filter(u=>o.some(x=>u.text.toLowerCase().includes(x))),k=c.filter(u=>!p.includes(u));return[...p,...k].slice(0,a).sort((u,x)=>u.at-x.at)}const E=n=>n?new Date(n).toISOString().slice(0,10):"",Ce=new RegExp("^\\s*(?:\\[\\s*\\d{1,2}:\\d{2}(?::\\d{2})?(?:\\s*[AaPp]\\.?[Mm]\\.?)?\\s*\\]\\s*|\\(?\\d{1,2}:\\d{2}(?::\\d{2})?(?:\\s*[AaPp]\\.?[Mm]\\.?)?\\)?\\s+)?(?:\\*\\*)?(\\p{Lu}[\\p{L}\\p{N}'. -]{0,48}?(?:\\s*[([][^()[\\]\\n]{1,40}[)\\]])?)(?:\\*\\*)?\\s*(?:_?\\(\\d{1,2}:\\d{2}(?::\\d{2})?\\)_?)?\\s*:\\s+\\S","gmu"),Ae=/^(https?|note|notes|summary|topics|action items|key moments|decisions?|risks?|questions?|meeting|transcript|date|time|duration|title|subject|agenda|location|attendees|participants|speakers?|recording|source|link|url|tags?|status|owner|next steps)$/i;function Ee(n){const s=new Map;for(const d of String(n||"").matchAll(Ce)){const a=d[1].replace(/\s*[([]\d{1,2}:\d{2}(?::\d{2})?[)\]]$/,"").trim(),r=a.replace(/\s*[([][^()[\]]*[)\]]$/,"").trim();if(!r||Ae.test(r))continue;const c=r.toLowerCase(),o=s.get(c);o?o.lines++:s.set(c,{name:a,lines:1})}return[...s.values()].sort((d,a)=>a.lines-d.lines)}function Le(n,s=""){if(!Array.isArray(n))return null;const d=o=>String(o||"").replace(/\s*[([][^()[\]]*[)\]]$/,"").trim().toLowerCase(),a=String(s||"").trim().toLowerCase(),r=o=>!!a&&(o===a||!a.includes(" ")&&o.split(/\s+/)[0]===a),c=new Map;for(const o of n){const p=d(o?.key);if(!p||r(p))continue;const k=c.get(p);k?k.count+=Number(o.count)||0:c.set(p,{key:String(o.key).trim(),count:Number(o.count)||0})}return[...c.values()].sort((o,p)=>p.count-o.count||o.key.localeCompare(p.key))}const Z=z({name:"frame",purpose:"what kind of question about the person's own records this is",fields:{intent:{type:"enum",values:["find","latest","earliest","count","group","people","list","detail"],required:!0,describe:"latest/earliest: the most recent or first one; count: how many; group: counts per person or per month/week/day; people: who was there; list: several items; detail: what one said or was about; find: anything else"},kind:{type:"enum",values:["","meeting","note","chat"],describe:"the kind of record asked about, or empty"},names:{type:"string[]",max:3,describe:"people named in the question, exactly as written; empty when none"},group:{type:"enum",values:["","person","month","week","day"],describe:"for group: what to count by; else empty"}}});function ve(n){return`Classify this question about the person's own chats, notes and meetings.
|
|
2
2
|
|
|
3
|
-
${
|
|
3
|
+
${B(Z)}
|
|
4
4
|
|
|
5
|
-
Question: ${String(n).slice(0,400)}`}const
|
|
5
|
+
Question: ${String(n).slice(0,400)}`}const ee=z({name:"evidence",purpose:"whether what was found answers the question",fields:{answered:{type:"enum",values:["yes","partly","no"],required:!0,describe:"yes when the found text answers the question, partly when it answers some of it, no when it does not"},missing:{type:"string",max:120,describe:"when not yes: a few search words (names, topics, dates) for what is missing; else empty"}}});function Te(n,s,{maxChars:d=6e3}={}){const a=String(s||"");return`Does the text found below answer the question? Judge only from the text.
|
|
6
6
|
|
|
7
|
-
${
|
|
7
|
+
${B(ee)}
|
|
8
8
|
|
|
9
9
|
Question: ${String(n).slice(0,400)}
|
|
10
10
|
|
|
11
11
|
---
|
|
12
|
-
${a.length>
|
|
13
|
-
…`:a}`}function
|
|
12
|
+
${a.length>d?`${a.slice(0,d)}
|
|
13
|
+
…`:a}`}function Re(n){const s={meeting:"meetings",note:"notes",chat:"chats"}[n.kind]||"records",d=n.names.length?` naming ${n.names.join(" and ")}`:"",a=n.terms.length?` about ${n.terms.slice(0,6).join(", ")}`:"",r=[n.after?`after ${E(n.after-864e5)}`:"",n.before?`before ${E(n.before)}`:"",n.since?`since ${E(n.since)}`:""].filter(Boolean).join(", "),c=n.sort==="newest"?", newest first":n.sort==="oldest"?", oldest first":", most relevant first";return`${s}${d}${a}${r?` ${r}`:""}${c}`}async function Ue(n,{query:s,readText:d,searchModes:a=null,complete:r=null,memories:c=[],previous:o=null,knownNames:p=[],limits:k=F,now:u=()=>Date.now(),mapWindow:x=0,answerWindow:e=0,parallel:b=1,corrections:m=null,self:L=""}={}){const $=u(),y={...F,...k},N=he(m),j=new Set(N.notNames),R=new Set(N.hidden),t=$e(n,{previous:o,knownNames:p.filter(l=>!j.has(String(l).toLowerCase())),now:$}),te=String(n||""),D={framedBy:"rules"};if(t.names=t.names.filter(l=>!j.has(String(l).toLowerCase())),t.target&&R.has(t.target)&&(t.target=null),r&&y.modelFrame!==!1&&t.intent==="find"&&!t.followUp&&!t.target){const l=await r(ve(n),{maxTokens:90}).catch(()=>""),h=G(l,Z);if(h){D.framedBy="model",h.intent&&h.intent!=="find"&&(t.intent=h.intent),!t.kind&&h.kind&&(t.kind=h.kind);const g=(h.names||[]).map(f=>String(f).trim()).filter(f=>f&&te.toLowerCase().includes(f.toLowerCase())&&!j.has(f.toLowerCase()));!t.names.length&&g.length&&(t.names=g.slice(0,3)),t.intent==="group"&&(t.group=h.group||(t.kind==="meeting"?"person":"month"),t.terms=t.terms.filter(f=>!V.test(f)),t.limit=5),t.intent==="latest"&&(t.sort="newest",t.limit=5),t.intent==="earliest"&&(t.sort="oldest",t.limit=5),t.intent==="list"&&(t.limit=12),t.intent==="detail"&&(t.readFull=!0),t.intent==="people"&&(t.sort="newest",t.limit=3,t.readFull=!0,t.kind=t.kind||"meeting")}}const i={plan:t,rows:[],count:null,read:[],rounds:0,ms:0,attachment:null,how:Re(t),...D};i.memory=ie(c,{text:`${n} ${t.names.join(" ")}`,includeAmbient:!1,limit:5}).map(l=>l.text);const C=()=>u()-$>y.ms;try{i.rounds=1;const l=await s(t)||{};i.rows=(l.rows||[]).filter(h=>!R.has(h.id)),i.count=Number.isFinite(l.count)?Math.max(0,l.count-((l.rows||[]).length-i.rows.length)):i.rows.length,i.groups=t.group==="person"?Le(l.groups,L):l.groups||null}catch{i.rows=[]}if(!i.rows.length&&!i.groups?.length&&a&&i.rounds<y.rounds&&!C()){i.rounds=2;try{const l=await a(n);i.rows=(l?.modes?.hybrid||[]).filter(h=>!h.echo&&!R.has(h.id)).slice(0,t.limit),i.how=`${i.how}; nothing matched that exactly, so a wider search of everything`}catch{}}if(!i.rows.length&&!t.target&&!i.groups?.length)return i.ms=u()-$,i.memory.length&&(i.attachment=_(n,i,{now:$})),i;const ne=["count","group"].includes(t.intent)?0:["latest","earliest","detail","people"].includes(t.intent)?1:y.records,se=t.target?[{id:t.target}]:i.rows.filter(l=>!String(l.id).startsWith("memory:")).slice(0,ne),I=q({windowTokens:x,reserveTokens:450}),M=async l=>{const h=await d(l.id).catch(()=>null),g=h?.text?H(h.text):"",f=h?.text?{...h,text:ue(e)?Fe(g):g}:h;if(!f?.text)return;const P=Ee(f.text),A=r&&t.readFull&&I>0,w=A?Se(ae(f.text,{maxChars:I}),t,y.parts):xe(f.text,t,{chunkChars:y.chunkChars,max:t.readFull?y.chunks:2}).map(v=>({...v,index:Math.floor(v.at/y.chunkChars)+1,of:Math.ceil(f.text.length/y.chunkChars)}));let S=[];r&&t.readFull&&t.intent!=="people"&&(S=(await ce(w,T=>r(le({question:n,title:f.title||l.title,date:E(f.date||l.date),speakers:P,part:T}),{maxTokens:A?400:220}),{concurrency:b,late:C})).map((T,U)=>T&&w.length>1?`[part ${w[U].index}/${w[U].of}] ${T}`:T).filter(Boolean)),S.length||(S=w.map(v=>v.text.replace(/\s+/g," ").trim()).filter(Boolean)),i.read.push({id:f.id||l.id,title:f.title||l.title,date:f.date||l.date,notes:S,chunks:w.length,of:w[0]?.of||1,speakers:P})};for(const l of se){if(C())break;await M(l)}if(r&&y.check!==!1&&a&&i.rounds<y.rounds&&!C()&&!["count","group","people","latest","earliest"].includes(t.intent)&&(i.read.length||i.rows.length)){const l=_(n,i,{now:$}),h=l?await r(Te(n,l.text),{maxTokens:80}).catch(()=>""):"",g=G(h,ee);if(i.verdict=g?.answered||null,g?.answered==="no"){i.rounds+=1;const f=[n,g.missing].filter(Boolean).join(" ").slice(0,600);try{const A=((await a(f))?.modes?.hybrid||[]).filter(w=>!w.echo&&!R.has(w.id)&&!i.rows.some(S=>S.id===w.id));if(A.length){i.rows.push(...A.slice(0,5)),i.how=`${i.how}; what that found did not answer it, so a wider search${g.missing?` for "${String(g.missing).slice(0,80)}"`:""}`;const w=A.find(S=>!String(S.id).startsWith("memory:"));w&&!C()&&await M(w)}}catch{}}}const O=q({windowTokens:e,reserveTokens:1024,frameTokens:900});if(O>0&&i.read.length){i.fitted=!0;const l=Math.floor(O/i.read.length);for(const h of i.read)h.notes=await de(h.notes,{question:n,budgetChars:l,batchChars:I||l,complete:r?g=>r(g,{maxTokens:500}):null,concurrency:b,late:C})}return i.ms=u()-$,i.attachment=_(n,i,{now:$}),i}function _(n,s,{now:d=Date.now()}={}){const a=[];s.memory?.length&&a.push("Kept by the person (memory):",...s.memory.map(o=>`- [memory] ${o}`),""),a.push(`Searched ${s.how}${s.count!=null&&s.plan.intent!=="detail"?` — ${s.count} found`:""}.`),s.groups?.length&&a.push("","Grouped:",...s.groups.slice(0,24).map(o=>`- ${o.key}: ${o.count}`)),s.rows.length&&(a.push("","Found:"),s.rows.slice(0,12).forEach((o,p)=>a.push(`${p+1}. [${o.id}] ${o.title||""}${o.date?` — ${E(o.date)}`:""}${o.snippet?` — ${H(String(o.snippet).replace(/\s+/g," ")).slice(0,160)}`:""}`)));for(const o of s.read)a.push("",`Read [${o.id}] "${o.title}"${o.date?` (${E(o.date)})`:""} — ${o.chunks} of ${o.of} part${o.of===1?"":"s"}:`),(s.plan.intent==="people"||o.speakers?.length>1)&&a.push(` Speakers (lines spoken): ${(o.speakers||[]).map(p=>`${p.name} (${p.lines})`).join(", ")||"none recorded"}`),s.plan.intent!=="people"&&a.push(...o.notes.map(p=>` ${s.fitted?p:p.slice(0,1600)}`));if(!s.rows.length&&!s.read.length&&!s.memory?.length&&!s.groups?.length)return null;const c=`(ALREADY RESEARCHED the person's own data for the question below — the whole store, not a guess. ${s.plan.intent==="latest"?"The FIRST found item is the most recent; answer with its date.":s.plan.intent==="earliest"?"The FIRST found item is the earliest; answer with its date.":s.plan.intent==="count"?"Answer with the count found.":s.plan.intent==="group"?s.groups?.length?"Answer from the grouped counts; they cover the whole store.":"The store could not group this; say so, and answer from what was found.":s.plan.intent==="people"?"Answer with the speakers listed for the meeting read.":"Answer from what was read."} Cite the [id] you use. If the answer is not here, say it was not found in their data; never guess and never say you have no access.)
|
|
14
14
|
|
|
15
15
|
${a.join(`
|
|
16
|
-
`)}`;return{id:`prefetch_research_${
|
|
16
|
+
`)}`;return{id:`prefetch_research_${d}`,kind:"prefetch",prefetch:"personal",title:"Researched your own data",text:c,chars:c.length}}function Fe(n){return String(n||"").replace(/^(\s*)User:\s/gm,"$1(they asked) ").replace(/^(\s*)Assistant:\s/gm,"$1(the answer was) ")}export{ee as EVIDENCE_SCHEMA,Z as FRAME_SCHEMA,F as RESEARCH_LIMITS,xe as chunksFor,ke as dateIn,Re as describePlan,Te as evidencePrompt,ve as framePrompt,$e as frameQuestion,Le as peopleGroups,Fe as quotedTurns,Ue as research,_ as researchAttachment,Ee as speakersIn};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{needsWhole as $}from"./digest.js";import{lookupSubject as I,prefetchPlan as C,answeredByPrefetch as D}from"./prefetch.js";import{partChars as E,STITCH_LIMITS as _}from"./stitch.js";import{isSmallWindow as x,FIT_HEADROOM as L,SMALL_WINDOW_ROUNDS as v}from"./context-window.js";const P=4,W={device:3,api:2,agent:8};function V({question:o="",sources:t=[],fixedTokens:n=0,target:l={}}={}){const c=l.kind||"api",a=Number(l.window)||0,s=x(a),d=$(o),g=Math.max(1,Number(l.concurrency)||(c==="device"?1:4)),b=Number(l.secondsPerCall)||W[c]||2,i=(Array.isArray(t)?t:[]).filter(Boolean).map(e=>({...e,chars:Math.max(0,Number(e.chars)||0)})),m=a?Math.floor(a*L)-(Number(l.reserve)||1024)-(Number(n)||0):1/0,y=Number.isFinite(m)?Math.max(0,m)*P:1/0,u=new Map,h=new Set;let f=y;for(let e=!0;e;){e=!1;const r=i.filter(w=>!h.has(w.id)),p=r.length?f/r.length:0;for(const w of r)w.chars<=p&&(h.add(w.id),f-=w.chars,e=!0)}const T=i.filter(e=>!h.has(e.id)).reduce((e,r)=>e+r.chars,0);for(const e of i)u.set(e.id,h.has(e.id)?e.chars:Math.floor(f*e.chars/(T||1)));const k=E({windowTokens:a,reserveTokens:450})||0,M=i.map(e=>{const r={id:e.id,kind:e.kind,title:e.title||"",chars:e.chars,share:u.get(e.id)};if(c==="agent")return{...r,how:"agent",calls:0,why:"an agent reads it itself — handed the material, not a digest"};if(h.has(e.id)||!Number.isFinite(y))return{...r,how:"whole",calls:0,why:"it fits"};if(!s)return{...r,how:"merge",calls:Math.ceil(e.chars/Math.max(1,r.share)),why:"a large window: what does not fit is merged by the model"};if(d&&k>0){const p=Math.min(_.parts,Math.ceil(e.chars/k)),w=Math.ceil(e.chars/k),R=Math.max(1,Math.ceil(p/4));return{...r,how:"digest",parts:p,calls:p+R,unread:Math.max(0,w-p),why:"the question needs all of it, and it does not fit: read in parts, the notes combined"}}return{...r,how:"cut",calls:0,why:d?"no room to read it in parts: the parts that bear on the question":"a focused question: the parts that bear on it, by relevance"}}),A=i.some(e=>e.prefetched),O=c==="agent"?{offer:!0,rounds:null,why:"an agent keeps its own tools"}:s&&A?{offer:!1,rounds:1,why:"a small window, and a prefetch already answered"}:s?{offer:!0,rounds:v,why:"a small window: one tool round, then the answer"}:{offer:!0,rounds:null,why:""},N=M.reduce((e,r)=>e+(r.calls||0),0),S=Math.round((Math.ceil(N/g)+1)*b);return{sources:M,tools:O,estimate:{calls:N+1,seconds:S},say:F(M,S)}}function F(o,t){const n=o.filter(s=>s.how==="digest");if(!n.length)return"";const l=n.length===1?`"${n[0].title||"what is attached"}"`:`${n.length} attachments`,c=n.reduce((s,d)=>s+d.parts,0),a=n.reduce((s,d)=>s+(d.unread||0),0);return`Reading all of ${l} in ${c} part${c===1?"":"s"} first, so the answer covers the whole of it${a?` (the last ${a} part${a===1?"":"s"} will not fit)`:""} — about ${t} s.`}const q=/\b(?:schedule|reschedule|remind(?:er)?|calendar|invite|e-?mail|inbox|send|reply|draft|create|add|save|write (?:a |an )?note|open|click|fill|book|order|cancel|delete|rename|move|upload|download|run|execute|deploy|commit|share|post)\b/i,H=/\b(?:find out|find more|more (?:info|information|details)|look into|latest|current(?:ly)?|today|tonight|tomorrow|right now|this (?:week|weekend|month|year)|price|prices|cost|stock|shares?|score|news|headlines?|weather|forecast|hours|near me|nearby|directions|traffic|flight|look (?:it |that )?up|search|google|website|link|url|https?:\/\/|who(?:'s| is| was| are)|where(?:'s| is| are)|when(?:'s| is| does| do))\b/i,U=/\b(?:my|mine|our|ours|we|us|did i|have i|i (?:said|asked|wrote|told|had|was)|remember|last time|earlier today|meetings?|notes?|transcripts?|conversations?|chats?)\b/i;function j(o){const t=String(o||"").trim();return t?q.test(t)||H.test(t)||U.test(t)||!!I(t):!1}const B=new Set(["weather","stock","news","page","web","research"]);function X(o=[]){return(Array.isArray(o)?o:[]).some(t=>t?.kind==="prefetch"&&B.has(t.prefetch)&&String(t.text||"").trim())}function K({window:o=0,question:t="",answered:n=!1}={}){return x(o)?n?{offer:!1,rounds:1,why:"a small window, and a prefetch already answered"}:j(t)?{offer:!0,rounds:v,why:"a small window: one tool round, then the answer"}:{offer:!1,rounds:1,why:"a small window, and a question that needs no tools"}:{offer:!0,rounds:null,why:""}}function Y({question:o="",previousText:t="",previousAnswer:n="",previous:l=null,reach:c=new Set,window:a=0,personal:s=!1,lookup:d=null,now:g=Date.now()}={}){const b=x(a),i=C({text:o,previous:l,previousText:t,previousAnswer:n,reach:c,research:!0,page:!0,lookup:d??b,now:g}),m=i.some(f=>["weather","stock","news","page","web","research"].includes(f.kind)),y=!!s&&!m,u=[];i.length&&u.push(`fetch first: ${i.map(f=>f.label||f.kind).join(", ")}`),s&&m&&u.push("a world fact — the person's history is not searched for it");const h=K({window:a,question:o,answered:i.length>0});return h.why&&u.push(h.why),{prefetch:i,world:m,research:y,tools:h,why:u}}export{D as answeredByPrefetch,V as planRetrieval,Y as planTurn,K as toolPlan,j as toolsWanted,X as worldAnswered};
|
package/sandbox-policy.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{EventError as L}from"./event.js";import{normalizeGrant as x}from"./sandbox-grant.js";import{SECRET_DIR_NAMES as P,SECRET_DIR_PAIRS as N}from"./secret-names.js";const R=Object.freeze(["none","process","container","kubernetes"]),S=Object.freeze(["open","allowlist","none","gateway"]),E=Object.freeze(["~/.chatpanel","~/.ssh","~/.gnupg","~/.aws","~/.azure","~/.config/gcloud","~/.kube","~/.netrc","~/.docker/config.json","~/.npmrc","~/.pypirc"]),g=e=>{let t=String(e||"").trim();for(;t.length>1&&(t.endsWith("/")||t.endsWith("\\"));)t=t.slice(0,-1);return t},_=(e,t)=>t&&(e==="~"||e.startsWith("~/")||e.startsWith("~\\"))?t+e.slice(1):e,m=e=>String(e||"").replace(/\\/g,"/"),b=(e,t)=>{const n=m(g(e)),r=m(g(t));return!!n&&!!r&&(n===r||n.startsWith(`${r}/`))},v=E.map(e=>m(g(e)).replace(/^~\//,"").split("/").filter(Boolean));function I(e,t=""){const n=m(g(_(g(e),t)));if(!n)return!1;for(const o of E)if(b(n,o)||t&&b(n,_(o,t)))return!0;const r=n.split("/").filter(Boolean).map(o=>o.toLowerCase());return v.some(o=>{for(let s=0;s+o.length<=r.length;s+=1)if(o.every((c,l)=>c.toLowerCase()===r[s+l]))return!0;return!1})}const $=Object.freeze([...[...P].map(e=>`~/**/${e}`),...N.map(([e,t])=>`~/**/${e}/${t}`),...[".env",".netrc","_netrc",".git-credentials",".pgpass",".my.cnf",".npmrc",".pypirc",".htpasswd",".terraformrc",".vault-token","credentials","credentials.toml","id_rsa","id_dsa","id_ecdsa","id_ed25519","*.pem","*.p12","*.pfx","*.jks","*.keystore","*.kdbx","*.ppk"].map(e=>`~/**/${e}`)]);function J(e,{home:t="",globs:n=[...E,...$]}={}){const r=m(g(_(g(e),t)));if(!r)return null;const o=r.split("/").filter(Boolean),s=m(g(t));for(const c of n){const l=m(g(c));if(l){if(l.startsWith("~/**/")){if(s&&!b(r,s))continue;const a=l.slice(5).split("/").filter(Boolean).map(z);for(let i=0;i+a.length<=o.length;i+=1)if(a.every((f,p)=>f.test(o[i+p])))return c;continue}if(b(r,_(l,t)))return c}}return null}function z(e){return new RegExp(`^${e.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*/g,"[^/]*")}$`,"i")}const W=".cache/chatpanel/ca-bundle.crt",ee=".cache/chatpanel/ca-bundle.pem";function te(e=""){const t=m(g(e));return t?`${t}/${W}`:`~/${W}`}const H=Object.freeze(["~/.npm","~/.cache","~/.local","~/Library/Caches","~/.nvm","~/.volta","~/.asdf","~/.nodenv","~/.bun","~/.deno","~/.pyenv","~/.rye","~/.pdm","~/.cargo","~/.rustup","~/go","~/.goenv","~/.m2","~/.gradle","~/.sdkman","~/.jenv","~/.gem","~/.rbenv","~/.bundle","~/.composer","~/.nuget","~/.dotnet","~/.stack","~/.ghcup","~/.opam","~/.pub-cache","~/.gitconfig","~/.config/git"]),D=Object.freeze(["/tmp","/private/tmp","~/.cache","~/.npm","~/.local/share/uv","~/.local/state"]),C=Object.freeze({codex:Object.freeze({hosts:["api.openai.com","chatgpt.com","auth.openai.com","*.openai.com"],write:["~/.codex"]}),claude:Object.freeze({hosts:["api.anthropic.com","*.anthropic.com","claude.ai","statsig.anthropic.com"],write:["~/.claude","~/.claude.json"],keychain:!0}),antigravity:Object.freeze({hosts:["*.googleapis.com","*.google.com","oauth2.googleapis.com"],write:["~/.gemini","~/.antigravity","~/.config/antigravity"]}),custom:Object.freeze({hosts:[],write:[]}),mcp:Object.freeze({hosts:[],write:[]}),extract:Object.freeze({hosts:[],write:[]}),"model-server":Object.freeze({hosts:["huggingface.co","*.huggingface.co","*.hf.co","cdn-lfs.huggingface.co","cas-bridge.xethub.hf.co","dl.chatpanel.net"],write:[]})}),T="~/Library/Keychains",K=/(^|\/)Keychains\/?$/,k=Object.freeze(["github.com","*.github.com","*.githubusercontent.com","gitlab.com","bitbucket.org","registry.npmjs.org","pypi.org","files.pythonhosted.org","crates.io","static.crates.io","proxy.golang.org","sum.golang.org","huggingface.co","*.huggingface.co"]),h=e=>!!e&&typeof e=="object"&&!Array.isArray(e),O=e=>Array.isArray(e)&&e.every(t=>typeof t=="string"&&t.length>0),d=(e,t)=>{if(!e)throw new L("SHAPE",t)},u=e=>[...new Set(e)];function j(e){d(h(e),"kit: must be an object"),d(typeof e.id=="string"&&e.id.length>0,"kit: id required"),d(h(e.network)&&S.includes(e.network.mode),`kit ${e.id}: network.mode must be one of ${S.join(", ")}`),d(O(e.network.allowedDomains||[]),`kit ${e.id}: network.allowedDomains must be string[]`),d(O(e.network.deniedDomains||[]),`kit ${e.id}: network.deniedDomains must be string[]`),d(h(e.filesystem),`kit ${e.id}: filesystem required`);for(const t of["allowWrite","denyWrite","allowRead","denyRead"])d(O(e.filesystem[t]||[]),`kit ${e.id}: filesystem.${t} must be string[]`);return d(O(e.filesystem.allowWrite)&&e.filesystem.allowWrite.length>0,`kit ${e.id}: filesystem.allowWrite must name at least the working directory`),e.image!=null&&d(typeof e.image=="string",`kit ${e.id}: image must be a string`),e.credentials!=null&&d(Array.isArray(e.credentials)&&e.credentials.every(t=>h(t)&&typeof t.name=="string"&&typeof t.forHost=="string"),`kit ${e.id}: credentials must be [{ name, forHost }]`),{id:e.id,kind:e.kind||"process",image:e.image||null,network:{mode:e.network.mode,allowedDomains:u(e.network.allowedDomains||[]),deniedDomains:u(e.network.deniedDomains||[])},filesystem:{allowWrite:u(e.filesystem.allowWrite),denyWrite:u(e.filesystem.denyWrite||[]),allowRead:u(e.filesystem.allowRead||[]),denyRead:u(e.filesystem.denyRead||[])},credentials:e.credentials||[],limits:h(e.limits)?{...e.limits}:{}}}import{normalizeGrant as pe,mergeGrants as ge,parseHostList as me}from"./sandbox-grant.js";const Y=e=>String(e).replace(/([\\/])\*$/,"$1**");function ne({engine:e="custom",cwd:t,mode:n="open",extraHosts:r=[],extraWrite:o=[],extraDenyRead:s=[],grant:c=null,home:l="",reads:a="enumerated",readOnly:i=!1}={}){const f=C[e]||C.custom;d(typeof t=="string"&&t.length>0,"kit: cwd required");const p=x(c);return j({id:`${e}:${n}`,kind:"process",network:{mode:n,allowedDomains:n==="open"?["*"]:n==="none"?[]:u([...f.hosts,...k,...r,...p.hosts]),deniedDomains:[]},filesystem:{allowWrite:u(i?[...D,...f.write]:[t,...D,...f.write,...[...o,...p.write].filter(A=>!I(A,l)).map(Y)]),denyWrite:[],allowRead:a==="inverted"?u([t,...H,...f.write,...f.keychain?[T]:[],...B({grant:p,extraWrite:o,cwd:t,home:l})]):[t],denyRead:u([...a==="inverted"?["~",...l?[l]:[]]:[],...[...E,...$].filter(A=>!(f.keychain&&K.test(A))),...s])}})}function U(e){if(!/[*?[{]/.test(e))return e;const t=e.split(/[\\/]/),n=t.findIndex(s=>/[*?[{]/.test(s)),r=e.includes("\\")&&!e.includes("/")?"\\":"/",o=t.slice(0,n).join(r);return o&&o!=="~"?o:""}function B({grant:e=null,extraWrite:t=[],cwd:n="",home:r=""}={}){const o=i=>r&&(i==="~"||i.startsWith("~/")||i.startsWith("~\\"))?r+i.slice(1):i,s=i=>{let f=String(i||"").trim();for(;f.length>1&&(f.endsWith("/")||f.endsWith("\\"));)f=f.slice(0,-1);return f},c=(i,f)=>i===f||i.startsWith(`${f}/`)||i.startsWith(`${f}\\`),l=s(o(n)),a=[];for(const i of[...x(e).write,...Array.isArray(t)?t:[]]){const f=U(s(o(s(i))));if(f&&!I(f,r)&&!(l&&c(f,l))&&!a.some(p=>c(f,p))){for(let p=a.length-1;p>=0;p--)c(a[p],f)&&a.splice(p,1);a.push(f)}}return a}function oe(e,{loopback:t=[],home:n="",platform:r="darwin"}={}){const o=j(e),s=l=>n&&l.startsWith("~")?n+l.slice(1):l,c=o.network.mode==="none"?[]:t.map(l=>`127.0.0.1:${l}`);return{network:{allowedDomains:u([...o.network.allowedDomains,...c]),deniedDomains:o.network.deniedDomains,allowLocalBinding:r==="darwin"&&c.length>0},filesystem:{denyRead:o.filesystem.denyRead.map(s),allowRead:o.filesystem.allowRead.map(s),allowWrite:o.filesystem.allowWrite.map(s),denyWrite:o.filesystem.denyWrite.map(s)}}}function re({layer:e="none",runtime:t=null,kitId:n=null,mode:r=null,reason:o=null,hosts:s=null}={}){return d(R.includes(e),`sandbox record: layer must be one of ${R.join(", ")}`),{layer:e,runtime:t,kit:n,mode:r,...e==="none"&&o?{reason:o}:{},...Array.isArray(s)&&s.length?{hosts:u(s)}:{}}}function G(e,{platform:t="darwin"}={}){const n=String(e);if(t==="win32"){d(!/[\r\n]/.test(n),"win32 command line: an argument holds a newline, which cmd.exe cannot carry");let r=n;if(n===""||/[ \t\v"]/.test(n)){r='"';for(let o=0;o<n.length;o++){let s=0;for(;o<n.length&&n[o]==="\\";)s++,o++;if(o===n.length){r+="\\".repeat(s*2);break}n[o]==='"'?r+="\\".repeat(s*2+1)+'"':r+="\\".repeat(s)+n[o]}r+='"'}return r.replace(/[()%!^"<>&|]/g,"^$&")}return n===""?"''":/^[A-Za-z0-9_\-./=:@%+,]+$/.test(n)?n:`'${n.replace(/'/g,"'\\''")}'`}const M=Object.freeze(["SSL_CERT_FILE","REQUESTS_CA_BUNDLE","CURL_CA_BUNDLE","GIT_SSL_CAINFO"]);function se(e={},{platform:t="darwin",caBundle:n=""}={}){const r={NODE_USE_ENV_PROXY:"1"};if(n)for(const o of M)e[o]||(r[o]=n);if(t==="linux")for(const o of["no_proxy","NO_PROXY"])typeof e[o]=="string"&&(r[o]=e[o].split(",").map(s=>s.trim()).filter(s=>s&&!/^(localhost|127\.0\.0\.1|::1|\[::1\])$/i.test(s)).join(","));return r}function ie(e,t=[],{platform:n="darwin"}={}){return[e,...t].map(r=>G(r,{platform:n})).join(" ")}const ae=/[\\/]+/,w=e=>String(e||"").replace(/\//g,"\\").replace(/\\+$/,"").toLowerCase(),q=e=>/^[a-z]:$/i.test(w(e))||w(e)==="";function y(e,t){const n=w(e),r=w(t);return!!r&&n!==r&&n.startsWith(r+"\\")}function F(e){const t=String(e||"").replace(/\//g,"\\").split("\\");if(t.length<2)return"";const n=t.findIndex(r=>r.toLowerCase()==="node_modules");return(n>0?t.slice(0,n):t.slice(0,-1)).join("\\")}function ce({kit:e,files:t=[],home:n}){d(typeof n=="string"&&n.length>0,"windows grants: home required");const r=a=>(a.startsWith("~")?n+a.slice(1):a).replace(/\//g,"\\"),o=[];for(const a of e?.filesystem?.allowWrite||[]){const i=r(a);!/^[a-z]:\\/i.test(i)&&!i.startsWith("\\\\")||(d(!q(i)&&w(i)!==w(n),`windows grants: a write on ${i} would hand the sandbox account the whole profile`),y(i,n)&&o.push(i))}const s=(a,i)=>i.some(f=>w(a)===w(f)||y(a,f)),c=[];for(const a of t){const i=F(a);i&&y(i,n)&&c.push(i)}for(const a of e?.filesystem?.allowRead||[]){const i=r(a);y(i,n)&&c.push(i)}const l=u(c).filter(a=>!s(a,o));return{read:l.filter(a=>!l.some(i=>i!==a&&y(a,i))),write:u(o)}}const X=Object.freeze(["ANTHROPIC_API_KEY","ANTHROPIC_AUTH_TOKEN","ANTHROPIC_BASE_URL","CLAUDE_CONFIG_DIR","OPENAI_API_KEY","OPENAI_BASE_URL","OPENAI_API_BASE","CODEX_HOME","GEMINI_API_KEY","GOOGLE_API_KEY","DEEPSEEK_API_KEY","DSH_HOME","OPENROUTER_API_KEY","GROQ_API_KEY","XAI_API_KEY","MISTRAL_API_KEY"]);function le({engine:e="custom",home:t,env:n={},base:r={},carry:o=X}={}){d(typeof t=="string"&&t.length>0,"windows env: home required");const s=t.replace(/\//g,"\\"),c=/^[a-z]:/i.test(s)?s.slice(0,2):"",l={USERPROFILE:s,...c?{HOMEDRIVE:c,HOMEPATH:s.slice(2)}:{}};for(const[a,i]of Object.entries(n))typeof i=="string"&&(r[a]!==i||o.includes(a))&&(l[a]=i);return e==="codex"&&!l.CODEX_HOME&&(l.CODEX_HOME=s+"\\.codex"),l}function fe(e,t){d(Array.isArray(e),"srt-win argv: must be an array");const n=e.indexOf("exec"),r=n>=0?e.indexOf("--",n+1):-1;d(n>=0&&r>n,"srt-win argv: expected `exec … -- <shell> <command>`");const o=new Set;for(let c=n+1;c<r;c++)e[c]==="--env"&&typeof e[c+1]=="string"&&o.add(e[c+1].split("=")[0].toUpperCase());const s=[];for(const[c,l]of Object.entries(t||{}))d(/^[A-Za-z_][A-Za-z0-9_]*$/.test(c),`srt-win env: bad key ${c}`),d(!/[\r\n]/.test(l),`srt-win env: ${c} holds a newline`),o.has(c.toUpperCase())||s.push("--env",`${c}=${l}`);return[...e.slice(0,r),...s,...e.slice(r)]}export{W as CA_BUNDLE_RELPATH,ee as CA_BUNDLE_RELPATH_LEGACY,D as COMMON_WRITE,k as DEVELOPER_HOSTS,C as ENGINE_KITS,S as NETWORK_MODES,R as SANDBOX_LAYERS,E as SECRET_PATHS,$ as SECRET_READ_GLOBS,H as TOOLCHAIN_READ,X as WINDOWS_CARRY_KEYS,te as caBundlePath,I as isSecretWritePath,ne as kitFor,ge as mergeGrants,pe as normalizeGrant,me as parseHostList,J as readDenialFor,se as sandboxEnvOverlay,re as sandboxRecord,ie as shellJoin,G as shellQuote,oe as toSrtSettings,y as underWindowsHome,j as validateKit,ce as windowsGrantsFor,F as windowsInstallRoot,le as windowsSandboxEnv,fe as withSrtWinEnv,B as writableRoots};
|
|
1
|
+
import{EventError as L}from"./event.js";import{normalizeGrant as S}from"./sandbox-grant.js";import{SECRET_DIR_NAMES as P,SECRET_DIR_PAIRS as v}from"./secret-names.js";const R=Object.freeze(["none","process","container","kubernetes"]),$=Object.freeze(["open","allowlist","none","gateway"]),_=Object.freeze(["~/.chatpanel","~/.ssh","~/.gnupg","~/.aws","~/.azure","~/.config/gcloud","~/.kube","~/.netrc","~/.docker/config.json","~/.npmrc","~/.pypirc"]),g=e=>{let t=String(e||"").trim();for(;t.length>1&&(t.endsWith("/")||t.endsWith("\\"));)t=t.slice(0,-1);return t},x=(e,t)=>t&&(e==="~"||e.startsWith("~/")||e.startsWith("~\\"))?t+e.slice(1):e,m=e=>String(e||"").replace(/\\/g,"/"),b=(e,t)=>{const n=m(g(e)),r=m(g(t));return!!n&&!!r&&(n===r||n.startsWith(`${r}/`))},N=_.map(e=>m(g(e)).replace(/^~\//,"").split("/").filter(Boolean));function I(e,t=""){const n=m(g(x(g(e),t)));if(!n)return!1;for(const o of _)if(b(n,o)||t&&b(n,x(o,t)))return!0;const r=n.split("/").filter(Boolean).map(o=>o.toLowerCase());return N.some(o=>{for(let s=0;s+o.length<=r.length;s+=1)if(o.every((a,l)=>a.toLowerCase()===r[s+l]))return!0;return!1})}const W=Object.freeze([...[...P].map(e=>`~/**/${e}`),...v.map(([e,t])=>`~/**/${e}/${t}`),...[".env",".netrc","_netrc",".git-credentials",".pgpass",".my.cnf",".npmrc",".pypirc",".htpasswd",".terraformrc",".vault-token","credentials","credentials.toml","id_rsa","id_dsa","id_ecdsa","id_ed25519","*.pem","*.p12","*.pfx","*.jks","*.keystore","*.kdbx","*.ppk"].map(e=>`~/**/${e}`)]);function ee(e,{home:t="",globs:n=[..._,...W]}={}){const r=m(g(x(g(e),t)));if(!r)return null;const o=r.split("/").filter(Boolean),s=m(g(t));for(const a of n){const l=m(g(a));if(l){if(l.startsWith("~/**/")){if(s&&!b(r,s))continue;const c=l.slice(5).split("/").filter(Boolean).map(z);for(let i=0;i+c.length<=o.length;i+=1)if(c.every((d,u)=>d.test(o[i+u])))return a;continue}if(b(r,x(l,t)))return a}}return null}function z(e){return new RegExp(`^${e.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*/g,"[^/]*")}$`,"i")}const D=".cache/chatpanel/ca-bundle.crt",te=".cache/chatpanel/ca-bundle.pem";function ne(e=""){const t=m(g(e));return t?`${t}/${D}`:`~/${D}`}const H=Object.freeze(["~/.npm","~/.cache","~/.local","~/Library/Caches","~/.nvm","~/.volta","~/.asdf","~/.nodenv","~/.bun","~/.deno","~/.pyenv","~/.rye","~/.pdm","~/.cargo","~/.rustup","~/go","~/.goenv","~/.m2","~/.gradle","~/.sdkman","~/.jenv","~/.gem","~/.rbenv","~/.bundle","~/.composer","~/.nuget","~/.dotnet","~/.stack","~/.ghcup","~/.opam","~/.pub-cache","~/.gitconfig","~/.config/git"]),k=Object.freeze(["/tmp","/private/tmp","~/.cache","~/.npm","~/.local/share/uv","~/.local/state"]),C=Object.freeze({codex:Object.freeze({hosts:["api.openai.com","chatgpt.com","auth.openai.com","*.openai.com"],write:["~/.codex"]}),claude:Object.freeze({hosts:["api.anthropic.com","*.anthropic.com","claude.ai","statsig.anthropic.com"],write:["~/.claude","~/.claude.json"],keychain:!0,sockets:["/tmp/cc-socks","/private/tmp/cc-socks"]}),antigravity:Object.freeze({hosts:["*.googleapis.com","*.google.com","oauth2.googleapis.com"],write:["~/.gemini","~/.antigravity","~/.config/antigravity"]}),custom:Object.freeze({hosts:[],write:[]}),mcp:Object.freeze({hosts:[],write:[]}),extract:Object.freeze({hosts:[],write:[]}),"model-server":Object.freeze({hosts:["huggingface.co","*.huggingface.co","*.hf.co","cdn-lfs.huggingface.co","cas-bridge.xethub.hf.co","dl.chatpanel.net"],write:[]})}),T="~/Library/Keychains",K=/(^|\/)Keychains\/?$/,Y=Object.freeze(["github.com","*.github.com","*.githubusercontent.com","gitlab.com","bitbucket.org","registry.npmjs.org","pypi.org","files.pythonhosted.org","crates.io","static.crates.io","proxy.golang.org","sum.golang.org","huggingface.co","*.huggingface.co"]),h=e=>!!e&&typeof e=="object"&&!Array.isArray(e),y=e=>Array.isArray(e)&&e.every(t=>typeof t=="string"&&t.length>0),f=(e,t)=>{if(!e)throw new L("SHAPE",t)},p=e=>[...new Set(e)];function j(e){f(h(e),"kit: must be an object"),f(typeof e.id=="string"&&e.id.length>0,"kit: id required"),f(h(e.network)&&$.includes(e.network.mode),`kit ${e.id}: network.mode must be one of ${$.join(", ")}`),f(y(e.network.allowedDomains||[]),`kit ${e.id}: network.allowedDomains must be string[]`),f(y(e.network.deniedDomains||[]),`kit ${e.id}: network.deniedDomains must be string[]`),f(h(e.filesystem),`kit ${e.id}: filesystem required`);for(const t of["allowWrite","denyWrite","allowRead","denyRead"])f(y(e.filesystem[t]||[]),`kit ${e.id}: filesystem.${t} must be string[]`);return f(y(e.filesystem.allowWrite)&&e.filesystem.allowWrite.length>0,`kit ${e.id}: filesystem.allowWrite must name at least the working directory`),f(y(e.network.unixSockets||[])&&(e.network.unixSockets||[]).every(t=>t.startsWith("/")&&t.replace(/\/+$/,"")!==""),`kit ${e.id}: network.unixSockets must be absolute folders, never /`),e.image!=null&&f(typeof e.image=="string",`kit ${e.id}: image must be a string`),e.credentials!=null&&f(Array.isArray(e.credentials)&&e.credentials.every(t=>h(t)&&typeof t.name=="string"&&typeof t.forHost=="string"),`kit ${e.id}: credentials must be [{ name, forHost }]`),{id:e.id,kind:e.kind||"process",image:e.image||null,network:{mode:e.network.mode,allowedDomains:p(e.network.allowedDomains||[]),deniedDomains:p(e.network.deniedDomains||[]),...(e.network.unixSockets||[]).length?{unixSockets:p(e.network.unixSockets)}:{}},filesystem:{allowWrite:p(e.filesystem.allowWrite),denyWrite:p(e.filesystem.denyWrite||[]),allowRead:p(e.filesystem.allowRead||[]),denyRead:p(e.filesystem.denyRead||[])},credentials:e.credentials||[],limits:h(e.limits)?{...e.limits}:{}}}import{normalizeGrant as ge,mergeGrants as me,parseHostList as we}from"./sandbox-grant.js";const U=e=>String(e).replace(/([\\/])\*$/,"$1**");function oe({engine:e="custom",cwd:t,mode:n="open",extraHosts:r=[],extraWrite:o=[],extraDenyRead:s=[],grant:a=null,home:l="",reads:c="enumerated",readOnly:i=!1,peers:d=!0}={}){const u=C[e]||C.custom;f(typeof t=="string"&&t.length>0,"kit: cwd required");const O=S(a);return j({id:`${e}:${n}`,kind:"process",network:{mode:n,allowedDomains:n==="open"?["*"]:n==="none"?[]:p([...u.hosts,...Y,...r,...O.hosts]),deniedDomains:[],unixSockets:d?[...u.sockets||[]]:[]},filesystem:{allowWrite:p(i?[...k,...u.write]:[t,...k,...u.write,...[...o,...O.write].filter(A=>!I(A,l)).map(U)]),denyWrite:[],allowRead:c==="inverted"?p([t,...H,...u.write,...u.keychain?[T]:[],...G({grant:O,extraWrite:o,cwd:t,home:l})]):[t],denyRead:p([...c==="inverted"?["~",...l?[l]:[]]:[],...[..._,...W].filter(A=>!(u.keychain&&K.test(A))),...s])}})}function B(e){if(!/[*?[{]/.test(e))return e;const t=e.split(/[\\/]/),n=t.findIndex(s=>/[*?[{]/.test(s)),r=e.includes("\\")&&!e.includes("/")?"\\":"/",o=t.slice(0,n).join(r);return o&&o!=="~"?o:""}function G({grant:e=null,extraWrite:t=[],cwd:n="",home:r=""}={}){const o=i=>r&&(i==="~"||i.startsWith("~/")||i.startsWith("~\\"))?r+i.slice(1):i,s=i=>{let d=String(i||"").trim();for(;d.length>1&&(d.endsWith("/")||d.endsWith("\\"));)d=d.slice(0,-1);return d},a=(i,d)=>i===d||i.startsWith(`${d}/`)||i.startsWith(`${d}\\`),l=s(o(n)),c=[];for(const i of[...S(e).write,...Array.isArray(t)?t:[]]){const d=B(s(o(s(i))));if(d&&!I(d,r)&&!(l&&a(d,l))&&!c.some(u=>a(d,u))){for(let u=c.length-1;u>=0;u--)a(c[u],d)&&c.splice(u,1);c.push(d)}}return c}function re(e,{loopback:t=[],home:n="",platform:r="darwin"}={}){const o=j(e),s=l=>n&&l.startsWith("~")?n+l.slice(1):l,a=o.network.mode==="none"?[]:t.map(l=>`127.0.0.1:${l}`);return{network:{allowedDomains:p([...o.network.allowedDomains,...a]),deniedDomains:o.network.deniedDomains,allowLocalBinding:r==="darwin"&&a.length>0,...r==="darwin"&&o.network.unixSockets?.length?{allowUnixSockets:o.network.unixSockets}:{}},filesystem:{denyRead:o.filesystem.denyRead.map(s),allowRead:o.filesystem.allowRead.map(s),allowWrite:o.filesystem.allowWrite.map(s),denyWrite:o.filesystem.denyWrite.map(s)}}}function se({layer:e="none",runtime:t=null,kitId:n=null,mode:r=null,reason:o=null,hosts:s=null}={}){return f(R.includes(e),`sandbox record: layer must be one of ${R.join(", ")}`),{layer:e,runtime:t,kit:n,mode:r,...e==="none"&&o?{reason:o}:{},...Array.isArray(s)&&s.length?{hosts:p(s)}:{}}}function M(e,{platform:t="darwin"}={}){const n=String(e);if(t==="win32"){f(!/[\r\n]/.test(n),"win32 command line: an argument holds a newline, which cmd.exe cannot carry");let r=n;if(n===""||/[ \t\v"]/.test(n)){r='"';for(let o=0;o<n.length;o++){let s=0;for(;o<n.length&&n[o]==="\\";)s++,o++;if(o===n.length){r+="\\".repeat(s*2);break}n[o]==='"'?r+="\\".repeat(s*2+1)+'"':r+="\\".repeat(s)+n[o]}r+='"'}return r.replace(/[()%!^"<>&|]/g,"^$&")}return n===""?"''":/^[A-Za-z0-9_\-./=:@%+,]+$/.test(n)?n:`'${n.replace(/'/g,"'\\''")}'`}const q=Object.freeze(["SSL_CERT_FILE","REQUESTS_CA_BUNDLE","CURL_CA_BUNDLE","GIT_SSL_CAINFO"]);function ie(e={},{platform:t="darwin",caBundle:n=""}={}){const r={NODE_USE_ENV_PROXY:"1"};if(n)for(const o of q)e[o]||(r[o]=n);if(t==="linux")for(const o of["no_proxy","NO_PROXY"])typeof e[o]=="string"&&(r[o]=e[o].split(",").map(s=>s.trim()).filter(s=>s&&!/^(localhost|127\.0\.0\.1|::1|\[::1\])$/i.test(s)).join(","));return r}function ce(e,t=[],{platform:n="darwin"}={}){return[e,...t].map(r=>M(r,{platform:n})).join(" ")}const ae=/[\\/]+/,w=e=>String(e||"").replace(/\//g,"\\").replace(/\\+$/,"").toLowerCase(),F=e=>/^[a-z]:$/i.test(w(e))||w(e)==="";function E(e,t){const n=w(e),r=w(t);return!!r&&n!==r&&n.startsWith(r+"\\")}function X(e){const t=String(e||"").replace(/\//g,"\\").split("\\");if(t.length<2)return"";const n=t.findIndex(r=>r.toLowerCase()==="node_modules");return(n>0?t.slice(0,n):t.slice(0,-1)).join("\\")}function le({kit:e,files:t=[],home:n}){f(typeof n=="string"&&n.length>0,"windows grants: home required");const r=c=>(c.startsWith("~")?n+c.slice(1):c).replace(/\//g,"\\"),o=[];for(const c of e?.filesystem?.allowWrite||[]){const i=r(c);!/^[a-z]:\\/i.test(i)&&!i.startsWith("\\\\")||(f(!F(i)&&w(i)!==w(n),`windows grants: a write on ${i} would hand the sandbox account the whole profile`),E(i,n)&&o.push(i))}const s=(c,i)=>i.some(d=>w(c)===w(d)||E(c,d)),a=[];for(const c of t){const i=X(c);i&&E(i,n)&&a.push(i)}for(const c of e?.filesystem?.allowRead||[]){const i=r(c);E(i,n)&&a.push(i)}const l=p(a).filter(c=>!s(c,o));return{read:l.filter(c=>!l.some(i=>i!==c&&E(c,i))),write:p(o)}}const V=Object.freeze(["ANTHROPIC_API_KEY","ANTHROPIC_AUTH_TOKEN","ANTHROPIC_BASE_URL","CLAUDE_CONFIG_DIR","OPENAI_API_KEY","OPENAI_BASE_URL","OPENAI_API_BASE","CODEX_HOME","GEMINI_API_KEY","GOOGLE_API_KEY","DEEPSEEK_API_KEY","DSH_HOME","OPENROUTER_API_KEY","GROQ_API_KEY","XAI_API_KEY","MISTRAL_API_KEY"]);function de({engine:e="custom",home:t,env:n={},base:r={},carry:o=V}={}){f(typeof t=="string"&&t.length>0,"windows env: home required");const s=t.replace(/\//g,"\\"),a=/^[a-z]:/i.test(s)?s.slice(0,2):"",l={USERPROFILE:s,...a?{HOMEDRIVE:a,HOMEPATH:s.slice(2)}:{}};for(const[c,i]of Object.entries(n))typeof i=="string"&&(r[c]!==i||o.includes(c))&&(l[c]=i);return e==="codex"&&!l.CODEX_HOME&&(l.CODEX_HOME=s+"\\.codex"),l}function fe(e,t){f(Array.isArray(e),"srt-win argv: must be an array");const n=e.indexOf("exec"),r=n>=0?e.indexOf("--",n+1):-1;f(n>=0&&r>n,"srt-win argv: expected `exec … -- <shell> <command>`");const o=new Set;for(let a=n+1;a<r;a++)e[a]==="--env"&&typeof e[a+1]=="string"&&o.add(e[a+1].split("=")[0].toUpperCase());const s=[];for(const[a,l]of Object.entries(t||{}))f(/^[A-Za-z_][A-Za-z0-9_]*$/.test(a),`srt-win env: bad key ${a}`),f(!/[\r\n]/.test(l),`srt-win env: ${a} holds a newline`),o.has(a.toUpperCase())||s.push("--env",`${a}=${l}`);return[...e.slice(0,r),...s,...e.slice(r)]}export{D as CA_BUNDLE_RELPATH,te as CA_BUNDLE_RELPATH_LEGACY,k as COMMON_WRITE,Y as DEVELOPER_HOSTS,C as ENGINE_KITS,$ as NETWORK_MODES,R as SANDBOX_LAYERS,_ as SECRET_PATHS,W as SECRET_READ_GLOBS,H as TOOLCHAIN_READ,V as WINDOWS_CARRY_KEYS,ne as caBundlePath,I as isSecretWritePath,oe as kitFor,me as mergeGrants,ge as normalizeGrant,we as parseHostList,ee as readDenialFor,ie as sandboxEnvOverlay,se as sandboxRecord,ce as shellJoin,M as shellQuote,re as toSrtSettings,E as underWindowsHome,j as validateKit,le as windowsGrantsFor,X as windowsInstallRoot,de as windowsSandboxEnv,fe as withSrtWinEnv,G as writableRoots};
|