@buoy-gg/agent-core 7.0.65 → 7.0.66
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commonjs/catalog/catalog.g.js +2 -2
- package/lib/commonjs/catalog/catalog.source.json +10 -6
- package/lib/commonjs/catalog/validateParams.js +1 -1
- package/lib/commonjs/engine/runAgentTurn.js +6 -6
- package/lib/module/catalog/catalog.g.js +2 -2
- package/lib/module/catalog/catalog.source.json +10 -6
- package/lib/module/catalog/validateParams.js +1 -1
- package/lib/module/engine/runAgentTurn.js +6 -6
- package/lib/web/index.mjs +32 -32
- package/package.json +1 -1
|
@@ -328,6 +328,10 @@
|
|
|
328
328
|
"replace": {
|
|
329
329
|
"type": "boolean",
|
|
330
330
|
"description": "Replace the current screen instead of pushing it on top. Default false. Use true when resetting the app to a base route."
|
|
331
|
+
},
|
|
332
|
+
"reset": {
|
|
333
|
+
"type": "boolean",
|
|
334
|
+
"description": "Clear the old screens, then go to this path. This ignores replace when true. Default false."
|
|
331
335
|
}
|
|
332
336
|
},
|
|
333
337
|
"required": [
|
|
@@ -1391,7 +1395,7 @@
|
|
|
1391
1395
|
{
|
|
1392
1396
|
"toolId": "events",
|
|
1393
1397
|
"title": "Events",
|
|
1394
|
-
"summary": "The cross-tool activity timeline: one chronological ring buffer (max 200, newest-first) that aggregates events from every other installed Buoy tool \u2014 network requests, redux/zustand/jotai state changes, react-query query/mutation updates, AsyncStorage/MMKV writes, route navigations, and component renders. Reach for it first for any \"what just happened in the app?\" question, before drilling into a single-tool reader. It exposes 3 actions: exportEvents (formatted read), setEnabledSources (choose what the device records), clearEvents (wipe the timeline). CRITICAL: it only records while something is watching \u2014 a cold exportEvents on a freshly connected session usually returns 0 events because nothing has ever armed capture, which is NOT the same as \"the app did nothing\". Swift captures network, storage-async, storage-mmkv, and route. React state and render sources are unavailable. Native export accepts format, includeEventData, includeSource, includeStatus, includeTitle, includeSubtitle, includeSummaryHeader, filterMode, filterSources, dataSizeThreshold, and timestampFormat; other settings are rejected. Native detail inherits source snapshot payload limits.",
|
|
1398
|
+
"summary": "For a request to record new events, call setEnabledSources before the app action. Then read exportEvents. A storage snapshot shows past writes; it does not start event capture. The cross-tool activity timeline: one chronological ring buffer (max 200, newest-first) that aggregates events from every other installed Buoy tool \u2014 network requests, redux/zustand/jotai state changes, react-query query/mutation updates, AsyncStorage/MMKV writes, route navigations, and component renders. Reach for it first for any \"what just happened in the app?\" question, before drilling into a single-tool reader. It exposes 3 actions: exportEvents (formatted read), setEnabledSources (choose what the device records), clearEvents (wipe the timeline). CRITICAL: it only records while something is watching \u2014 a cold exportEvents on a freshly connected session usually returns 0 events because nothing has ever armed capture, which is NOT the same as \"the app did nothing\". Swift captures network, storage-async, storage-mmkv, and route. React state and render sources are unavailable. Native export accepts format, includeEventData, includeSource, includeStatus, includeTitle, includeSubtitle, includeSummaryHeader, filterMode, filterSources, dataSizeThreshold, and timestampFormat; other settings are rejected. Native detail inherits source snapshot payload limits.",
|
|
1395
1399
|
"actions": [
|
|
1396
1400
|
{
|
|
1397
1401
|
"action": "exportEvents",
|
|
@@ -2273,7 +2277,7 @@
|
|
|
2273
2277
|
{
|
|
2274
2278
|
"toolId": "time-machine",
|
|
2275
2279
|
"title": "Time Machine",
|
|
2276
|
-
"summary": "Save and restore the app's entire client-side state (device storage, redux, zustand, jotai, react-query) as named snapshots (\"restore points\"), plus the route it was captured on. Reach for it to put the app back into a known state before re-running a flow, to preview exactly what a restore would change before committing, or to wipe the app to fresh-install state. Snapshot payloads stay on-device \u2014 `list` returns metadata only; use `inspect` for one source's actual captured data and `preview` for item-level diffs. Swift supports live restore of registered providers, with UserDefaults and MMKV supplied by default. Keychain
|
|
2280
|
+
"summary": "Save and restore the app's entire client-side state (device storage, redux, zustand, jotai, react-query) as named snapshots (\"restore points\"), plus the route it was captured on. Reach for it to put the app back into a known state before re-running a flow, to preview exactly what a restore would change before committing, or to wipe the app to fresh-install state. Snapshot payloads stay on-device \u2014 `list` returns metadata only; use `inspect` for one source's actual captured data and `preview` for item-level diffs. Swift supports live restore of registered providers, with UserDefaults and MMKV supplied by default. RN saves SecureStore keys you register. It can put them back. Swift does this for Keychain keys you register. Both skip keys that need a face or fingerprint check. They also skip Buoy keys. Read provider detail and restoreModes. Swift has captureBaseline and wipeAll. It also accepts mode reload. Reload runs if the app has a reload hook. Read willReload to see if one was queued. A restore from the bar saves a safety copy. This does not reset the whole app process.",
|
|
2277
2281
|
"actions": [
|
|
2278
2282
|
{
|
|
2279
2283
|
"action": "list",
|
|
@@ -2285,7 +2289,7 @@
|
|
|
2285
2289
|
},
|
|
2286
2290
|
"effect": "read",
|
|
2287
2291
|
"release": "works",
|
|
2288
|
-
"description": "Same payload as the tool's synced snapshot. Returns { snapshots, busy, lastOutcome, providers, route }. `snapshots[]` = { id (e.g. \"snap_m1x2y3_4\"), name, createdAt, sizeBytes, baseline?, route?:{pathname,href}, restoreRoute?, scope?, excludedKeys?, sources:{ [sourceId]: { warnings:string[] } } } \u2014 METADATA ONLY, no captured values. `providers[]` = { id, label, canCapture, canRestore, detail } for the registered sources: \"storage\", \"redux\", \"zustand\", \"jotai\", \"query\" (plus any custom ones the app registered). Read `detail` before reporting a source as broken \u2014 e.g. redux says \"Auto-instrumented store cannot be restored\" when the app didn't wrap its root reducer. `route.available` is false on apps without expo-router (those snapshots record no route). `lastOutcome` is the previous restore's per-source result. Call this first \u2014 every other action needs an `id` from here. Swift supports live restore of registered providers, with UserDefaults and MMKV supplied by default. Keychain
|
|
2292
|
+
"description": "Same payload as the tool's synced snapshot. Returns { snapshots, busy, lastOutcome, providers, route }. `snapshots[]` = { id (e.g. \"snap_m1x2y3_4\"), name, createdAt, sizeBytes, baseline?, route?:{pathname,href}, restoreRoute?, scope?, excludedKeys?, sources:{ [sourceId]: { warnings:string[] } } } \u2014 METADATA ONLY, no captured values. `providers[]` = { id, label, canCapture, canRestore, detail } for the registered sources: \"storage\", \"redux\", \"zustand\", \"jotai\", \"query\" (plus any custom ones the app registered). Read `detail` before reporting a source as broken \u2014 e.g. redux says \"Auto-instrumented store cannot be restored\" when the app didn't wrap its root reducer. `route.available` is false on apps without expo-router (those snapshots record no route). `lastOutcome` is the previous restore's per-source result. Call this first \u2014 every other action needs an `id` from here. Swift supports live restore of registered providers, with UserDefaults and MMKV supplied by default. RN saves SecureStore keys you register. It can put them back. Swift does this for Keychain keys you register. Both skip keys that need a face or fingerprint check. They also skip Buoy keys. Read provider detail and restoreModes. Swift has captureBaseline and wipeAll. It also accepts mode reload. Reload runs if the app has a reload hook. Read willReload to see if one was queued. A restore from the bar saves a safety copy. This does not reset the whole app process.",
|
|
2289
2293
|
"requires": [
|
|
2290
2294
|
"@buoy-gg/time-machine registered in FloatingDevTools"
|
|
2291
2295
|
]
|
|
@@ -2385,7 +2389,7 @@
|
|
|
2385
2389
|
},
|
|
2386
2390
|
"effect": "destructive",
|
|
2387
2391
|
"release": "works",
|
|
2388
|
-
"description": "Requires `id` (throws \"restore requires a snapshot `id`\" without it). mode \"live\" (default) replaces state in place source by source in a fixed order (storage \u2192 redux \u2192 zustand \u2192 jotai \u2192 query); mode \"reload\" restores ONLY persisted storage and then reloads the JS bundle so in-memory stores rebuild themselves. A baseline snapshot ALWAYS takes the clear+reload path regardless of mode. Storage restore is a diff \u2014 app keys missing from the snapshot are DELETED. Returns a RestoreOutcome: read `results[sourceId].applied` / `.skipped[].reason` / `.warnings` rather than assuming success (a source with canRestore:false comes back skipped with a reason, not an error), and read `willReload` and `route.status` (\"navigated\" | \"deferred\" | \"failed\" | \"unavailable\"). TWO GOTCHAS: (1) omitting `excludeKeys` makes the snapshot's own SAVED excludedKeys apply, and a saved `scope` narrows the restore to only the scoped items \u2014 passing an explicit `excludeKeys` array disables that saved scope. (2) omitting `restoreRoute` does NOT mean false: it falls back to the snapshot's own setting, which is ON whenever the snapshot captured a route. Pass restoreRoute:false to keep the app on the current screen. Swift supports live restore of registered providers, with UserDefaults and MMKV supplied by default. Keychain
|
|
2392
|
+
"description": "Requires `id` (throws \"restore requires a snapshot `id`\" without it). mode \"live\" (default) replaces state in place source by source in a fixed order (storage \u2192 redux \u2192 zustand \u2192 jotai \u2192 query); mode \"reload\" restores ONLY persisted storage and then reloads the JS bundle so in-memory stores rebuild themselves. A baseline snapshot ALWAYS takes the clear+reload path regardless of mode. Storage restore is a diff \u2014 app keys missing from the snapshot are DELETED. Returns a RestoreOutcome: read `results[sourceId].applied` / `.skipped[].reason` / `.warnings` rather than assuming success (a source with canRestore:false comes back skipped with a reason, not an error), and read `willReload` and `route.status` (\"navigated\" | \"deferred\" | \"failed\" | \"unavailable\"). TWO GOTCHAS: (1) omitting `excludeKeys` makes the snapshot's own SAVED excludedKeys apply, and a saved `scope` narrows the restore to only the scoped items \u2014 passing an explicit `excludeKeys` array disables that saved scope. (2) omitting `restoreRoute` does NOT mean false: it falls back to the snapshot's own setting, which is ON whenever the snapshot captured a route. Pass restoreRoute:false to keep the app on the current screen. Swift supports live restore of registered providers, with UserDefaults and MMKV supplied by default. RN saves SecureStore keys you register. It can put them back. Swift does this for Keychain keys you register. Both skip keys that need a face or fingerprint check. They also skip Buoy keys. Read provider detail and restoreModes. Swift has captureBaseline and wipeAll. It also accepts mode reload. Reload runs if the app has a reload hook. Read willReload to see if one was queued. A restore from the bar saves a safety copy. This does not reset the whole app process.",
|
|
2389
2393
|
"requires": [
|
|
2390
2394
|
"a source's provider must report canRestore:true or that source is skipped with a reason",
|
|
2391
2395
|
"expo-router for the route leg",
|
|
@@ -3094,7 +3098,7 @@
|
|
|
3094
3098
|
},
|
|
3095
3099
|
{
|
|
3096
3100
|
"action": "runRecipe",
|
|
3097
|
-
"summary": "Run the
|
|
3101
|
+
"summary": "Run the fixed recipe named by `id`: phone-call (20s), quick-switch (5s), away-31m, overnight, low-memory, dying-battery or relaunch. If the user gives a call length, use interrupt with duration.",
|
|
3098
3102
|
"description": "Each recipe is a short sequence of the actions above; getState lists them with `unavailable` when a dependency is missing (away-31m and overnight need @buoy-gg/clock, dying-battery needs a battery library). Returns the new state.",
|
|
3099
3103
|
"effect": "write",
|
|
3100
3104
|
"release": "works",
|
|
@@ -3709,7 +3713,7 @@
|
|
|
3709
3713
|
{
|
|
3710
3714
|
"toolId": "storage",
|
|
3711
3715
|
"title": "Storage",
|
|
3712
|
-
"summary": "Read and write the app's persisted state across all three backends \u2014 AsyncStorage, every registered MMKV instance, and registered Expo SecureStore keys \u2014 plus a recorded timeline of storage writes with per-event undo/jump. Reach for this first when a value is wrong, stale, missing, or only broken after a restart/upgrade: the bad value is usually sitting in storage. Buoy's own devtool keys (@react_buoy*, @buoy*, buoy-*) are stripped from every read path, so results are app data only. Nothing here is __DEV__-gated \u2014 every action really runs in a release build. When a saved value looks wrong, compare it with getRequiredKeys: a key written by an older app version shows up there with the wrong type (a bare \"1856\" where the app expects an object). The storage write timeline is this tool's getSnapshot (newest events, each with its key, value and the value it replaced) \u2014 read it for \"what changed in storage?\" and to find the event to undo. Do not use the Events tool for that: it records a source only after setEnabledSources, so earlier writes are not there.",
|
|
3716
|
+
"summary": "Read and write the app's persisted state across all three backends \u2014 AsyncStorage, every registered MMKV instance, and registered Expo SecureStore keys \u2014 plus a recorded timeline of storage writes with per-event undo/jump. Reach for this first when a value is wrong, stale, missing, or only broken after a restart/upgrade: the bad value is usually sitting in storage. Buoy's own devtool keys (@react_buoy*, @buoy*, buoy-*) are stripped from every read path, so results are app data only. Nothing here is __DEV__-gated \u2014 every action really runs in a release build. When a saved value looks wrong, compare it with getRequiredKeys: a key written by an older app version shows up there with the wrong type (a bare \"1856\" where the app expects an object). The storage write timeline is this tool's getSnapshot (newest events, each with its key, value and the value it replaced) \u2014 read it for \"what changed in storage?\" and to find the event to undo. Do not use the Events tool for that: it records a source only after setEnabledSources, so earlier writes are not there. When asked to record a new write, call events.setEnabledSources first. Then write once and read events.exportEvents. A storage snapshot does not start Events capture.",
|
|
3713
3717
|
"actions": [
|
|
3714
3718
|
{
|
|
3715
3719
|
"action": "getSnapshot",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.applyDefaults=applyDefaults;exports.validateParams=validateParams;function typeOf(
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.applyDefaults=applyDefaults;exports.validateParams=validateParams;function typeOf(e){if(e===null)return"null";if(Array.isArray(e))return"array";return typeof e}function checkType(e,t){if(Array.isArray(t))return t.some(n=>checkType(e,n));switch(t){case"integer":return typeof e==="number"&&Number.isInteger(e);case"number":return typeof e==="number"&&Number.isFinite(e);case"null":return e===null;case"array":return Array.isArray(e);case"object":return typeOf(e)==="object";default:return typeof e===t}}function validate(e,t,n,r){if(t.anyOf?.length){const o=t.anyOf.some(i=>{const f=[];validate(e,i,n,f);return f.length===0});if(!o){const i=t.anyOf.map(f=>f.type??"?").join(" | ");r.push(`${n}: expected ${i}, got ${typeOf(e)}`)}return}if(t.type&&!checkType(e,t.type)){r.push(`${n}: expected ${t.type}, got ${typeOf(e)}`);return}if(t.enum&&!t.enum.includes(e)){r.push(`${n}: expected one of ${t.enum.map(o=>JSON.stringify(o)).join(", ")}, got ${JSON.stringify(e)}`);return}const u=Array.isArray(t.type)?t.type:[t.type];if(u.includes("array")&&Array.isArray(e)){if(t.minItems!==void 0&&e.length<t.minItems){r.push(`${n}: expected at least ${t.minItems} item(s), got ${e.length}`)}if(t.maxItems!==void 0&&e.length>t.maxItems){r.push(`${n}: expected at most ${t.maxItems} item(s), got ${e.length}`)}if(t.items){e.forEach((o,i)=>validate(o,t.items,`${n}[${i}]`,r))}return}if(u.includes("object")&&typeOf(e)==="object"){const o=e;for(const i of t.required??[]){if(o[i]===void 0)r.push(`${n}.${i}: required`)}if(t.properties){for(const[i,f]of Object.entries(t.properties)){if(o[i]!==void 0)validate(o[i],f,`${n}.${i}`,r)}if(t.additionalProperties===false){const i=new Set(Object.keys(t.properties));for(const f of Object.keys(o)){if(!i.has(f))r.push(`${n}.${f}: unexpected property`)}}}}}function validateParams(e,t){const n=[];const r=t.type&&checkType(null,t.type);const u=e===void 0||e===null&&!r?{}:e;validate(u,t,"params",n);return{ok:n.length===0,errors:n}}function applyDefaults(e,t){const n=typeOf(e)==="object"?{...e}:{};for(const[r,u]of Object.entries(t.properties??{})){if(n[r]===void 0&&u.default!==void 0)n[r]=u.default}return n}
|
|
@@ -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
|
|
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
2
|
${t.systemVolatile??""}${ne?.role==="user"&&ne.liveBlock?`
|
|
3
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 n.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,n.protocol));yield{type:"usage",...u.usage,model:u.model}}}}if(!e)break;const r=e.problem.kind;if(z&&r==="overflow"){G={message:Re};break}const s=1+(r==="throttled"?THROTTLE_RETRIES:OVERFLOW_RETRIES);const b=ke[r];let h=r==="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&&r==="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=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 y=e.problem.hosted;yield y?{type:"error",message:y.message,hosted:y}:{type:"error",message:`${u} (${e.message})`};ye=true;break}ke[r]+=1;yield{type:"retrying",reason:r,attempt:ke[r]+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 r=Se||l?null:(0,_askGate.synthesizeAskBlock)(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 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 r=(0,_toProviderTools.fromProviderToolName)(l.name,o);if(!r||r==="ask-buoy")return false;const s=l.input?.action;if(typeof s!=="string"||s===_snapshotReads.SNAPSHOT_ACTION)return false;const b=findDescriptor(o,r,s);if(!b||b.effect!=="read")return false;return(0,_policy.decide)({descriptor:b,toolId:r,policy:x,isRelease:D}).verdict==="allow"});if(e){for(const l of S){const r=(0,_toProviderTools.fromProviderToolName)(l.name,o);const s=String(l.input.action);const b={...l.input.params??{}};const h=findDescriptor(o,r,s);const C=(0,_normalizeParams.normalizeParams)(r,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(r,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 r=typeof e.input?.action==="string"?e.input.action:"";const s=r?findDescriptor(o,l,r):void 0;const b=e.input?.params??{};return[{type:"tool-start",id:e.id,toolId:l,action:r,label:s?(0,_policy.describeCall)(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 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 r=findDescriptor(o,"highlight-updates","describeScreen");const s=findDescriptor(o,"highlight-updates","tapElement");if(_?.aborted||!r||!s||(0,_policy.decide)({descriptor:r,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 r=typeof e.input?.action==="string"?e.input.action:void 0;if(!l||!r)return void 0;const s=findDescriptor(o,l,r);if(!s)return void 0;const b=e.input.params??{};const h=(0,_validateParams.applyDefaults)((0,_normalizeParams.normalizeParams)(l,r,b).params,s.params);if(emptyTap(l,r,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:r,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 r=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:r}):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
|
|
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
6
|
${te.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)(
|
|
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}
|
|
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
|
|
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=`
|
|
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
|
|
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}
|