@buoy-gg/agent-core 7.0.68 → 7.0.69

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,13 +1,13 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});Object.defineProperty(exports,"digestOf",{enumerable:true,get:function(){return _digest.digestOf}});exports.readTargetDigest=readTargetDigest;exports.runAgentTurn=runAgentTurn;exports.runGatedAction=runGatedAction;var _catalog=require("../catalog/catalog.g");var _validateParams=require("../catalog/validateParams");var _normalizeParams=require("../catalog/normalizeParams");var _toProviderTools=require("../catalog/toProviderTools");var _snapshotReads=require("../catalog/snapshotReads");var _types=require("../providers/types");var _ledger=require("../effects/ledger");var _turnScope=require("../policy/turnScope");var _policy=require("../policy/policy");var _redact=require("../policy/redact");var _idGrounding=require("./idGrounding");var _effectFor=require("./effectFor");var _digest=require("../effects/digest");var _uiTool=require("../blocks/uiTool");var _receipts=require("../blocks/receipts");var _types2=require("../blocks/types");var _askGate=require("./askGate");var _textToolCalls=require("./textToolCalls");var _planOnlyStop=require("./planOnlyStop");var _compactScreen=require("./compactScreen");var _historyBudget=require("./historyBudget");var _tokenCalibration=require("./tokenCalibration");var _evidence=require("./evidence");var _retrieve=require("./retrieve");var _verify=require("./verify");var _realNow=require("../realNow");const MAX_RESULT_CHARS=24e3;const MAX_TRACE_RESULT_CHARS=2e3;const LOOP_REPEATS=3;function callSignature(t){const r=o=>{if(o===null||typeof o!=="object")return o;if(Array.isArray(o))return o.map(r);const a=o;return Object.keys(a).sort().reduce((d,v)=>(d[v]=r(a[v]),d),{})};return t.map(o=>`${o.name}:${JSON.stringify(r(o.input??{}))}`).join("|")}const LOOP_WARNING="[Buoy] You have now made this exact call three times in a row and gotten the same thing back. Repeating it again will not change the answer. Read the result you already have, then either try a different tool or different arguments, or tell the user plainly what you could not get and what you tried.";const DEFAULT_MAX_STEPS=24;const CONTINUE_SEND="Resume where you left off. Don't redo past changes. Read the past tool results first.";const STEP_CAP_WRAP_UP="You are out of steps. No more tools may run. Reply in the user's language with plain words. Name every write that ran, what you found, and what is still not done. Use the tool results as proof. A tap alone does not prove a save or an order worked. Do not claim the job is done if you have not checked it. Keep the reply short.";const DEFAULT_TURN_MS=18e4;const THROTTLE_RETRIES=2;const OVERFLOW_RETRIES=1;const RETRY_BASE_MS=1e3;const RETRY_JITTER_MS=250;const RETRY_AFTER_CAP_MS=3e4;function sleep(t,r){return new Promise(o=>{if(r?.aborted)return o();const a=(0,_realNow.realSetTimeout)(d,t);function d(){(0,_realNow.realClearTimeout)(a);r?.removeEventListener("abort",d);o()}r?.addEventListener("abort",d,{once:true})})}function readAnswer(t){if(typeof t==="boolean")return{approved:t,trust:false};const r=t.reason?.trim();return{approved:t.approved,...r?{reason:r}:{},trust:t.trust===true&&t.approved}}function declinedResult(t){return t?`The user declined this change and said: "${t}". Do not retry it as proposed; take their note into account and, if a different change would fit, propose that instead.`:"The user declined this change. Do not retry it; ask what they would prefer."}function closeAction(t,r){const o=t.toLowerCase();const a=r.toLowerCase();if(Math.abs(o.length-a.length)>1)return false;let d=0;while(d<o.length&&o[d]===a[d])d++;return o===a||o.slice(d+1)===a.slice(d+1)||o.slice(d+1)===a.slice(d)||o.slice(d)===a.slice(d+1)}function findDescriptor(t,r,o){return t.find(a=>a.toolId===r)?.actions.find(a=>a.action===o)}const URL_PROVENANCE_REJECTION="Rejected: every image URL must be one you read from a tool result in THIS conversation (images.list, a storage value, a response body). Never invent or remember URLs \u2014 read them first, then show them.";const droppedImageNote=t=>` NOTE: ${t} image ${t===1?"URL was":"URLs were"} dropped \u2014 they were not read from a tool result in this conversation, so the card the user is looking at has no picture there. Do not tell them it does; read the URLs and show it again, or say the artwork is missing.`;function fullText(t){try{return JSON.stringify(t??null)}catch{return String(t)}}function encodeResult(t,r){if(t.length<=MAX_RESULT_CHARS)return t;return`${t.slice(0,MAX_RESULT_CHARS)}${(0,_evidence.truncationMarker)(t.length,r)}`}function summarise(t){if(t===null||t===void 0)return"Done";if(Array.isArray(t))return countOf(t.length);if(typeof t==="boolean")return t?"Done":"Failed";if(typeof t==="object"){const r=t;if(r.ok===false)return typeof r.error==="string"?r.error:"Failed";if(r.found===false)return"Not found";if(r.tapped===false)return"Nothing to tap";if(r.active===false&&typeof r.inactiveReason==="string"&&r.inactiveReason.length>0){return"Saved, but inactive in this build"}for(const a of["returned","count","total"]){const d=r[a];if(typeof d==="number")return countOf(d)}const o=Object.values(r).filter(Array.isArray);if(o.length===1)return countOf(o[0].length);return"Done"}return String(t).slice(0,80)}function countOf(t){return t===1?"1 item":`${t} items`}function reportsFailure(t){return typeof t==="object"&&t!==null&&t.ok===false}const EMPTY_TAP_ERROR="tapElement needs nativeTag, testID or query. Read describeScreen and pass one.";function emptyTap(t,r,o){return t==="highlight-updates"&&r==="tapElement"&&![o.nativeTag,o.testID,o.query].some(a=>typeof a==="string"?a.trim().length>0:a!=null)}function tapResult(t,r,o){if(t!=="highlight-updates"||r!=="tapElement"||!o||typeof o!=="object")return o;const a=o;if(a.tapped!==false)return o;return{...a,ok:false,error:typeof a.reason==="string"?a.reason:typeof a.error==="string"?a.error:"Nothing was tapped. Read describeScreen and try again."}}async function*runAgentTurn(t){const{provider:r,catalog:o,system:a,systemVolatile:d,model:v,maxTokens:m,dispatch:c,readSnapshot:g,storeKeyOwners:U,ledger:k,policy:x,isRelease:D,requestApproval:J,signal:_,evidence:W,trusted:A,procedures:B}=t;const Y=new Map;const O=t.calibration??new _tokenCalibration.TokenCalibration;const ne=[...t.messages].reverse().find(p=>(0,_types.isRealUserMessage)(p));const M=(0,_turnScope.classifyTurn)(ne?.role==="user"?ne.text:"");const f=[...t.messages];const ue=r.protocol==="anthropic"?t.feedOptions??{}:{};const z=ue.freezeHistory===true;const P=ue.notices==="system-msg";const se=(p,I=false)=>({role:"user",text:p,...r.protocol==="anthropic"?{source:"engine"}:{},...I?{systemNotice:true}:{}});const qe=()=>{const p=f[f.length-1];return P&&(p?.role==="tool-results"||p?.role==="user"&&p.systemNotice===true)};const Ue=(0,_idGrounding.idGrounding)(f,`${t.system}
2
- ${t.systemVolatile??""}${ne?.role==="user"&&ne.liveBlock?`
3
- ${ne.liveBlock.text}`:""}
4
- ${JSON.stringify(B??[])}`);let Q=(0,_toProviderTools.toProviderTools)(o,{availableToolIds:t.availableToolIds,availableActions:t.availableActions,isRelease:D});Q.push((0,_uiTool.uiProviderTool)());if(z)Q=JSON.parse(JSON.stringify(Q));const V=x.maxSteps??DEFAULT_MAX_STEPS;const xe=newAskId();const st=k.generation;const it=new Set(k.list().map(p=>p.id));const De=a.length+(d?.length??0)+Q.reduce((p,I)=>p+I.description.length+JSON.stringify(I.inputSchema).length,0);const fe=()=>De+O.chars(m);let pe=(0,_realNow.realNow)()+DEFAULT_TURN_MS;const ke={throttled:0,overflow:0};let K=_historyBudget.MAX_HISTORY_TOKENS;const ve=t.seenUrls??new Set;const at=/https?:\/\/[^\s"'\\)\]}>]+/g;let we=false;const X=[];let Le=false;const Te=[];let Se=false;let Me=false;let he=false;let je=false;let Be=false;const dt=[...f].reverse().find(_types.isRealUserMessage);const lt=/\?\s*$/.test(dt?.text?.trim()??"");const ze=p=>p.reduce((I,$)=>I+(0,_historyBudget.messageSize)($),0)<=Math.min(O.chars(K),O.chars(_historyBudget.MAX_REQUEST_TOKENS)-fe());const Re="This turn has no room left. Tap Continue to go on.";for(let p=0;p<V;p++){if(_?.aborted){yield{type:"done",stopReason:"stopped"};return f}if((0,_realNow.realNow)()>pe){yield{type:"block",block:{id:`cap${(0,_realNow.realNow)()}`,kind:"notice",tone:"warning",text:`This is taking too long \u2014 stopped after ${Math.round(DEFAULT_TURN_MS/1e3)}s. What it found so far is above.`,actions:[{label:"Continue",primary:true,send:CONTINUE_SEND}]}};yield{type:"done",stopReason:"time-cap"};return f}const I=z&&p>0?{messages:f,droppedRounds:0,droppedPinned:0}:(0,_historyBudget.budgetForRequest)(f,fe(),O.chars(K),O.charsPerToken,k.liveCallIds());if(I.droppedRounds>0){f.length=0;f.push(...I.messages);yield{type:"history-trimmed",droppedRounds:I.droppedRounds,droppedPinned:I.droppedPinned}}else if(I.messages!==f){f.length=0;f.push(...I.messages)}if(V>6&&p===V-6){f.push(se("6 steps left. Finish what the user asked. Skip extra checks. Batch reads that do not depend on each other in one round.",qe()))}if(z&&!ze(f)){yield{type:"block",block:{id:`space${(0,_realNow.realNow)()}`,kind:"notice",tone:"warning",text:Re,actions:[{label:"Continue",primary:true,send:CONTINUE_SEND}]}};yield{type:"done",stopReason:"incomplete"};return f}let $="";let Je=false;const ee=e=>{const l=we&&!Je;Je=true;we=true;return l?{type:"text",delta:e,breakBefore:true}:{type:"text",delta:e}};let S=[];const We=new Set;let q="";let Ie=true;let ae=[];let ye=false;let F;let G;let Ne=0;for(;;){Ne+=1;$="";S=[];q="";Ie=true;ae=[];ye=false;F=void 0;G=void 0;let e;const l=De+f.reduce((u,y)=>u+(0,_historyBudget.messageSize)(y),0);for await(const u of r.send({messages:f,system:a,systemVolatile:d,tools:Q,model:v,maxTokens:m,signal:_,meta:{askId:xe,round:p+1,attempt:Ne}})){if(u.type==="text"){$+=u.delta;if(!Ie){yield ee(u.delta)}else if((0,_textToolCalls.couldBeToolCallEnvelope)($)){q+=u.delta}else{Ie=false;q="";yield ee($)}}else if(u.type==="tool-call"){S.push(u.call)}else if(u.type==="meter"){yield{type:"meter",frame:u.frame}}else if(u.type==="thinking"){ae.push(u.block);if(u.block.type==="thinking"&&u.block.thinking.trim()){yield{type:"reasoning",text:u.block.thinking}}}else if(u.type==="error"){if(u.kind==="truncated"||u.kind==="timeout"){G={message:u.message}}else if(u.problem&&(u.problem.kind==="throttled"||u.problem.kind==="overflow")&&$===""&&S.length===0&&ae.length===0){e={problem:u.problem,message:u.message}}else{yield{type:"error",message:u.message,...u.problem?.hosted?{hosted:u.problem.hosted}:{}};ye=true}}else if(u.type==="done"){F=u.outcome;if(u.usage){O.observe(l,(0,_tokenCalibration.promptTokensOf)(u.usage,r.protocol));yield{type:"usage",...u.usage,model:u.model}}}}if(!e)break;const n=e.problem.kind;if(z&&n==="overflow"){G={message:Re};break}const s=1+(n==="throttled"?THROTTLE_RETRIES:OVERFLOW_RETRIES);const b=ke[n];let h=n==="throttled"?Math.min(e.problem.retryAfterMs??RETRY_BASE_MS*2**b,RETRY_AFTER_CAP_MS)+Math.floor(Math.random()*RETRY_JITTER_MS):0;let C=b>=s-1||_?.aborted===true||(0,_realNow.realNow)()+h>pe;if(e.problem.hosted&&Ne>=2)C=true;if(!C&&n==="overflow"){K=Math.floor(K/2);const u=f.reduce((de,H)=>de+(0,_historyBudget.messageSize)(H),0);const y=(0,_historyBudget.budgetForRequest)(f,fe(),O.chars(K),O.charsPerToken,k.liveCallIds());const te=y.messages.reduce((de,H)=>de+(0,_historyBudget.messageSize)(H),0);if(te>=u){C=true}else{f.length=0;f.push(...y.messages);if(y.droppedRounds>0)yield{type:"history-trimmed",droppedRounds:y.droppedRounds,droppedPinned:y.droppedPinned}}}if(C){const u=n==="throttled"?b>0?`The AI endpoint is rate-limiting requests \u2014 tried ${b+1} times.`:"The AI endpoint is rate-limiting requests.":"This conversation is too large for the AI endpoint and there was nothing older to trim. Start a new conversation, or ask a shorter question.";const y=e.problem.hosted;yield y?{type:"error",message:y.message,hosted:y}:{type:"error",message:`${u} (${e.message})`};ye=true;break}ke[n]+=1;yield{type:"retrying",reason:n,attempt:ke[n]+1,maxAttempts:s,inMs:h};if(h>0)await sleep(h,_);if(_?.aborted){yield{type:"done",stopReason:"stopped"};return f}}if(F==="refused"||F==="context-limited"){yield{type:"error",message:F==="refused"?"Claude could not help with this request.":"Claude ran out of room for this turn. Please send a new message."};yield{type:"done",stopReason:"error"};return f}if(ye){if(q)yield ee(q);yield{type:"done",stopReason:"error"};return f}if(!G&&F!=="completed"){G={message:F==="output-limited"?S.length?"The model ran out of room mid-plan, so nothing was run. What it found so far is above.":"The model ran out of room before finishing this answer.":"The answer ended before the endpoint said it was finished, so nothing was run."}}if(G){if(q)yield ee(q);if($.trim())f.push({role:"assistant",text:$});yield{type:"block",block:{id:`cut${(0,_realNow.realNow)()}`,kind:"notice",tone:"warning",text:G.message,actions:[{label:"Continue",primary:true,send:CONTINUE_SEND}]}};yield{type:"done",stopReason:"incomplete"};return f}if(q){const e=S.length===0?(0,_textToolCalls.parseTextToolCalls)(q,o):void 0;if(e){for(const l of e.calls){S.push(l);We.add(l.id)}$=e.reply;if(e.reply)yield ee(e.reply)}else{yield ee(q)}q=""}f.push({role:"assistant",text:$,toolCalls:S.length?S:void 0,thinking:ae.length?ae:void 0});if($.trim())Te.push($.trim());if(S.length===0&&!he&&!Se&&p<V-1&&((0,_planOnlyStop.announcesUnstartedWork)($,M==="task")||je&&!Be&&!lt)){he=true;f.push(se(_planOnlyStop.PLAN_ONLY_NUDGE));continue}if(S.length===0&&!he&&Te.length===0&&p<V-1){he=true;f.push(se(_planOnlyStop.SILENT_NUDGE));continue}if(S.length===0){const e=Te.join("\n\n");const l=(0,_askGate.synthesizeShortfallBlock)({text:e,attempted:Me});if(l)yield{type:"block",block:l};const n=Se||l?null:(0,_askGate.synthesizeAskBlock)(e);if(n){yield{type:"block",block:n};yield{type:"awaiting-user",blockId:n.id}}yield{type:"done",stopReason:n?"awaiting-user":"answered"};return f}const w=[];const me=[];const L=e=>{if(!P)return e;me.push(e.trim());return""};let Ye=false;const Qe=new Map;if(S.length>1){const e=S.every(l=>{if(l.name===_uiTool.UI_TOOL_NAME)return false;const n=(0,_toProviderTools.fromProviderToolName)(l.name,o);if(!n||n==="ask-buoy")return false;const s=l.input?.action;if(typeof s!=="string"||s===_snapshotReads.SNAPSHOT_ACTION)return false;const b=findDescriptor(o,n,s);if(!b||b.effect!=="read")return false;return(0,_policy.decide)({descriptor:b,toolId:n,policy:x,isRelease:D}).verdict==="allow"});if(e){for(const l of S){const n=(0,_toProviderTools.fromProviderToolName)(l.name,o);const s=String(l.input.action);const b={...l.input.params??{}};const h=findDescriptor(o,n,s);const C=(0,_normalizeParams.normalizeParams)(n,s,b);const u=(0,_validateParams.applyDefaults)(C.params,h.params);if(!(0,_validateParams.validateParams)(u,h.params).ok)continue;const y=Promise.resolve(c(n,s,u)).catch(te=>{throw te});y.catch(()=>{});Qe.set(l.id,y)}}}let Ae=null;const ut=e=>{const l=(0,_toProviderTools.fromProviderToolName)(e.name,o)??e.name;const n=typeof e.input?.action==="string"?e.input.action:"";const s=n?findDescriptor(o,l,n):void 0;const b=e.input?.params??{};return[{type:"tool-start",id:e.id,toolId:l,action:n,label:s?(0,_policy.describeCall)(l,s,b):`${l}.${n}`,description:s?.summary??"",params:b,effect:s?.effect??"read"},{type:"tool-end",id:e.id,ok:false,summary:"stopped",durationMs:0}]};const ge=new Map;if(M==="question"){for(const e of S){if((0,_toProviderTools.fromProviderToolName)(e.name,o)!=="highlight-updates"||e.input?.action!=="tapElement")continue;const l=(0,_normalizeParams.normalizeParams)("highlight-updates","tapElement",e.input.params??{}).params;if(emptyTap("highlight-updates","tapElement",l))continue;const n=findDescriptor(o,"highlight-updates","describeScreen");const s=findDescriptor(o,"highlight-updates","tapElement");if(_?.aborted||!n||!s||(0,_policy.decide)({descriptor:n,toolId:"highlight-updates",policy:x,isRelease:D}).verdict!=="allow"||(0,_policy.decide)({descriptor:s,toolId:"highlight-updates",policy:x,isRelease:D,turnScope:M,params:l}).verdict==="refuse")continue;const b=await c("highlight-updates","describeScreen",{}).catch(()=>void 0);ge.set(e.id,(0,_turnScope.tapLabels)(b,l))}}const Ve=S.map(e=>{if(e.name===_uiTool.UI_TOOL_NAME)return void 0;const l=(0,_toProviderTools.fromProviderToolName)(e.name,o);const n=typeof e.input?.action==="string"?e.input.action:void 0;if(!l||!n)return void 0;const s=findDescriptor(o,l,n);if(!s)return void 0;const b=e.input.params??{};const h=(0,_validateParams.applyDefaults)((0,_normalizeParams.normalizeParams)(l,n,b).params,s.params);if(emptyTap(l,n,h)||!(0,_validateParams.validateParams)(h,s.params).ok)return void 0;const C=(0,_policy.decide)({descriptor:s,toolId:l,policy:x,isRelease:D,turnScope:M,params:h,tapLabels:ge.get(e.id)});return{call:e,toolId:l,action:n,descriptor:s,params:h,label:(0,_policy.describeCall)(l,s,h),mutates:s.effect!=="read",gated:C.verdict==="needs-approval",turnScoped:C.verdict==="needs-approval"&&C.turnScoped,reason:C.verdict==="needs-approval"?C.reason:""}});const ft=Ve.some(e=>e?.gated);const j=new Map;let Ke=false;let Xe=false;async function*pt(){Ke=true;for(const e of Ve){if(!e?.gated||j.has(e.call.id))continue;if(!e.turnScoped&&A?.has(`${e.toolId}.${e.action}`)){j.set(e.call.id,true);continue}yield{type:"approval-required",id:e.call.id,toolId:e.toolId,action:e.action,label:e.label,description:e.descriptor.summary,reason:e.reason};const l=(0,_realNow.realNow)();const n=await readTargetDigest({toolId:e.toolId,action:e.action,params:e.params,dispatch:c,catalog:o});const s=readAnswer(!e.turnScoped&&A?.has(`${e.toolId}.${e.action}`)?true:J?await J({id:e.call.id,toolId:e.toolId,action:e.action,label:e.label,description:e.descriptor.summary,reason:e.reason,params:e.params,targetDigest:n}):false);pe+=(0,_realNow.realNow)()-l;const b=s.approved;j.set(e.call.id,b);if(s.trust)A?.add(`${e.toolId}.${e.action}`);if(s.reason)Y.set(e.call.id,s.reason);if(!b){Xe=true;return}}}for(const e of S){if(_?.aborted){if(e.name!==_uiTool.UI_TOOL_NAME){for(const i of ut(e))yield i}w.push({toolCallId:e.id,content:"Not run \u2014 the user pressed Stop before this call started.",isError:true});continue}const l=e.input?.[_types.UNPARSEABLE_ARGS];if(typeof l==="string"){w.push({toolCallId:e.id,content:`Not run \u2014 this call's arguments were not valid JSON, so nothing changed (${l.slice(0,120)}). Send the call again with compact JSON: {"action": "...", "params": {...}}.`,isError:true});continue}if(e.name===_uiTool.UI_TOOL_NAME){const i=(0,_uiTool.buildUiBlock)(e.input);if(!i.ok||!i.block){w.push({toolCallId:e.id,content:`Invalid ${_uiTool.UI_TOOL_NAME} block:
5
- ${i.errors.join("\n")}`+L("\n\nResend ONLY the corrected block. Do not rewrite your answer \u2014 whatever you already said this turn has been shown to the user, and saying it again repeats it on their screen."),isError:true});continue}let R=0;if(i.block.kind==="imageGrid"){const N=i.block.images.filter(E=>ve.has(E.url));R=i.block.images.length-N.length;if(N.length===0){w.push({toolCallId:e.id,content:P?"Rejected: image URLs were not read from a tool result."+L(URL_PROVENANCE_REJECTION):URL_PROVENANCE_REJECTION,isError:true});continue}i.block={...i.block,images:N}}if(i.block.kind==="list"){const N=i.block.items.map(E=>{if(!E.image||ve.has(E.image))return E;R+=1;return{...E,image:void 0}});i.block={...i.block,items:N}}yield{type:"block",block:i.block,forToolCallId:e.id};if(i.block.kind==="actions"||i.block.kind==="suggestions"||i.block.kind==="plan"&&i.block.pending){Se=true}if((0,_types2.isAskBlock)(i.block)){Ae=i.block.id;w.push({toolCallId:e.id,content:"Shown. Waiting for the user's answer \u2014 it will arrive as their next message."+L(" Do not guess it.")})}else{w.push({toolCallId:e.id,content:"Shown to the user."+L(" Don't repeat its contents in text.")+(R>0?droppedImageNote(R):"")})}continue}const n=(0,_toProviderTools.fromProviderToolName)(e.name,o);const s=e.input.action;const b=(i,R)=>[{type:"tool-start",id:e.id,toolId:n??e.name,action:s??"",label:i,description:"",params:e.input.params??{},effect:"read"},{type:"tool-end",id:e.id,ok:false,summary:R,durationMs:0}];if(!n){for(const i of b(e.name,"No such tool"))yield i;w.push({toolCallId:e.id,content:`There is no tool called "${e.name}". Use one of the tools you were given.`,isError:true});continue}if(!s){for(const i of b(e.name,"No action given"))yield i;w.push({toolCallId:e.id,content:`"${e.name}" needs an "action" \u2014 it is required, and it names which of this tool's actions to run. See the action list in the tool's description.`,isError:true});continue}const h=findDescriptor(o,n,s);if(!h){const i=o.find(T=>T.toolId===n)?.actions.map(T=>T.action)??[];const R=o.filter(T=>T.toolId!==n&&T.actions.some(Ce=>Ce.action===s));const N=i.filter(T=>closeAction(T,s));const E=[...R.map(T=>`${T.toolId}.${s}`),...N.map(T=>`${n}.${T}`)].slice(0,3);const re=`${n} has no ${s}.${E.length?` Did you mean ${E.join(" or ")}?`:""}`;for(const T of b(`${n}.${s}`,E.length?re:"No such action"))yield T;w.push({toolCallId:e.id,content:`${re}${i.length?` Valid actions: ${i.join(", ")}.`:""}`,isError:true});continue}const C=e.input.params??{};const u=(0,_normalizeParams.normalizeParams)(n,s,C);const y=(0,_validateParams.applyDefaults)(u.params,h.params);if(emptyTap(n,s,y)){for(const i of b(`${n}.${s}`,EMPTY_TAP_ERROR))yield i;w.push({toolCallId:e.id,content:JSON.stringify({ok:false,error:P?"tapElement needs nativeTag, testID or query."+L("Read describeScreen and pass nativeTag, testID or query."):EMPTY_TAP_ERROR}),isError:true});continue}const te=(0,_validateParams.validateParams)(y,h.params);if(!te.ok){w.push({toolCallId:e.id,content:`Invalid parameters for ${n}.${s}:
6
- ${te.errors.join("\n")}
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});Object.defineProperty(exports,"digestOf",{enumerable:true,get:function(){return _digest.digestOf}});exports.readTargetDigest=readTargetDigest;exports.runAgentTurn=runAgentTurn;exports.runGatedAction=runGatedAction;var _catalog=require("../catalog/catalog.g");var _validateParams=require("../catalog/validateParams");var _normalizeParams=require("../catalog/normalizeParams");var _toProviderTools=require("../catalog/toProviderTools");var _snapshotReads=require("../catalog/snapshotReads");var _types=require("../providers/types");var _ledger=require("../effects/ledger");var _turnScope=require("../policy/turnScope");var _policy=require("../policy/policy");var _redact=require("../policy/redact");var _idGrounding=require("./idGrounding");var _effectFor=require("./effectFor");var _digest=require("../effects/digest");var _uiTool=require("../blocks/uiTool");var _receipts=require("../blocks/receipts");var _types2=require("../blocks/types");var _askGate=require("./askGate");var _textToolCalls=require("./textToolCalls");var _planOnlyStop=require("./planOnlyStop");var _compactScreen=require("./compactScreen");var _historyBudget=require("./historyBudget");var _tokenCalibration=require("./tokenCalibration");var _evidence=require("./evidence");var _retrieve=require("./retrieve");var _verify=require("./verify");var _realNow=require("../realNow");const MAX_RESULT_CHARS=24e3;const MAX_TRACE_RESULT_CHARS=2e3;const LOOP_REPEATS=3;function callSignature(t){const r=o=>{if(o===null||typeof o!=="object")return o;if(Array.isArray(o))return o.map(r);const d=o;return Object.keys(d).sort().reduce((l,k)=>(l[k]=r(d[k]),l),{})};return t.map(o=>`${o.name}:${JSON.stringify(r(o.input??{}))}`).join("|")}const LOOP_WARNING="[Buoy] You have now made this exact call three times in a row and gotten the same thing back. Repeating it again will not change the answer. Read the result you already have, then either try a different tool or different arguments, or tell the user plainly what you could not get and what you tried.";const DEFAULT_MAX_STEPS=24;const CONTINUE_SEND="Resume where you left off. Don't redo past changes. Read the past tool results first.";const STEP_CAP_WRAP_UP="You are out of steps. No more tools may run. Reply in the user's language with plain words. Name every write that ran, what you found, and what is still not done. Use the tool results as proof. A tap alone does not prove a save or an order worked. Do not claim the job is done if you have not checked it. Keep the reply short.";const DEFAULT_TURN_MS=18e4;const THROTTLE_RETRIES=2;const OVERFLOW_RETRIES=1;const NETWORK_RETRIES=1;const NETWORK_RETRY_MS=1e3;const RETRY_BASE_MS=1e3;const RETRY_JITTER_MS=250;const RETRY_AFTER_CAP_MS=3e4;function sleep(t,r){return new Promise(o=>{if(r?.aborted)return o();const d=(0,_realNow.realSetTimeout)(l,t);function l(){(0,_realNow.realClearTimeout)(d);r?.removeEventListener("abort",l);o()}r?.addEventListener("abort",l,{once:true})})}function readAnswer(t){if(typeof t==="boolean")return{approved:t,trust:false};const r=t.reason?.trim();return{approved:t.approved,...r?{reason:r}:{},trust:t.trust===true&&t.approved}}function declinedResult(t){return t?`The user declined this change and said: "${t}". Do not retry it as proposed; take their note into account and, if a different change would fit, propose that instead.`:"The user declined this change. Do not retry it; ask what they would prefer."}function closeAction(t,r){const o=t.toLowerCase();const d=r.toLowerCase();if(Math.abs(o.length-d.length)>1)return false;let l=0;while(l<o.length&&o[l]===d[l])l++;return o===d||o.slice(l+1)===d.slice(l+1)||o.slice(l+1)===d.slice(l)||o.slice(l)===d.slice(l+1)}function findDescriptor(t,r,o){return t.find(d=>d.toolId===r)?.actions.find(d=>d.action===o)}const URL_PROVENANCE_REJECTION="Rejected: every image URL must be one you read from a tool result in THIS conversation (images.list, a storage value, a response body). Never invent or remember URLs \u2014 read them first, then show them.";const droppedImageNote=t=>` NOTE: ${t} image ${t===1?"URL was":"URLs were"} dropped \u2014 they were not read from a tool result in this conversation, so the card the user is looking at has no picture there. Do not tell them it does; read the URLs and show it again, or say the artwork is missing.`;function fullText(t){try{return JSON.stringify(t??null)}catch{return String(t)}}function encodeResult(t,r){if(t.length<=MAX_RESULT_CHARS)return t;return`${t.slice(0,MAX_RESULT_CHARS)}${(0,_evidence.truncationMarker)(t.length,r)}`}function summarise(t){if(t===null||t===void 0)return"Done";if(Array.isArray(t))return countOf(t.length);if(typeof t==="boolean")return t?"Done":"Failed";if(typeof t==="object"){const r=t;if(r.ok===false)return typeof r.error==="string"?r.error:"Failed";if(r.found===false)return"Not found";if(r.tapped===false)return"Nothing to tap";if(r.active===false&&typeof r.inactiveReason==="string"&&r.inactiveReason.length>0){return"Saved, but inactive in this build"}for(const d of["returned","count","total"]){const l=r[d];if(typeof l==="number")return countOf(l)}const o=Object.values(r).filter(Array.isArray);if(o.length===1)return countOf(o[0].length);return"Done"}return String(t).slice(0,80)}function countOf(t){return t===1?"1 item":`${t} items`}function reportsFailure(t){return typeof t==="object"&&t!==null&&t.ok===false}const EMPTY_TAP_ERROR="tapElement needs nativeTag, testID or query. Read describeScreen and pass one.";function emptyTap(t,r,o){return t==="highlight-updates"&&r==="tapElement"&&![o.nativeTag,o.testID,o.query].some(d=>typeof d==="string"?d.trim().length>0:d!=null)}function tapResult(t,r,o){if(t!=="highlight-updates"||r!=="tapElement"||!o||typeof o!=="object")return o;const d=o;if(d.tapped!==false)return o;return{...d,ok:false,error:typeof d.reason==="string"?d.reason:typeof d.error==="string"?d.error:"Nothing was tapped. Read describeScreen and try again."}}async function*runAgentTurn(t){const{provider:r,catalog:o,system:d,systemVolatile:l,model:k,maxTokens:y,dispatch:u,readSnapshot:m,storeKeyOwners:U,ledger:g,policy:x,isRelease:M,requestApproval:Y,signal:_,evidence:K,trusted:A,procedures:F}=t;const Q=new Map;const O=t.calibration??new _tokenCalibration.TokenCalibration;const ae=[...t.messages].reverse().find(p=>(0,_types.isRealUserMessage)(p));const j=(0,_turnScope.classifyTurn)(ae?.role==="user"?ae.text:"");const f=[...t.messages];const pe=r.protocol==="anthropic"?t.feedOptions??{}:{};const G=pe.freezeHistory===true;const P=pe.notices==="system-msg";const de=(p,E=false)=>({role:"user",text:p,...r.protocol==="anthropic"?{source:"engine"}:{},...E?{systemNotice:true}:{}});const qe=()=>{const p=f[f.length-1];return P&&(p?.role==="tool-results"||p?.role==="user"&&p.systemNotice===true)};const Ue=(0,_idGrounding.idGrounding)(f,`${t.system}
2
+ ${t.systemVolatile??""}${ae?.role==="user"&&ae.liveBlock?`
3
+ ${ae.liveBlock.text}`:""}
4
+ ${JSON.stringify(F??[])}`);let V=(0,_toProviderTools.toProviderTools)(o,{availableToolIds:t.availableToolIds,availableActions:t.availableActions,isRelease:M});V.push((0,_uiTool.uiProviderTool)());if(G)V=JSON.parse(JSON.stringify(V));const X=x.maxSteps??DEFAULT_MAX_STEPS;const xe=newAskId();const st=g.generation;const it=new Set(g.list().map(p=>p.id));const Me=d.length+(l?.length??0)+V.reduce((p,E)=>p+E.description.length+JSON.stringify(E.inputSchema).length,0);const he=()=>Me+O.chars(y);let le=(0,_realNow.realNow)()+DEFAULT_TURN_MS;const Z={throttled:0,overflow:0,network:0};let ee=_historyBudget.MAX_HISTORY_TOKENS;const ke=t.seenUrls??new Set;const at=/https?:\/\/[^\s"'\\)\]}>]+/g;let ve=false;const te=[];let De=false;const we=[];let Te=false;let Le=false;let ye=false;let je=false;let Be=false;const dt=[...f].reverse().find(_types.isRealUserMessage);const lt=/\?\s*$/.test(dt?.text?.trim()??"");const ze=p=>p.reduce((E,$)=>E+(0,_historyBudget.messageSize)($),0)<=Math.min(O.chars(ee),O.chars(_historyBudget.MAX_REQUEST_TOKENS)-he());const Re="This turn has no room left. Tap Continue to go on.";for(let p=0;p<X;p++){if(_?.aborted){yield{type:"done",stopReason:"stopped"};return f}if((0,_realNow.realNow)()>le){yield{type:"block",block:{id:`cap${(0,_realNow.realNow)()}`,kind:"notice",tone:"warning",text:`This is taking too long \u2014 stopped after ${Math.round(DEFAULT_TURN_MS/1e3)}s. What it found so far is above.`,actions:[{label:"Continue",primary:true,send:CONTINUE_SEND}]}};yield{type:"done",stopReason:"time-cap"};return f}const E=G&&p>0?{messages:f,droppedRounds:0,droppedPinned:0}:(0,_historyBudget.budgetForRequest)(f,he(),O.chars(ee),O.charsPerToken,g.liveCallIds());if(E.droppedRounds>0){f.length=0;f.push(...E.messages);yield{type:"history-trimmed",droppedRounds:E.droppedRounds,droppedPinned:E.droppedPinned}}else if(E.messages!==f){f.length=0;f.push(...E.messages)}if(X>6&&p===X-6){f.push(de("6 steps left. Finish what the user asked. Skip extra checks. Batch reads that do not depend on each other in one round.",qe()))}if(G&&!ze(f)){yield{type:"block",block:{id:`space${(0,_realNow.realNow)()}`,kind:"notice",tone:"warning",text:Re,actions:[{label:"Continue",primary:true,send:CONTINUE_SEND}]}};yield{type:"done",stopReason:"incomplete"};return f}let $="";let We=false;const re=e=>{const c=ve&&!We;We=true;ve=true;return c?{type:"text",delta:e,breakBefore:true}:{type:"text",delta:e}};let w=[];const Je=new Set;let q="";let Ee=true;let ne=[];let me=false;let H;let W;let Ie=0;for(;;){Ie+=1;$="";w=[];q="";Ee=true;ne=[];me=false;H=void 0;W=void 0;let e;const c=Me+f.reduce((i,I)=>i+(0,_historyBudget.messageSize)(I),0);let n=false;try{for await(const i of r.send({messages:f,system:d,systemVolatile:l,tools:V,model:k,maxTokens:y,signal:_,meta:{askId:xe,round:p+1,attempt:Ie}})){if(i.type==="text"){$+=i.delta;if(!Ee){yield re(i.delta)}else if((0,_textToolCalls.couldBeToolCallEnvelope)($)){q+=i.delta}else{Ee=false;q="";yield re($)}}else if(i.type==="tool-call"){w.push(i.call)}else if(i.type==="meter"){yield{type:"meter",frame:i.frame}}else if(i.type==="thinking"){ne.push(i.block);if(i.block.type==="thinking"&&i.block.thinking.trim()){yield{type:"reasoning",text:i.block.thinking}}}else if(i.type==="error"){if(i.kind==="truncated"||i.kind==="timeout"){W={message:i.message}}else if(i.problem&&(i.problem.kind==="throttled"||i.problem.kind==="overflow")&&$===""&&w.length===0&&ne.length===0){e={problem:i.problem,message:i.message}}else{yield{type:"error",message:i.message,...i.problem?.hosted?{hosted:i.problem.hosted}:{}};me=true}}else if(i.type==="done"){H=i.outcome;if(i.usage){O.observe(c,(0,_tokenCalibration.promptTokensOf)(i.usage,r.protocol));yield{type:"usage",...i.usage,model:i.model}}}}}catch(i){const I=$===""&&w.length===0&&ne.length===0;if(_?.aborted||!I||Z.network>=NETWORK_RETRIES||(0,_realNow.realNow)()+NETWORK_RETRY_MS>le)throw i;n=true}if(n){Z.network+=1;yield{type:"retrying",reason:"network",attempt:Z.network+1,maxAttempts:1+NETWORK_RETRIES,inMs:NETWORK_RETRY_MS};await sleep(NETWORK_RETRY_MS,_);if(_?.aborted){yield{type:"done",stopReason:"stopped"};return f}continue}if(!e)break;const s=e.problem.kind;if(G&&s==="overflow"){W={message:Re};break}const b=1+(s==="throttled"?THROTTLE_RETRIES:OVERFLOW_RETRIES);const h=Z[s];let C=s==="throttled"?Math.min(e.problem.retryAfterMs??RETRY_BASE_MS*2**h,RETRY_AFTER_CAP_MS)+Math.floor(Math.random()*RETRY_JITTER_MS):0;let D=h>=b-1||_?.aborted===true||(0,_realNow.realNow)()+C>le;if(e.problem.hosted&&Ie>=2)D=true;if(!D&&s==="overflow"){ee=Math.floor(ee/2);const i=f.reduce((J,z)=>J+(0,_historyBudget.messageSize)(z),0);const I=(0,_historyBudget.budgetForRequest)(f,he(),O.chars(ee),O.charsPerToken,g.liveCallIds());const _e=I.messages.reduce((J,z)=>J+(0,_historyBudget.messageSize)(z),0);if(_e>=i){D=true}else{f.length=0;f.push(...I.messages);if(I.droppedRounds>0)yield{type:"history-trimmed",droppedRounds:I.droppedRounds,droppedPinned:I.droppedPinned}}}if(D){const i=s==="throttled"?h>0?`The AI endpoint is rate-limiting requests \u2014 tried ${h+1} times.`:"The AI endpoint is rate-limiting requests.":"This conversation is too large for the AI endpoint and there was nothing older to trim. Start a new conversation, or ask a shorter question.";const I=e.problem.hosted;yield I?{type:"error",message:I.message,hosted:I}:{type:"error",message:`${i} (${e.message})`};me=true;break}Z[s]+=1;yield{type:"retrying",reason:s,attempt:Z[s]+1,maxAttempts:b,inMs:C};if(C>0)await sleep(C,_);if(_?.aborted){yield{type:"done",stopReason:"stopped"};return f}}if(H==="refused"||H==="context-limited"){yield{type:"error",message:H==="refused"?"Claude could not help with this request.":"Claude ran out of room for this turn. Please send a new message."};yield{type:"done",stopReason:"error"};return f}if(me){if(q)yield re(q);yield{type:"done",stopReason:"error"};return f}if(!W&&H!=="completed"){W={message:H==="output-limited"?w.length?"The model ran out of room mid-plan, so nothing was run. What it found so far is above.":"The model ran out of room before finishing this answer.":"The answer ended before the endpoint said it was finished, so nothing was run."}}if(W){if(q)yield re(q);if($.trim())f.push({role:"assistant",text:$});yield{type:"block",block:{id:`cut${(0,_realNow.realNow)()}`,kind:"notice",tone:"warning",text:W.message,actions:[{label:"Continue",primary:true,send:CONTINUE_SEND}]}};yield{type:"done",stopReason:"incomplete"};return f}if(q){const e=w.length===0?(0,_textToolCalls.parseTextToolCalls)(q,o):void 0;if(e){for(const c of e.calls){w.push(c);Je.add(c.id)}$=e.reply;if(e.reply)yield re(e.reply)}else{yield re(q)}q=""}f.push({role:"assistant",text:$,toolCalls:w.length?w:void 0,thinking:ne.length?ne:void 0});if($.trim())we.push($.trim());if(w.length===0&&!ye&&!Te&&p<X-1&&((0,_planOnlyStop.announcesUnstartedWork)($,j==="task")||je&&!Be&&!lt)){ye=true;f.push(de(_planOnlyStop.PLAN_ONLY_NUDGE));continue}if(w.length===0&&!ye&&we.length===0&&p<X-1){ye=true;f.push(de(_planOnlyStop.SILENT_NUDGE));continue}if(w.length===0){const e=we.join("\n\n");const c=(0,_askGate.synthesizeShortfallBlock)({text:e,attempted:Le});if(c)yield{type:"block",block:c};const n=Te||c?null:(0,_askGate.synthesizeAskBlock)(e);if(n){yield{type:"block",block:n};yield{type:"awaiting-user",blockId:n.id}}yield{type:"done",stopReason:n?"awaiting-user":"answered"};return f}const v=[];const ge=[];const L=e=>{if(!P)return e;ge.push(e.trim());return""};let Ye=false;const Ke=new Map;if(w.length>1){const e=w.every(c=>{if(c.name===_uiTool.UI_TOOL_NAME)return false;const n=(0,_toProviderTools.fromProviderToolName)(c.name,o);if(!n||n==="ask-buoy")return false;const s=c.input?.action;if(typeof s!=="string"||s===_snapshotReads.SNAPSHOT_ACTION)return false;const b=findDescriptor(o,n,s);if(!b||b.effect!=="read")return false;return(0,_policy.decide)({descriptor:b,toolId:n,policy:x,isRelease:M}).verdict==="allow"});if(e){for(const c of w){const n=(0,_toProviderTools.fromProviderToolName)(c.name,o);const s=String(c.input.action);const b={...c.input.params??{}};const h=findDescriptor(o,n,s);const C=(0,_normalizeParams.normalizeParams)(n,s,b);const D=(0,_validateParams.applyDefaults)(C.params,h.params);if(!(0,_validateParams.validateParams)(D,h.params).ok)continue;const i=Promise.resolve(u(n,s,D)).catch(I=>{throw I});i.catch(()=>{});Ke.set(c.id,i)}}}let Ne=null;const ut=e=>{const c=(0,_toProviderTools.fromProviderToolName)(e.name,o)??e.name;const n=typeof e.input?.action==="string"?e.input.action:"";const s=n?findDescriptor(o,c,n):void 0;const b=e.input?.params??{};return[{type:"tool-start",id:e.id,toolId:c,action:n,label:s?(0,_policy.describeCall)(c,s,b):`${c}.${n}`,description:s?.summary??"",params:b,effect:s?.effect??"read"},{type:"tool-end",id:e.id,ok:false,summary:"stopped",durationMs:0}]};const be=new Map;if(j==="question"){for(const e of w){if((0,_toProviderTools.fromProviderToolName)(e.name,o)!=="highlight-updates"||e.input?.action!=="tapElement")continue;const c=(0,_normalizeParams.normalizeParams)("highlight-updates","tapElement",e.input.params??{}).params;if(emptyTap("highlight-updates","tapElement",c))continue;const n=findDescriptor(o,"highlight-updates","describeScreen");const s=findDescriptor(o,"highlight-updates","tapElement");if(_?.aborted||!n||!s||(0,_policy.decide)({descriptor:n,toolId:"highlight-updates",policy:x,isRelease:M}).verdict!=="allow"||(0,_policy.decide)({descriptor:s,toolId:"highlight-updates",policy:x,isRelease:M,turnScope:j,params:c}).verdict==="refuse")continue;const b=await u("highlight-updates","describeScreen",{}).catch(()=>void 0);be.set(e.id,(0,_turnScope.tapLabels)(b,c))}}const Qe=w.map(e=>{if(e.name===_uiTool.UI_TOOL_NAME)return void 0;const c=(0,_toProviderTools.fromProviderToolName)(e.name,o);const n=typeof e.input?.action==="string"?e.input.action:void 0;if(!c||!n)return void 0;const s=findDescriptor(o,c,n);if(!s)return void 0;const b=e.input.params??{};const h=(0,_validateParams.applyDefaults)((0,_normalizeParams.normalizeParams)(c,n,b).params,s.params);if(emptyTap(c,n,h)||!(0,_validateParams.validateParams)(h,s.params).ok)return void 0;const C=(0,_policy.decide)({descriptor:s,toolId:c,policy:x,isRelease:M,turnScope:j,params:h,tapLabels:be.get(e.id)});return{call:e,toolId:c,action:n,descriptor:s,params:h,label:(0,_policy.describeCall)(c,s,h),mutates:s.effect!=="read",gated:C.verdict==="needs-approval",turnScoped:C.verdict==="needs-approval"&&C.turnScoped,reason:C.verdict==="needs-approval"?C.reason:""}});const ft=Qe.some(e=>e?.gated);const B=new Map;let Ve=false;let Xe=false;async function*pt(){Ve=true;for(const e of Qe){if(!e?.gated||B.has(e.call.id))continue;if(!e.turnScoped&&A?.has(`${e.toolId}.${e.action}`)){B.set(e.call.id,true);continue}yield{type:"approval-required",id:e.call.id,toolId:e.toolId,action:e.action,label:e.label,description:e.descriptor.summary,reason:e.reason};const c=(0,_realNow.realNow)();const n=await readTargetDigest({toolId:e.toolId,action:e.action,params:e.params,dispatch:u,catalog:o});const s=readAnswer(!e.turnScoped&&A?.has(`${e.toolId}.${e.action}`)?true:Y?await Y({id:e.call.id,toolId:e.toolId,action:e.action,label:e.label,description:e.descriptor.summary,reason:e.reason,params:e.params,targetDigest:n}):false);le+=(0,_realNow.realNow)()-c;const b=s.approved;B.set(e.call.id,b);if(s.trust)A?.add(`${e.toolId}.${e.action}`);if(s.reason)Q.set(e.call.id,s.reason);if(!b){Xe=true;return}}}for(const e of w){if(_?.aborted){if(e.name!==_uiTool.UI_TOOL_NAME){for(const a of ut(e))yield a}v.push({toolCallId:e.id,content:"Not run \u2014 the user pressed Stop before this call started.",isError:true});continue}const c=e.input?.[_types.UNPARSEABLE_ARGS];if(typeof c==="string"){v.push({toolCallId:e.id,content:`Not run \u2014 this call's arguments were not valid JSON, so nothing changed (${c.slice(0,120)}). Send the call again with compact JSON: {"action": "...", "params": {...}}.`,isError:true});continue}if(e.name===_uiTool.UI_TOOL_NAME){const a=(0,_uiTool.buildUiBlock)(e.input);if(!a.ok||!a.block){v.push({toolCallId:e.id,content:`Invalid ${_uiTool.UI_TOOL_NAME} block:
5
+ ${a.errors.join("\n")}`+L("\n\nResend ONLY the corrected block. Do not rewrite your answer \u2014 whatever you already said this turn has been shown to the user, and saying it again repeats it on their screen."),isError:true});continue}let R=0;if(a.block.kind==="imageGrid"){const N=a.block.images.filter(S=>ke.has(S.url));R=a.block.images.length-N.length;if(N.length===0){v.push({toolCallId:e.id,content:P?"Rejected: image URLs were not read from a tool result."+L(URL_PROVENANCE_REJECTION):URL_PROVENANCE_REJECTION,isError:true});continue}a.block={...a.block,images:N}}if(a.block.kind==="list"){const N=a.block.items.map(S=>{if(!S.image||ke.has(S.image))return S;R+=1;return{...S,image:void 0}});a.block={...a.block,items:N}}yield{type:"block",block:a.block,forToolCallId:e.id};if(a.block.kind==="actions"||a.block.kind==="suggestions"||a.block.kind==="plan"&&a.block.pending){Te=true}if((0,_types2.isAskBlock)(a.block)){Ne=a.block.id;v.push({toolCallId:e.id,content:"Shown. Waiting for the user's answer \u2014 it will arrive as their next message."+L(" Do not guess it.")})}else{v.push({toolCallId:e.id,content:"Shown to the user."+L(" Don't repeat its contents in text.")+(R>0?droppedImageNote(R):"")})}continue}const n=(0,_toProviderTools.fromProviderToolName)(e.name,o);const s=e.input.action;const b=(a,R)=>[{type:"tool-start",id:e.id,toolId:n??e.name,action:s??"",label:a,description:"",params:e.input.params??{},effect:"read"},{type:"tool-end",id:e.id,ok:false,summary:R,durationMs:0}];if(!n){for(const a of b(e.name,"No such tool"))yield a;v.push({toolCallId:e.id,content:`There is no tool called "${e.name}". Use one of the tools you were given.`,isError:true});continue}if(!s){for(const a of b(e.name,"No action given"))yield a;v.push({toolCallId:e.id,content:`"${e.name}" needs an "action" \u2014 it is required, and it names which of this tool's actions to run. See the action list in the tool's description.`,isError:true});continue}const h=findDescriptor(o,n,s);if(!h){const a=o.find(T=>T.toolId===n)?.actions.map(T=>T.action)??[];const R=o.filter(T=>T.toolId!==n&&T.actions.some(Ce=>Ce.action===s));const N=a.filter(T=>closeAction(T,s));const S=[...R.map(T=>`${T.toolId}.${s}`),...N.map(T=>`${n}.${T}`)].slice(0,3);const ie=`${n} has no ${s}.${S.length?` Did you mean ${S.join(" or ")}?`:""}`;for(const T of b(`${n}.${s}`,S.length?ie:"No such action"))yield T;v.push({toolCallId:e.id,content:`${ie}${a.length?` Valid actions: ${a.join(", ")}.`:""}`,isError:true});continue}const C=e.input.params??{};const D=(0,_normalizeParams.normalizeParams)(n,s,C);const i=(0,_validateParams.applyDefaults)(D.params,h.params);if(emptyTap(n,s,i)){for(const a of b(`${n}.${s}`,EMPTY_TAP_ERROR))yield a;v.push({toolCallId:e.id,content:JSON.stringify({ok:false,error:P?"tapElement needs nativeTag, testID or query."+L("Read describeScreen and pass nativeTag, testID or query."):EMPTY_TAP_ERROR}),isError:true});continue}const I=(0,_validateParams.validateParams)(i,h.params);if(!I.ok){v.push({toolCallId:e.id,content:`Invalid parameters for ${n}.${s}:
6
+ ${I.errors.join("\n")}
7
7
 
8
8
  Expected schema:
9
- ${JSON.stringify(h.params)}`,isError:true});continue}const de=(0,_normalizeParams.aliasNote)(u.notes);const H=h.effect!=="read"?Ue.trailer(y,!P):"";if(P&&H)L(_idGrounding.UNSEEN_ID_ADVICE);const be=(0,_policy.describeCall)(n,h,y);const oe=(0,_policy.decide)({descriptor:h,toolId:n,policy:x,isRelease:D,turnScope:M,params:y,tapLabels:ge.get(e.id)});const le=i=>[{type:"tool-start",id:e.id,toolId:n,action:s,label:be,description:h.summary,params:y,effect:h.effect},{type:"tool-end",id:e.id,ok:false,summary:i,durationMs:0}];if(oe.verdict==="refuse"){for(const i of le("refused"))yield i;w.push({toolCallId:e.id,content:oe.reason,isError:true});continue}const _e=oe.verdict==="needs-approval";if(ft&&!Ke&&(h.effect!=="read"||_e)){yield*pt()}if(Xe&&(h.effect!=="read"||_e)){for(const i of le("declined"))yield i;w.push({toolCallId:e.id,content:M==="question"?_turnScope.QUESTION_DECLINED:j.get(e.id)===false?declinedResult(Y.get(e.id)):"Not run \u2014 the user declined another change in this same batch, so none of it was applied. Ask what they would prefer before proposing it again.",isError:true});continue}if(_e){let i;if(j.has(e.id)){i=j.get(e.id)}else if(!oe.turnScoped&&A?.has(`${n}.${s}`)){i=true;j.set(e.id,true)}else{yield{type:"approval-required",id:e.id,toolId:n,action:s,label:be,description:h.summary,reason:oe.reason};const R=(0,_realNow.realNow)();const N=await readTargetDigest({toolId:n,action:s,params:y,dispatch:c,catalog:o});const E=readAnswer(J?await J({id:e.id,toolId:n,action:s,label:be,description:h.summary,reason:oe.reason,params:y,targetDigest:N}):false);pe+=(0,_realNow.realNow)()-R;i=E.approved;j.set(e.id,i);if(E.trust)A?.add(`${n}.${s}`);if(E.reason)Y.set(e.id,E.reason)}if(!i){for(const R of le("declined"))yield R;w.push({toolCallId:e.id,content:M==="question"?_turnScope.QUESTION_DECLINED:declinedResult(Y.get(e.id)),isError:true});continue}}if(_askGate.ACQUISITION_CALLS.has(`${n}.${s}`))Me=true;if(n==="ask-buoy"&&s==="openProcedure")je=true;yield{type:"tool-start",id:e.id,toolId:n,action:s,label:be,description:h.summary,params:y,effect:h.effect};const Ze=(0,_realNow.realNow)();const et=await captureBefore(h,n,y,c);const $e=await captureStoreState(h,n,y,c);if(_?.aborted){for(const i of le("stopped"))yield i;w.push({toolCallId:e.id,content:"Not run \u2014 the user pressed Stop before this call started.",isError:true});continue}const tt=(0,_policy.decide)({descriptor:h,toolId:n,policy:x,isRelease:D,turnScope:M,params:y,tapLabels:ge.get(e.id)});if(tt.verdict==="refuse"){for(const i of le("refused"))yield i;w.push({toolCallId:e.id,content:tt.reason,isError:true});continue}try{let i=s===_snapshotReads.SNAPSHOT_ACTION?(0,_snapshotReads.projectSnapshot)(n,await requireSnapshot(g,n),y):n==="ask-buoy"?await runAskBuoyAction(s,k,c,W,y,B):await(Qe.get(e.id)??c(n,s,y));i=tapResult(n,s,i);const R=(0,_redact.redact)((0,_redact.stripSelfTraffic)(i));const N=reportsFailure(i);if(h.effect!=="read"&&!N)Be=true;const E=fullText(n==="highlight-updates"&&s==="describeScreen"&&!N?(0,_compactScreen.compactScreen)(R):R);const re=W&&!N&&!(n==="ask-buoy"&&s==="retrieve")?W.stash({toolId:n,action:s,params:y,capturedAt:(0,_realNow.realNow)(),text:E}):void 0;const T=encodeResult(E,re);Ue.add(E);const Ce=T.length>MAX_TRACE_RESULT_CHARS?`${T.slice(0,MAX_TRACE_RESULT_CHARS)}\u2026`:T;yield{type:"tool-end",id:e.id,ok:!N,summary:summarise(i),durationMs:(0,_realNow.realNow)()-Ze,result:Ce};const Oe=$e===void 0||N?void 0:await captureStoreState(h,n,y,c);if(h.effect!=="read"&&n!=="ask-buoy"&&!N){const Pe=k.noteExternalRevert(n,s,y);const rt=(0,_effectFor.effectFor)(n,h,y,i,et,{before:$e,after:Oe});if(rt&&!Pe){const nt=k.record(n,s,rt,st);if(nt)nt.callId=e.id}}const ot=N?void 0:(0,_receipts.projectReceipt)({toolId:n,action:s,params:y,result:R,before:$e??et,after:Oe,effect:h.effect});if(ot)yield{type:"block",block:ot,forToolCallId:e.id};const ce=h.effect!=="read"&&!N?await(0,_verify.verifyOutcome)({toolId:n,action:s,params:y,result:i,dispatch:c,readSnapshot:g,signal:_,after:Oe}):void 0;if(ce)yield{type:"tool-verified",id:e.id,verification:ce};if(P&&ce?.status==="failed")L(_verify.VERIFICATION_REPAIR);for(const Pe of T.match(at)??[])ve.add(Pe);w.push({toolCallId:e.id,content:T+ownedKeyNote(n,h,y,U,P?L:void 0)+de+H+(ce?(0,_verify.verificationTrailer)(ce,!P):"")+(We.has(e.id)?L(_textToolCalls.SALVAGE_NOTE):""),...re?{ref:re}:{}});if(n==="app"&&(s==="reloadApp"||s==="reload")){Ye=true}}catch(i){const R=i instanceof Error?i.message:String(i);yield{type:"tool-end",id:e.id,ok:false,summary:R,durationMs:(0,_realNow.realNow)()-Ze};w.push({toolCallId:e.id,content:`Failed: ${R}${H}`,isError:true})}}if(S.length){X.push(callSignature(S));if(X.length>LOOP_REPEATS)X.shift();const e=!Le&&X.length===LOOP_REPEATS&&X.every(l=>l===X[0]);if(e){Le=true;const l=w[w.length-1];if(P)me.push(LOOP_WARNING);else if(l)l.content=`${l.content}
9
+ ${JSON.stringify(h.params)}`,isError:true});continue}const _e=(0,_normalizeParams.aliasNote)(D.notes);const J=h.effect!=="read"?Ue.trailer(i,!P):"";if(P&&J)L(_idGrounding.UNSEEN_ID_ADVICE);const z=(0,_policy.describeCall)(n,h,i);const se=(0,_policy.decide)({descriptor:h,toolId:n,policy:x,isRelease:M,turnScope:j,params:i,tapLabels:be.get(e.id)});const ue=a=>[{type:"tool-start",id:e.id,toolId:n,action:s,label:z,description:h.summary,params:i,effect:h.effect},{type:"tool-end",id:e.id,ok:false,summary:a,durationMs:0}];if(se.verdict==="refuse"){for(const a of ue("refused"))yield a;v.push({toolCallId:e.id,content:se.reason,isError:true});continue}const Ae=se.verdict==="needs-approval";if(ft&&!Ve&&(h.effect!=="read"||Ae)){yield*pt()}if(Xe&&(h.effect!=="read"||Ae)){for(const a of ue("declined"))yield a;v.push({toolCallId:e.id,content:j==="question"?_turnScope.QUESTION_DECLINED:B.get(e.id)===false?declinedResult(Q.get(e.id)):"Not run \u2014 the user declined another change in this same batch, so none of it was applied. Ask what they would prefer before proposing it again.",isError:true});continue}if(Ae){let a;if(B.has(e.id)){a=B.get(e.id)}else if(!se.turnScoped&&A?.has(`${n}.${s}`)){a=true;B.set(e.id,true)}else{yield{type:"approval-required",id:e.id,toolId:n,action:s,label:z,description:h.summary,reason:se.reason};const R=(0,_realNow.realNow)();const N=await readTargetDigest({toolId:n,action:s,params:i,dispatch:u,catalog:o});const S=readAnswer(Y?await Y({id:e.id,toolId:n,action:s,label:z,description:h.summary,reason:se.reason,params:i,targetDigest:N}):false);le+=(0,_realNow.realNow)()-R;a=S.approved;B.set(e.id,a);if(S.trust)A?.add(`${n}.${s}`);if(S.reason)Q.set(e.id,S.reason)}if(!a){for(const R of ue("declined"))yield R;v.push({toolCallId:e.id,content:j==="question"?_turnScope.QUESTION_DECLINED:declinedResult(Q.get(e.id)),isError:true});continue}}if(_askGate.ACQUISITION_CALLS.has(`${n}.${s}`))Le=true;if(n==="ask-buoy"&&s==="openProcedure")je=true;yield{type:"tool-start",id:e.id,toolId:n,action:s,label:z,description:h.summary,params:i,effect:h.effect};const Ze=(0,_realNow.realNow)();const et=await captureBefore(h,n,i,u);const $e=await captureStoreState(h,n,i,u);if(_?.aborted){for(const a of ue("stopped"))yield a;v.push({toolCallId:e.id,content:"Not run \u2014 the user pressed Stop before this call started.",isError:true});continue}const tt=(0,_policy.decide)({descriptor:h,toolId:n,policy:x,isRelease:M,turnScope:j,params:i,tapLabels:be.get(e.id)});if(tt.verdict==="refuse"){for(const a of ue("refused"))yield a;v.push({toolCallId:e.id,content:tt.reason,isError:true});continue}try{let a=s===_snapshotReads.SNAPSHOT_ACTION?(0,_snapshotReads.projectSnapshot)(n,await requireSnapshot(m,n),i):n==="ask-buoy"?await runAskBuoyAction(s,g,u,K,i,F):await(Ke.get(e.id)??u(n,s,i));a=tapResult(n,s,a);const R=(0,_redact.redact)((0,_redact.stripSelfTraffic)(a));const N=reportsFailure(a);if(h.effect!=="read"&&!N)Be=true;const S=fullText(n==="highlight-updates"&&s==="describeScreen"&&!N?(0,_compactScreen.compactScreen)(R):R);const ie=K&&!N&&!(n==="ask-buoy"&&s==="retrieve")?K.stash({toolId:n,action:s,params:i,capturedAt:(0,_realNow.realNow)(),text:S}):void 0;const T=encodeResult(S,ie);Ue.add(S);const Ce=T.length>MAX_TRACE_RESULT_CHARS?`${T.slice(0,MAX_TRACE_RESULT_CHARS)}\u2026`:T;yield{type:"tool-end",id:e.id,ok:!N,summary:summarise(a),durationMs:(0,_realNow.realNow)()-Ze,result:Ce};const Oe=$e===void 0||N?void 0:await captureStoreState(h,n,i,u);if(h.effect!=="read"&&n!=="ask-buoy"&&!N){const Pe=g.noteExternalRevert(n,s,i);const rt=(0,_effectFor.effectFor)(n,h,i,a,et,{before:$e,after:Oe});if(rt&&!Pe){const nt=g.record(n,s,rt,st);if(nt)nt.callId=e.id}}const ot=N?void 0:(0,_receipts.projectReceipt)({toolId:n,action:s,params:i,result:R,before:$e??et,after:Oe,effect:h.effect});if(ot)yield{type:"block",block:ot,forToolCallId:e.id};const fe=h.effect!=="read"&&!N?await(0,_verify.verifyOutcome)({toolId:n,action:s,params:i,result:a,dispatch:u,readSnapshot:m,signal:_,after:Oe}):void 0;if(fe)yield{type:"tool-verified",id:e.id,verification:fe};if(P&&fe?.status==="failed")L(_verify.VERIFICATION_REPAIR);for(const Pe of T.match(at)??[])ke.add(Pe);v.push({toolCallId:e.id,content:T+ownedKeyNote(n,h,i,U,P?L:void 0)+_e+J+(fe?(0,_verify.verificationTrailer)(fe,!P):"")+(Je.has(e.id)?L(_textToolCalls.SALVAGE_NOTE):""),...ie?{ref:ie}:{}});if(n==="app"&&(s==="reloadApp"||s==="reload")){Ye=true}}catch(a){const R=a instanceof Error?a.message:String(a);yield{type:"tool-end",id:e.id,ok:false,summary:R,durationMs:(0,_realNow.realNow)()-Ze};v.push({toolCallId:e.id,content:`Failed: ${R}${J}`,isError:true})}}if(w.length){te.push(callSignature(w));if(te.length>LOOP_REPEATS)te.shift();const e=!De&&te.length===LOOP_REPEATS&&te.every(c=>c===te[0]);if(e){De=true;const c=v[v.length-1];if(P)ge.push(LOOP_WARNING);else if(c)c.content=`${c.content}
10
10
 
11
- ${LOOP_WARNING}`}}f.push({role:"tool-results",results:w});if(me.length)f.push(se([...new Set(me)].join("\n\n"),true));if(Ae){yield{type:"awaiting-user",blockId:Ae};yield{type:"done",stopReason:"awaiting-user"};return f}if(Ye){yield{type:"done",stopReason:"realm-died"};return f}}if(_?.aborted){yield{type:"done",stopReason:"stopped"};return f}const Z=[];let Fe=false;let Ee=false;const ie=[...f,se(STEP_CAP_WRAP_UP,qe())];const ct=z?{messages:ie}:(0,_historyBudget.budgetForRequest)(ie,fe(),O.chars(K),O.charsPerToken,k.liveCallIds());try{if(z&&!ze(ie))throw new Error(Re);if(z||P||ue.liveBlock==="append"||ue.liveBlock==="system-msg")f.push(ie[ie.length-1]);for await(const p of r.send({messages:ct.messages,system:a,systemVolatile:d,tools:Q,toolChoice:"none",model:v,maxTokens:m,signal:_,meta:{askId:xe,round:V+1,attempt:1}})){if(p.type==="text")Z.push(p.delta);else if(p.type==="tool-call"||p.type==="error")Ee=true;else if(p.type==="meter")yield{type:"meter",frame:p.frame};else if(p.type==="done"){if(p.outcome==="refused"||p.outcome==="context-limited"){yield{type:"error",message:p.outcome==="refused"?"Claude could not help with this request.":"Claude ran out of room for this turn. Please send a new message."};yield{type:"done",stopReason:"error"};return f}Fe=p.outcome==="completed";if(p.usage)yield{type:"usage",...p.usage,model:p.model}}}}catch{Ee=true}if(_?.aborted){yield{type:"done",stopReason:"stopped"};return f}const Ge=Z.join("");if(Ee||!Fe||!Ge.trim()||(0,_textToolCalls.couldBeToolCallEnvelope)(Ge)){const p=k.list().filter(I=>!it.has(I.id));Z.length=0;Z.push(["I ran out of steps. The job is not done.",...p.length?["These steps ran:",...p.map(I=>`- ${I.effect.label}${I.undoneAt?" (since undone)":""}`),"This list does not prove each change worked."]:[]].join("\n"))}let He=true;for(const p of Z){if(!p)continue;yield{type:"text",delta:p,...He&&we?{breakBefore:true}:{}};He=false}f.push({role:"assistant",text:Z.join("")});yield{type:"block",block:{id:`cap${(0,_realNow.realNow)()}`,kind:"notice",tone:"warning",text:"I ran out of steps. The job is not done. Tap Continue to go on.",actions:[{label:"Continue",primary:true,send:CONTINUE_SEND}]}};yield{type:"done",stopReason:"step-cap"};return f}function ownedKeyNote(t,r,o,a,d){if(t!=="storage"||r.effect==="read")return"";if(!a||typeof o.key!=="string")return"";const v=a[o.key];if(!v)return"";const m=`
11
+ ${LOOP_WARNING}`}}f.push({role:"tool-results",results:v});if(ge.length)f.push(de([...new Set(ge)].join("\n\n"),true));if(Ne){yield{type:"awaiting-user",blockId:Ne};yield{type:"done",stopReason:"awaiting-user"};return f}if(Ye){yield{type:"done",stopReason:"realm-died"};return f}}if(_?.aborted){yield{type:"done",stopReason:"stopped"};return f}const oe=[];let Fe=false;let Se=false;const ce=[...f,de(STEP_CAP_WRAP_UP,qe())];const ct=G?{messages:ce}:(0,_historyBudget.budgetForRequest)(ce,he(),O.chars(ee),O.charsPerToken,g.liveCallIds());try{if(G&&!ze(ce))throw new Error(Re);if(G||P||pe.liveBlock==="append"||pe.liveBlock==="system-msg")f.push(ce[ce.length-1]);for await(const p of r.send({messages:ct.messages,system:d,systemVolatile:l,tools:V,toolChoice:"none",model:k,maxTokens:y,signal:_,meta:{askId:xe,round:X+1,attempt:1}})){if(p.type==="text")oe.push(p.delta);else if(p.type==="tool-call"||p.type==="error")Se=true;else if(p.type==="meter")yield{type:"meter",frame:p.frame};else if(p.type==="done"){if(p.outcome==="refused"||p.outcome==="context-limited"){yield{type:"error",message:p.outcome==="refused"?"Claude could not help with this request.":"Claude ran out of room for this turn. Please send a new message."};yield{type:"done",stopReason:"error"};return f}Fe=p.outcome==="completed";if(p.usage)yield{type:"usage",...p.usage,model:p.model}}}}catch{Se=true}if(_?.aborted){yield{type:"done",stopReason:"stopped"};return f}const Ge=oe.join("");if(Se||!Fe||!Ge.trim()||(0,_textToolCalls.couldBeToolCallEnvelope)(Ge)){const p=g.list().filter(E=>!it.has(E.id));oe.length=0;oe.push(["I ran out of steps. The job is not done.",...p.length?["These steps ran:",...p.map(E=>`- ${E.effect.label}${E.undoneAt?" (since undone)":""}`),"This list does not prove each change worked."]:[]].join("\n"))}let He=true;for(const p of oe){if(!p)continue;yield{type:"text",delta:p,...He&&ve?{breakBefore:true}:{}};He=false}f.push({role:"assistant",text:oe.join("")});yield{type:"block",block:{id:`cap${(0,_realNow.realNow)()}`,kind:"notice",tone:"warning",text:"I ran out of steps. The job is not done. Tap Continue to go on.",actions:[{label:"Continue",primary:true,send:CONTINUE_SEND}]}};yield{type:"done",stopReason:"step-cap"};return f}function ownedKeyNote(t,r,o,d,l){if(t!=="storage"||r.effect==="read")return"";if(!d||typeof o.key!=="string")return"";const k=d[o.key];if(!k)return"";const y=`
12
12
 
13
- [Buoy] This wrote to disk, but "${o.key}" is the saved copy of the live "${v}" store, so nothing on screen has changed \u2014 the app read that key once at startup and has held the state in memory since.`;if(d){d("Use zustand.rehydrate for the store named in the result to load the saved value. Use zustand.setState to change the live store. If the change was for the next app launch, no more work is needed.");return m}return m+` Call zustand.rehydrate({"storeName":"${v}"}) to make the app pick this up, or use zustand.setState next time to change the store directly. If you meant to set the value for the app's next launch, this is already done and no further action is needed.`}async function readTargetDigest(t){const r=findDescriptor(t.catalog??_catalog.CATALOG,t.toolId,t.action);if(!r||r.effect==="read")return void 0;const o=await captureStoreState(r,t.toolId,t.params,t.dispatch);if(o!==void 0)return(0,_digest.digestOf)(o);const a=await captureBefore(r,t.toolId,t.params,t.dispatch);if(a!==void 0)return(0,_digest.digestOf)(a);return void 0}async function runGatedAction(t){const{toolId:r,action:o,dispatch:a,ledger:d,policy:v,isRelease:m}=t;const c=t.catalog??_catalog.CATALOG;const g=findDescriptor(c,r,o);if(!g){return{ok:false,error:`${r}.${o} is not in Buoy's catalog.`}}const U=(0,_normalizeParams.normalizeParams)(r,o,t.params??{});const k=(0,_validateParams.applyDefaults)(U.params,g.params);if(emptyTap(r,o,k))return{ok:false,error:EMPTY_TAP_ERROR};const x=(0,_validateParams.validateParams)(k,g.params);if(!x.ok){return{ok:false,error:x.errors.join("\n")}}const D=(0,_policy.decide)({descriptor:g,toolId:r,policy:v,isRelease:m});if(D.verdict==="refuse"){return{ok:false,error:D.reason}}const J=await captureBefore(g,r,k,a);const _=await captureStoreState(g,r,k,a);const W=(0,_policy.decide)({descriptor:g,toolId:r,policy:v,isRelease:m});if(W.verdict==="refuse"){return{ok:false,error:W.reason}}try{let A=r==="ask-buoy"?await runAskBuoyAction(o,d,a,void 0,k):await a(r,o,k);A=tapResult(r,o,A);if(reportsFailure(A)){const B=A.error;return{ok:false,error:typeof B==="string"?B:"The tool refused this."}}if(g.effect!=="read"&&r!=="ask-buoy"){const B=d.noteExternalRevert(r,o,k);const Y=await captureStoreState(g,r,k,a);const O=(0,_effectFor.effectFor)(r,g,k,A,J,{before:_,after:Y});if(O&&!B)d.record(r,o,O)}return{ok:true,result:A}}catch(A){return{ok:false,error:A instanceof Error?A.message:String(A)}}}async function runAskBuoyAction(t,r,o,a,d,v){if(t==="retrieve"){return(0,_retrieve.retrieveEvidence)(a,d??{})}if(t==="openProcedure"){const m=typeof d?.id==="string"?d.id:"";const c=v?.find(g=>g.id===m);if(!c){const g=(v??[]).map(U=>U.id);return{ok:false,error:g.length?`No procedure "${m}". This app's procedures: ${g.join(", ")}.`:"This app has no procedures written for it."}}return{id:c.id,title:c.title,...c.version?{version:c.version}:{},...c.requires?.length?{requires:c.requires}:{},body:c.body,note:"Follow these steps with the ordinary tools. Every write still goes through the same policy, approval and undo as any other call; a step that is refused stays refused."}}if(t==="listChanges"){const m=r.list().filter(c=>!c.undoneAt).map(c=>({id:c.id,toolId:c.toolId,action:c.action,kind:c.effect.kind,label:c.effect.label,reversible:(0,_ledger.isReversible)(c.effect)}));return{changes:m,returned:m.length}}if(t==="undoChange"){const m=typeof d?.id==="string"?d.id:"";const c=r.list().find(U=>U.id===m);if(!c){const U=r.list().filter(k=>!k.undoneAt).map(k=>k.id);return{ok:false,error:`No change with id "${m}". Call listChanges for the current ids${U.length?` (${U.join(", ")})`:""}.`}}if(c.undoneAt)return{ok:false,error:`"${c.effect.label}" was already undone.`};if(!(0,_ledger.isReversible)(c.effect)){return{ok:false,error:`"${c.effect.label}" can't be undone automatically \u2014 it is permanent.`}}const g=await r.revertOne(c,o);return g?{ok:false,error:g}:{ok:true,undone:{id:c.id,label:c.effect.label}}}if(t==="undoAll"){const m=await r.revertAll(o);return{ok:m.failed.length===0,...m}}throw new Error(`Unknown ask-buoy action "${t}"`)}async function requireSnapshot(t,r){if(!t){throw new Error(`This app cannot read ${r}'s snapshot \u2014 Buoy's tool registry is not published here.`)}return await t(r)}async function captureStoreState(t,r,o,a){if(r==="zustand"&&t.action==="setState"){if(typeof o.storeName!=="string")return void 0;try{return await a(r,"getStoreState",{storeName:o.storeName})}catch{return void 0}}if(r==="query"&&t.action==="setQueryData"){const d=typeof o.queryHash==="string"?o.queryHash:Array.isArray(o.queryKey)?(0,_normalizeParams.hashQueryKey)(o.queryKey):void 0;if(!d)return void 0;try{return await a(r,"getQueryData",{queryHash:d})}catch{return void 0}}return void 0}async function captureBefore(t,r,o,a){if(t.effect==="read")return void 0;if(r==="network")return captureRuleSwitch(t,o,a);if(r!=="storage"||typeof o.key!=="string")return void 0;const d=t.action.startsWith("async.")?"async.getItem":t.action.startsWith("mmkv.")?"mmkv.get":void 0;if(!d)return void 0;const v={key:o.key};if(d==="mmkv.get"){if(typeof o.instanceId!=="string")return void 0;v.instanceId=o.instanceId}try{const m=await a(r,d,v);const c=m&&typeof m==="object"?m:void 0;if(c?.found===false)return void 0;const g=c?c.value:m;return{had:g!==void 0&&g!==null,value:g??void 0}}catch{return void 0}}async function captureRuleSwitch(t,r,o){if(t.action!=="setOverrideRuleEnabled"&&t.action!=="setOverridesEnabled"){return void 0}try{const a=await o("network","listOverrideRules",{});if(!a||typeof a!=="object")return void 0;if(t.action==="setOverridesEnabled"){return{had:true,value:String(a.enabled!==false)}}const d=(a.rules??[]).find(v=>v&&v.id===r.id);if(!d)return void 0;return{had:true,value:String(d.enabled!==false)}}catch{return void 0}}function newAskId(){const t="abcdefghijklmnopqrstuvwxyz0123456789";let r="ask_";for(let o=0;o<20;o++)r+=t[Math.floor(Math.random()*t.length)];return r}
13
+ [Buoy] This wrote to disk, but "${o.key}" is the saved copy of the live "${k}" store, so nothing on screen has changed \u2014 the app read that key once at startup and has held the state in memory since.`;if(l){l("Use zustand.rehydrate for the store named in the result to load the saved value. Use zustand.setState to change the live store. If the change was for the next app launch, no more work is needed.");return y}return y+` Call zustand.rehydrate({"storeName":"${k}"}) to make the app pick this up, or use zustand.setState next time to change the store directly. If you meant to set the value for the app's next launch, this is already done and no further action is needed.`}async function readTargetDigest(t){const r=findDescriptor(t.catalog??_catalog.CATALOG,t.toolId,t.action);if(!r||r.effect==="read")return void 0;const o=await captureStoreState(r,t.toolId,t.params,t.dispatch);if(o!==void 0)return(0,_digest.digestOf)(o);const d=await captureBefore(r,t.toolId,t.params,t.dispatch);if(d!==void 0)return(0,_digest.digestOf)(d);return void 0}async function runGatedAction(t){const{toolId:r,action:o,dispatch:d,ledger:l,policy:k,isRelease:y}=t;const u=t.catalog??_catalog.CATALOG;const m=findDescriptor(u,r,o);if(!m){return{ok:false,error:`${r}.${o} is not in Buoy's catalog.`}}const U=(0,_normalizeParams.normalizeParams)(r,o,t.params??{});const g=(0,_validateParams.applyDefaults)(U.params,m.params);if(emptyTap(r,o,g))return{ok:false,error:EMPTY_TAP_ERROR};const x=(0,_validateParams.validateParams)(g,m.params);if(!x.ok){return{ok:false,error:x.errors.join("\n")}}const M=(0,_policy.decide)({descriptor:m,toolId:r,policy:k,isRelease:y});if(M.verdict==="refuse"){return{ok:false,error:M.reason}}const Y=await captureBefore(m,r,g,d);const _=await captureStoreState(m,r,g,d);const K=(0,_policy.decide)({descriptor:m,toolId:r,policy:k,isRelease:y});if(K.verdict==="refuse"){return{ok:false,error:K.reason}}try{let A=r==="ask-buoy"?await runAskBuoyAction(o,l,d,void 0,g):await d(r,o,g);A=tapResult(r,o,A);if(reportsFailure(A)){const F=A.error;return{ok:false,error:typeof F==="string"?F:"The tool refused this."}}if(m.effect!=="read"&&r!=="ask-buoy"){const F=l.noteExternalRevert(r,o,g);const Q=await captureStoreState(m,r,g,d);const O=(0,_effectFor.effectFor)(r,m,g,A,Y,{before:_,after:Q});if(O&&!F)l.record(r,o,O)}return{ok:true,result:A}}catch(A){return{ok:false,error:A instanceof Error?A.message:String(A)}}}async function runAskBuoyAction(t,r,o,d,l,k){if(t==="retrieve"){return(0,_retrieve.retrieveEvidence)(d,l??{})}if(t==="openProcedure"){const y=typeof l?.id==="string"?l.id:"";const u=k?.find(m=>m.id===y);if(!u){const m=(k??[]).map(U=>U.id);return{ok:false,error:m.length?`No procedure "${y}". This app's procedures: ${m.join(", ")}.`:"This app has no procedures written for it."}}return{id:u.id,title:u.title,...u.version?{version:u.version}:{},...u.requires?.length?{requires:u.requires}:{},body:u.body,note:"Follow these steps with the ordinary tools. Every write still goes through the same policy, approval and undo as any other call; a step that is refused stays refused."}}if(t==="listChanges"){const y=r.list().filter(u=>!u.undoneAt).map(u=>({id:u.id,toolId:u.toolId,action:u.action,kind:u.effect.kind,label:u.effect.label,reversible:(0,_ledger.isReversible)(u.effect)}));return{changes:y,returned:y.length}}if(t==="undoChange"){const y=typeof l?.id==="string"?l.id:"";const u=r.list().find(U=>U.id===y);if(!u){const U=r.list().filter(g=>!g.undoneAt).map(g=>g.id);return{ok:false,error:`No change with id "${y}". Call listChanges for the current ids${U.length?` (${U.join(", ")})`:""}.`}}if(u.undoneAt)return{ok:false,error:`"${u.effect.label}" was already undone.`};if(!(0,_ledger.isReversible)(u.effect)){return{ok:false,error:`"${u.effect.label}" can't be undone automatically \u2014 it is permanent.`}}const m=await r.revertOne(u,o);return m?{ok:false,error:m}:{ok:true,undone:{id:u.id,label:u.effect.label}}}if(t==="undoAll"){const y=await r.revertAll(o);return{ok:y.failed.length===0,...y}}throw new Error(`Unknown ask-buoy action "${t}"`)}async function requireSnapshot(t,r){if(!t){throw new Error(`This app cannot read ${r}'s snapshot \u2014 Buoy's tool registry is not published here.`)}return await t(r)}async function captureStoreState(t,r,o,d){if(r==="zustand"&&t.action==="setState"){if(typeof o.storeName!=="string")return void 0;try{return await d(r,"getStoreState",{storeName:o.storeName})}catch{return void 0}}if(r==="query"&&t.action==="setQueryData"){const l=typeof o.queryHash==="string"?o.queryHash:Array.isArray(o.queryKey)?(0,_normalizeParams.hashQueryKey)(o.queryKey):void 0;if(!l)return void 0;try{return await d(r,"getQueryData",{queryHash:l})}catch{return void 0}}return void 0}async function captureBefore(t,r,o,d){if(t.effect==="read")return void 0;if(r==="network")return captureRuleSwitch(t,o,d);if(r!=="storage"||typeof o.key!=="string")return void 0;const l=t.action.startsWith("async.")?"async.getItem":t.action.startsWith("mmkv.")?"mmkv.get":void 0;if(!l)return void 0;const k={key:o.key};if(l==="mmkv.get"){if(typeof o.instanceId!=="string")return void 0;k.instanceId=o.instanceId}try{const y=await d(r,l,k);const u=y&&typeof y==="object"?y:void 0;if(u?.found===false)return void 0;const m=u?u.value:y;return{had:m!==void 0&&m!==null,value:m??void 0}}catch{return void 0}}async function captureRuleSwitch(t,r,o){if(t.action!=="setOverrideRuleEnabled"&&t.action!=="setOverridesEnabled"){return void 0}try{const d=await o("network","listOverrideRules",{});if(!d||typeof d!=="object")return void 0;if(t.action==="setOverridesEnabled"){return{had:true,value:String(d.enabled!==false)}}const l=(d.rules??[]).find(k=>k&&k.id===r.id);if(!l)return void 0;return{had:true,value:String(l.enabled!==false)}}catch{return void 0}}function newAskId(){const t="abcdefghijklmnopqrstuvwxyz0123456789";let r="ask_";for(let o=0;o<20;o++)r+=t[Math.floor(Math.random()*t.length)];return r}
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});Object.defineProperty(exports,"compressConsumed",{enumerable:true,get:function(){return _historyBudget.compressConsumed}});exports.createAskBuoySession=createAskBuoySession;exports.resumableHistory=resumableHistory;Object.defineProperty(exports,"trimHistory",{enumerable:true,get:function(){return _historyBudget.trimHistory}});Object.defineProperty(exports,"trimHistoryReport",{enumerable:true,get:function(){return _historyBudget.trimHistoryReport}});var _feeds=require("./feeds");var _catalog=require("./catalog/catalog.g");var _buildContextPack=require("./context/buildContextPack");var _runAgentTurn=require("./engine/runAgentTurn");var _systemPrompt=require("./engine/systemPrompt");var _ledger=require("./effects/ledger");var _evidence=require("./engine/evidence");var _tokenCalibration=require("./engine/tokenCalibration");var _historyBudget=require("./engine/historyBudget");var _anthropic=require("./providers/anthropic");var _openai=require("./providers/openai");var _fallback=require("./providers/fallback");var _policy=require("./policy/policy");var _redact=require("./policy/redact");function resumableHistory(e){let r=e.length;while(r>0){const s=e[r-1];if(s.role==="assistant"&&!s.toolCalls?.length)break;r-=1}return e.slice(0,r).map(s=>s.role==="assistant"&&s.thinking?{...s,thinking:void 0}:s)}function createAskBuoySession(e){const r=(0,_feeds.selectFeed)(e.provider?.protocol??e.protocol,e.feedOptions);e={...e,feedOptions:r.options};let s=0;const T=e.catalog??_catalog.CATALOG;const l=new _ledger.EffectLedger;const A=e.policy??{};let a=[];const g=new Set;const O=new _evidence.EvidenceStore;const c=new _tokenCalibration.TokenCalibration;let u;let q=false;let m=false;const v=new Set;let y=false;let b=0;let k=0;let f={};let P={};(0,_redact.registerSelfEndpoint)(e.endpoint);const S=(t,o)=>t==="openai"?(0,_openai.createOpenAIProvider)(o):(0,_anthropic.createAnthropicProvider)(o);let w=null;if(!e.provider&&e.fallback){const t=e.fallback;(0,_redact.registerSelfEndpoint)(t.endpoint);const o={...e,endpoint:t.endpoint,model:t.model,feedOptions:(0,_feeds.selectFeed)(t.protocol).options};w=(0,_fallback.createFallbackProvider)({provider:S(e.protocol,e),model:e.model},{provider:S(t.protocol,o),model:t.model},h=>e.onModelSwitch?.(h==="second"?"fallback":"primary"))}const $=e.provider??w??S(e.protocol,e);let d=e.availableActions;let i=Object.keys(d);const n={...A};function j(){for(const t of Object.keys(n))delete n[t];Object.assign(n,A);if(m){n.requireApproval=[];n.requireApprovalFor=[]}if(y)n.readOnly=true}function E(){return n}function B(){u=(0,_systemPrompt.buildSystemPrompt)({catalog:T,context:{...e.context,digest:{...f,...e.context?.digest}},isRelease:e.isRelease,readOnly:n.readOnly??false,readOnlySource:A.readOnly?"app":y?"device":void 0,requireApproval:(0,_policy.resolveRequireApproval)(n),approvalsBypassed:m,appName:e.appName,platform:e.platform,availableToolIds:i})}async function H(){if(q)return;q=true;f={};try{f=await(0,_buildContextPack.buildContextDigest)({dispatch:e.dispatch,readSnapshot:e.readSnapshot,availableToolIds:i,availableActions:d})}catch{}P={};for(const t of f.zustandStores??[]){const o=t;if(o?.persistsTo&&o.name)P[o.persistsTo]=o.name}B()}return{ledger:l,evidence:O,calibration:c,trustedActions:()=>[...v],untrust:t=>{v.delete(t)},get messages(){return a},prime:H,setAvailableActions(t){d=t;i=Object.keys(t)},setApprovalBypass(t){if(m===t)return;m=t;j();if(u)B()},setReadOnly(t){if(y===t)return;y=t;j();if(u)B()},restore(t){if(a.length>0)return;const o=(0,_historyBudget.trimHistoryReport)(resumableHistory(t),c.charsPerToken,l.liveCallIds());a=o.messages;b=o.droppedRounds},async*send(t,o){const h=k;await H();let R;try{R=await(0,_buildContextPack.buildLiveContext)({dispatch:e.dispatch,readSnapshot:e.readSnapshot,availableToolIds:i,availableActions:d})}catch{R=void 0}if(h!==k){yield{type:"done",stopReason:"superseded"};return}const I=(0,_systemPrompt.buildLiveBlock)(R,l.list().map(p=>({label:`${p.toolId}.${p.action}${p.effect.label?` \u2014 ${p.effect.label}`:""}`,undone:p.undoneAt!==void 0})));const F={role:"user",text:t,...r.name==="claude"?{turnId:`turn-${++s}`}:{},...r.options.liveBlock&&r.options.liveBlock!=="system-tail"?{liveBlock:{placement:r.options.liveBlock,text:I}}:{}};const _=a[a.length-1];const M=_?.role==="user"&&(_.systemNotice||_.liveBlock?.placement==="system-msg")?[{role:"assistant",text:"[Buoy: The prior turn stopped before an answer.]"}]:[];const C=(0,_historyBudget.trimHistoryReport)([...a,...M,F],c.charsPerToken,l.liveCallIds());const G=C.messages;const L=C.droppedRounds+b;b=0;if(L>0)yield{type:"history-trimmed",droppedRounds:L,droppedPinned:C.droppedPinned};const N=(0,_runAgentTurn.runAgentTurn)({provider:$,catalog:T,messages:G,system:u,systemVolatile:r.options.liveBlock&&r.options.liveBlock!=="system-tail"?void 0:I,feedOptions:r.options,model:e.model,maxTokens:r.options.maxTokens??e.maxTokens??4096,dispatch:e.dispatch,readSnapshot:e.readSnapshot,storeKeyOwners:P,ledger:l,policy:E(),isRelease:e.isRelease,availableToolIds:i,availableActions:d,requestApproval:e.requestApproval,seenUrls:g,evidence:O,calibration:c,trusted:v,procedures:(0,_systemPrompt.listableProcedures)(e.context?.procedures,i),signal:o});let x=await N.next();while(!x.done){yield x.value;x=await N.next()}if(h===k)a=x.value},reset(){k+=1;w?.reset();a=[];b=0;l.clear();g.clear();O.clear();v.clear();q=false}}}
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});Object.defineProperty(exports,"compressConsumed",{enumerable:true,get:function(){return _historyBudget.compressConsumed}});exports.createAskBuoySession=createAskBuoySession;exports.resumableHistory=resumableHistory;Object.defineProperty(exports,"trimHistory",{enumerable:true,get:function(){return _historyBudget.trimHistory}});Object.defineProperty(exports,"trimHistoryReport",{enumerable:true,get:function(){return _historyBudget.trimHistoryReport}});var _feeds=require("./feeds");var _catalog=require("./catalog/catalog.g");var _buildContextPack=require("./context/buildContextPack");var _runAgentTurn=require("./engine/runAgentTurn");var _systemPrompt=require("./engine/systemPrompt");var _ledger=require("./effects/ledger");var _evidence=require("./engine/evidence");var _tokenCalibration=require("./engine/tokenCalibration");var _historyBudget=require("./engine/historyBudget");var _anthropic=require("./providers/anthropic");var _openai=require("./providers/openai");var _fallback=require("./providers/fallback");var _policy=require("./policy/policy");var _redact=require("./policy/redact");function resumableHistory(e){let r=e.length;while(r>0){const o=e[r-1];if(o.role==="assistant"&&!o.toolCalls?.length)break;r-=1}return e.slice(0,r).map(o=>o.role==="assistant"&&o.thinking?{...o,thinking:void 0}:o)}function createAskBuoySession(e){const r=(0,_feeds.selectFeed)(e.provider?.protocol??e.protocol,e.feedOptions);e={...e,feedOptions:r.options};let o=0;const T=e.catalog??_catalog.CATALOG;const l=new _ledger.EffectLedger;const A=e.policy??{};let a=[];const g=new Set;const O=new _evidence.EvidenceStore;const u=new _tokenCalibration.TokenCalibration;let d;let q=false;let m=false;const v=new Set;let y=false;let b=0;let k=0;let f={};let P={};(0,_redact.registerSelfEndpoint)(e.endpoint);const S=(t,s)=>t==="openai"?(0,_openai.createOpenAIProvider)(s):(0,_anthropic.createAnthropicProvider)(s);let w=null;if(!e.provider&&e.fallback){const t=e.fallback;(0,_redact.registerSelfEndpoint)(t.endpoint);const s={...e,endpoint:t.endpoint,model:t.model,feedOptions:(0,_feeds.selectFeed)(t.protocol).options};w=(0,_fallback.createFallbackProvider)({provider:S(e.protocol,e),model:e.model},{provider:S(t.protocol,s),model:t.model},h=>e.onModelSwitch?.(h==="second"?"fallback":"primary"))}const $=e.provider??w??S(e.protocol,e);let p=e.availableActions;let i=Object.keys(p);const n={...A};function j(){for(const t of Object.keys(n))delete n[t];Object.assign(n,A);if(m){n.requireApproval=[];n.requireApprovalFor=[]}if(y)n.readOnly=true}function E(){return n}function B(){if(e.system!==void 0){d=e.system;return}d=(0,_systemPrompt.buildSystemPrompt)({catalog:T,context:{...e.context,digest:{...f,...e.context?.digest}},isRelease:e.isRelease,readOnly:n.readOnly??false,readOnlySource:A.readOnly?"app":y?"device":void 0,requireApproval:(0,_policy.resolveRequireApproval)(n),approvalsBypassed:m,appName:e.appName,platform:e.platform,availableToolIds:i})}async function H(){if(q)return;q=true;f={};try{f=await(0,_buildContextPack.buildContextDigest)({dispatch:e.dispatch,readSnapshot:e.readSnapshot,availableToolIds:i,availableActions:p})}catch{}P={};for(const t of f.zustandStores??[]){const s=t;if(s?.persistsTo&&s.name)P[s.persistsTo]=s.name}B()}return{ledger:l,evidence:O,calibration:u,trustedActions:()=>[...v],untrust:t=>{v.delete(t)},get messages(){return a},prime:H,setAvailableActions(t){p=t;i=Object.keys(t)},setApprovalBypass(t){if(m===t)return;m=t;j();if(d)B()},setReadOnly(t){if(y===t)return;y=t;j();if(d)B()},restore(t){if(a.length>0)return;const s=(0,_historyBudget.trimHistoryReport)(resumableHistory(t),u.charsPerToken,l.liveCallIds());a=s.messages;b=s.droppedRounds},async*send(t,s){const h=k;await H();let R;try{R=await(0,_buildContextPack.buildLiveContext)({dispatch:e.dispatch,readSnapshot:e.readSnapshot,availableToolIds:i,availableActions:p})}catch{R=void 0}if(h!==k){yield{type:"done",stopReason:"superseded"};return}const I=(0,_systemPrompt.buildLiveBlock)(R,l.list().map(c=>({label:`${c.toolId}.${c.action}${c.effect.label?` \u2014 ${c.effect.label}`:""}`,undone:c.undoneAt!==void 0})));const F={role:"user",text:t,...r.name==="claude"?{turnId:`turn-${++o}`}:{},...r.options.liveBlock&&r.options.liveBlock!=="system-tail"?{liveBlock:{placement:r.options.liveBlock,text:I}}:{}};const _=a[a.length-1];const M=_?.role==="user"&&(_.systemNotice||_.liveBlock?.placement==="system-msg")?[{role:"assistant",text:"[Buoy: The prior turn stopped before an answer.]"}]:[];const C=(0,_historyBudget.trimHistoryReport)([...a,...M,F],u.charsPerToken,l.liveCallIds());const G=C.messages;const L=C.droppedRounds+b;b=0;if(L>0)yield{type:"history-trimmed",droppedRounds:L,droppedPinned:C.droppedPinned};const N=(0,_runAgentTurn.runAgentTurn)({provider:$,catalog:T,messages:G,system:d,systemVolatile:r.options.liveBlock&&r.options.liveBlock!=="system-tail"?void 0:I,feedOptions:r.options,model:e.model,maxTokens:r.options.maxTokens??e.maxTokens??4096,dispatch:e.dispatch,readSnapshot:e.readSnapshot,storeKeyOwners:P,ledger:l,policy:E(),isRelease:e.isRelease,availableToolIds:i,availableActions:p,requestApproval:e.requestApproval,seenUrls:g,evidence:O,calibration:u,trusted:v,procedures:(0,_systemPrompt.listableProcedures)(e.context?.procedures,i),signal:s});let x=await N.next();while(!x.done){yield x.value;x=await N.next()}if(h===k)a=x.value},reset(){k+=1;w?.reset();a=[];b=0;l.clear();g.clear();O.clear();v.clear();q=false}}}
@@ -1,13 +1,13 @@
1
- "use strict";import{CATALOG as St}from"../catalog/catalog.g";import{applyDefaults as Ee,validateParams as Ae}from"../catalog/validateParams";import{normalizeParams as me,aliasNote as Kt}from"../catalog/normalizeParams";import{fromProviderToolName as ae,toProviderTools as Qt}from"../catalog/toProviderTools";import{hashQueryKey as Xt}from"../catalog/normalizeParams";import{projectSnapshot as Zt,SNAPSHOT_ACTION as Tt}from"../catalog/snapshotReads";import{UNPARSEABLE_ARGS as eo,isRealUserMessage as It}from"../providers/types";import{isReversible as Et}from"../effects/ledger";import{classifyTurn as to,QUESTION_DECLINED as At,tapLabels as oo}from"../policy/turnScope";import{describeCall as We,decide as z}from"../policy/policy";import{redact as no,stripSelfTraffic as ro}from"../policy/redact";import{idGrounding as so,UNSEEN_ID_ADVICE as io}from"./idGrounding";import{effectFor as $t}from"./effectFor";import{digestOf as Ge}from"../effects/digest";import{buildUiBlock as ao,UI_TOOL_NAME as ye,uiProviderTool as lo}from"../blocks/uiTool";import{projectReceipt as co}from"../blocks/receipts";import{isAskBlock as uo}from"../blocks/types";import{ACQUISITION_CALLS as fo,synthesizeAskBlock as po,synthesizeShortfallBlock as ho}from"./askGate";import{couldBeToolCallEnvelope as Nt,parseTextToolCalls as mo,SALVAGE_NOTE as yo}from"./textToolCalls";import{announcesUnstartedWork as go,PLAN_ONLY_NUDGE as bo,SILENT_NUDGE as ko}from"./planOnlyStop";import{compactScreen as wo}from"./compactScreen";import{budgetForRequest as Ye,MAX_HISTORY_TOKENS as vo,MAX_REQUEST_TOKENS as Ro,messageSize as $e}from"./historyBudget";import{promptTokensOf as So,TokenCalibration as To}from"./tokenCalibration";import{truncationMarker as Io}from"./evidence";import{retrieveEvidence as Eo}from"./retrieve";import{VERIFICATION_REPAIR as Ao,verificationTrailer as $o,verifyOutcome as No}from"./verify";import{realClearTimeout as Co,realNow as N,realSetTimeout as _o}from"../realNow";const Ct=24e3;const _t=2e3;const Ot=3;function Oo(t){const n=o=>{if(o===null||typeof o!=="object")return o;if(Array.isArray(o))return o.map(n);const a=o;return Object.keys(a).sort().reduce((d,w)=>(d[w]=n(a[w]),d),{})};return t.map(o=>`${o.name}:${JSON.stringify(n(o.input??{}))}`).join("|")}const xt="[Buoy] You have now made this exact call three times in a row and gotten the same thing back. Repeating it again will not change the answer. Read the result you already have, then either try a different tool or different arguments, or tell the user plainly what you could not get and what you tried.";const xo=24;const Ne="Resume where you left off. Don't redo past changes. Read the past tool results first.";const Uo="You are out of steps. No more tools may run. Reply in the user's language with plain words. Name every write that ran, what you found, and what is still not done. Use the tool results as proof. A tap alone does not prove a save or an order worked. Do not claim the job is done if you have not checked it. Keep the reply short.";const Ut=18e4;const Po=2;const Do=1;const Lo=1e3;const Mo=250;const qo=3e4;function jo(t,n){return new Promise(o=>{if(n?.aborted)return o();const a=_o(d,t);function d(){Co(a);n?.removeEventListener("abort",d);o()}n?.addEventListener("abort",d,{once:true})})}function Pt(t){if(typeof t==="boolean")return{approved:t,trust:false};const n=t.reason?.trim();return{approved:t.approved,...n?{reason:n}:{},trust:t.trust===true&&t.approved}}function Dt(t){return t?`The user declined this change and said: "${t}". Do not retry it as proposed; take their note into account and, if a different change would fit, propose that instead.`:"The user declined this change. Do not retry it; ask what they would prefer."}function Bo(t,n){const o=t.toLowerCase();const a=n.toLowerCase();if(Math.abs(o.length-a.length)>1)return false;let d=0;while(d<o.length&&o[d]===a[d])d++;return o===a||o.slice(d+1)===a.slice(d+1)||o.slice(d+1)===a.slice(d)||o.slice(d)===a.slice(d+1)}function j(t,n,o){return t.find(a=>a.toolId===n)?.actions.find(a=>a.action===o)}const Lt="Rejected: every image URL must be one you read from a tool result in THIS conversation (images.list, a storage value, a response body). Never invent or remember URLs \u2014 read them first, then show them.";const Fo=t=>` NOTE: ${t} image ${t===1?"URL was":"URLs were"} dropped \u2014 they were not read from a tool result in this conversation, so the card the user is looking at has no picture there. Do not tell them it does; read the URLs and show it again, or say the artwork is missing.`;function zo(t){try{return JSON.stringify(t??null)}catch{return String(t)}}function Ho(t,n){if(t.length<=Ct)return t;return`${t.slice(0,Ct)}${Io(t.length,n)}`}function Jo(t){if(t===null||t===void 0)return"Done";if(Array.isArray(t))return Ve(t.length);if(typeof t==="boolean")return t?"Done":"Failed";if(typeof t==="object"){const n=t;if(n.ok===false)return typeof n.error==="string"?n.error:"Failed";if(n.found===false)return"Not found";if(n.tapped===false)return"Nothing to tap";if(n.active===false&&typeof n.inactiveReason==="string"&&n.inactiveReason.length>0){return"Saved, but inactive in this build"}for(const a of["returned","count","total"]){const d=n[a];if(typeof d==="number")return Ve(d)}const o=Object.values(n).filter(Array.isArray);if(o.length===1)return Ve(o[0].length);return"Done"}return String(t).slice(0,80)}function Ve(t){return t===1?"1 item":`${t} items`}function Mt(t){return typeof t==="object"&&t!==null&&t.ok===false}const Ke="tapElement needs nativeTag, testID or query. Read describeScreen and pass one.";function Ce(t,n,o){return t==="highlight-updates"&&n==="tapElement"&&![o.nativeTag,o.testID,o.query].some(a=>typeof a==="string"?a.trim().length>0:a!=null)}function qt(t,n,o){if(t!=="highlight-updates"||n!=="tapElement"||!o||typeof o!=="object")return o;const a=o;if(a.tapped!==false)return o;return{...a,ok:false,error:typeof a.reason==="string"?a.reason:typeof a.error==="string"?a.error:"Nothing was tapped. Read describeScreen and try again."}}export async function*runAgentTurn(t){const{provider:n,catalog:o,system:a,systemVolatile:d,model:w,maxTokens:y,dispatch:c,readSnapshot:g,storeKeyOwners:D,ledger:k,policy:L,isRelease:M,requestApproval:V,signal:C,evidence:K,trusted:$,procedures:H}=t;const Q=new Map;const x=t.calibration??new To;const de=[...t.messages].reverse().find(p=>It(p));const B=to(de?.role==="user"?de.text:"");const f=[...t.messages];const be=n.protocol==="anthropic"?t.feedOptions??{}:{};const J=be.freezeHistory===true;const U=be.notices==="system-msg";const le=(p,E=false)=>({role:"user",text:p,...n.protocol==="anthropic"?{source:"engine"}:{},...E?{systemNotice:true}:{}});const Xe=()=>{const p=f[f.length-1];return U&&(p?.role==="tool-results"||p?.role==="user"&&p.systemNotice===true)};const Ze=so(f,`${t.system}
2
- ${t.systemVolatile??""}${de?.role==="user"&&de.liveBlock?`
3
- ${de.liveBlock.text}`:""}
4
- ${JSON.stringify(H??[])}`);let X=Qt(o,{availableToolIds:t.availableToolIds,availableActions:t.availableActions,isRelease:M});X.push(lo());if(J)X=JSON.parse(JSON.stringify(X));const Z=L.maxSteps??xo;const et=Vo();const Bt=k.generation;const Ft=new Set(k.list().map(p=>p.id));const tt=a.length+(d?.length??0)+X.reduce((p,E)=>p+E.description.length+JSON.stringify(E.inputSchema).length,0);const ke=()=>tt+x.chars(y);let we=N()+Ut;const _e={throttled:0,overflow:0};let ee=vo;const Oe=t.seenUrls??new Set;const zt=/https?:\/\/[^\s"'\\)\]}>]+/g;let xe=false;const te=[];let ot=false;const Ue=[];let Pe=false;let nt=false;let ve=false;let rt=false;let st=false;const Ht=[...f].reverse().find(It);const Jt=/\?\s*$/.test(Ht?.text?.trim()??"");const it=p=>p.reduce((E,_)=>E+$e(_),0)<=Math.min(x.chars(ee),x.chars(Ro)-ke());const De="This turn has no room left. Tap Continue to go on.";for(let p=0;p<Z;p++){if(C?.aborted){yield{type:"done",stopReason:"stopped"};return f}if(N()>we){yield{type:"block",block:{id:`cap${N()}`,kind:"notice",tone:"warning",text:`This is taking too long \u2014 stopped after ${Math.round(Ut/1e3)}s. What it found so far is above.`,actions:[{label:"Continue",primary:true,send:Ne}]}};yield{type:"done",stopReason:"time-cap"};return f}const E=J&&p>0?{messages:f,droppedRounds:0,droppedPinned:0}:Ye(f,ke(),x.chars(ee),x.charsPerToken,k.liveCallIds());if(E.droppedRounds>0){f.length=0;f.push(...E.messages);yield{type:"history-trimmed",droppedRounds:E.droppedRounds,droppedPinned:E.droppedPinned}}else if(E.messages!==f){f.length=0;f.push(...E.messages)}if(Z>6&&p===Z-6){f.push(le("6 steps left. Finish what the user asked. Skip extra checks. Batch reads that do not depend on each other in one round.",Xe()))}if(J&&!it(f)){yield{type:"block",block:{id:`space${N()}`,kind:"notice",tone:"warning",text:De,actions:[{label:"Continue",primary:true,send:Ne}]}};yield{type:"done",stopReason:"incomplete"};return f}let _="";let ct=false;const ne=e=>{const l=xe&&!ct;ct=true;xe=true;return l?{type:"text",delta:e,breakBefore:true}:{type:"text",delta:e}};let S=[];const ut=new Set;let P="";let Me=true;let ue=[];let Re=false;let W;let G;let qe=0;for(;;){qe+=1;_="";S=[];P="";Me=true;ue=[];Re=false;W=void 0;G=void 0;let e;const l=tt+f.reduce((u,m)=>u+$e(m),0);for await(const u of n.send({messages:f,system:a,systemVolatile:d,tools:X,model:w,maxTokens:y,signal:C,meta:{askId:et,round:p+1,attempt:qe}})){if(u.type==="text"){_+=u.delta;if(!Me){yield ne(u.delta)}else if(Nt(_)){P+=u.delta}else{Me=false;P="";yield ne(_)}}else if(u.type==="tool-call"){S.push(u.call)}else if(u.type==="meter"){yield{type:"meter",frame:u.frame}}else if(u.type==="thinking"){ue.push(u.block);if(u.block.type==="thinking"&&u.block.thinking.trim()){yield{type:"reasoning",text:u.block.thinking}}}else if(u.type==="error"){if(u.kind==="truncated"||u.kind==="timeout"){G={message:u.message}}else if(u.problem&&(u.problem.kind==="throttled"||u.problem.kind==="overflow")&&_===""&&S.length===0&&ue.length===0){e={problem:u.problem,message:u.message}}else{yield{type:"error",message:u.message,...u.problem?.hosted?{hosted:u.problem.hosted}:{}};Re=true}}else if(u.type==="done"){W=u.outcome;if(u.usage){x.observe(l,So(u.usage,n.protocol));yield{type:"usage",...u.usage,model:u.model}}}}if(!e)break;const r=e.problem.kind;if(J&&r==="overflow"){G={message:De};break}const s=1+(r==="throttled"?Po:Do);const b=_e[r];let h=r==="throttled"?Math.min(e.problem.retryAfterMs??Lo*2**b,qo)+Math.floor(Math.random()*Mo):0;let O=b>=s-1||C?.aborted===true||N()+h>we;if(e.problem.hosted&&qe>=2)O=true;if(!O&&r==="overflow"){ee=Math.floor(ee/2);const u=f.reduce((fe,Y)=>fe+$e(Y),0);const m=Ye(f,ke(),x.chars(ee),x.charsPerToken,k.liveCallIds());const re=m.messages.reduce((fe,Y)=>fe+$e(Y),0);if(re>=u){O=true}else{f.length=0;f.push(...m.messages);if(m.droppedRounds>0)yield{type:"history-trimmed",droppedRounds:m.droppedRounds,droppedPinned:m.droppedPinned}}}if(O){const u=r==="throttled"?b>0?`The AI endpoint is rate-limiting requests \u2014 tried ${b+1} times.`:"The AI endpoint is rate-limiting requests.":"This conversation is too large for the AI endpoint and there was nothing older to trim. Start a new conversation, or ask a shorter question.";const m=e.problem.hosted;yield m?{type:"error",message:m.message,hosted:m}:{type:"error",message:`${u} (${e.message})`};Re=true;break}_e[r]+=1;yield{type:"retrying",reason:r,attempt:_e[r]+1,maxAttempts:s,inMs:h};if(h>0)await jo(h,C);if(C?.aborted){yield{type:"done",stopReason:"stopped"};return f}}if(W==="refused"||W==="context-limited"){yield{type:"error",message:W==="refused"?"Claude could not help with this request.":"Claude ran out of room for this turn. Please send a new message."};yield{type:"done",stopReason:"error"};return f}if(Re){if(P)yield ne(P);yield{type:"done",stopReason:"error"};return f}if(!G&&W!=="completed"){G={message:W==="output-limited"?S.length?"The model ran out of room mid-plan, so nothing was run. What it found so far is above.":"The model ran out of room before finishing this answer.":"The answer ended before the endpoint said it was finished, so nothing was run."}}if(G){if(P)yield ne(P);if(_.trim())f.push({role:"assistant",text:_});yield{type:"block",block:{id:`cut${N()}`,kind:"notice",tone:"warning",text:G.message,actions:[{label:"Continue",primary:true,send:Ne}]}};yield{type:"done",stopReason:"incomplete"};return f}if(P){const e=S.length===0?mo(P,o):void 0;if(e){for(const l of e.calls){S.push(l);ut.add(l.id)}_=e.reply;if(e.reply)yield ne(e.reply)}else{yield ne(P)}P=""}f.push({role:"assistant",text:_,toolCalls:S.length?S:void 0,thinking:ue.length?ue:void 0});if(_.trim())Ue.push(_.trim());if(S.length===0&&!ve&&!Pe&&p<Z-1&&(go(_,B==="task")||rt&&!st&&!Jt)){ve=true;f.push(le(bo));continue}if(S.length===0&&!ve&&Ue.length===0&&p<Z-1){ve=true;f.push(le(ko));continue}if(S.length===0){const e=Ue.join("\n\n");const l=ho({text:e,attempted:nt});if(l)yield{type:"block",block:l};const r=Pe||l?null:po(e);if(r){yield{type:"block",block:r};yield{type:"awaiting-user",blockId:r.id}}yield{type:"done",stopReason:r?"awaiting-user":"answered"};return f}const v=[];const Se=[];const q=e=>{if(!U)return e;Se.push(e.trim());return""};let ft=false;const pt=new Map;if(S.length>1){const e=S.every(l=>{if(l.name===ye)return false;const r=ae(l.name,o);if(!r||r==="ask-buoy")return false;const s=l.input?.action;if(typeof s!=="string"||s===Tt)return false;const b=j(o,r,s);if(!b||b.effect!=="read")return false;return z({descriptor:b,toolId:r,policy:L,isRelease:M}).verdict==="allow"});if(e){for(const l of S){const r=ae(l.name,o);const s=String(l.input.action);const b={...l.input.params??{}};const h=j(o,r,s);const O=me(r,s,b);const u=Ee(O.params,h.params);if(!Ae(u,h.params).ok)continue;const m=Promise.resolve(c(r,s,u)).catch(re=>{throw re});m.catch(()=>{});pt.set(l.id,m)}}}let je=null;const Gt=e=>{const l=ae(e.name,o)??e.name;const r=typeof e.input?.action==="string"?e.input.action:"";const s=r?j(o,l,r):void 0;const b=e.input?.params??{};return[{type:"tool-start",id:e.id,toolId:l,action:r,label:s?We(l,s,b):`${l}.${r}`,description:s?.summary??"",params:b,effect:s?.effect??"read"},{type:"tool-end",id:e.id,ok:false,summary:"stopped",durationMs:0}]};const Te=new Map;if(B==="question"){for(const e of S){if(ae(e.name,o)!=="highlight-updates"||e.input?.action!=="tapElement")continue;const l=me("highlight-updates","tapElement",e.input.params??{}).params;if(Ce("highlight-updates","tapElement",l))continue;const r=j(o,"highlight-updates","describeScreen");const s=j(o,"highlight-updates","tapElement");if(C?.aborted||!r||!s||z({descriptor:r,toolId:"highlight-updates",policy:L,isRelease:M}).verdict!=="allow"||z({descriptor:s,toolId:"highlight-updates",policy:L,isRelease:M,turnScope:B,params:l}).verdict==="refuse")continue;const b=await c("highlight-updates","describeScreen",{}).catch(()=>void 0);Te.set(e.id,oo(b,l))}}const ht=S.map(e=>{if(e.name===ye)return void 0;const l=ae(e.name,o);const r=typeof e.input?.action==="string"?e.input.action:void 0;if(!l||!r)return void 0;const s=j(o,l,r);if(!s)return void 0;const b=e.input.params??{};const h=Ee(me(l,r,b).params,s.params);if(Ce(l,r,h)||!Ae(h,s.params).ok)return void 0;const O=z({descriptor:s,toolId:l,policy:L,isRelease:M,turnScope:B,params:h,tapLabels:Te.get(e.id)});return{call:e,toolId:l,action:r,descriptor:s,params:h,label:We(l,s,h),mutates:s.effect!=="read",gated:O.verdict==="needs-approval",turnScoped:O.verdict==="needs-approval"&&O.turnScoped,reason:O.verdict==="needs-approval"?O.reason:""}});const Yt=ht.some(e=>e?.gated);const F=new Map;let mt=false;let yt=false;async function*Vt(){mt=true;for(const e of ht){if(!e?.gated||F.has(e.call.id))continue;if(!e.turnScoped&&$?.has(`${e.toolId}.${e.action}`)){F.set(e.call.id,true);continue}yield{type:"approval-required",id:e.call.id,toolId:e.toolId,action:e.action,label:e.label,description:e.descriptor.summary,reason:e.reason};const l=N();const r=await readTargetDigest({toolId:e.toolId,action:e.action,params:e.params,dispatch:c,catalog:o});const s=Pt(!e.turnScoped&&$?.has(`${e.toolId}.${e.action}`)?true:V?await V({id:e.call.id,toolId:e.toolId,action:e.action,label:e.label,description:e.descriptor.summary,reason:e.reason,params:e.params,targetDigest:r}):false);we+=N()-l;const b=s.approved;F.set(e.call.id,b);if(s.trust)$?.add(`${e.toolId}.${e.action}`);if(s.reason)Q.set(e.call.id,s.reason);if(!b){yt=true;return}}}for(const e of S){if(C?.aborted){if(e.name!==ye){for(const i of Gt(e))yield i}v.push({toolCallId:e.id,content:"Not run \u2014 the user pressed Stop before this call started.",isError:true});continue}const l=e.input?.[eo];if(typeof l==="string"){v.push({toolCallId:e.id,content:`Not run \u2014 this call's arguments were not valid JSON, so nothing changed (${l.slice(0,120)}). Send the call again with compact JSON: {"action": "...", "params": {...}}.`,isError:true});continue}if(e.name===ye){const i=ao(e.input);if(!i.ok||!i.block){v.push({toolCallId:e.id,content:`Invalid ${ye} block:
5
- ${i.errors.join("\n")}`+q("\n\nResend ONLY the corrected block. Do not rewrite your answer \u2014 whatever you already said this turn has been shown to the user, and saying it again repeats it on their screen."),isError:true});continue}let T=0;if(i.block.kind==="imageGrid"){const A=i.block.images.filter(I=>Oe.has(I.url));T=i.block.images.length-A.length;if(A.length===0){v.push({toolCallId:e.id,content:U?"Rejected: image URLs were not read from a tool result."+q(Lt):Lt,isError:true});continue}i.block={...i.block,images:A}}if(i.block.kind==="list"){const A=i.block.items.map(I=>{if(!I.image||Oe.has(I.image))return I;T+=1;return{...I,image:void 0}});i.block={...i.block,items:A}}yield{type:"block",block:i.block,forToolCallId:e.id};if(i.block.kind==="actions"||i.block.kind==="suggestions"||i.block.kind==="plan"&&i.block.pending){Pe=true}if(uo(i.block)){je=i.block.id;v.push({toolCallId:e.id,content:"Shown. Waiting for the user's answer \u2014 it will arrive as their next message."+q(" Do not guess it.")})}else{v.push({toolCallId:e.id,content:"Shown to the user."+q(" Don't repeat its contents in text.")+(T>0?Fo(T):"")})}continue}const r=ae(e.name,o);const s=e.input.action;const b=(i,T)=>[{type:"tool-start",id:e.id,toolId:r??e.name,action:s??"",label:i,description:"",params:e.input.params??{},effect:"read"},{type:"tool-end",id:e.id,ok:false,summary:T,durationMs:0}];if(!r){for(const i of b(e.name,"No such tool"))yield i;v.push({toolCallId:e.id,content:`There is no tool called "${e.name}". Use one of the tools you were given.`,isError:true});continue}if(!s){for(const i of b(e.name,"No action given"))yield i;v.push({toolCallId:e.id,content:`"${e.name}" needs an "action" \u2014 it is required, and it names which of this tool's actions to run. See the action list in the tool's description.`,isError:true});continue}const h=j(o,r,s);if(!h){const i=o.find(R=>R.toolId===r)?.actions.map(R=>R.action)??[];const T=o.filter(R=>R.toolId!==r&&R.actions.some(ze=>ze.action===s));const A=i.filter(R=>Bo(R,s));const I=[...T.map(R=>`${R.toolId}.${s}`),...A.map(R=>`${r}.${R}`)].slice(0,3);const ie=`${r} has no ${s}.${I.length?` Did you mean ${I.join(" or ")}?`:""}`;for(const R of b(`${r}.${s}`,I.length?ie:"No such action"))yield R;v.push({toolCallId:e.id,content:`${ie}${i.length?` Valid actions: ${i.join(", ")}.`:""}`,isError:true});continue}const O=e.input.params??{};const u=me(r,s,O);const m=Ee(u.params,h.params);if(Ce(r,s,m)){for(const i of b(`${r}.${s}`,Ke))yield i;v.push({toolCallId:e.id,content:JSON.stringify({ok:false,error:U?"tapElement needs nativeTag, testID or query."+q("Read describeScreen and pass nativeTag, testID or query."):Ke}),isError:true});continue}const re=Ae(m,h.params);if(!re.ok){v.push({toolCallId:e.id,content:`Invalid parameters for ${r}.${s}:
6
- ${re.errors.join("\n")}
1
+ "use strict";import{CATALOG as Tt}from"../catalog/catalog.g";import{applyDefaults as Ie,validateParams as Ae}from"../catalog/validateParams";import{normalizeParams as ge,aliasNote as Zt}from"../catalog/normalizeParams";import{fromProviderToolName as ce,toProviderTools as eo}from"../catalog/toProviderTools";import{hashQueryKey as to}from"../catalog/normalizeParams";import{projectSnapshot as oo,SNAPSHOT_ACTION as Et}from"../catalog/snapshotReads";import{UNPARSEABLE_ARGS as no,isRealUserMessage as It}from"../providers/types";import{isReversible as At}from"../effects/ledger";import{classifyTurn as ro,QUESTION_DECLINED as $t,tapLabels as so}from"../policy/turnScope";import{describeCall as Je,decide as H}from"../policy/policy";import{redact as io,stripSelfTraffic as ao}from"../policy/redact";import{idGrounding as lo,UNSEEN_ID_ADVICE as co}from"./idGrounding";import{effectFor as Nt}from"./effectFor";import{digestOf as Ye}from"../effects/digest";import{buildUiBlock as uo,UI_TOOL_NAME as ke,uiProviderTool as fo}from"../blocks/uiTool";import{projectReceipt as po}from"../blocks/receipts";import{isAskBlock as ho}from"../blocks/types";import{ACQUISITION_CALLS as mo,synthesizeAskBlock as yo,synthesizeShortfallBlock as go}from"./askGate";import{couldBeToolCallEnvelope as Ct,parseTextToolCalls as ko,SALVAGE_NOTE as bo}from"./textToolCalls";import{announcesUnstartedWork as wo,PLAN_ONLY_NUDGE as vo,SILENT_NUDGE as Ro}from"./planOnlyStop";import{compactScreen as So}from"./compactScreen";import{budgetForRequest as Ge,MAX_HISTORY_TOKENS as To,MAX_REQUEST_TOKENS as Eo,messageSize as $e}from"./historyBudget";import{promptTokensOf as Io,TokenCalibration as Ao}from"./tokenCalibration";import{truncationMarker as $o}from"./evidence";import{retrieveEvidence as No}from"./retrieve";import{VERIFICATION_REPAIR as Co,verificationTrailer as _o,verifyOutcome as Oo}from"./verify";import{realClearTimeout as xo,realNow as C,realSetTimeout as Uo}from"../realNow";const _t=24e3;const Ot=2e3;const xt=3;function Po(t){const n=o=>{if(o===null||typeof o!=="object")return o;if(Array.isArray(o))return o.map(n);const d=o;return Object.keys(d).sort().reduce((l,b)=>(l[b]=n(d[b]),l),{})};return t.map(o=>`${o.name}:${JSON.stringify(n(o.input??{}))}`).join("|")}const Ut="[Buoy] You have now made this exact call three times in a row and gotten the same thing back. Repeating it again will not change the answer. Read the result you already have, then either try a different tool or different arguments, or tell the user plainly what you could not get and what you tried.";const Mo=24;const Ne="Resume where you left off. Don't redo past changes. Read the past tool results first.";const Do="You are out of steps. No more tools may run. Reply in the user's language with plain words. Name every write that ran, what you found, and what is still not done. Use the tool results as proof. A tap alone does not prove a save or an order worked. Do not claim the job is done if you have not checked it. Keep the reply short.";const Pt=18e4;const Lo=2;const qo=1;const Mt=1;const Ke=1e3;const jo=1e3;const Bo=250;const Fo=3e4;function Dt(t,n){return new Promise(o=>{if(n?.aborted)return o();const d=Uo(l,t);function l(){xo(d);n?.removeEventListener("abort",l);o()}n?.addEventListener("abort",l,{once:true})})}function Lt(t){if(typeof t==="boolean")return{approved:t,trust:false};const n=t.reason?.trim();return{approved:t.approved,...n?{reason:n}:{},trust:t.trust===true&&t.approved}}function qt(t){return t?`The user declined this change and said: "${t}". Do not retry it as proposed; take their note into account and, if a different change would fit, propose that instead.`:"The user declined this change. Do not retry it; ask what they would prefer."}function zo(t,n){const o=t.toLowerCase();const d=n.toLowerCase();if(Math.abs(o.length-d.length)>1)return false;let l=0;while(l<o.length&&o[l]===d[l])l++;return o===d||o.slice(l+1)===d.slice(l+1)||o.slice(l+1)===d.slice(l)||o.slice(l)===d.slice(l+1)}function B(t,n,o){return t.find(d=>d.toolId===n)?.actions.find(d=>d.action===o)}const jt="Rejected: every image URL must be one you read from a tool result in THIS conversation (images.list, a storage value, a response body). Never invent or remember URLs \u2014 read them first, then show them.";const Wo=t=>` NOTE: ${t} image ${t===1?"URL was":"URLs were"} dropped \u2014 they were not read from a tool result in this conversation, so the card the user is looking at has no picture there. Do not tell them it does; read the URLs and show it again, or say the artwork is missing.`;function Ho(t){try{return JSON.stringify(t??null)}catch{return String(t)}}function Jo(t,n){if(t.length<=_t)return t;return`${t.slice(0,_t)}${$o(t.length,n)}`}function Yo(t){if(t===null||t===void 0)return"Done";if(Array.isArray(t))return Ve(t.length);if(typeof t==="boolean")return t?"Done":"Failed";if(typeof t==="object"){const n=t;if(n.ok===false)return typeof n.error==="string"?n.error:"Failed";if(n.found===false)return"Not found";if(n.tapped===false)return"Nothing to tap";if(n.active===false&&typeof n.inactiveReason==="string"&&n.inactiveReason.length>0){return"Saved, but inactive in this build"}for(const d of["returned","count","total"]){const l=n[d];if(typeof l==="number")return Ve(l)}const o=Object.values(n).filter(Array.isArray);if(o.length===1)return Ve(o[0].length);return"Done"}return String(t).slice(0,80)}function Ve(t){return t===1?"1 item":`${t} items`}function Bt(t){return typeof t==="object"&&t!==null&&t.ok===false}const Qe="tapElement needs nativeTag, testID or query. Read describeScreen and pass one.";function Ce(t,n,o){return t==="highlight-updates"&&n==="tapElement"&&![o.nativeTag,o.testID,o.query].some(d=>typeof d==="string"?d.trim().length>0:d!=null)}function Ft(t,n,o){if(t!=="highlight-updates"||n!=="tapElement"||!o||typeof o!=="object")return o;const d=o;if(d.tapped!==false)return o;return{...d,ok:false,error:typeof d.reason==="string"?d.reason:typeof d.error==="string"?d.error:"Nothing was tapped. Read describeScreen and try again."}}export async function*runAgentTurn(t){const{provider:n,catalog:o,system:d,systemVolatile:l,model:b,maxTokens:m,dispatch:u,readSnapshot:y,storeKeyOwners:M,ledger:g,policy:D,isRelease:L,requestApproval:Q,signal:$,evidence:X,trusted:N,procedures:J}=t;const Z=new Map;const x=t.calibration??new Ao;const ue=[...t.messages].reverse().find(p=>It(p));const F=ro(ue?.role==="user"?ue.text:"");const f=[...t.messages];const we=n.protocol==="anthropic"?t.feedOptions??{}:{};const Y=we.freezeHistory===true;const U=we.notices==="system-msg";const fe=(p,E=false)=>({role:"user",text:p,...n.protocol==="anthropic"?{source:"engine"}:{},...E?{systemNotice:true}:{}});const Ze=()=>{const p=f[f.length-1];return U&&(p?.role==="tool-results"||p?.role==="user"&&p.systemNotice===true)};const et=lo(f,`${t.system}
2
+ ${t.systemVolatile??""}${ue?.role==="user"&&ue.liveBlock?`
3
+ ${ue.liveBlock.text}`:""}
4
+ ${JSON.stringify(J??[])}`);let ee=eo(o,{availableToolIds:t.availableToolIds,availableActions:t.availableActions,isRelease:L});ee.push(fo());if(Y)ee=JSON.parse(JSON.stringify(ee));const te=D.maxSteps??Mo;const tt=Qo();const Wt=g.generation;const Ht=new Set(g.list().map(p=>p.id));const ot=d.length+(l?.length??0)+ee.reduce((p,E)=>p+E.description.length+JSON.stringify(E.inputSchema).length,0);const ve=()=>ot+x.chars(m);let pe=C()+Pt;const oe={throttled:0,overflow:0,network:0};let ne=To;const _e=t.seenUrls??new Set;const Jt=/https?:\/\/[^\s"'\\)\]}>]+/g;let Oe=false;const re=[];let nt=false;const xe=[];let Ue=false;let rt=false;let Re=false;let st=false;let it=false;const Yt=[...f].reverse().find(It);const Gt=/\?\s*$/.test(Yt?.text?.trim()??"");const at=p=>p.reduce((E,_)=>E+$e(_),0)<=Math.min(x.chars(ne),x.chars(Eo)-ve());const Pe="This turn has no room left. Tap Continue to go on.";for(let p=0;p<te;p++){if($?.aborted){yield{type:"done",stopReason:"stopped"};return f}if(C()>pe){yield{type:"block",block:{id:`cap${C()}`,kind:"notice",tone:"warning",text:`This is taking too long \u2014 stopped after ${Math.round(Pt/1e3)}s. What it found so far is above.`,actions:[{label:"Continue",primary:true,send:Ne}]}};yield{type:"done",stopReason:"time-cap"};return f}const E=Y&&p>0?{messages:f,droppedRounds:0,droppedPinned:0}:Ge(f,ve(),x.chars(ne),x.charsPerToken,g.liveCallIds());if(E.droppedRounds>0){f.length=0;f.push(...E.messages);yield{type:"history-trimmed",droppedRounds:E.droppedRounds,droppedPinned:E.droppedPinned}}else if(E.messages!==f){f.length=0;f.push(...E.messages)}if(te>6&&p===te-6){f.push(fe("6 steps left. Finish what the user asked. Skip extra checks. Batch reads that do not depend on each other in one round.",Ze()))}if(Y&&!at(f)){yield{type:"block",block:{id:`space${C()}`,kind:"notice",tone:"warning",text:Pe,actions:[{label:"Continue",primary:true,send:Ne}]}};yield{type:"done",stopReason:"incomplete"};return f}let _="";let ut=false;const ie=e=>{const c=Oe&&!ut;ut=true;Oe=true;return c?{type:"text",delta:e,breakBefore:true}:{type:"text",delta:e}};let v=[];const ft=new Set;let P="";let De=true;let ae=[];let Se=false;let G;let K;let Le=0;for(;;){Le+=1;_="";v=[];P="";De=true;ae=[];Se=false;G=void 0;K=void 0;let e;const c=ot+f.reduce((i,I)=>i+$e(I),0);let r=false;try{for await(const i of n.send({messages:f,system:d,systemVolatile:l,tools:ee,model:b,maxTokens:m,signal:$,meta:{askId:tt,round:p+1,attempt:Le}})){if(i.type==="text"){_+=i.delta;if(!De){yield ie(i.delta)}else if(Ct(_)){P+=i.delta}else{De=false;P="";yield ie(_)}}else if(i.type==="tool-call"){v.push(i.call)}else if(i.type==="meter"){yield{type:"meter",frame:i.frame}}else if(i.type==="thinking"){ae.push(i.block);if(i.block.type==="thinking"&&i.block.thinking.trim()){yield{type:"reasoning",text:i.block.thinking}}}else if(i.type==="error"){if(i.kind==="truncated"||i.kind==="timeout"){K={message:i.message}}else if(i.problem&&(i.problem.kind==="throttled"||i.problem.kind==="overflow")&&_===""&&v.length===0&&ae.length===0){e={problem:i.problem,message:i.message}}else{yield{type:"error",message:i.message,...i.problem?.hosted?{hosted:i.problem.hosted}:{}};Se=true}}else if(i.type==="done"){G=i.outcome;if(i.usage){x.observe(c,Io(i.usage,n.protocol));yield{type:"usage",...i.usage,model:i.model}}}}}catch(i){const I=_===""&&v.length===0&&ae.length===0;if($?.aborted||!I||oe.network>=Mt||C()+Ke>pe)throw i;r=true}if(r){oe.network+=1;yield{type:"retrying",reason:"network",attempt:oe.network+1,maxAttempts:1+Mt,inMs:Ke};await Dt(Ke,$);if($?.aborted){yield{type:"done",stopReason:"stopped"};return f}continue}if(!e)break;const s=e.problem.kind;if(Y&&s==="overflow"){K={message:Pe};break}const k=1+(s==="throttled"?Lo:qo);const h=oe[s];let O=s==="throttled"?Math.min(e.problem.retryAfterMs??jo*2**h,Fo)+Math.floor(Math.random()*Bo):0;let q=h>=k-1||$?.aborted===true||C()+O>pe;if(e.problem.hosted&&Le>=2)q=true;if(!q&&s==="overflow"){ne=Math.floor(ne/2);const i=f.reduce((V,W)=>V+$e(W),0);const I=Ge(f,ve(),x.chars(ne),x.charsPerToken,g.liveCallIds());const je=I.messages.reduce((V,W)=>V+$e(W),0);if(je>=i){q=true}else{f.length=0;f.push(...I.messages);if(I.droppedRounds>0)yield{type:"history-trimmed",droppedRounds:I.droppedRounds,droppedPinned:I.droppedPinned}}}if(q){const i=s==="throttled"?h>0?`The AI endpoint is rate-limiting requests \u2014 tried ${h+1} times.`:"The AI endpoint is rate-limiting requests.":"This conversation is too large for the AI endpoint and there was nothing older to trim. Start a new conversation, or ask a shorter question.";const I=e.problem.hosted;yield I?{type:"error",message:I.message,hosted:I}:{type:"error",message:`${i} (${e.message})`};Se=true;break}oe[s]+=1;yield{type:"retrying",reason:s,attempt:oe[s]+1,maxAttempts:k,inMs:O};if(O>0)await Dt(O,$);if($?.aborted){yield{type:"done",stopReason:"stopped"};return f}}if(G==="refused"||G==="context-limited"){yield{type:"error",message:G==="refused"?"Claude could not help with this request.":"Claude ran out of room for this turn. Please send a new message."};yield{type:"done",stopReason:"error"};return f}if(Se){if(P)yield ie(P);yield{type:"done",stopReason:"error"};return f}if(!K&&G!=="completed"){K={message:G==="output-limited"?v.length?"The model ran out of room mid-plan, so nothing was run. What it found so far is above.":"The model ran out of room before finishing this answer.":"The answer ended before the endpoint said it was finished, so nothing was run."}}if(K){if(P)yield ie(P);if(_.trim())f.push({role:"assistant",text:_});yield{type:"block",block:{id:`cut${C()}`,kind:"notice",tone:"warning",text:K.message,actions:[{label:"Continue",primary:true,send:Ne}]}};yield{type:"done",stopReason:"incomplete"};return f}if(P){const e=v.length===0?ko(P,o):void 0;if(e){for(const c of e.calls){v.push(c);ft.add(c.id)}_=e.reply;if(e.reply)yield ie(e.reply)}else{yield ie(P)}P=""}f.push({role:"assistant",text:_,toolCalls:v.length?v:void 0,thinking:ae.length?ae:void 0});if(_.trim())xe.push(_.trim());if(v.length===0&&!Re&&!Ue&&p<te-1&&(wo(_,F==="task")||st&&!it&&!Gt)){Re=true;f.push(fe(vo));continue}if(v.length===0&&!Re&&xe.length===0&&p<te-1){Re=true;f.push(fe(Ro));continue}if(v.length===0){const e=xe.join("\n\n");const c=go({text:e,attempted:rt});if(c)yield{type:"block",block:c};const r=Ue||c?null:yo(e);if(r){yield{type:"block",block:r};yield{type:"awaiting-user",blockId:r.id}}yield{type:"done",stopReason:r?"awaiting-user":"answered"};return f}const w=[];const Te=[];const j=e=>{if(!U)return e;Te.push(e.trim());return""};let pt=false;const ht=new Map;if(v.length>1){const e=v.every(c=>{if(c.name===ke)return false;const r=ce(c.name,o);if(!r||r==="ask-buoy")return false;const s=c.input?.action;if(typeof s!=="string"||s===Et)return false;const k=B(o,r,s);if(!k||k.effect!=="read")return false;return H({descriptor:k,toolId:r,policy:D,isRelease:L}).verdict==="allow"});if(e){for(const c of v){const r=ce(c.name,o);const s=String(c.input.action);const k={...c.input.params??{}};const h=B(o,r,s);const O=ge(r,s,k);const q=Ie(O.params,h.params);if(!Ae(q,h.params).ok)continue;const i=Promise.resolve(u(r,s,q)).catch(I=>{throw I});i.catch(()=>{});ht.set(c.id,i)}}}let qe=null;const Vt=e=>{const c=ce(e.name,o)??e.name;const r=typeof e.input?.action==="string"?e.input.action:"";const s=r?B(o,c,r):void 0;const k=e.input?.params??{};return[{type:"tool-start",id:e.id,toolId:c,action:r,label:s?Je(c,s,k):`${c}.${r}`,description:s?.summary??"",params:k,effect:s?.effect??"read"},{type:"tool-end",id:e.id,ok:false,summary:"stopped",durationMs:0}]};const Ee=new Map;if(F==="question"){for(const e of v){if(ce(e.name,o)!=="highlight-updates"||e.input?.action!=="tapElement")continue;const c=ge("highlight-updates","tapElement",e.input.params??{}).params;if(Ce("highlight-updates","tapElement",c))continue;const r=B(o,"highlight-updates","describeScreen");const s=B(o,"highlight-updates","tapElement");if($?.aborted||!r||!s||H({descriptor:r,toolId:"highlight-updates",policy:D,isRelease:L}).verdict!=="allow"||H({descriptor:s,toolId:"highlight-updates",policy:D,isRelease:L,turnScope:F,params:c}).verdict==="refuse")continue;const k=await u("highlight-updates","describeScreen",{}).catch(()=>void 0);Ee.set(e.id,so(k,c))}}const mt=v.map(e=>{if(e.name===ke)return void 0;const c=ce(e.name,o);const r=typeof e.input?.action==="string"?e.input.action:void 0;if(!c||!r)return void 0;const s=B(o,c,r);if(!s)return void 0;const k=e.input.params??{};const h=Ie(ge(c,r,k).params,s.params);if(Ce(c,r,h)||!Ae(h,s.params).ok)return void 0;const O=H({descriptor:s,toolId:c,policy:D,isRelease:L,turnScope:F,params:h,tapLabels:Ee.get(e.id)});return{call:e,toolId:c,action:r,descriptor:s,params:h,label:Je(c,s,h),mutates:s.effect!=="read",gated:O.verdict==="needs-approval",turnScoped:O.verdict==="needs-approval"&&O.turnScoped,reason:O.verdict==="needs-approval"?O.reason:""}});const Qt=mt.some(e=>e?.gated);const z=new Map;let yt=false;let gt=false;async function*Xt(){yt=true;for(const e of mt){if(!e?.gated||z.has(e.call.id))continue;if(!e.turnScoped&&N?.has(`${e.toolId}.${e.action}`)){z.set(e.call.id,true);continue}yield{type:"approval-required",id:e.call.id,toolId:e.toolId,action:e.action,label:e.label,description:e.descriptor.summary,reason:e.reason};const c=C();const r=await readTargetDigest({toolId:e.toolId,action:e.action,params:e.params,dispatch:u,catalog:o});const s=Lt(!e.turnScoped&&N?.has(`${e.toolId}.${e.action}`)?true:Q?await Q({id:e.call.id,toolId:e.toolId,action:e.action,label:e.label,description:e.descriptor.summary,reason:e.reason,params:e.params,targetDigest:r}):false);pe+=C()-c;const k=s.approved;z.set(e.call.id,k);if(s.trust)N?.add(`${e.toolId}.${e.action}`);if(s.reason)Z.set(e.call.id,s.reason);if(!k){gt=true;return}}}for(const e of v){if($?.aborted){if(e.name!==ke){for(const a of Vt(e))yield a}w.push({toolCallId:e.id,content:"Not run \u2014 the user pressed Stop before this call started.",isError:true});continue}const c=e.input?.[no];if(typeof c==="string"){w.push({toolCallId:e.id,content:`Not run \u2014 this call's arguments were not valid JSON, so nothing changed (${c.slice(0,120)}). Send the call again with compact JSON: {"action": "...", "params": {...}}.`,isError:true});continue}if(e.name===ke){const a=uo(e.input);if(!a.ok||!a.block){w.push({toolCallId:e.id,content:`Invalid ${ke} block:
5
+ ${a.errors.join("\n")}`+j("\n\nResend ONLY the corrected block. Do not rewrite your answer \u2014 whatever you already said this turn has been shown to the user, and saying it again repeats it on their screen."),isError:true});continue}let S=0;if(a.block.kind==="imageGrid"){const A=a.block.images.filter(T=>_e.has(T.url));S=a.block.images.length-A.length;if(A.length===0){w.push({toolCallId:e.id,content:U?"Rejected: image URLs were not read from a tool result."+j(jt):jt,isError:true});continue}a.block={...a.block,images:A}}if(a.block.kind==="list"){const A=a.block.items.map(T=>{if(!T.image||_e.has(T.image))return T;S+=1;return{...T,image:void 0}});a.block={...a.block,items:A}}yield{type:"block",block:a.block,forToolCallId:e.id};if(a.block.kind==="actions"||a.block.kind==="suggestions"||a.block.kind==="plan"&&a.block.pending){Ue=true}if(ho(a.block)){qe=a.block.id;w.push({toolCallId:e.id,content:"Shown. Waiting for the user's answer \u2014 it will arrive as their next message."+j(" Do not guess it.")})}else{w.push({toolCallId:e.id,content:"Shown to the user."+j(" Don't repeat its contents in text.")+(S>0?Wo(S):"")})}continue}const r=ce(e.name,o);const s=e.input.action;const k=(a,S)=>[{type:"tool-start",id:e.id,toolId:r??e.name,action:s??"",label:a,description:"",params:e.input.params??{},effect:"read"},{type:"tool-end",id:e.id,ok:false,summary:S,durationMs:0}];if(!r){for(const a of k(e.name,"No such tool"))yield a;w.push({toolCallId:e.id,content:`There is no tool called "${e.name}". Use one of the tools you were given.`,isError:true});continue}if(!s){for(const a of k(e.name,"No action given"))yield a;w.push({toolCallId:e.id,content:`"${e.name}" needs an "action" \u2014 it is required, and it names which of this tool's actions to run. See the action list in the tool's description.`,isError:true});continue}const h=B(o,r,s);if(!h){const a=o.find(R=>R.toolId===r)?.actions.map(R=>R.action)??[];const S=o.filter(R=>R.toolId!==r&&R.actions.some(ze=>ze.action===s));const A=a.filter(R=>zo(R,s));const T=[...S.map(R=>`${R.toolId}.${s}`),...A.map(R=>`${r}.${R}`)].slice(0,3);const le=`${r} has no ${s}.${T.length?` Did you mean ${T.join(" or ")}?`:""}`;for(const R of k(`${r}.${s}`,T.length?le:"No such action"))yield R;w.push({toolCallId:e.id,content:`${le}${a.length?` Valid actions: ${a.join(", ")}.`:""}`,isError:true});continue}const O=e.input.params??{};const q=ge(r,s,O);const i=Ie(q.params,h.params);if(Ce(r,s,i)){for(const a of k(`${r}.${s}`,Qe))yield a;w.push({toolCallId:e.id,content:JSON.stringify({ok:false,error:U?"tapElement needs nativeTag, testID or query."+j("Read describeScreen and pass nativeTag, testID or query."):Qe}),isError:true});continue}const I=Ae(i,h.params);if(!I.ok){w.push({toolCallId:e.id,content:`Invalid parameters for ${r}.${s}:
6
+ ${I.errors.join("\n")}
7
7
 
8
8
  Expected schema:
9
- ${JSON.stringify(h.params)}`,isError:true});continue}const fe=Kt(u.notes);const Y=h.effect!=="read"?Ze.trailer(m,!U):"";if(U&&Y)q(io);const Ie=We(r,h,m);const se=z({descriptor:h,toolId:r,policy:L,isRelease:M,turnScope:B,params:m,tapLabels:Te.get(e.id)});const pe=i=>[{type:"tool-start",id:e.id,toolId:r,action:s,label:Ie,description:h.summary,params:m,effect:h.effect},{type:"tool-end",id:e.id,ok:false,summary:i,durationMs:0}];if(se.verdict==="refuse"){for(const i of pe("refused"))yield i;v.push({toolCallId:e.id,content:se.reason,isError:true});continue}const Be=se.verdict==="needs-approval";if(Yt&&!mt&&(h.effect!=="read"||Be)){yield*Vt()}if(yt&&(h.effect!=="read"||Be)){for(const i of pe("declined"))yield i;v.push({toolCallId:e.id,content:B==="question"?At:F.get(e.id)===false?Dt(Q.get(e.id)):"Not run \u2014 the user declined another change in this same batch, so none of it was applied. Ask what they would prefer before proposing it again.",isError:true});continue}if(Be){let i;if(F.has(e.id)){i=F.get(e.id)}else if(!se.turnScoped&&$?.has(`${r}.${s}`)){i=true;F.set(e.id,true)}else{yield{type:"approval-required",id:e.id,toolId:r,action:s,label:Ie,description:h.summary,reason:se.reason};const T=N();const A=await readTargetDigest({toolId:r,action:s,params:m,dispatch:c,catalog:o});const I=Pt(V?await V({id:e.id,toolId:r,action:s,label:Ie,description:h.summary,reason:se.reason,params:m,targetDigest:A}):false);we+=N()-T;i=I.approved;F.set(e.id,i);if(I.trust)$?.add(`${r}.${s}`);if(I.reason)Q.set(e.id,I.reason)}if(!i){for(const T of pe("declined"))yield T;v.push({toolCallId:e.id,content:B==="question"?At:Dt(Q.get(e.id)),isError:true});continue}}if(fo.has(`${r}.${s}`))nt=true;if(r==="ask-buoy"&&s==="openProcedure")rt=true;yield{type:"tool-start",id:e.id,toolId:r,action:s,label:Ie,description:h.summary,params:m,effect:h.effect};const gt=N();const bt=await Qe(h,r,m,c);const Fe=await ge(h,r,m,c);if(C?.aborted){for(const i of pe("stopped"))yield i;v.push({toolCallId:e.id,content:"Not run \u2014 the user pressed Stop before this call started.",isError:true});continue}const kt=z({descriptor:h,toolId:r,policy:L,isRelease:M,turnScope:B,params:m,tapLabels:Te.get(e.id)});if(kt.verdict==="refuse"){for(const i of pe("refused"))yield i;v.push({toolCallId:e.id,content:kt.reason,isError:true});continue}try{let i=s===Tt?Zt(r,await Go(g,r),m):r==="ask-buoy"?await jt(s,k,c,K,m,H):await(pt.get(e.id)??c(r,s,m));i=qt(r,s,i);const T=no(ro(i));const A=Mt(i);if(h.effect!=="read"&&!A)st=true;const I=zo(r==="highlight-updates"&&s==="describeScreen"&&!A?wo(T):T);const ie=K&&!A&&!(r==="ask-buoy"&&s==="retrieve")?K.stash({toolId:r,action:s,params:m,capturedAt:N(),text:I}):void 0;const R=Ho(I,ie);Ze.add(I);const ze=R.length>_t?`${R.slice(0,_t)}\u2026`:R;yield{type:"tool-end",id:e.id,ok:!A,summary:Jo(i),durationMs:N()-gt,result:ze};const He=Fe===void 0||A?void 0:await ge(h,r,m,c);if(h.effect!=="read"&&r!=="ask-buoy"&&!A){const Je=k.noteExternalRevert(r,s,m);const vt=$t(r,h,m,i,bt,{before:Fe,after:He});if(vt&&!Je){const Rt=k.record(r,s,vt,Bt);if(Rt)Rt.callId=e.id}}const wt=A?void 0:co({toolId:r,action:s,params:m,result:T,before:Fe??bt,after:He,effect:h.effect});if(wt)yield{type:"block",block:wt,forToolCallId:e.id};const he=h.effect!=="read"&&!A?await No({toolId:r,action:s,params:m,result:i,dispatch:c,readSnapshot:g,signal:C,after:He}):void 0;if(he)yield{type:"tool-verified",id:e.id,verification:he};if(U&&he?.status==="failed")q(Ao);for(const Je of R.match(zt)??[])Oe.add(Je);v.push({toolCallId:e.id,content:R+Wo(r,h,m,D,U?q:void 0)+fe+Y+(he?$o(he,!U):"")+(ut.has(e.id)?q(yo):""),...ie?{ref:ie}:{}});if(r==="app"&&(s==="reloadApp"||s==="reload")){ft=true}}catch(i){const T=i instanceof Error?i.message:String(i);yield{type:"tool-end",id:e.id,ok:false,summary:T,durationMs:N()-gt};v.push({toolCallId:e.id,content:`Failed: ${T}${Y}`,isError:true})}}if(S.length){te.push(Oo(S));if(te.length>Ot)te.shift();const e=!ot&&te.length===Ot&&te.every(l=>l===te[0]);if(e){ot=true;const l=v[v.length-1];if(U)Se.push(xt);else if(l)l.content=`${l.content}
9
+ ${JSON.stringify(h.params)}`,isError:true});continue}const je=Zt(q.notes);const V=h.effect!=="read"?et.trailer(i,!U):"";if(U&&V)j(co);const W=Je(r,h,i);const de=H({descriptor:h,toolId:r,policy:D,isRelease:L,turnScope:F,params:i,tapLabels:Ee.get(e.id)});const me=a=>[{type:"tool-start",id:e.id,toolId:r,action:s,label:W,description:h.summary,params:i,effect:h.effect},{type:"tool-end",id:e.id,ok:false,summary:a,durationMs:0}];if(de.verdict==="refuse"){for(const a of me("refused"))yield a;w.push({toolCallId:e.id,content:de.reason,isError:true});continue}const Be=de.verdict==="needs-approval";if(Qt&&!yt&&(h.effect!=="read"||Be)){yield*Xt()}if(gt&&(h.effect!=="read"||Be)){for(const a of me("declined"))yield a;w.push({toolCallId:e.id,content:F==="question"?$t:z.get(e.id)===false?qt(Z.get(e.id)):"Not run \u2014 the user declined another change in this same batch, so none of it was applied. Ask what they would prefer before proposing it again.",isError:true});continue}if(Be){let a;if(z.has(e.id)){a=z.get(e.id)}else if(!de.turnScoped&&N?.has(`${r}.${s}`)){a=true;z.set(e.id,true)}else{yield{type:"approval-required",id:e.id,toolId:r,action:s,label:W,description:h.summary,reason:de.reason};const S=C();const A=await readTargetDigest({toolId:r,action:s,params:i,dispatch:u,catalog:o});const T=Lt(Q?await Q({id:e.id,toolId:r,action:s,label:W,description:h.summary,reason:de.reason,params:i,targetDigest:A}):false);pe+=C()-S;a=T.approved;z.set(e.id,a);if(T.trust)N?.add(`${r}.${s}`);if(T.reason)Z.set(e.id,T.reason)}if(!a){for(const S of me("declined"))yield S;w.push({toolCallId:e.id,content:F==="question"?$t:qt(Z.get(e.id)),isError:true});continue}}if(mo.has(`${r}.${s}`))rt=true;if(r==="ask-buoy"&&s==="openProcedure")st=true;yield{type:"tool-start",id:e.id,toolId:r,action:s,label:W,description:h.summary,params:i,effect:h.effect};const kt=C();const bt=await Xe(h,r,i,u);const Fe=await be(h,r,i,u);if($?.aborted){for(const a of me("stopped"))yield a;w.push({toolCallId:e.id,content:"Not run \u2014 the user pressed Stop before this call started.",isError:true});continue}const wt=H({descriptor:h,toolId:r,policy:D,isRelease:L,turnScope:F,params:i,tapLabels:Ee.get(e.id)});if(wt.verdict==="refuse"){for(const a of me("refused"))yield a;w.push({toolCallId:e.id,content:wt.reason,isError:true});continue}try{let a=s===Et?oo(r,await Ko(y,r),i):r==="ask-buoy"?await zt(s,g,u,X,i,J):await(ht.get(e.id)??u(r,s,i));a=Ft(r,s,a);const S=io(ao(a));const A=Bt(a);if(h.effect!=="read"&&!A)it=true;const T=Ho(r==="highlight-updates"&&s==="describeScreen"&&!A?So(S):S);const le=X&&!A&&!(r==="ask-buoy"&&s==="retrieve")?X.stash({toolId:r,action:s,params:i,capturedAt:C(),text:T}):void 0;const R=Jo(T,le);et.add(T);const ze=R.length>Ot?`${R.slice(0,Ot)}\u2026`:R;yield{type:"tool-end",id:e.id,ok:!A,summary:Yo(a),durationMs:C()-kt,result:ze};const We=Fe===void 0||A?void 0:await be(h,r,i,u);if(h.effect!=="read"&&r!=="ask-buoy"&&!A){const He=g.noteExternalRevert(r,s,i);const Rt=Nt(r,h,i,a,bt,{before:Fe,after:We});if(Rt&&!He){const St=g.record(r,s,Rt,Wt);if(St)St.callId=e.id}}const vt=A?void 0:po({toolId:r,action:s,params:i,result:S,before:Fe??bt,after:We,effect:h.effect});if(vt)yield{type:"block",block:vt,forToolCallId:e.id};const ye=h.effect!=="read"&&!A?await Oo({toolId:r,action:s,params:i,result:a,dispatch:u,readSnapshot:y,signal:$,after:We}):void 0;if(ye)yield{type:"tool-verified",id:e.id,verification:ye};if(U&&ye?.status==="failed")j(Co);for(const He of R.match(Jt)??[])_e.add(He);w.push({toolCallId:e.id,content:R+Go(r,h,i,M,U?j:void 0)+je+V+(ye?_o(ye,!U):"")+(ft.has(e.id)?j(bo):""),...le?{ref:le}:{}});if(r==="app"&&(s==="reloadApp"||s==="reload")){pt=true}}catch(a){const S=a instanceof Error?a.message:String(a);yield{type:"tool-end",id:e.id,ok:false,summary:S,durationMs:C()-kt};w.push({toolCallId:e.id,content:`Failed: ${S}${V}`,isError:true})}}if(v.length){re.push(Po(v));if(re.length>xt)re.shift();const e=!nt&&re.length===xt&&re.every(c=>c===re[0]);if(e){nt=true;const c=w[w.length-1];if(U)Te.push(Ut);else if(c)c.content=`${c.content}
10
10
 
11
- ${xt}`}}f.push({role:"tool-results",results:v});if(Se.length)f.push(le([...new Set(Se)].join("\n\n"),true));if(je){yield{type:"awaiting-user",blockId:je};yield{type:"done",stopReason:"awaiting-user"};return f}if(ft){yield{type:"done",stopReason:"realm-died"};return f}}if(C?.aborted){yield{type:"done",stopReason:"stopped"};return f}const oe=[];let at=false;let Le=false;const ce=[...f,le(Uo,Xe())];const Wt=J?{messages:ce}:Ye(ce,ke(),x.chars(ee),x.charsPerToken,k.liveCallIds());try{if(J&&!it(ce))throw new Error(De);if(J||U||be.liveBlock==="append"||be.liveBlock==="system-msg")f.push(ce[ce.length-1]);for await(const p of n.send({messages:Wt.messages,system:a,systemVolatile:d,tools:X,toolChoice:"none",model:w,maxTokens:y,signal:C,meta:{askId:et,round:Z+1,attempt:1}})){if(p.type==="text")oe.push(p.delta);else if(p.type==="tool-call"||p.type==="error")Le=true;else if(p.type==="meter")yield{type:"meter",frame:p.frame};else if(p.type==="done"){if(p.outcome==="refused"||p.outcome==="context-limited"){yield{type:"error",message:p.outcome==="refused"?"Claude could not help with this request.":"Claude ran out of room for this turn. Please send a new message."};yield{type:"done",stopReason:"error"};return f}at=p.outcome==="completed";if(p.usage)yield{type:"usage",...p.usage,model:p.model}}}}catch{Le=true}if(C?.aborted){yield{type:"done",stopReason:"stopped"};return f}const dt=oe.join("");if(Le||!at||!dt.trim()||Nt(dt)){const p=k.list().filter(E=>!Ft.has(E.id));oe.length=0;oe.push(["I ran out of steps. The job is not done.",...p.length?["These steps ran:",...p.map(E=>`- ${E.effect.label}${E.undoneAt?" (since undone)":""}`),"This list does not prove each change worked."]:[]].join("\n"))}let lt=true;for(const p of oe){if(!p)continue;yield{type:"text",delta:p,...lt&&xe?{breakBefore:true}:{}};lt=false}f.push({role:"assistant",text:oe.join("")});yield{type:"block",block:{id:`cap${N()}`,kind:"notice",tone:"warning",text:"I ran out of steps. The job is not done. Tap Continue to go on.",actions:[{label:"Continue",primary:true,send:Ne}]}};yield{type:"done",stopReason:"step-cap"};return f}function Wo(t,n,o,a,d){if(t!=="storage"||n.effect==="read")return"";if(!a||typeof o.key!=="string")return"";const w=a[o.key];if(!w)return"";const y=`
11
+ ${Ut}`}}f.push({role:"tool-results",results:w});if(Te.length)f.push(fe([...new Set(Te)].join("\n\n"),true));if(qe){yield{type:"awaiting-user",blockId:qe};yield{type:"done",stopReason:"awaiting-user"};return f}if(pt){yield{type:"done",stopReason:"realm-died"};return f}}if($?.aborted){yield{type:"done",stopReason:"stopped"};return f}const se=[];let dt=false;let Me=false;const he=[...f,fe(Do,Ze())];const Kt=Y?{messages:he}:Ge(he,ve(),x.chars(ne),x.charsPerToken,g.liveCallIds());try{if(Y&&!at(he))throw new Error(Pe);if(Y||U||we.liveBlock==="append"||we.liveBlock==="system-msg")f.push(he[he.length-1]);for await(const p of n.send({messages:Kt.messages,system:d,systemVolatile:l,tools:ee,toolChoice:"none",model:b,maxTokens:m,signal:$,meta:{askId:tt,round:te+1,attempt:1}})){if(p.type==="text")se.push(p.delta);else if(p.type==="tool-call"||p.type==="error")Me=true;else if(p.type==="meter")yield{type:"meter",frame:p.frame};else if(p.type==="done"){if(p.outcome==="refused"||p.outcome==="context-limited"){yield{type:"error",message:p.outcome==="refused"?"Claude could not help with this request.":"Claude ran out of room for this turn. Please send a new message."};yield{type:"done",stopReason:"error"};return f}dt=p.outcome==="completed";if(p.usage)yield{type:"usage",...p.usage,model:p.model}}}}catch{Me=true}if($?.aborted){yield{type:"done",stopReason:"stopped"};return f}const lt=se.join("");if(Me||!dt||!lt.trim()||Ct(lt)){const p=g.list().filter(E=>!Ht.has(E.id));se.length=0;se.push(["I ran out of steps. The job is not done.",...p.length?["These steps ran:",...p.map(E=>`- ${E.effect.label}${E.undoneAt?" (since undone)":""}`),"This list does not prove each change worked."]:[]].join("\n"))}let ct=true;for(const p of se){if(!p)continue;yield{type:"text",delta:p,...ct&&Oe?{breakBefore:true}:{}};ct=false}f.push({role:"assistant",text:se.join("")});yield{type:"block",block:{id:`cap${C()}`,kind:"notice",tone:"warning",text:"I ran out of steps. The job is not done. Tap Continue to go on.",actions:[{label:"Continue",primary:true,send:Ne}]}};yield{type:"done",stopReason:"step-cap"};return f}function Go(t,n,o,d,l){if(t!=="storage"||n.effect==="read")return"";if(!d||typeof o.key!=="string")return"";const b=d[o.key];if(!b)return"";const m=`
12
12
 
13
- [Buoy] This wrote to disk, but "${o.key}" is the saved copy of the live "${w}" store, so nothing on screen has changed \u2014 the app read that key once at startup and has held the state in memory since.`;if(d){d("Use zustand.rehydrate for the store named in the result to load the saved value. Use zustand.setState to change the live store. If the change was for the next app launch, no more work is needed.");return y}return y+` Call zustand.rehydrate({"storeName":"${w}"}) to make the app pick this up, or use zustand.setState next time to change the store directly. If you meant to set the value for the app's next launch, this is already done and no further action is needed.`}export{Ge as digestOf};export async function readTargetDigest(t){const n=j(t.catalog??St,t.toolId,t.action);if(!n||n.effect==="read")return void 0;const o=await ge(n,t.toolId,t.params,t.dispatch);if(o!==void 0)return Ge(o);const a=await Qe(n,t.toolId,t.params,t.dispatch);if(a!==void 0)return Ge(a);return void 0}export async function runGatedAction(t){const{toolId:n,action:o,dispatch:a,ledger:d,policy:w,isRelease:y}=t;const c=t.catalog??St;const g=j(c,n,o);if(!g){return{ok:false,error:`${n}.${o} is not in Buoy's catalog.`}}const D=me(n,o,t.params??{});const k=Ee(D.params,g.params);if(Ce(n,o,k))return{ok:false,error:Ke};const L=Ae(k,g.params);if(!L.ok){return{ok:false,error:L.errors.join("\n")}}const M=z({descriptor:g,toolId:n,policy:w,isRelease:y});if(M.verdict==="refuse"){return{ok:false,error:M.reason}}const V=await Qe(g,n,k,a);const C=await ge(g,n,k,a);const K=z({descriptor:g,toolId:n,policy:w,isRelease:y});if(K.verdict==="refuse"){return{ok:false,error:K.reason}}try{let $=n==="ask-buoy"?await jt(o,d,a,void 0,k):await a(n,o,k);$=qt(n,o,$);if(Mt($)){const H=$.error;return{ok:false,error:typeof H==="string"?H:"The tool refused this."}}if(g.effect!=="read"&&n!=="ask-buoy"){const H=d.noteExternalRevert(n,o,k);const Q=await ge(g,n,k,a);const x=$t(n,g,k,$,V,{before:C,after:Q});if(x&&!H)d.record(n,o,x)}return{ok:true,result:$}}catch($){return{ok:false,error:$ instanceof Error?$.message:String($)}}}async function jt(t,n,o,a,d,w){if(t==="retrieve"){return Eo(a,d??{})}if(t==="openProcedure"){const y=typeof d?.id==="string"?d.id:"";const c=w?.find(g=>g.id===y);if(!c){const g=(w??[]).map(D=>D.id);return{ok:false,error:g.length?`No procedure "${y}". This app's procedures: ${g.join(", ")}.`:"This app has no procedures written for it."}}return{id:c.id,title:c.title,...c.version?{version:c.version}:{},...c.requires?.length?{requires:c.requires}:{},body:c.body,note:"Follow these steps with the ordinary tools. Every write still goes through the same policy, approval and undo as any other call; a step that is refused stays refused."}}if(t==="listChanges"){const y=n.list().filter(c=>!c.undoneAt).map(c=>({id:c.id,toolId:c.toolId,action:c.action,kind:c.effect.kind,label:c.effect.label,reversible:Et(c.effect)}));return{changes:y,returned:y.length}}if(t==="undoChange"){const y=typeof d?.id==="string"?d.id:"";const c=n.list().find(D=>D.id===y);if(!c){const D=n.list().filter(k=>!k.undoneAt).map(k=>k.id);return{ok:false,error:`No change with id "${y}". Call listChanges for the current ids${D.length?` (${D.join(", ")})`:""}.`}}if(c.undoneAt)return{ok:false,error:`"${c.effect.label}" was already undone.`};if(!Et(c.effect)){return{ok:false,error:`"${c.effect.label}" can't be undone automatically \u2014 it is permanent.`}}const g=await n.revertOne(c,o);return g?{ok:false,error:g}:{ok:true,undone:{id:c.id,label:c.effect.label}}}if(t==="undoAll"){const y=await n.revertAll(o);return{ok:y.failed.length===0,...y}}throw new Error(`Unknown ask-buoy action "${t}"`)}async function Go(t,n){if(!t){throw new Error(`This app cannot read ${n}'s snapshot \u2014 Buoy's tool registry is not published here.`)}return await t(n)}async function ge(t,n,o,a){if(n==="zustand"&&t.action==="setState"){if(typeof o.storeName!=="string")return void 0;try{return await a(n,"getStoreState",{storeName:o.storeName})}catch{return void 0}}if(n==="query"&&t.action==="setQueryData"){const d=typeof o.queryHash==="string"?o.queryHash:Array.isArray(o.queryKey)?Xt(o.queryKey):void 0;if(!d)return void 0;try{return await a(n,"getQueryData",{queryHash:d})}catch{return void 0}}return void 0}async function Qe(t,n,o,a){if(t.effect==="read")return void 0;if(n==="network")return Yo(t,o,a);if(n!=="storage"||typeof o.key!=="string")return void 0;const d=t.action.startsWith("async.")?"async.getItem":t.action.startsWith("mmkv.")?"mmkv.get":void 0;if(!d)return void 0;const w={key:o.key};if(d==="mmkv.get"){if(typeof o.instanceId!=="string")return void 0;w.instanceId=o.instanceId}try{const y=await a(n,d,w);const c=y&&typeof y==="object"?y:void 0;if(c?.found===false)return void 0;const g=c?c.value:y;return{had:g!==void 0&&g!==null,value:g??void 0}}catch{return void 0}}async function Yo(t,n,o){if(t.action!=="setOverrideRuleEnabled"&&t.action!=="setOverridesEnabled"){return void 0}try{const a=await o("network","listOverrideRules",{});if(!a||typeof a!=="object")return void 0;if(t.action==="setOverridesEnabled"){return{had:true,value:String(a.enabled!==false)}}const d=(a.rules??[]).find(w=>w&&w.id===n.id);if(!d)return void 0;return{had:true,value:String(d.enabled!==false)}}catch{return void 0}}function Vo(){const t="abcdefghijklmnopqrstuvwxyz0123456789";let n="ask_";for(let o=0;o<20;o++)n+=t[Math.floor(Math.random()*t.length)];return n}
13
+ [Buoy] This wrote to disk, but "${o.key}" is the saved copy of the live "${b}" store, so nothing on screen has changed \u2014 the app read that key once at startup and has held the state in memory since.`;if(l){l("Use zustand.rehydrate for the store named in the result to load the saved value. Use zustand.setState to change the live store. If the change was for the next app launch, no more work is needed.");return m}return m+` Call zustand.rehydrate({"storeName":"${b}"}) to make the app pick this up, or use zustand.setState next time to change the store directly. If you meant to set the value for the app's next launch, this is already done and no further action is needed.`}export{Ye as digestOf};export async function readTargetDigest(t){const n=B(t.catalog??Tt,t.toolId,t.action);if(!n||n.effect==="read")return void 0;const o=await be(n,t.toolId,t.params,t.dispatch);if(o!==void 0)return Ye(o);const d=await Xe(n,t.toolId,t.params,t.dispatch);if(d!==void 0)return Ye(d);return void 0}export async function runGatedAction(t){const{toolId:n,action:o,dispatch:d,ledger:l,policy:b,isRelease:m}=t;const u=t.catalog??Tt;const y=B(u,n,o);if(!y){return{ok:false,error:`${n}.${o} is not in Buoy's catalog.`}}const M=ge(n,o,t.params??{});const g=Ie(M.params,y.params);if(Ce(n,o,g))return{ok:false,error:Qe};const D=Ae(g,y.params);if(!D.ok){return{ok:false,error:D.errors.join("\n")}}const L=H({descriptor:y,toolId:n,policy:b,isRelease:m});if(L.verdict==="refuse"){return{ok:false,error:L.reason}}const Q=await Xe(y,n,g,d);const $=await be(y,n,g,d);const X=H({descriptor:y,toolId:n,policy:b,isRelease:m});if(X.verdict==="refuse"){return{ok:false,error:X.reason}}try{let N=n==="ask-buoy"?await zt(o,l,d,void 0,g):await d(n,o,g);N=Ft(n,o,N);if(Bt(N)){const J=N.error;return{ok:false,error:typeof J==="string"?J:"The tool refused this."}}if(y.effect!=="read"&&n!=="ask-buoy"){const J=l.noteExternalRevert(n,o,g);const Z=await be(y,n,g,d);const x=Nt(n,y,g,N,Q,{before:$,after:Z});if(x&&!J)l.record(n,o,x)}return{ok:true,result:N}}catch(N){return{ok:false,error:N instanceof Error?N.message:String(N)}}}async function zt(t,n,o,d,l,b){if(t==="retrieve"){return No(d,l??{})}if(t==="openProcedure"){const m=typeof l?.id==="string"?l.id:"";const u=b?.find(y=>y.id===m);if(!u){const y=(b??[]).map(M=>M.id);return{ok:false,error:y.length?`No procedure "${m}". This app's procedures: ${y.join(", ")}.`:"This app has no procedures written for it."}}return{id:u.id,title:u.title,...u.version?{version:u.version}:{},...u.requires?.length?{requires:u.requires}:{},body:u.body,note:"Follow these steps with the ordinary tools. Every write still goes through the same policy, approval and undo as any other call; a step that is refused stays refused."}}if(t==="listChanges"){const m=n.list().filter(u=>!u.undoneAt).map(u=>({id:u.id,toolId:u.toolId,action:u.action,kind:u.effect.kind,label:u.effect.label,reversible:At(u.effect)}));return{changes:m,returned:m.length}}if(t==="undoChange"){const m=typeof l?.id==="string"?l.id:"";const u=n.list().find(M=>M.id===m);if(!u){const M=n.list().filter(g=>!g.undoneAt).map(g=>g.id);return{ok:false,error:`No change with id "${m}". Call listChanges for the current ids${M.length?` (${M.join(", ")})`:""}.`}}if(u.undoneAt)return{ok:false,error:`"${u.effect.label}" was already undone.`};if(!At(u.effect)){return{ok:false,error:`"${u.effect.label}" can't be undone automatically \u2014 it is permanent.`}}const y=await n.revertOne(u,o);return y?{ok:false,error:y}:{ok:true,undone:{id:u.id,label:u.effect.label}}}if(t==="undoAll"){const m=await n.revertAll(o);return{ok:m.failed.length===0,...m}}throw new Error(`Unknown ask-buoy action "${t}"`)}async function Ko(t,n){if(!t){throw new Error(`This app cannot read ${n}'s snapshot \u2014 Buoy's tool registry is not published here.`)}return await t(n)}async function be(t,n,o,d){if(n==="zustand"&&t.action==="setState"){if(typeof o.storeName!=="string")return void 0;try{return await d(n,"getStoreState",{storeName:o.storeName})}catch{return void 0}}if(n==="query"&&t.action==="setQueryData"){const l=typeof o.queryHash==="string"?o.queryHash:Array.isArray(o.queryKey)?to(o.queryKey):void 0;if(!l)return void 0;try{return await d(n,"getQueryData",{queryHash:l})}catch{return void 0}}return void 0}async function Xe(t,n,o,d){if(t.effect==="read")return void 0;if(n==="network")return Vo(t,o,d);if(n!=="storage"||typeof o.key!=="string")return void 0;const l=t.action.startsWith("async.")?"async.getItem":t.action.startsWith("mmkv.")?"mmkv.get":void 0;if(!l)return void 0;const b={key:o.key};if(l==="mmkv.get"){if(typeof o.instanceId!=="string")return void 0;b.instanceId=o.instanceId}try{const m=await d(n,l,b);const u=m&&typeof m==="object"?m:void 0;if(u?.found===false)return void 0;const y=u?u.value:m;return{had:y!==void 0&&y!==null,value:y??void 0}}catch{return void 0}}async function Vo(t,n,o){if(t.action!=="setOverrideRuleEnabled"&&t.action!=="setOverridesEnabled"){return void 0}try{const d=await o("network","listOverrideRules",{});if(!d||typeof d!=="object")return void 0;if(t.action==="setOverridesEnabled"){return{had:true,value:String(d.enabled!==false)}}const l=(d.rules??[]).find(b=>b&&b.id===n.id);if(!l)return void 0;return{had:true,value:String(l.enabled!==false)}}catch{return void 0}}function Qo(){const t="abcdefghijklmnopqrstuvwxyz0123456789";let n="ask_";for(let o=0;o<20;o++)n+=t[Math.floor(Math.random()*t.length)];return n}
@@ -1 +1 @@
1
- "use strict";import{selectFeed as G}from"./feeds";import{CATALOG as J}from"./catalog/catalog.g";import{buildContextDigest as Q,buildLiveContext as W}from"./context/buildContextPack";import{runAgentTurn as X}from"./engine/runAgentTurn";import{buildLiveBlock as Y,buildSystemPrompt as Z,listableProcedures as _}from"./engine/systemPrompt";import{EffectLedger as g}from"./effects/ledger";import{EvidenceStore as ee}from"./engine/evidence";import{TokenCalibration as te}from"./engine/tokenCalibration";import{compressConsumed as oe,trimHistory as re,trimHistoryReport as I}from"./engine/historyBudget";import{createAnthropicProvider as se}from"./providers/anthropic";import{createOpenAIProvider as le}from"./providers/openai";import{createFallbackProvider as ae}from"./providers/fallback";import{resolveRequireApproval as ne}from"./policy/policy";import{registerSelfEndpoint as M}from"./policy/redact";export{oe as compressConsumed,re as trimHistory,I as trimHistoryReport};export function resumableHistory(e){let o=e.length;while(o>0){const s=e[o-1];if(s.role==="assistant"&&!s.toolCalls?.length)break;o-=1}return e.slice(0,o).map(s=>s.role==="assistant"&&s.thinking?{...s,thinking:void 0}:s)}export function createAskBuoySession(e){const o=G(e.provider?.protocol??e.protocol,e.feedOptions);e={...e,feedOptions:o.options};let s=0;const L=e.catalog??J;const n=new g;const O=e.policy??{};let a=[];const N=new Set;const w=new ee;const c=new te;let m;let x=false;let u=false;const v=new Set;let y=false;let f=0;let k=0;let b={};let S={};M(e.endpoint);const B=(t,r)=>t==="openai"?le(r):se(r);let R=null;if(!e.provider&&e.fallback){const t=e.fallback;M(t.endpoint);const r={...e,endpoint:t.endpoint,model:t.model,feedOptions:G(t.protocol).options};R=ae({provider:B(e.protocol,e),model:e.model},{provider:B(t.protocol,r),model:t.model},h=>e.onModelSwitch?.(h==="second"?"fallback":"primary"))}const z=e.provider??R??B(e.protocol,e);let p=e.availableActions;let i=Object.keys(p);const l={...O};function $(){for(const t of Object.keys(l))delete l[t];Object.assign(l,O);if(u){l.requireApproval=[];l.requireApprovalFor=[]}if(y)l.readOnly=true}function D(){return l}function P(){m=Z({catalog:L,context:{...e.context,digest:{...b,...e.context?.digest}},isRelease:e.isRelease,readOnly:l.readOnly??false,readOnlySource:O.readOnly?"app":y?"device":void 0,requireApproval:ne(l),approvalsBypassed:u,appName:e.appName,platform:e.platform,availableToolIds:i})}async function j(){if(x)return;x=true;b={};try{b=await Q({dispatch:e.dispatch,readSnapshot:e.readSnapshot,availableToolIds:i,availableActions:p})}catch{}S={};for(const t of b.zustandStores??[]){const r=t;if(r?.persistsTo&&r.name)S[r.persistsTo]=r.name}P()}return{ledger:n,evidence:w,calibration:c,trustedActions:()=>[...v],untrust:t=>{v.delete(t)},get messages(){return a},prime:j,setAvailableActions(t){p=t;i=Object.keys(t)},setApprovalBypass(t){if(u===t)return;u=t;$();if(m)P()},setReadOnly(t){if(y===t)return;y=t;$();if(m)P()},restore(t){if(a.length>0)return;const r=I(resumableHistory(t),c.charsPerToken,n.liveCallIds());a=r.messages;f=r.droppedRounds},async*send(t,r){const h=k;await j();let T;try{T=await W({dispatch:e.dispatch,readSnapshot:e.readSnapshot,availableToolIds:i,availableActions:p})}catch{T=void 0}if(h!==k){yield{type:"done",stopReason:"superseded"};return}const E=Y(T,n.list().map(d=>({label:`${d.toolId}.${d.action}${d.effect.label?` \u2014 ${d.effect.label}`:""}`,undone:d.undoneAt!==void 0})));const K={role:"user",text:t,...o.name==="claude"?{turnId:`turn-${++s}`}:{},...o.options.liveBlock&&o.options.liveBlock!=="system-tail"?{liveBlock:{placement:o.options.liveBlock,text:E}}:{}};const C=a[a.length-1];const U=C?.role==="user"&&(C.systemNotice||C.liveBlock?.placement==="system-msg")?[{role:"assistant",text:"[Buoy: The prior turn stopped before an answer.]"}]:[];const q=I([...a,...U,K],c.charsPerToken,n.liveCallIds());const V=q.messages;const F=q.droppedRounds+f;f=0;if(F>0)yield{type:"history-trimmed",droppedRounds:F,droppedPinned:q.droppedPinned};const H=X({provider:z,catalog:L,messages:V,system:m,systemVolatile:o.options.liveBlock&&o.options.liveBlock!=="system-tail"?void 0:E,feedOptions:o.options,model:e.model,maxTokens:o.options.maxTokens??e.maxTokens??4096,dispatch:e.dispatch,readSnapshot:e.readSnapshot,storeKeyOwners:S,ledger:n,policy:D(),isRelease:e.isRelease,availableToolIds:i,availableActions:p,requestApproval:e.requestApproval,seenUrls:N,evidence:w,calibration:c,trusted:v,procedures:_(e.context?.procedures,i),signal:r});let A=await H.next();while(!A.done){yield A.value;A=await H.next()}if(h===k)a=A.value},reset(){k+=1;R?.reset();a=[];f=0;n.clear();N.clear();w.clear();v.clear();x=false}}}
1
+ "use strict";import{selectFeed as G}from"./feeds";import{CATALOG as J}from"./catalog/catalog.g";import{buildContextDigest as Q,buildLiveContext as W}from"./context/buildContextPack";import{runAgentTurn as X}from"./engine/runAgentTurn";import{buildLiveBlock as Y,buildSystemPrompt as Z,listableProcedures as _}from"./engine/systemPrompt";import{EffectLedger as g}from"./effects/ledger";import{EvidenceStore as ee}from"./engine/evidence";import{TokenCalibration as te}from"./engine/tokenCalibration";import{compressConsumed as oe,trimHistory as re,trimHistoryReport as I}from"./engine/historyBudget";import{createAnthropicProvider as se}from"./providers/anthropic";import{createOpenAIProvider as le}from"./providers/openai";import{createFallbackProvider as ae}from"./providers/fallback";import{resolveRequireApproval as ne}from"./policy/policy";import{registerSelfEndpoint as M}from"./policy/redact";export{oe as compressConsumed,re as trimHistory,I as trimHistoryReport};export function resumableHistory(e){let o=e.length;while(o>0){const s=e[o-1];if(s.role==="assistant"&&!s.toolCalls?.length)break;o-=1}return e.slice(0,o).map(s=>s.role==="assistant"&&s.thinking?{...s,thinking:void 0}:s)}export function createAskBuoySession(e){const o=G(e.provider?.protocol??e.protocol,e.feedOptions);e={...e,feedOptions:o.options};let s=0;const L=e.catalog??J;const n=new g;const O=e.policy??{};let a=[];const N=new Set;const w=new ee;const c=new te;let p;let x=false;let u=false;const v=new Set;let y=false;let f=0;let k=0;let b={};let S={};M(e.endpoint);const B=(t,r)=>t==="openai"?le(r):se(r);let R=null;if(!e.provider&&e.fallback){const t=e.fallback;M(t.endpoint);const r={...e,endpoint:t.endpoint,model:t.model,feedOptions:G(t.protocol).options};R=ae({provider:B(e.protocol,e),model:e.model},{provider:B(t.protocol,r),model:t.model},h=>e.onModelSwitch?.(h==="second"?"fallback":"primary"))}const z=e.provider??R??B(e.protocol,e);let d=e.availableActions;let i=Object.keys(d);const l={...O};function $(){for(const t of Object.keys(l))delete l[t];Object.assign(l,O);if(u){l.requireApproval=[];l.requireApprovalFor=[]}if(y)l.readOnly=true}function D(){return l}function P(){if(e.system!==void 0){p=e.system;return}p=Z({catalog:L,context:{...e.context,digest:{...b,...e.context?.digest}},isRelease:e.isRelease,readOnly:l.readOnly??false,readOnlySource:O.readOnly?"app":y?"device":void 0,requireApproval:ne(l),approvalsBypassed:u,appName:e.appName,platform:e.platform,availableToolIds:i})}async function j(){if(x)return;x=true;b={};try{b=await Q({dispatch:e.dispatch,readSnapshot:e.readSnapshot,availableToolIds:i,availableActions:d})}catch{}S={};for(const t of b.zustandStores??[]){const r=t;if(r?.persistsTo&&r.name)S[r.persistsTo]=r.name}P()}return{ledger:n,evidence:w,calibration:c,trustedActions:()=>[...v],untrust:t=>{v.delete(t)},get messages(){return a},prime:j,setAvailableActions(t){d=t;i=Object.keys(t)},setApprovalBypass(t){if(u===t)return;u=t;$();if(p)P()},setReadOnly(t){if(y===t)return;y=t;$();if(p)P()},restore(t){if(a.length>0)return;const r=I(resumableHistory(t),c.charsPerToken,n.liveCallIds());a=r.messages;f=r.droppedRounds},async*send(t,r){const h=k;await j();let T;try{T=await W({dispatch:e.dispatch,readSnapshot:e.readSnapshot,availableToolIds:i,availableActions:d})}catch{T=void 0}if(h!==k){yield{type:"done",stopReason:"superseded"};return}const E=Y(T,n.list().map(m=>({label:`${m.toolId}.${m.action}${m.effect.label?` \u2014 ${m.effect.label}`:""}`,undone:m.undoneAt!==void 0})));const K={role:"user",text:t,...o.name==="claude"?{turnId:`turn-${++s}`}:{},...o.options.liveBlock&&o.options.liveBlock!=="system-tail"?{liveBlock:{placement:o.options.liveBlock,text:E}}:{}};const C=a[a.length-1];const U=C?.role==="user"&&(C.systemNotice||C.liveBlock?.placement==="system-msg")?[{role:"assistant",text:"[Buoy: The prior turn stopped before an answer.]"}]:[];const q=I([...a,...U,K],c.charsPerToken,n.liveCallIds());const V=q.messages;const F=q.droppedRounds+f;f=0;if(F>0)yield{type:"history-trimmed",droppedRounds:F,droppedPinned:q.droppedPinned};const H=X({provider:z,catalog:L,messages:V,system:p,systemVolatile:o.options.liveBlock&&o.options.liveBlock!=="system-tail"?void 0:E,feedOptions:o.options,model:e.model,maxTokens:o.options.maxTokens??e.maxTokens??4096,dispatch:e.dispatch,readSnapshot:e.readSnapshot,storeKeyOwners:S,ledger:n,policy:D(),isRelease:e.isRelease,availableToolIds:i,availableActions:d,requestApproval:e.requestApproval,seenUrls:N,evidence:w,calibration:c,trusted:v,procedures:_(e.context?.procedures,i),signal:r});let A=await H.next();while(!A.done){yield A.value;A=await H.next()}if(h===k)a=A.value},reset(){k+=1;R?.reset();a=[];f=0;n.clear();N.clear();w.clear();v.clear();x=false}}}
@@ -155,7 +155,7 @@ export type TurnEvent = {
155
155
  */
156
156
  | {
157
157
  type: "retrying";
158
- reason: "throttled" | "overflow";
158
+ reason: "throttled" | "overflow" | "network";
159
159
  attempt: number;
160
160
  maxAttempts: number;
161
161
  inMs: number;
@@ -28,6 +28,11 @@ export interface AskBuoySessionConfig extends ProviderConfig {
28
28
  platform?: string;
29
29
  /** Override the built-in catalog. Tests and the desktop port use this. */
30
30
  catalog?: ToolDescriptor[];
31
+ /**
32
+ * The whole system prompt, for a host whose tools aren't an app's dev tools (the Buoy Web
33
+ * extension drives browser tabs). When set, the app-grounding prompt isn't built.
34
+ */
35
+ system?: string;
31
36
  requestApproval?: RunApproval;
32
37
  /**
33
38
  * A ready-made provider, injected by tests and benches — a scripted one,