@reviseio/engine 0.0.0-stage → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/FONT-LICENSE-HAN-EXT-B.txt +91 -0
- package/FONT-LICENSE-KATEX.txt +95 -0
- package/FONT-LICENSE-LIBERATION.txt +102 -0
- package/FONT-LICENSE-NOTO-MULTILINGUAL.txt +93 -0
- package/FONT-LICENSE-NOTO-SANS-SC.txt +93 -0
- package/FONT-LICENSE-NOTO.txt +94 -0
- package/FONT-LICENSE-SOURCE-CODE-PRO.txt +94 -0
- package/FONT-LICENSE-SOURCE-SERIF-4.txt +93 -0
- package/LICENSE +141 -0
- package/README.md +11 -2
- package/THIRD-PARTY-NOTICES.md +3376 -0
- package/assets/historyMaterializeWorker-Kl0syEbc.js +618 -0
- package/chunks/AgentHtmlConverter-BnK7NaYA.js +379 -0
- package/chunks/AgentPageRenderViews-BTLjPZJQ.js +2 -0
- package/chunks/AgentPageRenderer-DLwq6nAa.js +180 -0
- package/chunks/BidiText-Bkp4Y90s.js +160 -0
- package/chunks/BlockDiff-BdlcKY-t.js +42 -0
- package/chunks/CanvasRenderer-Bqsj1S0p.js +110 -0
- package/chunks/ColorParserFull-BKH72fK8.js +446 -0
- package/chunks/DocumentCompare-BqyiP87r.js +6 -0
- package/chunks/DocumentLayout-CsU5MR-3.js +12 -0
- package/chunks/DocumentLayoutEngine-7iOYvyVb.js +218 -0
- package/chunks/DocumentMutator-DIrZBuLr.js +13 -0
- package/chunks/DocumentScrubber-Cz8Q05hF.js +21 -0
- package/chunks/DocumentSession-lXSXqua5.js +1 -0
- package/chunks/DocumentStylesheet-CEEt18sr.js +7 -0
- package/chunks/DocxConverter-BfDw7777.js +1236 -0
- package/chunks/DocxGraft-D0uCnGCo.js +8 -0
- package/chunks/HorizontalRuleOrnaments-gmUZ3R7Q.js +3 -0
- package/chunks/HtmlConverter-7Xj_g9Jr.js +267 -0
- package/chunks/ListNumbering-Qlu6AuRZ.js +23 -0
- package/chunks/MarkdownConverter-cnW_oePY.js +57 -0
- package/chunks/MathRenderer-Bz9WEVvF.js +68 -0
- package/chunks/OdtConverter-GwRDMnwS.js +125 -0
- package/chunks/OfficeImportShared-nlMtIUni.js +30 -0
- package/chunks/PageNumeralFonts-BWzI061X.js +5 -0
- package/chunks/ParagraphDiffAnalysis-DrmStvmz.js +36 -0
- package/chunks/PdfConverter-yOlWiVIj.js +457 -0
- package/chunks/RtfConverter--wLd0qrw.js +186 -0
- package/chunks/TableBorders-C5pNsuxP.js +32 -0
- package/chunks/TableGrid-DbroRucl.js +12 -0
- package/chunks/TextFileDecoder--rsVs3NR.js +9 -0
- package/chunks/TxtConverter-BoRVCDZw.js +14 -0
- package/chunks/Typography-DAGM5kfI.js +28 -0
- package/chunks/UnicodeUtils-CXtusU4g.js +10 -0
- package/chunks/XmlConverter-CO8Z28dX.js +55 -0
- package/chunks/_commonjsHelpers-DaMA6jEr.js +2 -0
- package/chunks/_revise-sdk-lazy-harfbuzz-CDWdjF9f.js +1 -0
- package/chunks/base64-Di1bxoXD.js +1 -0
- package/chunks/browser-module-CFmqfGkE.js +1791 -0
- package/chunks/bundle.min-DRpfgV69.js +782 -0
- package/chunks/capture-Dtinb4bY.js +11 -0
- package/chunks/carrier-RNy67HN4.js +6 -0
- package/chunks/chromeImageLayout-bgHYmqTp.js +18 -0
- package/chunks/engine-TnK8N-gT.js +520 -0
- package/chunks/footnoteFlatten-BcKaWzVs.js +6 -0
- package/chunks/graftExport-DxAALMHp.js +104 -0
- package/chunks/html2canvas.esm-CntiHiYW.js +997 -0
- package/chunks/index-BWdRWxoH.js +1807 -0
- package/chunks/index-CTti7wRd.js +1002 -0
- package/chunks/index.es-CI0QPo8w.js +780 -0
- package/chunks/jspdf.es.min-DU74zN8b.js +1792 -0
- package/chunks/jszip.min-CPW0h1Kx.js +476 -0
- package/chunks/katex-DWj8TvwO.js +1462 -0
- package/chunks/pdf-BLWDCiFF.js +1828 -0
- package/chunks/purify.es-BwLardii.js +107 -0
- package/chunks/serverDocumentSession-BmYdjC6e.js +1011 -0
- package/chunks/signatures-CU2LMLBp.js +21 -0
- package/chunks/suggestionAuthorship-B-IuLQlE.js +1 -0
- package/chunks/web-tree-sitter-BXGZGnNj.js +2 -0
- package/chunks/xmlScan-DXjt2cTS.js +8 -0
- package/engine.d.ts +179 -0
- package/engine.js +3 -0
- package/package.json +64 -4
- package/serverToolContract.d.ts +420 -0
- package/serverToolInputs.generated.d.ts +264 -0
|
@@ -0,0 +1,1011 @@
|
|
|
1
|
+
import{DocumentSession as Ko}from"./DocumentSession-lXSXqua5.js";import{n as fn,A as ae,a as Vo,c as bn}from"./AgentHtmlConverter-BnK7NaYA.js";import{c as ke,a as _n,b as qt,e as Le,d as ht,g as Dt,h as Xo,
|
|
2
|
+
i as Qo,j as Zo,k as yn,l as Pt,m as Xe,n as Yo,o as er,p as tr,q as wn,s as nr,t as or,u as kn,v as rr,w as ir}from"./DocumentMutator-DIrZBuLr.js";import{b as Ce}from"./TableGrid-DbroRucl.js";import{
|
|
3
|
+
D as Rt,i as sr,A as ar}from"./AgentPageRenderViews-BTLjPZJQ.js";import{f as re,h as Ae,i as vn,j as lr}from"./CanvasRenderer-Bqsj1S0p.js";import*as Qe from"yjs";import{d as cr,y as In,r as xn,c as Sn,
|
|
4
|
+
e as dr,t as ur,i as mr,j as hr}from"./engine-TnK8N-gT.js";import{b as Nt}from"./base64-Di1bxoXD.js";import{createStandardLayout as pr}from"./DocumentLayout-CsU5MR-3.js";import{c as gr,h as fr}from"./DocumentLayoutEngine-7iOYvyVb.js";
|
|
5
|
+
import{c as br}from"./index-CTti7wRd.js";import"./ParagraphDiffAnalysis-DrmStvmz.js";import{c as _r}from"./UnicodeUtils-CXtusU4g.js";import{R as yr}from"./suggestionAuthorship-B-IuLQlE.js";class wr extends Error{constructor(t){
|
|
6
|
+
super(t.message),this.failure=t,this.name="ReviseToolError",this.callId=t.callId,this.tool=t.tool,this.code=t.code}}const kr={count:()=>{},gauge:()=>{},distribution:()=>{}},Mt=/(<img\b[^>]*?\bsrc\s*=\s*)(["'])([\s\S]*?)\2/gi,
|
|
7
|
+
$n=/(!\[[^\]]*\]\(\s*)(<[^>]+>|[^)\s]+)((?:\s+(?:"[^"]*"|'[^']*'|\([^)]*\)))?\s*\))/g;function pt(e){const t=e.trim();return t.startsWith("<")&&t.endsWith(">")?t.slice(1,-1).trim():t}function vr(e){const t=new Set(
|
|
8
|
+
["images.revise.io"]);for(const n of e.flatMap(o=>(o??"").split(",")))if(n.trim())try{t.add(new URL(n.includes("://")?n.trim():"https://"+n.trim()).host)}catch{}return t}function Ir(e,t,n){try{const o=new URL(
|
|
9
|
+
pt(e),n);return!["http:","https:"].includes(o.protocol)||t.has(o.host)?!1:!n||o.origin!==new URL(n).origin}catch{return!1}}function xr(e,t,n,o=!1){for(const r of e.matchAll(Mt)){const i=pt(r[3]);n(i)&&
|
|
10
|
+
t.add(i)}if(o)for(const r of e.matchAll($n)){const i=pt(r[2]);n(i)&&t.add(i)}}function Sr(e){try{const t=new URL(e);if(t.hostname!=="upload.wikimedia.org")return e;const n=t.pathname.split("/");return n.
|
|
11
|
+
length<8||n[1]!=="wikipedia"||n[2]!=="commons"||n[3]!=="thumb"?e:(t.pathname=["","wikipedia","commons",...n.slice(4,-1)].join("/"),t.toString())}catch{return e}}function $r(e){return e.replace(/&/g,"&\
|
|
12
|
+
amp;").replace(/"/g,""").replace(/</g,"<").replace(/>/g,">")}function Cr(e,t){return e.replace(/<img\b[^>]*>/gi,n=>{const o=Array.from(n.matchAll(Mt))[0];if(!o)return n;const r=o[3].trim(),
|
|
13
|
+
i=t.get(r);if(!i)return n;let a=n.replace(Mt,(c,d,u)=>`${d}${u}${i.url}${u}`);const l=[];return/\bdata-source-url\s*=/i.test(a)||l.push(`data-source-url="${$r(r)}"`),i.naturalWidth&&i.naturalHeight&&!/\bdata-revise-natural-(?:width|height)\s*=/i.
|
|
14
|
+
test(a)&&l.push(`data-revise-natural-width="${i.naturalWidth}"`,`data-revise-natural-height="${i.naturalHeight}"`),l.length>0&&(a=a.replace(/\s*\/?>$/,c=>` ${l.join(" ")}${c}`)),a})}function Cn(e,t,n=!1){
|
|
15
|
+
const o=n?e.replace($n,(r,i,a,l)=>{const c=t.get(pt(a));return c?i+"<"+c.url+">"+l:r}):e;return Cr(o,t)}const Ar="https://app-api.revise-sdk.invalid";function An(e){return Ir(e,vr([""]),typeof window<
|
|
16
|
+
"u"?window.location.href:void 0)}function Tn(e){return typeof e=="number"&&Number.isInteger(e)&&e>0?e:void 0}async function Tr(e){try{const t=await fetch(`${Ar}/uploads/images/rehost`,{method:"POST",headers:{
|
|
17
|
+
"Content-Type":"application/json"},body:JSON.stringify({url:Sr(e)}),signal:AbortSignal.timeout(3e4)});if(!t.ok){let i=`Image copy request failed (HTTP ${t.status}).`;try{const a=await t.json();typeof a.
|
|
18
|
+
error=="string"&&a.error.trim().length>0&&(i=a.error.trim())}catch{}return{ok:!1,failure:{url:e,status:t.status,message:i}}}const n=await t.json();if(typeof n.fileUrl!="string"||!n.fileUrl)return{ok:!1,
|
|
19
|
+
failure:{url:e,status:t.status,message:"Image copy response did not include a file URL."}};const o=Tn(n.width),r=Tn(n.height);return{ok:!0,image:{url:n.fileUrl,...o&&r?{naturalWidth:o,naturalHeight:r}:
|
|
20
|
+
{}}}}catch{return{ok:!1,failure:{url:e,message:"Image copy request could not reach Revise storage."}}}}function qn(e){if(e?.name!=="set_header_footer")return null;const t=e.arguments?.image;if(!t||typeof t!=
|
|
21
|
+
"object")return null;const n=t.url;return typeof n=="string"&&n.trim().length>0?t:null}const Dn=new Set(["insert_block","replace_block"]);function qr(e){const t=new Set;for(const n of e??[]){const o=qn(
|
|
22
|
+
n);if(o&&An(o.url)&&t.add(o.url),!n?.name||!Dn.has(n.name))continue;const r=n.arguments?.content;for(const i of Array.isArray(r)?r:[r])typeof i=="string"&&xr(i,t,An)}return t}async function Pn(e,t=Tr){
|
|
23
|
+
const n={attempted:0,rehosted:0,failedUrls:[],failures:[]};if(!Array.isArray(e)||e.length===0)return n;const o=qr(e);if(o.size===0)return n;const r=new Map,i=[];await Promise.all([...o].map(async l=>{
|
|
24
|
+
const c=await t(l);c.ok?r.set(l,c.image):i.push(c.failure)}));const a=[...o].filter(l=>!r.has(l));if(r.size===0)return{attempted:o.size,rehosted:0,failedUrls:a,failures:i};for(const l of e){const c=qn(
|
|
25
|
+
l),d=c&&r.get(c.url);if(c&&d&&(c.url=d.url,d.naturalWidth&&d.naturalHeight&&(c.naturalWidth=d.naturalWidth,c.naturalHeight=d.naturalHeight)),!l?.name||!Dn.has(l.name))continue;const u=l.arguments;u&&(typeof u.
|
|
26
|
+
content=="string"?u.content=Cn(u.content,r):Array.isArray(u.content)&&(u.content=u.content.map(f=>typeof f=="string"?Cn(f,r):f)))}return{attempted:o.size,rehosted:r.size,failedUrls:a,failures:i}}const Dr=20*
|
|
27
|
+
1024*1024,Pr=2e4,Rr=5,Nr=1e8;function Mr(e){const t=new DataView(e.buffer,e.byteOffset,e.byteLength),n=(o,r)=>String.fromCharCode(...e.subarray(o,o+r));if(e.length>=24&&n(1,3)==="PNG")return{mime:"ima\
|
|
28
|
+
ge/png",width:t.getUint32(16),height:t.getUint32(20)};if(e.length>=10&&n(0,3)==="GIF")return{mime:"image/gif",width:t.getUint16(6,!0),height:t.getUint16(8,!0)};if(e.length>=30&&n(0,4)==="RIFF"&&n(8,4)===
|
|
29
|
+
"WEBP"){const o=n(12,4);if(o==="VP8X"){const r=i=>e[i]|e[i+1]<<8|e[i+2]<<16;return{mime:"image/webp",width:r(24)+1,height:r(27)+1}}if(o==="VP8 ")return{mime:"image/webp",width:t.getUint16(26,!0)&16383,
|
|
30
|
+
height:t.getUint16(28,!0)&16383};if(o==="VP8L"&&e[20]===47){const r=t.getUint32(21,!0);return{mime:"image/webp",width:(r&16383)+1,height:(r>>14&16383)+1}}return null}if(e.length>=4&&e[0]===255&&e[1]===
|
|
31
|
+
216){let o=2;for(;o+9<e.length&&e[o]===255;){const r=e[o+1],i=t.getUint16(o+2);if(r>=192&&r<=207&&r!==196&&r!==200&&r!==204)return{mime:"image/jpeg",height:t.getUint16(o+5),width:t.getUint16(o+7)};o+=
|
|
32
|
+
2+i}return{mime:"image/jpeg"}}return null}function Br(e){let t=e.toLowerCase().replace(/^\[|\]$/g,"").replace(/%.*$/,"");if(!t.includes(":"))return null;const n=/(\d+)\.(\d+)\.(\d+)\.(\d+)$/.exec(t);if(n){
|
|
33
|
+
const[u,f,b,y]=n.slice(1).map(Number);t=`${t.slice(0,n.index)}${(u<<8|f).toString(16)}:${(b<<8|y).toString(16)}`}const[o,r]=t.split("::"),i=u=>u?u.split(":").map(f=>Number.parseInt(f,16)):[],a=i(o),l=t.
|
|
34
|
+
includes("::")?i(r):[],c=8-a.length-l.length;if(c<0||!t.includes("::")&&c!==0)return null;const d=[...a,...Array(c).fill(0),...l];return d.every(u=>Number.isInteger(u)&&u>=0&&u<=65535)?d:null}function Rn(e,t){
|
|
35
|
+
return e===0||e===10||e===127||e===100&&t>=64&&t<=127||e===169&&t===254||e===172&&t>=16&&t<=31||e===192&&t===168||e===198&&(t===18||t===19)||e>=224}function Nn(e){const t=/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/.
|
|
36
|
+
exec(e);if(t)return Rn(Number(t[1]),Number(t[2]));const n=Br(e);if(!n)return!0;const o=i=>Rn(i>>8,i&255),r=(i,a)=>n.slice(i,a).every(l=>l===0);return r(0,5)&&n[5]===65535?o(n[6]):r(0,6)?!0:n[0]===100&&
|
|
37
|
+
n[1]===65435&&r(2,6)?o(n[6]):n[0]===8194?o(n[1]):(n[0]&65024)===64512||(n[0]&65472)===65152||(n[0]&65280)===65280}class Te extends Error{constructor(t,n){super(t),this.status=n}}async function Or(e,t,n){
|
|
38
|
+
if(e.protocol!=="http:"&&e.protocol!=="https:")throw new Te(`Only http(s) image URLs can be fetched, not ${e.protocol}`);const[{isIP:o},r,i]=await Promise.all([import("node:net"),import("node:dns"),e.
|
|
39
|
+
protocol==="https:"?import("node:https"):import("node:http")]),a=e.hostname.replace(/^\[|\]$/g,""),l=()=>new Te(`${a} is a private or local address; images are fetched only from public hosts.`);if(o(a)&&
|
|
40
|
+
!t.allowPrivateNetwork&&Nn(a))throw l();const c=(d,u,f)=>{r.lookup(d,{...u,all:!0},(b,y)=>{if(b)return f(b,"");const N=y;return!t.allowPrivateNetwork&&(N.length===0||N.some(L=>Nn(L.address)))?f(l(),""):
|
|
41
|
+
u.all?f(null,N):f(null,N[0].address,N[0].family)})};return new Promise((d,u)=>{const f=i.request(e,{lookup:c,signal:n,headers:{"user-agent":"revise"}},d);f.on("error",u),f.end()})}async function jr(e,t,n){
|
|
42
|
+
const o=AbortSignal.timeout(Pr),r=()=>new Te(`The image is larger than ${Math.round(n/1048576)} MB.`),i=[];let a=0;const l=u=>{if(a+=u.length,a>n)throw r();i.push(u)};if(t.fetch){const u=await t.fetch(
|
|
43
|
+
e,{signal:o});if(!u.ok)throw new Te(`The image URL answered HTTP ${u.status}.`,u.status);if(Number(u.headers.get("content-length")??0)>n)throw await u.body?.cancel(),r();if(u.body){const f=u.body.getReader();
|
|
44
|
+
try{for(;;){const{done:b,value:y}=await f.read();if(b)break;l(y)}}catch(b){throw await f.cancel().catch(()=>{}),b}}else l(new Uint8Array(await u.arrayBuffer()))}else{let u=new URL(e);for(let f=0;;f+=1){
|
|
45
|
+
const b=await Or(u,t,o),y=b.statusCode??0,N=b.headers.location;if(y>=300&&y<400&&N){if(b.resume(),f>=Rr)throw new Te("Too many redirects.");u=new URL(N,u);continue}if(y<200||y>=300)throw b.resume(),new Te(
|
|
46
|
+
`The image URL answered HTTP ${y}.`,y);if(Number(b.headers["content-length"]??0)>n)throw b.destroy(),r();try{for await(const L of b)l(L)}catch(L){throw b.destroy(),L}break}}const c=new Uint8Array(a);let d=0;
|
|
47
|
+
for(const u of i)c.set(u,d),d+=u.length;return c}function gt(e,t,n){const o={url:e,message:t};return n!==void 0&&(o.status=n),{ok:!1,failure:o}}function Er(e={}){const t=e.maxBytes??Dr;return async function(n){
|
|
48
|
+
let o;try{o=await jr(n,e,t)}catch(i){return gt(n,i instanceof Te?i.message:`Could not download the image: ${i.message}`,i instanceof Te?i.status:void 0)}const r=Mr(o);return r?!r.width||!r.height?gt(n,
|
|
49
|
+
"The image's pixel size could not be read."):r.width*r.height>Nr?gt(n,"The image's pixel dimensions are implausibly large."):{ok:!0,image:{url:`data:${r.mime};base64,${Buffer.from(o).toString("base64")}`,
|
|
50
|
+
...r.width?{naturalWidth:r.width}:{},...r.height?{naturalHeight:r.height}:{}}}:gt(n,"The URL did not return a PNG, JPEG, GIF, or WebP image (an HTML page or SVG, perhaps). Use a direct link to a raste\
|
|
51
|
+
r image.")}}const Bt=new Set(["move_blocks","edit_table_cells","import_attachment_into_document","insert_block","insert_footnote","replace_block","set_block_attribute","style_blocks","clear_formatting",
|
|
52
|
+
"append_to_paragraph","break_paragraph","join_paragraphs","replace","replace_all","replace_many","rollback_agent_suggestions","leave_comment","remove_blocks","remove_block","set_title","set_notes","se\
|
|
53
|
+
t_page_layout","set_header_footer","insert_table_row","remove_table_rows","remove_table_row","insert_table_column","remove_table_column"]),Lr=new Set(["pending","in_progress","completed","blocked","ca\
|
|
54
|
+
ncelled"]);function Mn(e){return Array.isArray(e.work)&&e.work.length>0}const Bn="create_plan/update_plan have no work field; the calls listed in work were NOT executed. Emit them as ordinary tool cal\
|
|
55
|
+
ls.";function On(e){if(!Array.isArray(e)||e.some(t=>typeof t!="string"||!t.trim()))throw new Error("steps must be an array of non-empty strings.");return e.map(t=>t.trim())}function jn(e,t,n){if(t==="\
|
|
56
|
+
create_plan"){if(typeof n.objective!="string"||!n.objective.trim())throw new Error("objective is required.");const l=On(n.steps);if(!l.length)throw new Error("A plan requires at least one step.");if(e.
|
|
57
|
+
plan&&n.supersedes_plan_id!==e.plan.id)throw new Error(`To start a new task, explicitly set supersedes_plan_id to ${e.plan.id}. Use update_plan for steering the existing task.`);if(!e.plan&&n.supersedes_plan_id!=
|
|
58
|
+
null)throw new Error("There is no plan to supersede.");const c=`plan_${e.nextPlanNumber}`;return{nextPlanNumber:e.nextPlanNumber+1,plan:{id:c,objective:n.objective.trim(),items:l.map((d,u)=>({id:`${c}\
|
|
59
|
+
_item_${u+1}`,step:d,status:"pending"}))}}}const o=e.plan;if(!o||n.plan_id!==o.id)throw new Error(`Use the current plan_id: ${o?.id??"no plan; call create_plan first"}.`);const r=n.add_steps===void 0?
|
|
60
|
+
[]:On(n.add_steps),i=n.updates===void 0?[]:n.updates;if(!Array.isArray(i))throw new Error("updates must be an array.");const a=new Set;for(const l of i){if(!l||typeof l!="object"||!o.items.some(c=>c.id===
|
|
61
|
+
l.item_id)||!Lr.has(l.status)||Object.keys(l).some(c=>!["item_id","status"].includes(c))||a.has(l.item_id))throw new Error("Each update requires a unique existing item_id and valid status. Step text i\
|
|
62
|
+
s immutable; add a new item and cancel the old item to change a requirement.");a.add(l.item_id)}if(!i.length&&!r.length)throw new Error(Mn(n)?`Provide updates or add_steps. ${Bn}`:"Provide updates or \
|
|
63
|
+
add_steps.");return{nextPlanNumber:e.nextPlanNumber,plan:{...o,items:[...o.items.map(l=>({...l,status:i.find(c=>c.item_id===l.id)?.status??l.status})),...r.map((l,c)=>({id:`${o.id}_item_${o.items.length+
|
|
64
|
+
c+1}`,step:l,status:"pending"}))]}}}const En=50,Ur=32*1024;function Fr(e,t){const n=[];if(Ue(e.cell,c=>n.push(c.id)),n.length)return{id:e.cell.id,column:e.col,kind:"rich",truncated:!0,block_ids:e.cell.
|
|
65
|
+
children.map(c=>c.id),text:`Contains nested tables. Read them with read_table: ${n.slice(0,20).join(", ")}. Read other nested blocks separately. This preview does not authorize replacement.`};const o=Ft(
|
|
66
|
+
e.cell),r=et(e.cell);let i={id:e.cell.id,column:e.col,kind:r?"empty":o?"text":"rich",row_span:e.rowSpan,col_span:e.colSpan,block_ids:ue(e.cell)};const a=(o?.children.find(c=>c.text)??o?.children[0])?.
|
|
67
|
+
marks,l=a?ft(a):void 0;return i.formatting={cell:ft(e.cell),...o?{paragraph:ft(o),text_marks:l&&Object.keys(l).length?l:void 0}:{}},o||r?i.text=zt(e.cell):i.html=t?.(e.cell)??"Rich content; read neste\
|
|
68
|
+
d blocks before editing.",JSON.stringify(i).length>2e4&&(i={id:e.cell.id,column:e.col,kind:i.kind,truncated:!0,text:"Content omitted: use cell_text with this cell_id, or read a nested block with read_\
|
|
69
|
+
specific_blocks and edit that block ID. This preview does not authorize replacement."}),i}const zr=/^(oxml|docx)/;function ft(e){return Object.fromEntries(Object.entries(e).filter(([t])=>!["type","id",
|
|
70
|
+
"children"].includes(t)&&!zr.test(t)))}const Jr=new Set(["bold","italic","underline","strikethrough","doubleStrikethrough","smallCaps","allCaps","hidden","letterSpacing","lang","code","superscript","s\
|
|
71
|
+
ubscript","fontSize","color","backgroundColor","fontFamily"]),Wr=e=>JSON.stringify(Object.fromEntries(Object.entries(e).sort(([t],[n])=>t.localeCompare(n))));function ue(e){if(!e||typeof e!="object")return[];
|
|
72
|
+
const t=e;return[...t.id?[t.id]:[],...Ot(e).flatMap(ue)]}function Ot(e){const t=e;return[t.children,t.notes,t.chrome].flatMap(n=>Array.isArray(n)?n:[])}const Ze=24e3,Hr=2e3;function Gr(e,t,n,o,r){const i=n.
|
|
73
|
+
map(u=>e.children[u].id),a=i.reduce((u,f)=>f.length>u.length?f:u,""),l=u=>({table_id:e.id,...u,column_start:t.cols,column_count:t.cols,continuation_revision:r}),c=l(o===null?{row_ids:i}:{row_start:t.rows,
|
|
74
|
+
row_count:o}),d=u=>JSON.stringify(u).length-1;return Math.max(d({next_row:t.rows,next_read:c}),d({next_row:t.rows,next_column:t.cols,next_read:l({row_ids:[a]}),following_read:c,remaining_row_ids:i}))}
|
|
75
|
+
function jt(e){return ke([e.columnWidths,e.children.map(t=>[t.id,t.children.map(n=>[n.id,n.rowSpan,n.colSpan])])])}function Et(e,t,n){const o=Ne(e,String(t.table_id??"")),r={table_id:String(t.table_id??
|
|
76
|
+
""),row_count:0,column_count:0,revision:"",columns:[],unplaced_cell_ids:[],rows:[],complete_cell_ids:[]};if(!o)return{...r,error:"Unknown table_id."};const i=Ce(o);r.row_count=i.rows,r.column_count=i.
|
|
77
|
+
cols,r.revision=jt(o),r.columns=Array.from({length:i.cols},(D,A)=>({column:A,empty:0,filled:0,covered:0}));for(let D=0;D<i.rows;D++)for(let A=0;A<i.cols;A++){const M=i.occupancy[D][A];M&&(M.row!==D||M.
|
|
78
|
+
col!==A?r.columns[A].covered++:et(M.cell)?r.columns[A].empty++:r.columns[A].filled++)}const a=o.children.flatMap(D=>D.children.filter(A=>!i.byId.has(A.id)).map(A=>A.id));r.unplaced_cell_count=a.length;
|
|
79
|
+
let l=2;for(const D of a){if(r.unplaced_cell_ids.length>=100)break;const A=JSON.stringify(D).length+(r.unplaced_cell_ids.length?1:0);l+A>Hr||(r.unplaced_cell_ids.push(D),l+=A)}const c=Number.isInteger(
|
|
80
|
+
t.column_start)&&Number(t.column_start)>=0?Number(t.column_start):0;r.columns=r.columns.slice(c,c+100),c+100<i.cols&&(r.next_summary={table_id:o.id,mode:"summary",column_start:c+100});const d=t.mode??
|
|
81
|
+
"rows";if(d==="summary")return r;if(d==="cell_text"){const D=i.byId.get(String(t.cell_id??""));if(!D)return{...r,error:"Unknown cell_id."};const A=ke(D.cell);if(t.continuation_revision!=null&&t.continuation_revision!==
|
|
82
|
+
A)return{...r,error:"Cell changed since the previous window; restart at text_offset=0."};const M=t.text_offset??0,I=Zr(D.cell);if("error"in I)return{...r,error:I.error};const C=I.text,q=(h,$)=>I.segments.
|
|
83
|
+
filter((we,pe)=>{const lt=I.segments[pe+1]?.start??C.length+1;return we.start<$&<>h}).map(we=>({id:we.id,text_offset:we.start}));if(!Number.isInteger(M)||Number(M)<0||Number(M)>C.length)return{...r,
|
|
84
|
+
error:"Invalid text_offset."};if(Number(M)>0&&/[\uDC00-\uDFFF]/u.test(C.charAt(Number(M))))return{...r,error:"text_offset splits a Unicode character."};const J=Ze-JSON.stringify({...r,revision:A,cell_id:D.
|
|
85
|
+
cell.id,text:"",text_offset:Number(M),next_text_offset:C.length,blocks:q(Number(M),Math.min(C.length,Number(M)+8e3))}).length,z=Math.min(C.length,Number(M)+8e3);let j=Number(M),oe=0;for(;j<z;){const h=/[\uD800-\uDBFF]/.
|
|
86
|
+
test(C.charAt(j))&&/[\uDC00-\uDFFF]/.test(C.charAt(j+1))?2:1;if(j+h>z)break;const $=JSON.stringify(C.slice(j,j+h)).length-2;if(oe+$>J)break;oe+=$,j+=h}return j===Number(M)&&j<C.length?{...r,error:"Thi\
|
|
87
|
+
s cell's text cannot fit beside the table summary within 24,000 characters."}:{...r,revision:A,cell_id:D.cell.id,text:C.slice(Number(M),j),text_offset:Number(M),...j<C.length?{next_text_offset:j}:{},blocks:q(
|
|
88
|
+
Number(M),Math.max(j,Number(M)+1))}}if(d!=="rows")return{...r,error:"mode must be summary, rows, or cell_text."};if(t.continuation_revision!=null&&t.continuation_revision!==r.revision)return{...r,error:"\
|
|
89
|
+
Table geometry changed since the previous window; reread the summary and resume using stable row_ids."};const u=t.row_start??0,f=t.row_count??25,b=t.column_start??0,y=t.column_count??i.cols;if(![u,f,b,
|
|
90
|
+
y].every(D=>Number.isInteger(D))||Number(u)<0||Number(f)<1||Number(f)>50||Number(b)<0||Number(y)<1)return{...r,error:"Invalid row or column window (maximum 50 rows)."};let N;if(t.row_ids!=null){if(!Array.
|
|
91
|
+
isArray(t.row_ids)||!t.row_ids.length||t.row_ids.length>50||new Set(t.row_ids).size!==t.row_ids.length)return{...r,error:"row_ids requires 1-50 unique row IDs."};if(N=t.row_ids.map(D=>o.children.findIndex(
|
|
92
|
+
A=>A.id===D)),N.some(D=>D<0))return{...r,error:"Unknown row_id; nothing read."}}else N=Array.from({length:Math.max(0,Math.min(Number(f),i.rows-Number(u)))},(D,A)=>Number(u)+A);if(Number(b)>=i.cols)return{
|
|
93
|
+
...r,error:`column_start is beyond the table's ${i.cols} columns.`};let L=JSON.stringify(r).length;const O=Gr(o,i,N,t.row_ids==null?Number(f):null,r.revision);for(const D of N){const A={row_id:o.children[D].
|
|
94
|
+
id,row_index:D,cells:[]},M=JSON.stringify({...A,cells:[]}).length+(r.rows.length?1:0);for(let I=Number(b);I<Math.min(i.cols,Number(b)+Number(y));I++){const C=i.occupancy[D][I];let q;C?C.row!==D||C.col!==
|
|
95
|
+
I?q={id:"",column:I,kind:"covered",anchor_id:C.cell.id}:q=Fr(C,n):q={id:"",column:I,kind:"unplaced"};const J=!!C&&C.row===D&&C.col===I&&!q.truncated&&!!(Ft(C.cell)||et(C.cell)||n),z=(oe,h)=>(A.cells.length?
|
|
96
|
+
1:M)+JSON.stringify(oe).length+(h?JSON.stringify(oe.id).length+(r.complete_cell_ids.length?1:0):0);let j=z(q,J);if(L+j+O>Ze&&!r.rows.length&&!A.cells.length){if(q={id:q.id,column:I,kind:q.kind,truncated:!0,
|
|
97
|
+
text:"Content omitted: this cell does not fit in a row window. Page its text with mode=cell_text and this cell_id, or read a nested block with read_specific_blocks and edit that block ID. This preview\
|
|
98
|
+
does not authorize replacement."},j=z(q,!1),L+j+O>Ze)return{...r,error:"This table window cannot fit even one cell preview within 24,000 characters. Read fewer columns with column_start and column_co\
|
|
99
|
+
unt, request fewer row_ids, or page one cell with mode=cell_text."};A.cells.push(q),L+=j;continue}if(L+j+O>Ze){if(r.rows.length){const h=new Set(A.cells.map($=>$.id));return r.complete_cell_ids=r.complete_cell_ids.
|
|
100
|
+
filter($=>!h.has($)),r.next_row=D,r.next_read={table_id:o.id,...t.row_ids==null?{row_start:D,row_count:Number(f)}:{row_ids:N.slice(N.indexOf(D)).map($=>o.children[$].id)},column_start:Number(b),column_count:Number(
|
|
101
|
+
y),continuation_revision:r.revision},r}A.cells.length&&r.rows.push(A),r.next_row=D,r.next_column=I,r.next_read={table_id:o.id,row_ids:[o.children[D].id],column_start:I,column_count:Math.min(i.cols,Number(
|
|
102
|
+
b)+Number(y))-I,continuation_revision:r.revision};const oe=N.slice(N.indexOf(D)+1).map(h=>o.children[h].id);return t.row_ids==null&&D+1<i.rows?r.following_read={table_id:o.id,row_start:D+1,row_count:Number(
|
|
103
|
+
f),column_start:Number(b),column_count:Number(y),continuation_revision:r.revision}:oe.length&&(r.following_read={table_id:o.id,row_ids:oe,column_start:Number(b),column_count:Number(y),continuation_revision:r.
|
|
104
|
+
revision}),r.remaining_row_ids=oe,r}A.cells.push(q),L+=j,J&&r.complete_cell_ids.push(C.cell.id)}r.rows.push(A)}const T=N.at(-1);return t.row_ids==null&&T!==void 0&&T+1<i.rows&&(r.next_row=T+1,r.next_read=
|
|
105
|
+
{table_id:o.id,row_start:T+1,row_count:Number(f),column_start:Number(b),column_count:Number(y),continuation_revision:r.revision}),r}function Ye(e,t,n){if(!t?.scopedTableIds?.length)return n;const o=new Set(
|
|
106
|
+
n);for(const r of t.scopedTableIds){const i=Ne(e,r);if(!i)continue;for(const d of ue(i))o.delete(d);const a=d=>{const u=d,f=u.id===r||Ot(d).map(a).some(Boolean);return f&&u.id&&o.delete(u.id),f};a(e);
|
|
107
|
+
const l=Ce(i);let c=!0;for(const d of l.cells){const u=t.cells[bt(r,i.children[d.row].id,d.col)];if(!u||!Vr(i,l,d,u)){c=!1;continue}for(const f of u.blockIds)o.add(f)}if(c&&l.cells.length===i.children.
|
|
108
|
+
reduce((d,u)=>d+u.children.length,0)){o.add(i.id);for(const d of i.children)o.add(d.id)}}for(const[r,i]of Object.entries(t.blocks??{})){const a=re(e,r),l=Ne(e,i.tableId);if(a?.id===r&&l&&ue(l).includes(
|
|
109
|
+
r)&&ke(a)===i.content)for(const c of i.blockIds)o.add(c)}return o}function Ln(e,t,n,o){const r=re(e,o);!r||r.id!==o||(t.blocks??(t.blocks={}),t.blocks[o]={tableId:n,content:ke(r),blockIds:ue(r)})}function Kr(e,t,n,o){
|
|
110
|
+
const r=Ne(e,String(o.tableId??""));if(!r)return!1;const i=jt(r),a=t.geometries?.[r.id]===i;if(n==="insert_table_row"||n==="insert_table_column")return a;let l,c=!1;if(n==="remove_table_row"){const b=_n(
|
|
111
|
+
r,o);if("error"in b)return!1;l=b.rowIndices,c=b.byId}if(!c&&!a)return!1;const d=o.columnIndex;if(!l&&(!Number.isInteger(d)||Number(d)<0))return!1;const u=Ce(r).cells.filter(b=>l?l.some(y=>b.row<=y&&b.
|
|
112
|
+
row+b.rowSpan>y):b.col<=Number(d)&&b.col+b.colSpan>Number(d)),f=Ye(e,t,new Set);return u.length>0&&u.every(b=>f.has(b.cell.id)&&(c||!l||t.cells[bt(r.id,r.children[b.row].id,b.col)]?.revision===i))}function Un(){
|
|
113
|
+
return{cells:{}}}function Ne(e,t){const n=re(e,t);return n?.type==="table"&&n.id===t?n:null}function Ue(e,t){if(!e||typeof e!="object")return;const n=e;n.type==="table"&&t(n);for(const o of Ot(e))Ue(o,
|
|
114
|
+
t)}const bt=(e,t,n)=>JSON.stringify([e,t,n]),Lt=(e,t)=>ke([t,e.columnWidths]),Ut=(e,t)=>JSON.stringify(e.children.slice(t.row,t.row+t.rowSpan).map(n=>n.id));function Vr(e,t,n,o){return o.cellId===n.cell.
|
|
115
|
+
id&&o.rowId===e.children[n.row].id&&o.column===n.col&&o.content===ke(n.cell)&&o.coveredRows===Ut(e,n)&&o.geometry===Lt(e,t.cols)&&o.rowSpan===n.rowSpan&&o.colSpan===n.colSpan}function _t(e,t,n,o){const r=Ne(
|
|
116
|
+
e,n);if(!r)return;const i=Ce(r),a=o?new Set(o):null,l=Lt(r,i.cols),c=jt(r);for(const d of i.cells){if(a&&!a.has(d.cell.id))continue;const u=r.children[d.row].id;t.cells[bt(n,u,d.col)]={tableId:n,rowId:u,
|
|
117
|
+
column:d.col,cellId:d.cell.id,rowSpan:d.rowSpan,colSpan:d.colSpan,geometry:l,coveredRows:Ut(r,d),content:ke(d.cell),blockIds:ue(d.cell),revision:c}}}function Ft(e){if(e.children.length!==1)return null;
|
|
118
|
+
const t=e.children[0];if(t.type!=="paragraph"||!t.children.every(o=>o.type==="text"))return null;let n;for(const o of t.children){const r=ft(o.marks??{});if(Object.keys(r).some(a=>!Jr.has(a)))return null;
|
|
119
|
+
if(!o.text)continue;const i=Wr(r);if(n!==void 0&&i!==n)return null;n=i}return t}const Xr=Ze,Qr=e=>`[[${e}]] `;function Zr(e){const t=[];for(const d of e.children)Ue(d,u=>t.push(u.id));if(t.length)return{
|
|
120
|
+
error:`Cell contains nested tables (${t.slice(0,20).join(", ")}). Read them with read_table(table_id=...) and read the cell's other blocks with read_specific_blocks; cell_text does not flatten nested \
|
|
121
|
+
tables.`};const n=[],o=[],r=(d,u)=>{n.push(d),o.push(u??"")},i=d=>d.map(u=>u.type==="text"?u.text??"":"").join(""),a=d=>{if(d.type==="paragraph"){r(i(d.children),d.id);return}if(d.type==="list"){const f=[];
|
|
122
|
+
for(const b of d.children){const y=Math.max(0,b.indentLevel??0);f.length=y+1;const N=y===0?d.startNumber??1:1;f[y]=f[y]===void 0?N:f[y]+1;const L=d.variant==="ordered"?`${f[y]}. `:d.variant==="todo"?b.
|
|
123
|
+
checked?"[x] ":"[ ] ":"• ";r(`${" ".repeat(y)}${L}${i(b.children)}`,b.id??d.id)}return}const u=d;if(typeof u.content=="string"){r(u.content,u.id);return}if(Array.isArray(u.children)&&u.children.length){
|
|
124
|
+
for(const f of u.children)a(f);return}r(`[${u.type}${u.id?` ${u.id}`:""}]`,u.id)};for(const d of e.children)a(d);const l=[];let c=0;return{text:n.map((d,u)=>{const f=o[u],b=!!f&&l.at(-1)?.id!==f;b&&l.
|
|
125
|
+
push({id:f,start:c});const y=b?`${Qr(f)}${d}`:d;return c+=y.length+1,y}).join(`
|
|
126
|
+
`),segments:l}}function zt(e){return e.children.map(t=>t.type==="paragraph"?t.children.map(n=>n.type==="text"?n.text:"").join(""):"").join(`
|
|
127
|
+
`)}function et(e){return e.children.every(t=>t.type==="paragraph"&&t.children.every(n=>n.type==="text"&&!n.text.replace(/[\s\u200b\u200c\u200d\ufeff]/gu,"")))}const Fn=e=>`<span>${e.replaceAll("&","&a\
|
|
128
|
+
mp;").replaceAll("<","<").replaceAll(">",">").replaceAll(`
|
|
129
|
+
`,"<br>").replaceAll(" ","	")}</span>`;function zn(e,t,n,o={}){const r={actions:[],targets:[],errors:[],skipped:[],unchanged:[]},i=n,a=b=>(r.errors.push({row_id:"",column:-1,reason:b}),r);if(!i||typeof i.
|
|
130
|
+
table_id!="string")return a("table_id is required.");if(i.mode!=="fill_if_empty"&&i.mode!=="replace")return a("mode must be fill_if_empty or replace.");if(!Array.isArray(i.cells)||!i.cells.length||i.cells.
|
|
131
|
+
length>En)return a(`Provide 1-${En} cells.`);if(new TextEncoder().encode(JSON.stringify(i)).length>Ur)return a("Cell-edit arguments exceed 32KiB; split the batch.");const l=Ne(e,i.table_id);if(!l)return a(
|
|
132
|
+
"Unknown table_id; read the current table first.");const c=Ce(l),d=Lt(l,c.cols),u=new Set,f=new Map;for(const b of ue(e))f.set(b,(f.get(b)??0)+1);for(const b of i.cells){const y=b,N=typeof y?.row_id==
|
|
133
|
+
"string"?y.row_id:"",L=typeof y?.column=="number"?y.column:-1,O=q=>({row_id:N,column:L,reason:q});if(!N||!Number.isInteger(L)||L<0||typeof y?.text!="string"){r.errors.push(O("Each item requires row_id\
|
|
134
|
+
, a zero-based integer column, and exact text."));continue}const T=bt(l.id,N,L);if(u.has(T)){r.errors.push(O("Duplicate target in batch."));continue}u.add(T);const D=l.children.findIndex(q=>q.id===N),
|
|
135
|
+
A=c.occupancy[D]?.[L];if(!A||A.row!==D||A.col!==L){r.errors.push(O("Unknown row/column or covered merge position; target the anchor cell."));continue}const M=t.cells[T];if(!M&&zt(A.cell).length>Xr){r.
|
|
136
|
+
errors.push(O(`Cell ${A.cell.id} is too large for any table read to deliver, so edit_table_cells cannot target it. To change a passage inside it, find the nested block with read_table mode=cell_text, \
|
|
137
|
+
read that block with read_specific_blocks, then edit the block ID with replace.`));continue}if(!M){r.errors.push(O("Cell was not delivered in this request. Read it before editing."));continue}if(ue(A.
|
|
138
|
+
cell).some(q=>f.get(q)!==1)||f.get(N)!==1){r.errors.push(O("Duplicate document identity makes this target ambiguous; repair the malformed table before editing."));continue}if(M.cellId!==A.cell.id||M.rowSpan!==
|
|
139
|
+
A.rowSpan||M.colSpan!==A.colSpan||M.coveredRows!==Ut(l,A)||M.geometry!==d){r.errors.push(O("Table geometry or anchor identity changed since delivery; reread."));continue}if(o.responseTurn!==void 0&&t.
|
|
140
|
+
responseClaims?.turn===o.responseTurn&&t.responseClaims.cellIds.includes(A.cell.id)){r.errors.push(O("Another call in this response already edited this cell; inspect the result before editing again."));
|
|
141
|
+
continue}if(o.hasForeignSuggestion?.(A.cell)){(i.mode==="fill_if_empty"?r.skipped:r.errors).push(O("Cell has a conflicting pending suggestion from another author; preserved."));continue}if(i.mode==="f\
|
|
142
|
+
ill_if_empty"&&!et(A.cell)){r.skipped.push(O("Cell is non-empty; preserved."));continue}if(M.content!==ke(A.cell)){r.errors.push(O("Cell changed after delivery; reread before replacing."));continue}const I=Ft(
|
|
143
|
+
A.cell);if(!I){r.errors.push(O("Cell contains rich or multi-block content. Use its nested block IDs with the existing rich editing tools."));continue}const C=zt(A.cell);if(C===y.text){r.unchanged.push(
|
|
144
|
+
O("Already equal."));continue}r.actions.push({name:"replace",arguments:{id:I.id,find:C?Fn(C):"",replace:Fn(y.text)}}),r.targets.push({row_id:N,column:L,cellId:A.cell.id,paragraphId:I.id})}return r.errors.
|
|
145
|
+
length&&(r.actions=[],r.targets=[]),r}function Yr(e){const t=[/"([^"\n]{2,300})"/g,/“([^”\n]{2,300})”/g,/‘([^’\n]{2,300})’/g,/(?<![\p{L}\p{N}])'([^'\n]{2,300})'(?![\p{L}\p{N}])/gu],n=new Set;
|
|
146
|
+
for(const o of t)for(const r of e.matchAll(o)){const i=r[1].trim();i&&n.add(i)}return[...n]}function ei(e,t,n){const o=qt(e,t);if(o.length!==1)return null;const[r]=o,i=fn(t).text.trim();if(i.length<3)
|
|
147
|
+
return null;const a=Le(e),l=Yr(n).filter(d=>{const u=fn(d).text.trim();return u.length>i.length&&(u.startsWith(i)||u.endsWith(i))}),c=new Set;for(const d of l){const u=qt(e,d);if(u.length!==1)continue;
|
|
148
|
+
const[f]=u;f.start<=r.start&&f.end>=r.end&&c.add(a.slice(f.start,f.end))}return c.size===1?[...c][0]:null}const ti="outside_user_selection",ni=new Set(["replace","replace_all","replace_block","remove_\
|
|
149
|
+
block","style_blocks","clear_formatting","edit_table_cells"]);function Jn(e){const t=[],n=(o,r)=>{const i=o,a=typeof i.id=="string"?i.id:null;if(a&&t.push({id:a,ancestors:r}),Array.isArray(i.children))
|
|
150
|
+
for(const l of i.children)n(l,a?[...r,a]:r)};for(const o of e.children)n(o,[]);return t}function oi(e,t){const n=Jn(e),o=new Map(n.map((a,l)=>[a.id,l])),r=new Set,i=new Set;for(const a of t){const l=o.
|
|
151
|
+
get(a.startBlock),c=o.get(a.endBlock);if(l===void 0||c===void 0)return null;const[d,u]=l<=c?[l,c]:[c,l];for(let b=d;b<=u;b++)r.add(n[b].id);const f=n[u].id;for(let b=u+1;b<n.length&&n[b].ancestors.includes(
|
|
152
|
+
f);b++)r.add(n[b].id);for(const b of[n[d].id,f])for(const y of n[o.get(b)].ancestors)i.add(y)}return{selected:r,containers:i}}function ri(e,t){let n=null;const o=r=>{if(n)return;const i=r;if(i.type===
|
|
153
|
+
"table"&&i.id===t){n=r;return}i.children?.forEach(o)};return e.children.forEach(o),n}function ii(e,t,n){if(!ni.has(t)||!n)return[];const o=new Set,r=i=>{typeof i=="string"&&i.trim()&&o.add(i.trim())};
|
|
154
|
+
if(t==="edit_table_cells"){const i=typeof n.table_id=="string"?ri(e,n.table_id):null;if(!i||!Array.isArray(n.cells))return[];const a=Ce(i);for(const l of n.cells){const c=l,d=i.children.findIndex(f=>f.
|
|
155
|
+
id===c?.row_id),u=typeof c?.column=="number"?c.column:-1;r(a.occupancy[d]?.[u]?.cell.id)}return[...o]}r(n.id);for(const i of["id","ids","block_ids"])Array.isArray(n[i])&&n[i].forEach(r);if(Array.isArray(
|
|
156
|
+
n.replacements))for(const i of n.replacements)r(i?.id);if(Array.isArray(n.selectors)){for(const i of n.selectors)if(typeof i=="string"){const a=/^#([A-Za-z0-9_-]+)$/.exec(i.trim());a&&r(a[1])}}return[
|
|
157
|
+
...o]}function si(e,t,n){if(!n.length||!t.length)return[];const o=oi(e,t);if(!o)return[];const r=Jn(e),i=new Map(r.map(c=>[c.id,c])),a=new Map,l=c=>{const d=c;typeof d.id=="string"&&a.set(d.id,c),d.children?.
|
|
158
|
+
forEach(l)};return e.children.forEach(l),n.filter(c=>{if(!i.get(c)||o.selected.has(c)||o.containers.has(c)||r.some(u=>u.ancestors.includes(c)&&o.selected.has(u.id)))return!1;const d=a.get(c);return(d?.
|
|
159
|
+
structuralSuggestionKind??d?.diffState)!=="insert"})}function ai(e){const t=e.map(n=>n.selectedText.replace(/\s+/g," ").trim()).join(" … ");return t.length>160?`${t.slice(0,157)}...`:t}const li="emp\
|
|
160
|
+
ty_mutation_arguments",yt="To change colors, borders, shading, fonts, alignment or other formatting, use style_blocks",Wn="to delete blocks, use remove_blocks",Jt="to add a table column use insert_tab\
|
|
161
|
+
le_column, and to add rows insert_table_row",Hn="to swap or reorder blocks or images, use move_blocks";function ci(e){return typeof e=="string"?e.trim().length===0:e==null}function Wt(e){return e==null?
|
|
162
|
+
!0:typeof e=="string"?e.trim().length===0:Array.isArray(e)?e.length===0||e.every(ci):!1}function Gn(e){return typeof e=="string"&&e.trim().length>0}function ve(e,t,n){return`${e} was called with an em\
|
|
163
|
+
pty ${t}, so nothing was changed. ${n}`}function di(e,t){const n=t&&typeof t=="object"?t:{};switch(e){case"replace_block":return Wt(n.content)?ve("replace_block","content array",`It never removes or r\
|
|
164
|
+
estyles a block. ${yt}; ${Wn}; ${Jt}; ${Hn}. Otherwise call replace_block again with the complete replacement HTML.`):null;case"insert_block":return Wt(n.content)?ve("insert_block","content array",`Pa\
|
|
165
|
+
ss the HTML of each block to insert. ${yt}; ${Jt}.`):null;case"replace":case"replace_many":{const o=n.replacements;return Array.isArray(o)&&o.length===0?ve(e,"replacements array",`Each replacement nee\
|
|
166
|
+
ds find and replace text. ${yt}; ${Hn}; ${Wn}.`):null}case"edit_table_cells":return Array.isArray(n.cells)&&n.cells.length===0?ve("edit_table_cells","cells array",`List each cell to write as {row_id, \
|
|
167
|
+
column, text}; it only edits existing cells. ${Jt} (content holds one cell per row or column); to delete rows use remove_table_rows; ${yt}.`):null;case"remove_block":case"remove_blocks":return Array.isArray(
|
|
168
|
+
n.ids)&&n.ids.length===0&&!Gn(n.id)&&!Gn(n.search_result_id)?ve("remove_blocks","ids array","List the exact IDs of the blocks to delete. To delete table rows, use remove_table_rows."):null;case"remove\
|
|
169
|
+
_table_row":case"remove_table_rows":{const o=n.rowIds,r=n.rowIndices,i=o==null||Wt(o),a=r==null||Array.isArray(r)&&r.length===0,l=typeof n.rowIndex=="number";return i&&a&&!l?ve("remove_table_rows","ro\
|
|
170
|
+
wIds list","List the row IDs (<tr id> / row_id) of the rows to remove. To clear cell text instead, use edit_table_cells."):null}case"move_blocks":return Array.isArray(n.block_ids)&&n.block_ids.length===
|
|
171
|
+
0?ve("move_blocks","block_ids array","List the source block IDs in current document order, plus reference_id and position."):null;case"style_blocks":return Array.isArray(n.attrs)&&n.attrs.length===0?ve(
|
|
172
|
+
"style_blocks","attrs array",'List each formatting change as {name, value}, e.g. {name: "color", value: "#c00000"}.'):Array.isArray(n.selectors)&&n.selectors.length===0?ve("style_blocks","selectors li\
|
|
173
|
+
st","Name what to style, e.g. #blockId, #tableId td p, or p."):null;default:return null}}const Kn=50,Vn=200,Xn=5e3,ui=5e3,mi=8,hi=200,Qn=32*1024;function Zn(){return{version:1,nextTaskNumber:1,task:null}}
|
|
174
|
+
const pi=new TextEncoder;function tt(e){return pi.encode(e).length}function Yn(e,t,n="…"){if(tt(e)<=t)return e;const o=Math.max(0,t-tt(n));let r=0,i="";for(const a of e){const l=tt(a);if(r+l>o)break;
|
|
175
|
+
r+=l,i+=a}return i+n}function gi(e,t){const n=e.replace(/[\u0000-\u001f\u007f]+/gu," ").replace(/\s+/gu," ").trim();return Yn(n,t)}const wt=e=>typeof e=="number"&&Number.isInteger(e)&&e>=0,fi=e=>wt(e)&&
|
|
176
|
+
e>0,kt=e=>typeof e=="string";function bi(e,t,n){const o=tt(t),r=o>Qn;return{requestId:e,text:r?Yn(t,Qn,""):t,originalBytes:o,truncated:r,...typeof n=="number"&&Number.isFinite(n)?{timestamp:n}:{}}}function _i(e){
|
|
177
|
+
for(let t=e.length-1;t>=0;t--){const n=e[t];if(n.role!=="user")continue;const o=It(n);if(o.trim())return`${n.requestId??"?"}|${n.timestamp??""}|${ke(o)}`}}function eo(e,t,n){const o=e??{};if(!(t in o)&&
|
|
178
|
+
Object.keys(o).length>=mi)return o;const r=new Set(o[t]??[]);for(const l of n)r.delete(l),r.add(l);const i=Object.entries(o).filter(([l])=>l!==t).reduce((l,[,c])=>l+c.length,0),a=Math.max(0,ui-i);return{
|
|
179
|
+
...o,[t]:a?[...r].slice(-a):[]}}const yi=["task_kind","scope_row_start","scope_row_count","scope_columns","source_attachment_id"];function vt(e){return e==null?!1:typeof e=="string"?e.trim().length>0:
|
|
180
|
+
Array.isArray(e)?e.length>0:!0}function It(e){return typeof e.content=="string"?e.content:""}function wi(e,t){const n=e.find(o=>o.role==="user"&&o.requestId===t&&It(o).trim());if(n)return n;for(let o=e.
|
|
181
|
+
length-1;o>=0;o--){const r=e[o];if(r.role==="user"&&It(r).trim())return r}}function ki(e,t,n,o,r,i,a){const l={cells:0,rows:[],columns:[]};if(!e||e.requestId!==i||e.userMarker!==void 0&&e.userMarker!==
|
|
182
|
+
a)return l;const c=(e.guardedCellIds??e.cellIds)?.[t.id]??[],d=new Set,u=new Set;let f=0;for(const b of c){const y=n.byId.get(b);if(!y||et(y.cell))continue;let N=!1;for(let L=y.row;L<y.row+y.rowSpan&&
|
|
183
|
+
!N;L++)if(o.has(t.children[L]?.id??""))for(let O=y.col;O<y.col+y.colSpan;O++)r.has(O)&&(N=!0);N||(f++,d.add(y.row),u.add(y.col))}return{cells:f,rows:[...d].sort((b,y)=>b-y),columns:[...u].sort((b,y)=>b-
|
|
184
|
+
y)}}function vi(e,t,n,o){const r=yi.some(f=>vt(n[f])),i=n.deliberate_blanks,a=vt(i);if(!r&&!a)return{state:e,declared:!1};const l=kt(n.table_id)?n.table_id:"",c=Ne(t,l);if(!c)return{error:"Unknown tab\
|
|
185
|
+
le_id; no task scope was recorded."};const d=Ce(c);let u;if(r){const f=n.task_kind;if(f!=="fill"&&f!=="transform")return{error:"Declaring a table task requires task_kind (fill or transform) together w\
|
|
186
|
+
ith scope_row_start, scope_row_count and scope_columns; no scope was recorded."};const b=n.scope_row_start,y=n.scope_row_count,N=n.scope_columns;if(!wt(b)||!fi(y)||!Array.isArray(N)||!N.length)return{
|
|
187
|
+
error:"A table task scope requires integer scope_row_start, scope_row_count >= 1 and a non-empty scope_columns array; no scope was recorded."};if(b+y>d.rows)return{error:`Task scope rows ${b}-${b+y-1}\
|
|
188
|
+
exceed the table's ${d.rows} rows; no scope was recorded.`};if(y>Xn)return{error:`A table task scope may cover at most ${Xn} rows; declare the scope in parts.`};if(!N.every(wt)||new Set(N).size!==N.length||
|
|
189
|
+
N.some(j=>j>=d.cols))return{error:`scope_columns must be unique 0-based columns below ${d.cols}; no scope was recorded.`};let L;if(vt(n.source_attachment_id)){if(!kt(n.source_attachment_id)||!n.source_attachment_id.
|
|
190
|
+
trim()||tt(n.source_attachment_id)>200)return{error:"source_attachment_id must be a non-empty attachment ID; no scope was recorded."};if(o.attachmentExists&&!o.attachmentExists(n.source_attachment_id))
|
|
191
|
+
return{error:`Attachment '${n.source_attachment_id}' is not available in this conversation; no scope was recorded.`};L=n.source_attachment_id}const O=c.children.slice(b,b+y).map(j=>j.id),T=e.task,D=T&&
|
|
192
|
+
T.tableId===c.id&&T.kind===f,A=wi(o.chatHistory,o.requestId),M=D?T.originRequest:bi(typeof A?.requestId=="number"?A.requestId:o.requestId,A?It(A):"",A?.timestamp),I=new Set(O),C=new Set(N),q=_i(o.chatHistory);
|
|
193
|
+
let J=q;if(D){const j=new Set(c.children.map(pe=>pe.id)),oe=T.rowIds.filter(pe=>j.has(pe)&&!I.has(pe)),h=T.columns.filter(pe=>!C.has(pe)),$=oe.length>0||h.length>0,we=!$&&O.length===T.rowIds.length&&N.
|
|
194
|
+
length===T.columns.length;if($&&T.scopeUserMarker!==void 0&&T.scopeUserMarker===q)return{error:`This declaration would drop ${[oe.length?`${oe.length} rows`:"",h.length?`columns ${h.join(",")}`:""].filter(
|
|
195
|
+
Boolean).join(" and ")} from the declared task scope without a newer user instruction. The task scope must cover the user's whole request: repeat the full scope (or omit the scope fields) and use row_\
|
|
196
|
+
start/row_count or row_ids for a smaller read window. The declared scope is unchanged.`};we&&(J=T.scopeUserMarker??q)}else{const j=ki(e.localEdits,c,d,I,C,o.requestId,q);if(j.cells)return{error:`This \
|
|
197
|
+
first task declaration omits ${j.cells} cell${j.cells===1?"":"s"} this request already edited in this table (row_index ${xi(j.rows,12)}; columns ${j.columns.join(",")}). The task scope must cover the \
|
|
198
|
+
user's whole request, including work already done: declare the full scope and use row_start/row_count or row_ids for a smaller read window. No scope was recorded.`}}const z=L??(D?T.sourceAttachmentId:
|
|
199
|
+
void 0);u={id:D?T.id:`table_task_${e.nextTaskNumber}`,tableId:c.id,kind:f,rowIds:O,declaredRowStart:b,columns:[...N].sort((j,oe)=>j-oe),...z?{sourceAttachmentId:z}:{},deliberateBlanks:D?T.deliberateBlanks.
|
|
200
|
+
filter(j=>I.has(j.rowId)&&C.has(j.column)):[],touchedCellIds:D?T.touchedCellIds:[],originRequest:M,...D&&T.latestSteering?{latestSteering:T.latestSteering}:{},declaredRequestId:o.requestId,lastActivityRequestId:o.
|
|
201
|
+
requestId,...J?{scopeUserMarker:J}:{}}}else{const f=e.task;if(!f||f.tableId!==c.id)return{error:"deliberate_blanks require a declared task for this table; include task_kind and scope_* first."};u={...f,
|
|
202
|
+
deliberateBlanks:[...f.deliberateBlanks],lastActivityRequestId:o.requestId}}if(a){if(!Array.isArray(i)||i.length>Kn)return{error:`deliberate_blanks must be an array of at most ${Kn} cells; no scope wa\
|
|
203
|
+
s recorded.`};const f=new Set(u.rowIds),b=new Set(u.columns),y=new Set,N=[];for(const O of i){const T=O,D=`${String(T?.row_id)}:${String(T?.column)}`;if(!T||!kt(T.row_id)||!wt(T.column)||!kt(T.reason)||
|
|
204
|
+
!T.reason.trim())return{error:`Each deliberate blank needs row_id, column and a non-empty reason (${D}); no scope was recorded.`};if(!f.has(T.row_id)||!b.has(T.column))return{error:`Deliberate blank ${D}\
|
|
205
|
+
is outside the declared task scope; no scope was recorded.`};const A=c.children.findIndex(I=>I.id===T.row_id),M=d.occupancy[A]?.[T.column];if(!M||M.row!==A||M.col!==T.column)return{error:`Deliberate \
|
|
206
|
+
blank ${D} is a covered merge position or unplaced cell; name the anchor cell.`};if(y.has(D))return{error:`Duplicate deliberate blank ${D}; no scope was recorded.`};y.add(D),N.push({rowId:T.row_id,column:T.
|
|
207
|
+
column,reason:gi(T.reason,hi)})}const L=new Map(u.deliberateBlanks.map(O=>[`${O.rowId}:${O.column}`,O]));for(const O of N)L.set(`${O.rowId}:${O.column}`,O);if(L.size>Vn)return{error:`A task may record\
|
|
208
|
+
at most ${Vn} deliberate blanks; no scope was recorded.`};u.deliberateBlanks=[...L.values()]}return{state:{version:1,nextTaskNumber:u.id!==e.task?.id?e.nextTaskNumber+1:e.nextTaskNumber,task:u,...e.localEdits?
|
|
209
|
+
{localEdits:e.localEdits}:{}},declared:!0}}function Ii(e,t){if(!t.cellIds.length)return e;const n=e.localEdits?.requestId===t.requestId?e.localEdits:{requestId:t.requestId,tables:{}},o={...n,tables:{...n.
|
|
210
|
+
tables,[t.tableId]:(n.tables[t.tableId]??0)+t.cellIds.length},cellIds:eo(n.cellIds,t.tableId,t.cellIds),...n.guardedCellIds?{guardedCellIds:eo(n.guardedCellIds,t.tableId,t.cellIds)}:{}},r=e.task;if(!r||
|
|
211
|
+
r.tableId!==t.tableId)return{...e,localEdits:o};const i=[...new Set([...r.touchedCellIds,...t.cellIds])].slice(-5e3);return{...e,localEdits:o,task:{...r,touchedCellIds:i,lastActivityRequestId:t.requestId}}}
|
|
212
|
+
function xi(e,t){if(!e.length)return"none";const n=[];let o=e[0],r=e[0];for(const i of e.slice(1)){if(i===r+1){r=i;continue}n.push(o===r?`${o}`:`${o}-${r}`),o=r=i}return n.push(o===r?`${o}`:`${o}-${r}`),
|
|
213
|
+
n.length<=t?n.join(","):`${n.slice(0,t).join(",")} +${n.length-t} more ranges`}const to=50,Si="out_of_context_edit";function $i(e){const{toolCall:t,docBefore:n,isTargetAllowed:o}=e;if(t.name!=="remove\
|
|
214
|
+
_block")return null;const r=t.arguments;if(!r||typeof r!="object")return null;const i=r.through_end;if(i==null||i===!1)return null;if(i!==!0)return{toolCall:t,targetBlockIds:[],error:"remove_blocks th\
|
|
215
|
+
rough_end must be true when provided."};const a=r.id,l=r.count,c=r.ids,d=r.search_result_id;if(typeof a!="string"||a.trim().length===0)return{toolCall:t,targetBlockIds:[],error:"remove_blocks through_\
|
|
216
|
+
end requires a non-empty top-level id."};if(l!=null||c!=null||d!=null)return{toolCall:t,targetBlockIds:[],error:"remove_blocks through_end is mutually exclusive with count, ids, and search_result_id."};
|
|
217
|
+
const u=a.trim(),f=Ae(n,u);if(f<0||n.children[f]?.id!==u)return{toolCall:t,targetBlockIds:[],error:`remove_blocks through_end target '${u}' must be a current top-level block.`};if(!o(u))return{toolCall:t,
|
|
218
|
+
targetBlockIds:[],error:`remove_blocks through_end start '${u}' is outside the request-level document context. Read or search for that boundary block first, then retry.`,errorCode:Si};const b=n.children.
|
|
219
|
+
slice(f).map(y=>y.id).filter(y=>typeof y=="string"&&y.length>0);return{toolCall:{...t,arguments:{id:u,count:b.length}},targetBlockIds:b}}function Ci(e,t,n){if(e.name!=="remove_block")return{actions:[e]};
|
|
220
|
+
const o=e.arguments;if(!o||typeof o!="object")return{actions:[],error:"remove_blocks requires object arguments"};const r=o.ids;if(r==null)return{actions:[e]};if(typeof o.id=="string")return{actions:[],
|
|
221
|
+
error:"remove_blocks accepts either id + count or ids, not both."};if(!Array.isArray(r)||r.length===0)return{actions:[],error:"remove_blocks ids must be a non-empty array"};if(r.length>to)return{actions:[],
|
|
222
|
+
error:`remove_blocks supports at most ${to} exact IDs per call`};const i=[],a=new Set;for(const c of r){if(typeof c!="string"||c.trim().length===0)return{actions:[],error:"remove_blocks ids must all b\
|
|
223
|
+
e non-empty strings"};const d=c.trim();if(!a.has(d)){if(!re(t,d))return{actions:[],error:`remove_blocks target '${d}' was not found`};if(!n(d))return{actions:[],error:`remove_blocks target '${d}' is o\
|
|
224
|
+
utside the request-level document context. Read or search for that block first, then retry the exact ID batch.`};a.add(d),i.push(d)}}const l=i.filter(c=>ht(t,c)).length;return l>0&&l<i.length?{actions:[],
|
|
225
|
+
error:"Remove footnotes/endnotes separately from main-document blocks. Pass only note IDs in this batch so each note and its references are removed together."}:{actions:i.map((c,d)=>({id:`${e.id||"rem\
|
|
226
|
+
ove_block"}-${d+1}`,name:"remove_block",arguments:{id:c,count:1}}))}}const Ai=new Set(["replace_block","remove_block"]);function Ti(e,t){const n=vn(e,t);if(!n)return null;if(n===e){for(const o of[e.children,
|
|
227
|
+
e.chrome??[],e.notes??[]])if(o.some(r=>r.id===t))return o;return null}return"children"in n?n.children:null}function qi(e){const{toolCall:t,docBefore:n}=e;if(!Ai.has(t.name))return null;const o=t.arguments;
|
|
228
|
+
if(!o||typeof o!="object"||o.end_id==null)return null;const r=t.name==="remove_block"?"remove_blocks":t.name,i=N=>({toolCall:t,error:N}),{id:a,end_id:l}=o;if(typeof l!="string"||!l.trim())return i(`${r}\
|
|
229
|
+
end_id must be a block ID.`);if(typeof a!="string"||!a.trim())return i(`${r} end_id requires id, the first block of the range.`);for(const N of["ids","search_result_id","through_end"])if(o[N]!=null&&
|
|
230
|
+
o[N]!==!1)return i(`${r} end_id names a range from id; it cannot be combined with ${N}.`);const c=Ti(n,a),d=c?.findIndex(N=>N.id===a)??-1;if(!c||d===-1)return i(`${r} id '${a}' was not found in the do\
|
|
231
|
+
cument.`);const u=c.findIndex(N=>N.id===l);if(u===-1)return i(re(n,l)?`${r} end_id '${l}' is not in the same container as id '${a}'. A range covers consecutive sibling blocks: use end_id from the same\
|
|
232
|
+
level (for content inside a table cell or list, target blocks in that cell or list).`:`${r} end_id '${l}' was not found in the document.`);if(u<d)return i(`${r} end_id '${l}' comes before id '${a}'. \
|
|
233
|
+
Use the first block of the range as id and the last as end_id.`);const f=u-d+1;if(o.count!=null&&o.count!==f)return i(`${r} got count ${String(o.count)} but id '${a}' through end_id '${l}' is ${f} blo\
|
|
234
|
+
cks. Pass only id and end_id.`);const{end_id:b,...y}=o;return{toolCall:{...t,arguments:{...y,count:f}}}}function no(e){const t=new URLSearchParams;e.query!==void 0&&t.set("q",e.query),t.set("includeCo\
|
|
235
|
+
ntent","false");for(const n of["page","limit","currentFolderId","parentFolderId","sortBy","order"]){const o=e[n];o!=null&&o!==""&&t.set(n,String(o))}return e.includeFolders&&t.set("includeFolders","1"),
|
|
236
|
+
t}function oo(e,t=10){const n=e,o=Array.isArray(n?.items)?n.items:[],r=i=>typeof i=="number"&&Number.isFinite(i)&&i>=0;return{items:o,totalCount:r(n?.pagination?.totalCount)?n.pagination.totalCount:o.
|
|
237
|
+
length,totalPages:r(n?.pagination?.totalPages)?n.pagination.totalPages:Math.max(1,Math.ceil(o.length/Math.max(1,t))),hasMore:n?.pagination?.hasMore===!0}}function ro(e){return typeof e=="object"&&e!==
|
|
238
|
+
null&&e.type==="doc"&&Array.isArray(e.children)}function Di(e,t=[]){const n=new Qe.Doc;Qe.applyUpdate(n,Nt(e));for(const o of t)o&&Qe.applyUpdate(n,Nt(o));return In(n)}function Pi({content:e,yjsState:t,
|
|
239
|
+
yjsUpdates:n,source:o}){const r=Array.isArray(n)?n.filter(i=>i.length>0):[];if(typeof t=="string"&&t.length>0||r.length>0)try{if(typeof t=="string"&&t.length>0)return Di(t,r);const i=ro(e)?cr(e):new Qe.
|
|
240
|
+
Doc;if(r.length>0){for(const a of r)Qe.applyUpdate(i,Nt(a));return In(i)}}catch(i){console.error(`[resolveDocRootFromSerializedState] Failed to decode yjs updates${o?` for ${o}`:""}`,i)}return ro(e)?e:
|
|
241
|
+
null}const Ri="revise_conversations",Ni=2,io="conversations",nt="attachments";let qe=null;function so(){return typeof indexedDB<"u"}function ao(e){return qe||(qe=new Promise((t,n)=>{if(!so()){n(new Error(
|
|
242
|
+
"IndexedDB not available"));return}const o=indexedDB.open(Ri,e??Ni);o.onerror=()=>{qe=null,n(o.error)},o.onblocked=()=>{console.warn("[LocalConversationStorage] Database upgrade blocked - close other \
|
|
243
|
+
tabs")},o.onsuccess=()=>{const r=o.result;if(!r.objectStoreNames.contains(nt)){if(e!==void 0){r.close(),qe=null,n(new Error("Attachments store still missing after version bump"));return}console.warn("\
|
|
244
|
+
[LocalConversationStorage] Attachments store missing, bumping version to create it");const i=r.version+1;r.close(),qe=null,ao(i).then(t).catch(n);return}r.onclose=()=>{qe=null},r.onerror=()=>{qe=null},
|
|
245
|
+
t(r)},o.onupgradeneeded=r=>{const i=r.target.result;if(!i.objectStoreNames.contains(io)){const a=i.createObjectStore(io,{keyPath:"id"});a.createIndex("documentId","documentId",{unique:!1}),a.createIndex(
|
|
246
|
+
"updatedAt","updatedAt",{unique:!1})}i.objectStoreNames.contains(nt)||i.createObjectStore(nt,{keyPath:"id"}).createIndex("conversationId","conversationId",{unique:!1})}}),qe)}async function Mi(e){if(!so())
|
|
247
|
+
return null;try{const t=await ao();return new Promise((n,o)=>{const r=t.transaction(nt,"readonly").objectStore(nt).get(e);r.onsuccess=()=>{n(r.result??null)},r.onerror=()=>o(r.error)})}catch(t){return console.
|
|
248
|
+
warn("[LocalConversationStorage] Failed to get attachment:",t),null}}function Bi(e,t){const n=e.children.flatMap((o,r)=>o.type==="paragraph"&&o.heading?[{index:r,level:o.heading,blockId:o.id,title:Le(
|
|
249
|
+
o).replace(/\s+/g," ").trim()}]:[]);return n.filter(o=>o.level<=t?.maxDepth).map(o=>({...o,endIndex:(n.find(r=>r.index>o.index&&(t?.flat||r.level<=o.level))?.index??e.children.length)-1}))}const Oi=new Set(
|
|
250
|
+
[8203,8204,8205,8288,65279]);function ji(){return{wordCount:0,paragraphCount:0,characterCount:0,hasVisibleText:!1,inWord:!1}}function lo(e,t){for(let n=0;n<e.length;n+=1){const o=e.codePointAt(n);if(o===
|
|
251
|
+
void 0||(o>65535&&(n+=1),Oi.has(o)))continue;const r=String.fromCodePoint(o);if(t.characterCount+=r.length,/\s/.test(r)){t.inWord=!1;continue}t.hasVisibleText=!0,t.inWord||(t.wordCount+=1,t.inWord=!0)}}
|
|
252
|
+
function co(e,t){if(!e||typeof e!="object")return;const n=e;if(n.type==="text"&&typeof n.text=="string"){lo(n.text,t);return}if(n.type==="paragraph"&&(t.paragraphCount+=1),(n.type==="code"||n.type==="\
|
|
253
|
+
math")&&typeof n.content=="string"){lo(n.content,t),t.inWord=!1;return}if(n.type==="placeholder"||n.type==="image"||n.type==="page-break"||n.type==="section-break"){t.inWord=!1;return}if(Array.isArray(
|
|
254
|
+
n.children))for(const o of n.children)co(o,t),o&&typeof o=="object"&&"type"in o&&o.type!=="text"&&(t.inWord=!1)}function Ei(e){const t=ji();for(const o of e)co(o,t),t.inWord=!1;const n={parts:[],paragraphCount:0,
|
|
255
|
+
containsSentinel:!1};for(const o of e)uo(o,n),n.parts.push(" ");return t.wordCount=_r(n.parts.join("")),t}const ot="\0";function uo(e,t){if(!e||typeof e!="object")return;const n=e;if(n.type==="text"&&
|
|
256
|
+
typeof n.text=="string"){n.text.includes(ot)&&(t.containsSentinel=!0),t.parts.push(n.text);return}if(n.type==="paragraph"&&(t.paragraphCount+=1),(n.type==="code"||n.type==="math")&&typeof n.content=="\
|
|
257
|
+
string"){n.content.includes(ot)&&(t.containsSentinel=!0),t.parts.push(n.content,ot);return}if(n.type==="placeholder"||n.type==="image"||n.type==="page-break"||n.type==="section-break"){t.parts.push(ot);
|
|
258
|
+
return}if(Array.isArray(n.children))for(const o of n.children)uo(o,t),o&&typeof o=="object"&&"type"in o&&o.type!=="text"&&t.parts.push(ot)}function mo(e){return Ei(e)}function ho(e){const t=xn(e.pageLayout),
|
|
259
|
+
n=dr(t);return{layout:pr({pageWidth:n.pageWidth,pageHeight:n.pageHeight,pageMargin:t.marginLeftPx,pageMarginTop:t.marginTopPx,pageMarginRight:t.marginRightPx,pageMarginBottom:t.marginBottomPx,pageMarginLeft:t.
|
|
260
|
+
marginLeftPx,availableWidth:Math.max(1,n.pageWidth-t.marginLeftPx-t.marginRightPx),textStartY:t.marginTopPx,indentStepPx:t.indentStepPx,blockSpacingPx:t.blockSpacingPx,hyphenationEnabled:t.hyphenationEnabled,
|
|
261
|
+
lineNumbering:t.lineNumbering,columnCount:t.columnCount,columnGapPx:ur(t.columnGapTwips),pageless:e.pageless===!0}),resolved:t}}function po(e){if(typeof document>"u")return null;const t=document.createElement(
|
|
262
|
+
"canvas").getContext("2d");if(!t)return null;const n=br(t),{layout:o}=ho(e);return gr(e,n,o)}function go(e,t){const n=new Map;if(!t||e.pageless===!0)return new Map;const o=(a,l)=>{if(!a||typeof l!="nu\
|
|
263
|
+
mber"||!Number.isFinite(l))return;const c=Math.max(1,Math.floor(l)),d=n.get(a);if(!d){n.set(a,{min:c,max:c});return}d.min=Math.min(d.min,c),d.max=Math.max(d.max,c)};for(const a of t.fragments)o(a.blockId,
|
|
264
|
+
a.pageNumber);for(const a of t.blocks)o(a.blockId,a.pageNumber);const r=xn(e.pageLayout),i=new Map;for(const[a,l]of n)i.set(a,{pageStart:Sn(r,l.min-1),pageEnd:Sn(r,l.max-1)});return i}function Li(e,t){
|
|
265
|
+
let n,o;for(const r of e){const i=t.get(r);i&&(n=n===void 0?i.pageStart:Math.min(n,i.pageStart),o=o===void 0?i.pageEnd:Math.max(o,i.pageEnd))}return n!==void 0&&o!==void 0?{pageStart:n,pageEnd:o}:void 0}
|
|
266
|
+
function fo(e,t,n,o){const r=Math.max(0,Math.min(t,e.children.length-1)),i=Math.max(0,Math.min(n,e.children.length-1));if(r>i||e.children.length===0)return null;const a=e.children.slice(r,i+1),l=e.children[r],
|
|
267
|
+
c=e.children[i];if(!l?.id||!c?.id)return null;const d=mo(a),u=a.map(b=>b.id).filter(Boolean),f=Li(u,o);return{startIndex:r,endIndex:i,startBlockId:l.id,endBlockId:c.id,inclusive:!0,blockCount:a.length,
|
|
268
|
+
wordCount:d.wordCount,paragraphCount:d.paragraphCount,characterCount:d.characterCount,...f?{pageStart:f.pageStart,pageEnd:f.pageEnd}:{}}}function Ui(e,t,n){const o=[],r=n?new Set(n):null;for(const i of Bi(
|
|
269
|
+
e,{maxDepth:3})){const a=i.index,l=i.endIndex,c=i.level;if(r&&!r.has(c))continue;const d=fo(e,a,l,t);d&&o.push({startIndex:d.startIndex,endIndex:d.endIndex,startBlockId:d.startBlockId,endBlockId:d.endBlockId,
|
|
270
|
+
headingLevel:c,title:i.title,wordCount:d.wordCount,paragraphCount:d.paragraphCount,characterCount:d.characterCount,...d.pageStart!==void 0?{pageStart:d.pageStart,pageEnd:d.pageEnd}:{}})}return o}function bo(e,t){
|
|
271
|
+
const n=t&&"layout"in t?t.layout??null:e.pageless===!0?null:po(e),o=mo(e.children),r=e.pageless===!0?null:n,i=t?.includeSections===!0?go(e,n):new Map;return{inclusive:!0,totalBlocks:e.children.length,
|
|
272
|
+
wordCount:o.wordCount,paragraphCount:o.paragraphCount,characterCount:o.characterCount,...r?{pageCount:r.pageCount}:{},...t?.includeFractionalPageCount===!0&&r?{fractionalPageCount:Fi(e,r)}:{},...t?.includeSections===
|
|
273
|
+
!0?{sections:Ui(e,i,t.headingLevels).map(a=>({...a,inclusive:!0,blockCount:a.endIndex-a.startIndex+1}))}:{}}}function Fi(e,t){const{layout:n}=ho(e);return fr(n,t)}function _o(e){return typeof e!="stri\
|
|
274
|
+
ng"?"":e.trim().replace(/^#+/,"")}function zi(e,t,n){const o=po(e),r=go(e,o),i=new Map;for(let c=0;c<e.children.length;c+=1){const d=e.children[c]?.id;d&&i.set(d,c)}const a=[],l=[];for(const c of t){const d=_o(
|
|
275
|
+
c.startBlockId),u=_o(c.endBlockId??d),f=i.get(d),b=i.get(u);if(!d){l.push({error:"start_block_id is required."});continue}if(f===void 0){l.push({startBlockId:d,endBlockId:u,error:`start_block_id "${d}\
|
|
276
|
+
" was not found.`});continue}if(b===void 0){l.push({startBlockId:d,endBlockId:u,error:`end_block_id "${u}" was not found.`});continue}if(b<f){l.push({startBlockId:d,endBlockId:u,error:`end_block_id "${u}\
|
|
277
|
+
" comes before start_block_id "${d}". Ranges must be forward and inclusive.`});continue}const y=fo(e,f,b,r);if(!y){l.push({startBlockId:d,endBlockId:u,error:`Could not measure inclusive range "${d}"-"${u}\
|
|
278
|
+
".`});continue}a.push(y)}return{inclusive:!0,totalBlocks:e.children.length,ranges:a,errors:l}}const Ji="The agent had trouble completing this request. Please try again.",yo="Document session unavailab\
|
|
279
|
+
le after waiting for document load",Wi="document_session_unavailable";class Hi extends Error{constructor(t){super("Open the source document linked in the conversation to continue these edits."),this.sourceDocumentId=
|
|
280
|
+
t,this.name="ForeignDocumentTargetError"}}const Gi="InvalidAssistantResponseError",Ki="Couldn't reach the server. Please check your connection and try again.",Vi=["aborted without reason","bodystreamb\
|
|
281
|
+
uffer was aborted","client.timeout","connection reset by peer","context canceled","context cancellation","context cancelled","context deadline exceeded","econnreset","etimedout","failed to fetch","fai\
|
|
282
|
+
led to execute 'fetch'","fetch is aborted","gateway timeout","http error! status:","illegal access","illegal invocation","load failed","network request failed","socket hang up","upstream request timeo\
|
|
283
|
+
ut","while reading body"],Xi=["function call is missing a thought_signature","does not support the effort parameter","response with id=","gemini api error: 400","xai api error: 404","anthropic api err\
|
|
284
|
+
or: 400"],Qi=["server_error","service_unavailable","server_is_overloaded","503 service unavailable","error in input stream"],Zi=["context_length_exceeded","input token count exceeds","exceeds the cont\
|
|
285
|
+
ext window","maximum number of tokens","maximum context length","prompt is too long","too many input tokens"],Yi=['attachment "',"attachment not found","unable to download the file","failed to fetch a\
|
|
286
|
+
ttachment","expected a valid url","invalid 'input","image_url"],es=['block id "',"document changed while","reference block","not found in document","not found in the document","insert_block"];function ts(e){
|
|
287
|
+
const t=e.toLowerCase();return t.includes("network")||Vi.some(n=>t.includes(n))}function ns(e){if(e?.name==="AbortError"||e instanceof DOMException&&e.code===20)return{isAbort:!0,isRateLimited:!1,isNetworkError:!1,
|
|
288
|
+
kind:"abort",rawMessage:"",message:"",shouldRetryWithStableModel:!1,shouldTrackConversationError:!1};const t=e instanceof Error?e.message:typeof e?.toString=="function"?e.toString():String(e??""),n=t.
|
|
289
|
+
toLowerCase(),o=t==="RATE_LIMITED"||e?.message==="RATE_LIMITED",r=e instanceof TypeError||ts(t),i=e instanceof Error&&e.name===Gi,a=d=>d.some(u=>n.includes(u)),l=e instanceof Hi?"document_target":o?"r\
|
|
290
|
+
ate_limited":i?"invalid_assistant_response":t.trim().length===0?"unknown_empty":a(Zi)?"context_limit":a(Yi)?"attachment":n.includes(yo.toLowerCase())?"document_loading":a(es)?"document_state":a(Xi)?"p\
|
|
291
|
+
rovider_protocol":a(Qi)?"provider_transient":r?"connection":"unknown";let c;return o?c="Rate limit reached":i?c="The agent sent an invalid response. Please try again.":l==="connection"?c=Ki:l==="provi\
|
|
292
|
+
der_protocol"||l==="provider_transient"?c="The model service had trouble completing this request. Please try again.":l==="context_limit"?c="This request is too large for the model. Try a smaller reque\
|
|
293
|
+
st or attach fewer files.":l==="attachment"?c="The agent could not read one of the attached files.":l==="document_loading"?c="The document is still loading. Please wait a moment and try again.":l==="d\
|
|
294
|
+
ocument_target"?c=t:l==="document_state"?c="Document state changed during the request.":l==="unknown_empty"?c="The agent stopped unexpectedly. Your prompt is saved.":c=Ji,{isAbort:!1,isRateLimited:o,isNetworkError:r,
|
|
295
|
+
kind:l,rawMessage:t,message:c,shouldRetryWithStableModel:l==="provider_protocol"||l==="provider_transient",shouldTrackConversationError:l!=="rate_limited"&&l!=="connection"&&l!=="document_loading"}}const wo=[
|
|
296
|
+
{name:"get_selection",description:"Read the host user's current semantic editor selection. Returns selected text, caret/range positions, portable target segments, active formatting, comment IDs, and p\
|
|
297
|
+
ending suggestion IDs. Returns no viewport geometry. Use this when the host has not already supplied selection context.",inputSchema:{additionalProperties:!1,properties:{},type:"object"}},{name:"read_\
|
|
298
|
+
blocks_from_index",description:"Read consecutive blocks from a 0-based start index. Omit document_id for the current document, or pass a known document_id to read another document. If the user names o\
|
|
299
|
+
r links a specific document and you know its ID, use this directly instead of search_documents. Client chooses count by budget. Use at most one read/search tool per turn.",inputSchema:{additionalProperties:!1,
|
|
300
|
+
properties:{context_notes:{description:"Plain-text notes to carry forward from current context before this read/search. Use 'N/A' if none.",type:"string"},document_id:{description:"Optional document I\
|
|
301
|
+
D. Omit for the current document. Other documents are read-only sources: their block IDs cannot be used in mutation tools. To edit another document, ask the user to open it and continue there.",type:"\
|
|
302
|
+
string"},index:{description:"0-based start block index.",minimum:0,type:"integer"}},required:["index","context_notes"],type:"object"}},{name:"search_document",description:"Search text within one docum\
|
|
303
|
+
ent. Call this when you need to locate specific wording, a term, a name, or every occurrence of something and you do not already know which blocks contain it — searching is how you find the target bef\
|
|
304
|
+
ore editing it, and is cheaper and more reliable than reading through the document. Current-document results include a request-scoped search_result_id for the full unpaginated match set; pass it to re\
|
|
305
|
+
place, replace_block, style_blocks, or remove_blocks to target every match without paging through IDs. Omit document_id for the current document, or pass a known document_id to search within another d\
|
|
306
|
+
ocument. If you instead need to read a document start-to-finish and already know its ID, prefer read_blocks_from_index with document_id. Displayed matches are paginated. Use at most one read/search to\
|
|
307
|
+
ol per turn.",inputSchema:{additionalProperties:!1,properties:{context_notes:{description:"Plain-text notes to carry forward from current context before this read/search. Use 'N/A' if none.",type:"str\
|
|
308
|
+
ing"},document_id:{description:"Optional document ID. Omit for the current document. Other documents are read-only sources: their block IDs cannot be used in mutation tools. To edit another document, \
|
|
309
|
+
ask the user to open it and continue there.",type:"string"},page:{description:"0-based result page.",type:"integer"},queries:{description:"Search terms, max 20. Plain strings are case-insensitive; pre\
|
|
310
|
+
fix regex patterns with 'regex:'.",items:{type:"string"},type:"array"}},required:["queries","page","context_notes"],type:"object"}},{name:"find_highlights",description:'Find highlighted text blocks, o\
|
|
311
|
+
ptionally by color. Call this whenever the request refers to highlighted text — "the highlighted parts", "what I marked", "the yellow bits" — before acting on it; highlights are not visible in loaded \
|
|
312
|
+
document content, so this is the only way to learn which blocks the user means. Matching blocks load next turn. Results are paginated at 25 blocks/page. Use at most one read/search tool per turn.',inputSchema:{
|
|
313
|
+
additionalProperties:!1,properties:{color:{description:"Optional color filter.",enum:["yellow","orange","green","blue","purple","pink","gray"],type:"string"},context_notes:{description:"Plain-text not\
|
|
314
|
+
es to carry forward from current context before this read/search. Use 'N/A' if none.",type:"string"},page:{description:"0-based result page.",type:"integer"}},required:["page","context_notes"],type:"o\
|
|
315
|
+
bject"}},{name:"read_specific_blocks",description:"Read specific blocks by ID. Omit document_id for the current document, or pass a known document_id to read another document. If you already know both\
|
|
316
|
+
the document ID and block IDs, use this directly instead of search_documents. Use at most one read/search tool per turn.",inputSchema:{additionalProperties:!1,properties:{block_ids:{description:"Bloc\
|
|
317
|
+
k IDs to read, max 50.",items:{type:"string"},type:"array"},context_notes:{description:"Plain-text notes to carry forward from current context before this read/search. Use 'N/A' if none.",type:"string"},
|
|
318
|
+
document_id:{description:"Optional document ID. Omit for the current document. Other documents are read-only sources: their block IDs cannot be used in mutation tools. To edit another document, ask th\
|
|
319
|
+
e user to open it and continue there.",type:"string"}},required:["block_ids","context_notes"],type:"object"}},{name:"read_table",description:"Read a bounded part of a table in the current document by \
|
|
320
|
+
table_id. Native agents receive row contents in the next document snapshot; other callers receive rows in this result. Results include coverage metadata and continuations. When a serialized window is \
|
|
321
|
+
partial, consume next_read and then following_read to avoid skipping columns or later rows. mode=summary returns dimensions, merged anchors/spans, per-column fill counts and missing ranges only: it de\
|
|
322
|
+
livers no cell contents and grants no edit rights. mode=rows (default) delivers rows by row_start/row_count or explicit row_ids, optionally limited to a column range; only delivered cells can be edite\
|
|
323
|
+
d. mode=cell_text pages one oversized cell by cell_id/text_offset and continuation_revision; cell_text includes list markers and explicit non-text placeholders, opens each nested block's text with an \
|
|
324
|
+
inline [[block_id]] marker (metadata, not document text; never include it in find text), and routes nested tables to their own read_table calls. Its windows are always read-only and never authorize wh\
|
|
325
|
+
ole-cell replacement; read a complete nested block with read_specific_blocks to edit that block. For cells not already fully delivered in a table seed or cell snapshot, read the needed rows, then batc\
|
|
326
|
+
h edits with edit_table_cells. Do not re-read cells whose current contents are already delivered. Optionally declare the overall task scope (task_kind, scope_*, source_attachment_id) and deliberate_bl\
|
|
327
|
+
anks so progress can be tracked across turns; scope is never inferred from a partial edit. Use at most one read/search tool per turn.",inputSchema:{additionalProperties:!1,properties:{cell_id:{description:"\
|
|
328
|
+
Cell ID for mode=cell_text.",type:"string"},column_count:{description:"Optional number of logical columns starting at column_start.",minimum:1,type:"integer"},column_start:{description:"Optional 0-bas\
|
|
329
|
+
ed first logical column. Omit to read all columns. A partial column read authorizes edits only to the delivered cells, not the whole row.",minimum:0,type:"integer"},context_notes:{description:"Plain-t\
|
|
330
|
+
ext notes to carry forward from current context before this read/search. Use 'N/A' if none.",type:"string"},continuation_revision:{description:"Revision from the previous result continuation. Rejects \
|
|
331
|
+
continuation when cell text or table geometry changed, so stale and fresh windows are never combined.",type:"string"},deliberate_blanks:{description:"Optional in-scope cells intentionally left empty, \
|
|
332
|
+
each with a reason, so they are not reported as remaining work.",items:{additionalProperties:!1,properties:{column:{description:"0-based logical column.",minimum:0,type:"integer"},reason:{description:"\
|
|
333
|
+
Why the cell stays empty.",type:"string"},row_id:{description:"Stable row ID.",type:"string"}},required:["row_id","column","reason"],type:"object"},maxItems:50,type:"array"},mode:{description:"summary\
|
|
334
|
+
: metadata and counts only. rows (default when omitted): deliver row contents. cell_text: bounded text window of one oversized cell.",enum:["summary","rows","cell_text"],type:"string"},row_count:{description:"\
|
|
335
|
+
Rows to deliver for mode=rows. Defaults to 25; maximum 50.",maximum:50,minimum:1,type:"integer"},row_ids:{description:"Explicit stable row IDs (<tr id>) to deliver instead of row_start/row_count.",items:{
|
|
336
|
+
type:"string"},maxItems:50,type:"array"},row_start:{description:"0-based first row for mode=rows, counting header rows. Ignored when row_ids is supplied.",minimum:0,type:"integer"},scope_columns:{description:"\
|
|
337
|
+
Optional declared task scope: 0-based logical columns the task writes.",items:{minimum:0,type:"integer"},type:"array"},scope_row_count:{description:"Optional declared task scope: number of rows covere\
|
|
338
|
+
d by the user's whole request.",minimum:1,type:"integer"},scope_row_start:{description:"Optional declared task scope: first 0-based row covered by the user's whole request.",minimum:0,type:"integer"},
|
|
339
|
+
source_attachment_id:{description:"Optional attachment ID the task copies or derives values from.",type:"string"},table_id:{description:"Table block ID in the current document.",type:"string"},task_kind:{
|
|
340
|
+
description:"Optional task declaration. fill: populate empty cells. transform: rewrite existing cells (translate, shorten, etc.).",enum:["fill","transform"],type:"string"},text_offset:{description:"Ch\
|
|
341
|
+
aracter offset for mode=cell_text. Use the offset from the previous result's continuation.",minimum:0,type:"integer"}},required:["table_id","context_notes"],type:"object"}},{name:"measure_document",description:"\
|
|
342
|
+
Measure the current document without loading body text. Use this for total word count, paragraph count, block count, rendered page count, and paginated per-heading section measurements. Primary totals\
|
|
343
|
+
treat pending suggestions as accepted; when pending suggestions change counts, the result also reports the original review projection so you can reconcile the number visible in the user's editor view\
|
|
344
|
+
. Set include_sections=true for per-chapter/per-section counts and inclusive block ranges.",inputSchema:{additionalProperties:!1,properties:{heading_levels:{description:"Optional heading levels to inc\
|
|
345
|
+
lude when include_sections is true. Defaults to h1, h2, and h3.",items:{enum:[1,2,3],type:"integer"},type:"array"},include_sections:{description:"Whether to include heading section measurements. Defau\
|
|
346
|
+
lt false. Use true for per-chapter or per-section counts.",type:"boolean"},section_limit:{description:"Maximum heading sections to return when include_sections is true. Default and maximum 100.",maximum:100,
|
|
347
|
+
minimum:1,type:"integer"},section_offset:{description:"Zero-based section offset when include_sections is true. Default 0. Use nextSectionOffset from the previous result to continue.",minimum:0,type:"\
|
|
348
|
+
integer"}},type:"object"}},{name:"measure_blocks",description:"Measure inclusive block ranges in the current document without loading document text. Use this for word counts, paragraph counts, block c\
|
|
349
|
+
ounts, and rendered page ranges. Block IDs may be passed with or without a leading #.",inputSchema:{additionalProperties:!1,properties:{mode:{description:"Range mode. Only inclusive is supported.",enum:[
|
|
350
|
+
"inclusive"],type:"string"},ranges:{description:"Inclusive block ranges to measure. Omit end_block_id to measure only start_block_id.",items:{additionalProperties:!1,properties:{end_block_id:{description:"\
|
|
351
|
+
Last block ID in the inclusive range. Omit to measure only the start block.",type:"string"},start_block_id:{description:"First block ID in the inclusive range.",type:"string"}},required:["start_block_\
|
|
352
|
+
id"],type:"object"},type:"array"}},required:["ranges"],type:"object"}},{name:"view_image",description:'View a document image by block ID when its <img> src is hidden. Viewing is only for seeing pixels\
|
|
353
|
+
; you do not need the hidden source to copy, move, or swap an image—write <img src="IMAGE_ID"> with its exact document id in insert_block or replace_block HTML.',inputSchema:{additionalProperties:!1,
|
|
354
|
+
properties:{block_id:{description:"Image block ID.",type:"string"}},required:["block_id"],type:"object"}},{name:"insert_block",description:'Insert native block(s) before/after a reference block using \
|
|
355
|
+
HTML. To add items inside an existing list, reference a list-item ID and pass separate <li>...</li> entries in the desired order; this preserves the existing list numbering and style. Referencing the \
|
|
356
|
+
list container inserts a separate sibling block, not items within that list. A reference may be nested inside a table cell; inserting <img> (bare or wrapped by a paragraph/presentational span) next to\
|
|
357
|
+
that reference creates a native image block in the same cell. For a web-sourced image, use a verified direct raster URL returned by search for src; never guess or infer an image filename. Add data-so\
|
|
358
|
+
urce-url="..." to the <img> using the source webpage URL returned by web search, or the original image URL when no webpage URL is available; Revise preserves this provenance across later requests whil\
|
|
359
|
+
e rehosting the rendered image. For a live table of contents that automatically tracks document headings, insert <toc levels="3"></toc> (levels may be 1-6; omitting the attribute defaults to 3). Never\
|
|
360
|
+
build a table of contents from ordinary paragraphs, tabs, lists, or manually copied headings. For an Arabic/RTL live TOC, keep the toc block and set dir="rtl" and style="text-align:right" on it; dire\
|
|
361
|
+
ction:rtl and text-align:right also work through style_blocks. RTL places page numbers at the left edge. Do not replace a live TOC with a static table to adjust formatting. Put alignment directly in i\
|
|
362
|
+
nserted HTML when needed. To cite inside new content, embed native notes inline: <sup data-footnote="Note body.">1</sup> creates a footnote in this same call (data-note-kind="endnote" for endnotes).',
|
|
363
|
+
inputSchema:{additionalProperties:!1,properties:{content:{description:'HTML block elements to insert, e.g. <p>, <h1>, <li> (within an existing list), <ul> (a new list), <img>, <toc levels="3"></toc> (\
|
|
364
|
+
live table of contents), <page-break />, <hr /> (horizontal rule), <pre>. An image may be wrapped in a paragraph/span for alignment and display dimensions. For a web-sourced image, use a verified dire\
|
|
365
|
+
ct raster URL returned by search for src. Never guess or infer an image filename. Put its source webpage URL in data-source-url on the <img> (fall back to the original image URL). An image whose src i\
|
|
366
|
+
s hidden is still usable: to copy or move it, write <img src="IMAGE_ID"> with its exact document id (dimensions and alt may be restated); the source is resolved automatically, so never ask the user fo\
|
|
367
|
+
r it.',items:{type:"string"},minItems:1,type:"array"},position:{description:"Insert before or after reference block.",enum:["before","after"],type:"string"},referenceId:{description:"Current reference\
|
|
368
|
+
block ID. For a blank document, pass an empty string with position=after; the editor resolves the blank insertion location. Never ask the user to type placeholder text. For a document with content, u\
|
|
369
|
+
se an existing block ID.",type:"string"}},required:["content","position","referenceId"],type:"object"}},{name:"insert_footnote",description:"Insert a footnote: a numbered superscript reference placed \
|
|
370
|
+
right after the anchor text in a paragraph, plus the footnote body (rendered at the bottom of the page). Footnote bodies appear in the document as [^n] references with their own blocks — edit them wit\
|
|
371
|
+
h replace/replace_block and remove them with remove_blocks on the footnote block (removing a body also removes its reference).",inputSchema:{additionalProperties:!1,properties:{find:{description:"Anch\
|
|
372
|
+
or text inside the block; the reference is inserted right after it. Empty string appends at the end of the block.",type:"string"},id:{description:"Paragraph block ID that receives the reference.",type:"\
|
|
373
|
+
string"},kind:{description:"Note stream: footnote (per-page bottom area, numbered 1,2,3 — default) or endnote (grouped on its own page at the document end, numbered i,ii,iii).",enum:["footnote","end\
|
|
374
|
+
note"],type:"string"},text:{description:"Footnote body text.",type:"string"}},required:["id","find","text"],type:"object"}},{name:"remove_blocks",description:"Remove native footnotes/endnotes by targe\
|
|
375
|
+
ting the note ID or its body block ID with id alone; this removes the entire note and all its inline references while preserving the surrounding paragraph. To remove multiple notes, use ids containing\
|
|
376
|
+
only note/body IDs (do not mix with main-document block IDs or use an end_id range). For notes found by search, use their explicit IDs rather than search_result_id. Remove one or more blocks by a dir\
|
|
377
|
+
ect target (id alone for one block, or id + end_id for a consecutive range, both inclusive), an explicit tail range (id + through_end=true), an exact nonconsecutive ID batch (ids), or every block in a\
|
|
378
|
+
full search_document result (search_result_id). through_end removes the starting top-level block and every block after it through the current end of the document; use it only when that entire tail mu\
|
|
379
|
+
st be removed. The starting id must have appeared in current request context, but through_end does not require reading every interior block. Other direct targets must have appeared in current request \
|
|
380
|
+
context. Prefer search_result_id for large or sparse match sets; search discovers candidates but never deletes them implicitly.",inputSchema:{additionalProperties:!1,properties:{end_id:{description:"L\
|
|
381
|
+
ast block ID of a consecutive range to remove, inclusive, at the same level as id (same document level, table cell, or list). Omit to remove only id. Every block from id through end_id must have appea\
|
|
382
|
+
red in current request context.",type:"string"},id:{description:"First block ID to remove.",type:"string"},ids:{description:"Exact nonconsecutive block IDs to remove. Each ID must have appeared in doc\
|
|
383
|
+
ument context during this request. Do not infer IDs from a query.",items:{type:"string"},maxItems:50,minItems:1,type:"array"},search_result_id:{description:"Request-scoped ID returned by search_docume\
|
|
384
|
+
nt for the current document. Applies this operation to every block in the full unpaginated result set. Use instead of id or ids. Rerun search_document if the reference is unavailable or stale.",type:"\
|
|
385
|
+
string"},through_end:{description:"Set true with id to remove that top-level block and the entire document tail after it. Mutually exclusive with end_id, ids, and search_result_id. Omit unless the who\
|
|
386
|
+
le tail is intentionally in scope.",type:"boolean"}},type:"object"}},{name:"append_to_paragraph",description:"Append HTML content to a paragraph.",inputSchema:{additionalProperties:!1,properties:{content:{
|
|
387
|
+
description:"HTML content to append.",type:"string"},id:{description:"Paragraph ID.",type:"string"}},required:["id","content"],type:"object"}},{name:"break_paragraph",description:"Split a paragraph at\
|
|
388
|
+
the first occurrence of substring; second paragraph starts there.",inputSchema:{additionalProperties:!1,properties:{id:{description:"Paragraph ID.",type:"string"},substring:{description:"Substring wh\
|
|
389
|
+
ere split begins.",type:"string"}},required:["id","substring"],type:"object"}},{name:"join_paragraphs",description:"Join two adjacent paragraphs without rewriting their text. The second paragraph is a\
|
|
390
|
+
ppended to the first, preserving inline formatting from both paragraphs, then removed. Use this to repair an accidental paragraph break or hard return.",inputSchema:{additionalProperties:!1,properties:{
|
|
391
|
+
firstId:{description:"ID of the first paragraph. This paragraph and its block formatting are preserved.",type:"string"},secondId:{description:"ID of the immediately following sibling paragraph. Its in\
|
|
392
|
+
line-formatted text is appended, then this block is removed.",type:"string"},separator:{description:"Text placed between the paragraphs. Defaults to one space between non-empty paragraphs. A non-empty\
|
|
393
|
+
separator replaces existing boundary whitespace so it is not duplicated. Pass an empty string to add nothing and preserve existing boundary whitespace.",type:"string"}},required:["firstId","secondId"],
|
|
394
|
+
type:"object"}},{name:"replace_block",description:'Replace entire consecutive block(s) with HTML block(s), or apply the same one-block replacement independently to every block in a full search_documen\
|
|
395
|
+
t result via search_result_id. Use this only when the whole block must be replaced, its block type must change, or multiple consecutive blocks must become a different block structure. Prefer replace f\
|
|
396
|
+
or ordinary wording, sentence, paragraph-text, typo, punctuation, or formatting-preserving edits—even when most or all visible text in one paragraph changes—because replace preserves block identity an\
|
|
397
|
+
d untouched formatting. Preserve the existing block type unless the user asks to change it: use <pre language="..."> for code, <latex> for display math, and <latex-inline> for inline math. Put alignme\
|
|
398
|
+
nt in replacement HTML. For a web-sourced replacement image, use a verified direct raster URL returned by search for src; never guess or infer an image filename. Put its source webpage URL in data-sou\
|
|
399
|
+
rce-url on the <img> (fall back to the original image URL).',inputSchema:{additionalProperties:!1,properties:{content:{description:'Replacement HTML block elements, e.g. <p>, <h1>, <ul>, <pre language\
|
|
400
|
+
="typescript">code</pre>, <img>, or <latex>E = mc^2</latex>. Match the original block type unless a type change was requested. For a web-sourced image, use a verified direct raster URL returned by sea\
|
|
401
|
+
rch for src. Never guess or infer an image filename. Put its source webpage URL in data-source-url on the <img> (fall back to the original image URL). An image whose src is hidden is still usable: to \
|
|
402
|
+
copy or move it, write <img src="IMAGE_ID"> with its exact document id (dimensions and alt may be restated); the source is resolved automatically, so never ask the user for it.',items:{type:"string"},
|
|
403
|
+
minItems:1,type:"array"},end_id:{description:"Last block ID of a consecutive range to replace, inclusive, at the same level as id (same document level, table cell, or list). Omit to replace only id. E\
|
|
404
|
+
very block from id through end_id must have appeared in current request context.",type:"string"},id:{description:"First block ID to replace.",type:"string"},search_result_id:{description:"Request-scop\
|
|
405
|
+
ed ID returned by search_document for the current document. Applies this operation to every block in the full unpaginated result set. Use instead of id or ids. Rerun search_document if the reference i\
|
|
406
|
+
s unavailable or stale.",type:"string"}},required:["content"],type:"object"}},{name:"style_blocks",description:'Style existing content with forgiving CSS-lite selectors and values. Use one bulk style_\
|
|
407
|
+
blocks call instead of per-block replace calls when matching content shares a selector or search result. Pass search_result_id to scope selectors to every block in the full unpaginated search_document\
|
|
408
|
+
result; * then means each matched block. Block selectors include *, #blockId, p, h1-h6, li, lists, tables, and descendants. Inline selectors such as span, b/strong, i/em, u, s/strike/del, code, sup, \
|
|
409
|
+
sub, mark, and a target text ranges; they may be scoped, for example p span, p b, or #blockId strong. Text color accepts CSS named colors, hex colors, and CSS color functions and stores an absolute he\
|
|
410
|
+
x color. For text highlighting, use backgroundColor with one of the seven canonical values yellow, orange, green, blue, purple, pink, or gray; other names and CSS colors normalize to this palette by h\
|
|
411
|
+
ue (a pale lavender such as #E4DFEC becomes purple) and may be the same color. A backgroundColor on a table-cell selector sets the cell fill; on text blocks or inline selectors it highlights text, whi\
|
|
412
|
+
ch is also how to express paragraph shading. Setting a value back to the original reverts your pending formatting suggestion. Table-cell selectors apply text styles, alignment, and spacing to their de\
|
|
413
|
+
scendant paragraphs. Examples: highlight all h3 headings orange with selectors="h3" and attrs=[{"name":"backgroundColor","value":"orange"}]; remove all bold with selectors="b" and attrs=[{"name":"font\
|
|
414
|
+
Weight","value":"normal"}]; set the entire document to Century Schoolbook 14pt double-spaced with selectors="*" and fontFamily/fontSize/lineSpacing attrs; bold headings with selectors=["h1","h2","h3"]\
|
|
415
|
+
and fontWeight="bold".',inputSchema:{additionalProperties:!1,properties:{attrs:{description:"Use CSS/Revise names. Text colors accept CSS names, hex, or functions. Highlights: yellow, orange, green, \
|
|
416
|
+
blue, purple, pink, or gray. Supports text typography, block alignment, hanging indents, list presentation, image sizing with CSS lengths, and table/cell sizing with percentage widths. CSS maps to dur\
|
|
417
|
+
able document equivalents; feedback lists approximations and unsupported values. Null resets.",items:{additionalProperties:!1,properties:{name:{description:"Attribute/style name, e.g. fontSize, font-s\
|
|
418
|
+
ize, fontFamily, text-align.",type:"string"},value:{description:"Value to set, or null to remove/reset.",oneOf:[{type:"string"},{type:"number"},{type:"boolean"},{type:"null"}]}},required:["name","valu\
|
|
419
|
+
e"],type:"object"},minItems:1,type:"array"},search_result_id:{description:"Request-scoped ID returned by search_document for the current document. Applies this operation to every block in the full unp\
|
|
420
|
+
aginated result set. Use instead of id or ids. Rerun search_document if the reference is unavailable or stale.",type:"string"},selectors:{description:'CSS-lite selectors over the document HTML: * (als\
|
|
421
|
+
o all, document, or :root), #blockId, p, h1-h6, li, ul, ol, pre, latex, img, table, tr, td/th, div, p[data-style-id="StyleName"], and inline formatting tags span, b/strong, i/em, u, s/strike/del, code\
|
|
422
|
+
, sup, sub, mark, a. Simple descendants, general siblings, descendant wildcards, :first-child, and :nth-child(n) are accepted, e.g. table tr:first-child td, table td:nth-child(2) p, #blockId td p, #bl\
|
|
423
|
+
ockId *, #blockId ~ p, p span, p b, or #blockId strong. Inline selectors affect matching text ranges; span means all text in its scope. Arrays and comma grouping are allowed.',oneOf:[{type:"string"},{
|
|
424
|
+
items:{type:"string"},minItems:1,type:"array"}]}},required:["selectors","attrs"],type:"object"}},{name:"clear_formatting",description:"Clear removable inline emphasis from paragraph/list-item target(s\
|
|
425
|
+
): bold, italic, underline, code, LaTeX, superscript/subscript, background highlight, and links. Preserve font family, font size, text color, and paragraph attributes.",inputSchema:{additionalProperties:!1,
|
|
426
|
+
properties:{id:{description:"Target paragraph/list-item/list ID or IDs.",oneOf:[{type:"string"},{items:{type:"string"},minItems:1,type:"array"}]}},required:["id"],type:"object"}},{name:"set_title",description:"\
|
|
427
|
+
Change the document title",inputSchema:{additionalProperties:!1,properties:{title:{description:"The new document title",maxLength:300,type:"string"}},required:["title"],type:"object"}},{name:"set_page\
|
|
428
|
+
_layout",description:"Patch page or section layout: preset, size, margins, 1-3 columns, page numbers, spacing, pageless mode. ONLY the fields you pass change; everything else keeps its current or inhe\
|
|
429
|
+
rited value (a section keeps inheriting document-level settings for fields you don't pass). Pass sectionIndex to change one section; omit it to apply the passed fields to the document defaults and eve\
|
|
430
|
+
ry section. Length fields must be strings with explicit px/in/cm units. Preset 'apa7' applies standard APA layout.",inputSchema:{additionalProperties:!1,properties:{blockSpacing:{description:'Vertical\
|
|
431
|
+
spacing between adjacent blocks, shown in the UI in inches or centimeters. Typical values are "0.08in" to "0.25in" (about "0.2cm" to "0.64cm"); do not use whole-inch values like "2in" or "4in" for no\
|
|
432
|
+
rmal paragraph spacing. Include an explicit unit: in, cm, or px (examples: "1in", "3cm", "72px"). Prefer in/cm for page layout values shown in the UI. Do not send bare numbers.',type:"string"},clearPageBorders:{
|
|
433
|
+
description:"Set true to remove all page borders from the target section(s), including preserved Word art borders.",type:"boolean"},columnCount:{description:"Number of newspaper-style columns in the t\
|
|
434
|
+
arget section.",enum:[1,2,3],type:"integer"},columnGap:{description:'Gap between columns. Include an explicit unit: in, cm, or px (examples: "1in", "3cm", "72px"). Prefer in/cm for page layout values \
|
|
435
|
+
shown in the UI. Do not send bare numbers.',type:"string"},indentStep:{description:'Paragraph indent step. Include an explicit unit: in, cm, or px (examples: "1in", "3cm", "72px"). Prefer in/cm for pa\
|
|
436
|
+
ge layout values shown in the UI. Do not send bare numbers.',type:"string"},margin:{description:'Uniform page margin applied to all sides. Include an explicit unit: in, cm, or px (examples: "1in", "3c\
|
|
437
|
+
m", "72px"). Prefer in/cm for page layout values shown in the UI. Do not send bare numbers.',type:"string"},marginBottom:{description:'Bottom page margin. Include an explicit unit: in, cm, or px (exam\
|
|
438
|
+
ples: "1in", "3cm", "72px"). Prefer in/cm for page layout values shown in the UI. Do not send bare numbers.',type:"string"},marginLeft:{description:'Left page margin. Include an explicit unit: in, cm,\
|
|
439
|
+
or px (examples: "1in", "3cm", "72px"). Prefer in/cm for page layout values shown in the UI. Do not send bare numbers.',type:"string"},marginRight:{description:'Right page margin. Include an explicit\
|
|
440
|
+
unit: in, cm, or px (examples: "1in", "3cm", "72px"). Prefer in/cm for page layout values shown in the UI. Do not send bare numbers.',type:"string"},marginTop:{description:'Top page margin. Include a\
|
|
441
|
+
n explicit unit: in, cm, or px (examples: "1in", "3cm", "72px"). Prefer in/cm for page layout values shown in the UI. Do not send bare numbers.',type:"string"},noteMode:{description:"Bulk-convert exis\
|
|
442
|
+
ting native notes to this stream: footnotes (per-page areas, 1,2,3) or endnotes (own page at document end, i,ii,iii). Does not convert manually typed superscript numbers or note paragraphs; create nat\
|
|
443
|
+
ive notes with their complete bodies and references first. Individual notes choose a stream at insert time.",enum:["footnotes","endnotes"],type:"string"},orientation:{description:"Page orientation.",enum:[
|
|
444
|
+
"portrait","landscape"],type:"string"},pageBorders:{additionalProperties:!1,description:"Native page border for the target section(s), rendered in the editor and PDF and preserved in DOCX. Replaces th\
|
|
445
|
+
e whole border configuration; omitted sides have no border. To remove borders use clearPageBorders=true. Measurements are points (1/72 inch).",properties:{bottom:{additionalProperties:!1,properties:{color:{
|
|
446
|
+
pattern:"^#[0-9a-fA-F]{6}$",type:"string"},spacePt:{maximum:31,minimum:0,type:"number"},style:{enum:["single","double","dotted","dashed"],type:"string"},widthPt:{maximum:12,minimum:.25,type:"number"}},
|
|
447
|
+
required:["style","color","widthPt","spacePt"],type:"object"},display:{enum:["allPages","firstPage","notFirstPage"],type:"string"},left:{additionalProperties:!1,properties:{color:{pattern:"^#[0-9a-fA-\
|
|
448
|
+
F]{6}$",type:"string"},spacePt:{maximum:31,minimum:0,type:"number"},style:{enum:["single","double","dotted","dashed"],type:"string"},widthPt:{maximum:12,minimum:.25,type:"number"}},required:["style","\
|
|
449
|
+
color","widthPt","spacePt"],type:"object"},offsetFrom:{enum:["page","text"],type:"string"},right:{additionalProperties:!1,properties:{color:{pattern:"^#[0-9a-fA-F]{6}$",type:"string"},spacePt:{maximum:31,
|
|
450
|
+
minimum:0,type:"number"},style:{enum:["single","double","dotted","dashed"],type:"string"},widthPt:{maximum:12,minimum:.25,type:"number"}},required:["style","color","widthPt","spacePt"],type:"object"},
|
|
451
|
+
top:{additionalProperties:!1,properties:{color:{pattern:"^#[0-9a-fA-F]{6}$",type:"string"},spacePt:{maximum:31,minimum:0,type:"number"},style:{enum:["single","double","dotted","dashed"],type:"string"},
|
|
452
|
+
widthPt:{maximum:12,minimum:.25,type:"number"}},required:["style","color","widthPt","spacePt"],type:"object"},zOrder:{enum:["front","back"],type:"string"}},required:["offsetFrom","display","zOrder"],type:"\
|
|
453
|
+
object"},pageHeight:{description:'Explicit page height. Include an explicit unit: in, cm, or px (examples: "1in", "3cm", "72px"). Prefer in/cm for page layout values shown in the UI. Do not send bare \
|
|
454
|
+
numbers.',type:"string"},pageNumberFormat:{description:"Page number style: decimal (1, 2, 3), lowerRoman (i, ii, iii), or upperRoman (I, II, III). Applies to page-number fields, the table of contents,\
|
|
455
|
+
and exports. Use sectionIndex for front matter.",enum:["decimal","lowerRoman","upperRoman"],type:"string"},pageNumberPosition:{description:"Page number position.",enum:["top-left","top-right","bottom\
|
|
456
|
+
-left","bottom-right"],type:"string"},pageNumberRestart:{description:"Section numbering mode (use with sectionIndex, including the final section): true restarts at pageNumberStart (default 1); false c\
|
|
457
|
+
ontinues from the previous section. Typical thesis: Roman front matter, then the final body section restarts at 1.",type:"boolean"},pageNumberStart:{description:"First page number. With sectionIndex i\
|
|
458
|
+
t restarts numbering at that section (e.g. body starts again at 1 after Roman front matter).",minimum:1,type:"integer"},pageSize:{description:"Named page-size preset.",enum:["letter","tabloid","legal",
|
|
459
|
+
"statement","executive","folio","a3","a4","a5","b4","b5"],type:"string"},pageWidth:{description:'Explicit page width. Include an explicit unit: in, cm, or px (examples: "1in", "3cm", "72px"). Prefer i\
|
|
460
|
+
n/cm for page layout values shown in the UI. Do not send bare numbers.',type:"string"},pageless:{description:"Enable pageless mode.",type:"boolean"},preset:{description:"Preset applied before override\
|
|
461
|
+
s.",enum:["apa7"],type:"string"},sectionIndex:{description:"One-based section number to patch (invalid indexes fail the call). Omit to apply the passed fields to the document defaults and every sectio\
|
|
462
|
+
n.",minimum:1,type:"integer"},showPageNumbers:{description:"Show or hide page numbers. Page numbers are header/footer content: this manages an automatic page-number field slot (combine with pageNumber\
|
|
463
|
+
Position). Hand-authored header/footer content is never overwritten.",type:"boolean"}},required:[],type:"object"}},{name:"set_header_footer",description:`Edit page header/footer content. Each side has\
|
|
464
|
+
three zones (left, center, right); provide only the zones to change - untouched zones keep their content and formatting. Use the literal token {PAGE} for a live page number and {PAGES} for the total \
|
|
465
|
+
page count, anywhere in any zone (e.g. right: "Page {PAGE} of {PAGES}"). An empty string clears a zone; clear=true removes the header or footer from every page (all slots and every section's override,\
|
|
466
|
+
unless slot or sectionIndex narrows it). Without sectionIndex, zone edits change the document-wide header/footer; a section with its own override keeps it (the result says so). The result lists the h\
|
|
467
|
+
eaders/footers that exist afterwards, and a call that changes nothing fails with that list. For a plain bottom-right page number, set_page_layout with showPageNumbers also works.`,inputSchema:{properties:{
|
|
468
|
+
center:{description:"Center zone text ({PAGE}/{PAGES} tokens allowed). Omit to keep unchanged; empty string clears.",type:"string"},clear:{description:"Remove this side's header/footer: from every pag\
|
|
469
|
+
e and section unless slot or sectionIndex narrows it.",type:"boolean"},image:{additionalProperties:!1,description:"Put an image (e.g. a logo) in this header/footer on every page, replacing any image a\
|
|
470
|
+
lready in that band. Pass image_id to reuse an image already in the document, or url for a direct image URL. It is drawn in the page margin band, scaled down to fit (never into the body text), next to\
|
|
471
|
+
any zone text. Do not insert copies of the image into the body to fake a header. Applies to every section; do not combine with sectionIndex or clear.",properties:{alt:{description:"Short description \
|
|
472
|
+
of the image.",type:"string"},height:{description:"Optional display height in px.",type:"number"},image_id:{description:"ID of an existing image block to reuse.",type:"string"},url:{description:"Direc\
|
|
473
|
+
t http(s) URL of a raster image (PNG/JPEG/GIF/WebP).",type:"string"},width:{description:"Optional display width in px (height follows the aspect ratio). Omit to use the image's own size.",type:"number"},
|
|
474
|
+
zone:{description:"Horizontal position in the band. Default left.",enum:["left","center","right"],type:"string"}},type:"object"},left:{description:"Left zone text ({PAGE}/{PAGES} tokens allowed). Omit\
|
|
475
|
+
to keep unchanged; empty string clears.",type:"string"},right:{description:"Right zone text ({PAGE}/{PAGES} tokens allowed). Omit to keep unchanged; empty string clears.",type:"string"},sectionIndex:{
|
|
476
|
+
description:"One-based section whose own header/footer override to edit or clear. Omit for the document-wide header/footer (and, with clear, every section's override too).",minimum:1,type:"integer"},side:{
|
|
477
|
+
description:"Which band to edit.",enum:["header","footer"],type:"string"},slot:{description:"Which pages this applies to (Word slot model). Zone edits default to 'default' (all pages); clear without s\
|
|
478
|
+
lot removes every slot.",enum:["default","first","even"],type:"string"}},required:["side"],type:"object"}},{name:"replace",description:"Preferred/default tool for editing text inside an existing block\
|
|
479
|
+
, including wording, sentences, typos, punctuation, formatting-preserving rewrites, and even replacing all visible text in one paragraph when its block type/structure should stay the same. It preserve\
|
|
480
|
+
s block identity and untouched formatting; use replace_block only for whole-block structural or block-type changes. Supports one or more in-place edits inside one block, uniquely identifiable edits ac\
|
|
481
|
+
ross loaded blocks when id is omitted, or the same edits independently in every block from a full search_document result via search_result_id. An empty find safely fills a direct-id target only when t\
|
|
482
|
+
hat target is truly empty. Each operation may include its own comment, which is attached to every suggestion produced by that operation. For each edit, occurrence defaults to unique: its find HTML/tex\
|
|
483
|
+
t must be specific enough to match exactly one location in each target block or the entire call fails without changing the document. Use occurrence=all only when every exact occurrence should change. \
|
|
484
|
+
Omit no-op replacements where find and replace are identical.",inputSchema:{additionalProperties:!1,properties:{id:{description:"Target block ID. May be omitted only when every non-empty find uniquely\
|
|
485
|
+
identifies one loaded block, or when search_result_id is used.",type:"string"},replacements:{description:"Ordered replacement operations. Use one item for one edit and multiple items to batch edits i\
|
|
486
|
+
n the same block.",items:{additionalProperties:!1,properties:{comment:{description:"Optional comment explaining this operation. It is attached separately to every resulting suggestion from this operat\
|
|
487
|
+
ion, including every match when occurrence=all. Prefer this over a separate leave_comment when the feedback explains the suggested edit.",type:"string"},find:{description:"Exact text to find; HTML all\
|
|
488
|
+
owed for formatted targets. With occurrence=unique or when occurrence is omitted, include enough surrounding context to match exactly one location.",type:"string"},occurrence:{description:"unique (def\
|
|
489
|
+
ault when omitted) requires exactly one match; all replaces every exact match.",enum:["unique","all"],type:"string"},replace:{description:"Replacement text; HTML allowed for formatting changes. Must d\
|
|
490
|
+
iffer from find unless the replacement HTML creates a real formatting change.",type:"string"}},required:["find","replace"],type:"object"},maxItems:50,minItems:1,type:"array"},search_result_id:{description:"\
|
|
491
|
+
Request-scoped ID returned by search_document for the current document. Applies this operation to every block in the full unpaginated result set. Use instead of id or ids. Rerun search_document if the\
|
|
492
|
+
reference is unavailable or stale.",type:"string"}},required:["replacements"],type:"object"}},{name:"leave_comment",description:"Leave granular review feedback on the current document without changin\
|
|
493
|
+
g its text. Prefer this for substantive passage-specific critique, feedback, annotations, issues, or improvements instead of putting that feedback in a long chat response. Two modes. To START a thread\
|
|
494
|
+
: target one block with id and exactly one anchor form — unique exact text for a short range, start/end boundary text for a longer range without reproducing it, or the whole block for structural/empty\
|
|
495
|
+
content. To REPLY to a thread that already exists: pass reply_to_comment_id (a <comment-thread> id from loaded document content) and comment, with no id and no anchor. Existing threads are visible as\
|
|
496
|
+
<comment-thread> elements in loaded document content; when text already carries one, reply to it rather than starting a second thread that repeats the same point.",inputSchema:{additionalProperties:!1,
|
|
497
|
+
properties:{acknowledge_existing_thread_ids:{description:"Only for a NEW thread that deliberately overlaps existing unresolved threads: list their ids to confirm you read them and are raising a genuin\
|
|
498
|
+
ely different point. Without this, a new thread overlapping an existing one is rejected. Do not use it to restate a point an existing thread already makes — reply to that thread instead.",items:{type:"\
|
|
499
|
+
string"},type:"array"},anchor:{description:"Exactly one single-block anchor. Required for a new thread; omit when replying.",oneOf:[{additionalProperties:!1,properties:{text:{description:"Exact text o\
|
|
500
|
+
r HTML fragment that identifies exactly one occurrence in the block. When words repeat with different formatting, include the formatting, for example <b>claim</b> for the bold occurrence or <i>claim</\
|
|
501
|
+
i> for the italic occurrence. Include only the text to be commented on.",type:"string"}},required:["text"],type:"object"},{additionalProperties:!1,properties:{end_text:{description:"Exact text or HTML\
|
|
502
|
+
fragment at the end of the range. This boundary is included in the comment; do not use surrounding separators unless they should also be commented on.",type:"string"},start_text:{description:"Exact t\
|
|
503
|
+
ext or HTML fragment at the beginning of the range. This boundary is included in the comment; do not use surrounding separators unless they should also be commented on.",type:"string"}},required:["sta\
|
|
504
|
+
rt_text","end_text"],type:"object"},{additionalProperties:!1,properties:{whole_block:{const:!0,description:"Anchor the comment to the entire block.",type:"boolean"}},required:["whole_block"],type:"obj\
|
|
505
|
+
ect"}]},comment:{description:"Comment body.",type:"string"},id:{description:"Target block ID for a NEW thread. The block must be present in loaded document context. Omit when replying.",type:"string"},
|
|
506
|
+
reply_to_comment_id:{description:"Reply to an existing thread instead of starting a new one: any comment id in that thread (the reply attaches to the thread root). A reply inherits the thread's anchor\
|
|
507
|
+
, so omit id and anchor when replying.",type:"string"}},required:["comment"],type:"object"}},{name:"insert_table_row",description:"Insert a new row into an existing table. Prefer referenceRowId from t\
|
|
508
|
+
he visible <tr id> for a named row; this remains stable when earlier rows are inserted. Use position=before for above/before that row and after for below/after. Only call this when the target <table> \
|
|
509
|
+
block is visible in the loaded document content; read the table's blocks first if it is not loaded.",inputSchema:{additionalProperties:!1,properties:{content:{description:"HTML indexed by grid column \
|
|
510
|
+
(0-based); use an empty string as a placeholder for a position covered by a merged cell, or an empty array to insert empty cells. Nonempty content at covered positions and entries beyond the table dim\
|
|
511
|
+
ensions are rejected without changing the table.",items:{type:"string"},type:"array"},position:{description:"Whether to insert before or after the reference row",enum:["before","after"],type:"string"},
|
|
512
|
+
referenceIndex:{description:"Optional 0-based row index, counting header and empty rows. Required only without referenceRowId. If both are supplied, they must identify the same current row.",type:"int\
|
|
513
|
+
eger"},referenceRowId:{description:"Preferred stable row ID from <tr id> in the loaded table. Supply this or referenceIndex.",type:"string"},tableId:{description:"The table block ID",type:"string"}},required:[
|
|
514
|
+
"tableId","position","content"],type:"object"}},{name:"remove_table_rows",description:"Remove one or more rows from an existing table in one call. Identify rows by rowIds, the stable <tr id>/row_id va\
|
|
515
|
+
lues from the table you read; they stay valid after earlier rows are inserted or removed, so remove several rows in one call or consecutive calls without re-reading. Pass all rows to remove together w\
|
|
516
|
+
hen you know them. Every cell of each row must have been fully read. rowIndices (0-based, counting header rows) is a fallback only for rows read at the current table layout. An unknown, duplicate or u\
|
|
517
|
+
nread row rejects the whole call with no changes. Only call this when the target <table> block is visible in the loaded document content; read the table's blocks first if it is not loaded.",inputSchema:{
|
|
518
|
+
additionalProperties:!1,properties:{rowIds:{description:"Stable row IDs (<tr id> / row_id) of the rows to remove. Preferred.",items:{type:"string"},minItems:1,type:"array"},rowIndices:{description:"Fa\
|
|
519
|
+
llback 0-based row indexes, used only without rowIds and only for rows read at the current table layout.",items:{type:"integer"},minItems:1,type:"array"},tableId:{description:"The table block ID",type:"\
|
|
520
|
+
string"}},required:["tableId"],type:"object"}},{name:"insert_table_column",description:"Insert a new column into an existing table. Only call this when the target <table> block is visible in the loade\
|
|
521
|
+
d document content; read the table's blocks first if it is not loaded.",inputSchema:{additionalProperties:!1,properties:{content:{description:"HTML indexed by grid row (0-based); use an empty string a\
|
|
522
|
+
s a placeholder for a position covered by a merged cell, or an empty array to insert empty cells. Nonempty content at covered positions and entries beyond the table dimensions are rejected without cha\
|
|
523
|
+
nging the table.",items:{type:"string"},type:"array"},position:{description:"Whether to insert before or after the reference column",enum:["before","after"],type:"string"},referenceIndex:{description:"\
|
|
524
|
+
The column index to insert relative to (0-based)",type:"integer"},tableId:{description:"The table block ID",type:"string"}},required:["tableId","referenceIndex","position","content"],type:"object"}},{
|
|
525
|
+
name:"remove_table_column",description:"Remove a column from an existing table. Only call this when the target <table> block is visible in the loaded document content; read the table's blocks first if\
|
|
526
|
+
it is not loaded.",inputSchema:{additionalProperties:!1,properties:{columnIndex:{description:"The index of the column to remove (0-based)",type:"integer"},tableId:{description:"The table block ID",type:"\
|
|
527
|
+
string"}},required:["tableId","columnIndex"],type:"object"}},{name:"edit_table_cells",description:"Set the plain text of up to 50 table cells in one call, addressed by table_id, stable row_id and 0-ba\
|
|
528
|
+
sed logical column. Every target cell must be editable now: fully delivered by read_table or, in agent conversations, listed in editable_now of the table's newest <table_descriptor> for the current re\
|
|
529
|
+
quest (complete table seeds and full cell snapshots qualify). Edit listed cells directly without a redundant read_table call; summaries and partial cell_text windows do not count. text is literal exac\
|
|
530
|
+
t text, never HTML: values such as 007, 1e5, <b> and tabs/newlines are kept verbatim. Supports cells holding one plain-text paragraph; table and cell formatting is preserved. Cells with rich or multi-\
|
|
531
|
+
block content (images, lists, nested tables) are refused with a route to the existing rich editing tools. mode=fill_if_empty writes only cells that are still empty and reports every skipped non-empty \
|
|
532
|
+
cell; mode=replace overwrites. An unknown, duplicate, covered (merged non-anchor), cross-table or geometry-shifted target, or a stale replace target, rejects the whole batch with every invalid item li\
|
|
533
|
+
sted and no changes. Each cell is an individually reviewable suggestion and one successful call is one undo step. Collect targets from delivered table contents and batch up to 50 edits per call; never\
|
|
534
|
+
send one call per cell when a batch is possible. Serialized arguments are limited to 32 KiB.",inputSchema:{additionalProperties:!1,properties:{cells:{description:"Cell edits. Each (row_id, column) ma\
|
|
535
|
+
y appear once.",items:{additionalProperties:!1,properties:{column:{description:"0-based logical column of the cell's anchor.",minimum:0,type:"integer"},row_id:{description:"Stable row ID (<tr id>).",type:"\
|
|
536
|
+
string"},text:{description:"Exact literal cell text. Not HTML.",type:"string"}},required:["row_id","column","text"],type:"object"},maxItems:50,minItems:1,type:"array"},mode:{description:"fill_if_empty\
|
|
537
|
+
skips and reports cells that are no longer empty; replace overwrites the delivered cell text.",enum:["fill_if_empty","replace"],type:"string"},table_id:{description:"Table block ID in the current doc\
|
|
538
|
+
ument.",type:"string"}},required:["table_id","mode","cells"],type:"object"}}],os=new Map(wo.map(e=>[e.name,e.inputSchema]));function Ht(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function ko(e,t){
|
|
539
|
+
return Object.prototype.hasOwnProperty.call(e,t)}function rs(e,t){switch(t){case"null":return e===null;case"object":return Ht(e);case"array":return Array.isArray(e);case"string":return typeof e=="stri\
|
|
540
|
+
ng";case"number":return typeof e=="number"&&Number.isFinite(e);case"integer":return typeof e=="number"&&Number.isInteger(e);case"boolean":return typeof e=="boolean";default:return!0}}function Fe(e,t){
|
|
541
|
+
return!(e.const!==void 0&&!Object.is(e.const,t)||e.enum&&!e.enum.some(n=>Object.is(n,t))||e.type&&!(Array.isArray(e.type)?e.type:[e.type]).some(n=>rs(t,n))||e.allOf?.some(n=>!Fe(n,t))||e.anyOf&&!e.anyOf.
|
|
542
|
+
some(n=>Fe(n,t))||e.oneOf&&e.oneOf.filter(n=>Fe(n,t)).length!==1||e.not&&Fe(e.not,t)||Ht(t)&&e.required&&!e.required.every(n=>ko(t,n)))}function rt(e,t){let n=e;if(Array.isArray(n)&&t.items)n=n.map(o=>rt(
|
|
543
|
+
o,t.items));else if(Ht(n)&&t.properties){const o=new Set(t.required??[]),r={...n};for(const[i,a]of Object.entries(t.properties))if(ko(r,i)){if(r[i]===null&&!o.has(i)&&!Fe(a,null)){delete r[i];continue}
|
|
544
|
+
r[i]=rt(r[i],a)}n=r}for(const o of t.allOf??[])n=rt(n,o);for(const o of[t.anyOf,t.oneOf]){const r=o?.filter(i=>Fe(i,n));r?.length===1&&(n=rt(n,r[0]))}return n}function is(e,t){const n=os.get(e);return n?
|
|
545
|
+
rt(t,n):t}const ss="This request is non-interactive. Continue the supported work using the supplied context and reasonable assumptions. Explain material gaps in the final response or permitted comment\
|
|
546
|
+
s; do not invent facts or ask for clarification or approval.",as=new Set(["read_table","create_plan","update_plan","read_blocks","read_blocks_from_index","read_specific_blocks","search_document","find\
|
|
547
|
+
_highlights","measure_document","measure_blocks","list_documents","search_documents","get_attachment","view_image","render_document_pages","set_status","request_user_input","end_agent_run","finish_res\
|
|
548
|
+
ponse","ready_for_verification"]),ls=new Set(["missed_requirements","verification_passed"]);function vo(e){const t=e.trim();return t==="remove_blocks"?"remove_block":t==="remove_table_rows"?"remove_ta\
|
|
549
|
+
ble_row":t}function cs(e){return Array.from(new Set(e.map(vo).filter(Boolean)))}function ds(e,t){const n=vo(t);return ls.has(n)?{code:"agent_tool_not_allowed",message:"This legacy verification tool is\
|
|
550
|
+
unavailable. Continue supported work or finish with end_agent_run."}:n==="request_user_input"&&e.interaction==="best_effort"?{code:"agent_interaction_not_allowed",message:ss}:e.allowedTools!=null&&!cs(
|
|
551
|
+
e.allowedTools).includes(n)?{code:"agent_tool_not_allowed",message:"This tool is outside the host's execution allowlist. Continue using permitted tools or finish with the best supported response."}:Bt.
|
|
552
|
+
has(n)?e.documentAccess==="edit"||e.documentAccess==="comment"&&n==="leave_comment"?null:{code:"agent_document_access_denied",message:"This request does not permit this document mutation. Continue wit\
|
|
553
|
+
hin the granted document access and explain any work that could not be completed."}:as.has(n)?null:{code:"agent_tool_not_allowed",message:"This tool has no execution-policy classification and cannot r\
|
|
554
|
+
un. Continue using permitted tools."}}const Io="no_new_read_context",ze={scanDocumentFontFamily:!1};function Je(e){return e.getAgentAuthorName?.()?.trim()||yr}const xo=2,us=48,ms=.4,Me=10,hs=100,ps=100,
|
|
555
|
+
We=48e3,Be="out_of_context_edit",De="document_state_changed",So="table_batch_rejected",gs="duplicate_comment_anchor",fs="one_read_search_per_turn",Gt="terminal_tool_requires_turn_two_continuation",$o="\
|
|
556
|
+
terminal_response_status_only",bs="end_agent_run",_s="finish_response",ys="ready_for_verification",ws=new Set(["read_blocks","read_blocks_from_index","read_specific_blocks","search_document","search_d\
|
|
557
|
+
ocuments","find_highlights","render_document_pages"]);function ks(e){return e===bs||e===_s}function Co(e){return e.replace(/<status\b[^>]*>[\s\S]*?<\/status>/gi,"").trim().length===0}const Kt="https:/\
|
|
558
|
+
/app-api.revise-sdk.invalid";function vs(e){if(e&&typeof e=="object"&&!Array.isArray(e))return e;if(typeof e!="string")return null;const t=e.trim();if(!t)return null;if(!t.startsWith("{")||!t.endsWith(
|
|
559
|
+
"}"))return{text:t};try{const n=JSON.parse(t);return n&&typeof n=="object"&&!Array.isArray(n)?n:null}catch{return null}}function Is(e){const t=Xe(e.doc,e.requestedBlockId);if(!t||!Array.isArray(t.children))
|
|
560
|
+
return null;const n=[],o=r=>{if(!(!r||typeof r!="object")&&(r.id!==e.requestedBlockId&&typeof r.id=="string"&&ir(r)&&n.push({blockId:r.id,text:Le(r),html:bn(e.anchorText)?kn(r):void 0}),Array.isArray(
|
|
561
|
+
r.children)))for(const i of r.children)o(i)};return o(t),wn(n,e.anchorText)}function xs(e){return!e.loadedBlockIds||e.loadedBlockIds.size===0?null:wn(nr(e.doc).filter(t=>t.blockId!==e.requestedBlockId&&
|
|
562
|
+
or(t,e.loadedBlockIds)).map(t=>({...t,html:bn(e.anchorText)?kn(Xe(e.doc,t.blockId)):void 0})),e.anchorText)}function Ss(e,t,n,o,r,i,a){if(a.hasBlockId||a.hasAnchor)return v(e,"A reply inherits its thr\
|
|
563
|
+
ead's anchor: pass reply_to_comment_id and comment alone, without id or anchor.");const l=er(o,r);if(!l)return v(e,`Comment '${r}' was not found. Reply only to a <comment-thread> id you can see in loa\
|
|
564
|
+
ded document content.`,De);if(l.resolved===!0)return v(e,`Comment thread '${l.id}' is resolved. Leave a new anchored comment instead of replying to a settled thread.`);const c=n.getDocumentMutator(),d=tr(
|
|
565
|
+
o,c,l.id,i,{author:Je(t),authorType:"ai",agentName:Je(t),...t.getAgentModel?{agentModel:t.getAgentModel()}:{}}).commentId;if(!d)return v(e,`Could not reply to comment thread '${l.id}'.`);const u=$s(o,
|
|
566
|
+
l);return u&&t.toolState.editedBlockIds.add(u),t.turnState.hasMutatedSinceLastRead=!0,t.metrics?.count("agent.comment.reply",1),H(e,`Replied ${d} in comment thread ${l.id}.`,void 0,void 0,JSON.stringify(
|
|
567
|
+
{commentId:d,threadId:l.id,mode:"reply",...u?{blockId:u}:{}}))}function $s(e,t){if(t.anchorBlockId){const n=Ae(e,t.anchorBlockId);return n>=0?e.children[n]?.id??t.anchorBlockId:t.anchorBlockId}for(const n of e.
|
|
568
|
+
children)if(n.id&&rr(n).has(t.id))return n.id;return null}function Cs(e,t,n,o){const r=e.arguments??{};let i=typeof r.id=="string"?r.id.trim():"";const a=typeof r.comment=="string"?r.comment.trim():"";
|
|
569
|
+
let l=vs(r.anchor);const c=typeof r.reply_to_comment_id=="string"?r.reply_to_comment_id.trim():"",d=new Set((Array.isArray(r.acknowledge_existing_thread_ids)?r.acknowledge_existing_thread_ids:[]).filter(
|
|
570
|
+
q=>typeof q=="string").map(q=>q.trim()).filter(Boolean));if(!a)return v(e,"leave_comment requires a non-empty comment.");if(c)return Ss(e,t,n,o,c,a,{hasBlockId:!!i,hasAnchor:!!l});if(!i)return v(e,"le\
|
|
571
|
+
ave_comment requires id.");if(!l)return v(e,"leave_comment requires an anchor.");let u=Xe(o,i),f=null;const b=Vt(t.turnState),y=typeof l.text=="string"&&l.text.length>0?l.text:null;if(y&&u){const q=Is(
|
|
572
|
+
{doc:o,requestedBlockId:i,anchorText:y});q&&(i=q,u=Xe(o,i))}if(y&&(!u||qt(u,y).length===0)){const q=xs({doc:o,requestedBlockId:i,anchorText:y,loadedBlockIds:b});q&&q!==i&&(f=i,i=q,u=Xe(o,i))}if(!u)return v(
|
|
573
|
+
e,`Block '${i}' was not found.`,De);const N=Ae(o,i),L=N>=0?o.children[N]?.id:void 0;if(!$t(o,i,b))return v(e,`leave_comment targets block '${i}', which is outside the loaded <document_content> context\
|
|
574
|
+
. Read that block first, then retry.`,Be);let O=null;if(y){const q=[...t.getConversationHistory?.()??[]].reverse().find(z=>z.role==="user")?.content,J=typeof q=="string"?ei(u,y,q):null;J&&(O=y,l={...l,
|
|
575
|
+
text:J})}const T=n.getDocumentMutator(),D={author:Je(t),authorType:"ai",agentName:Je(t),...t.getAgentModel?{agentModel:t.getAgentModel()}:{}},A=Yo(n.getWorkingDocument(),o,T,i,a,l,D,Array.from(d));if(!A.
|
|
576
|
+
success)return A.overlappingThreadIds?.length&&t.metrics?.count("agent.comment.overlap_blocked",1),v(e,A.error??"Could not attach comment.",A.overlappingThreadIds?.length?gs:A.errorCode);const M=A.commentId,
|
|
577
|
+
I=l.whole_block===!0,C=A.range;return d.size&&t.metrics?.count("agent.comment.overlap_acknowledged",1),t.toolState.editedBlockIds.add(L??i),t.turnState.hasMutatedSinceLastRead=!0,H(e,(f?`Left comment ${M}\
|
|
578
|
+
on block ${i}: the anchor text was not in block ${f}, and ${i} is the only loaded block that contains it.`:`Left comment ${M} on block ${i}.`)+(O?` The anchor ${JSON.stringify(O)} covered only part o\
|
|
579
|
+
f the phrase the user quoted, so the comment is anchored to the full phrase ${JSON.stringify(l.text)}.`:""),void 0,void 0,JSON.stringify({commentId:M,blockId:i,...f?{requestedBlockId:f}:{},anchor:I?{wholeBlock:!0}:
|
|
580
|
+
C,...O?{requestedAnchorText:O,anchoredText:l.text}:{}}))}function As(e,t){const n=re(e,String(t.tableId??""));if(n?.type!=="table")return`Table ${String(t.tableId)} not found. Read the document and us\
|
|
581
|
+
e a current table ID.`;const o=_n(n,t);if("error"in o)return o.error;const r=JSON.stringify(o.rowIds);return o.byId?`Not every cell of rows ${r} was fully read, or one changed since it was read. Read \
|
|
582
|
+
those rows with read_table (row_ids ${r}), then retry. No rows were removed.`:"Row indexes may have shifted since these rows were read. Retry with rowIds (the stable row IDs from the table you read) i\
|
|
583
|
+
nstead of rowIndices, or read the rows again. No rows were removed."}function v(e,t,n){return{toolCall:e,success:!1,error:t,...n?{errorCode:n}:{}}}function Ts(e){return e&&ns(new Error(e)).kind==="doc\
|
|
584
|
+
ument_state"?De:void 0}function H(e,t,n,o,r){return{toolCall:e,success:!0,agentFeedback:t,...n?{imageAttachment:n}:{},...o?{nonMeaningful:!0}:{},...r?{toolOutput:r}:{}}}function qs(e){return e.tool||e.
|
|
585
|
+
name}function Ds(e){if(!e||typeof e!="object")return null;const t=typeof e.status=="string"?e.status:typeof e.message=="string"?e.message:null;if(!t)return null;const n=t.replace(/[\s\n]+/g," ").trim();
|
|
586
|
+
return n.length>0?n:null}function Ps(e){if(!e||typeof e!="object")return null;const t=typeof e.context_notes=="string"?e.context_notes:null;if(!t)return null;const n=t.trim();return n.length>0?n:null}
|
|
587
|
+
function Ao(e,t){for(const n of e){if(n.type==="image"&&n.id===t)return{src:n.src,sourceUrl:n.sourceUrl,alt:n.alt,width:n.width,height:n.height};if(Array.isArray(n.children)&&n.children.length>0){const o=Ao(
|
|
588
|
+
n.children,t);if(o)return o}}return null}function He(e){if(!e||typeof e!="object")return[];const t=e,n=[],o=new Set,r=a=>{if(typeof a!="string")return;const l=a.trim();!l||o.has(l)||(o.add(l),n.push(l))};
|
|
589
|
+
if(r(t.id),r(t.referenceId),r(t.reference_id),r(t.firstId),r(t.secondId),r(t.from_id),r(t.block_id),r(t.tableId),r(t.referenceRowId),r(t.after_block_id),Array.isArray(t.id))for(const a of t.id)r(a);if(Array.
|
|
590
|
+
isArray(t.block_ids))for(const a of t.block_ids)r(a);Array.isArray(t.ids)&&t.ids.forEach(r);const i=Array.isArray(t.selectors)?t.selectors:[t.selectors];for(const a of i)if(typeof a=="string")for(const l of a.
|
|
591
|
+
split(",")){const c=l.trim().match(/^#([A-Za-z0-9_-]+)(?=$|[\s:>~+])/);c&&r(c[1])}if(t.selector&&typeof t.selector=="object"&&He(t.selector).forEach(r),Array.isArray(t.replacements))for(const a of t.replacements)
|
|
592
|
+
He(a).forEach(r);return n}function To(e){const t=He(e.arguments),n=t.length===0?"the target block":t.length===1?`block ${t[0]}`:`${t.length} blocks`;if(e.name==="set_block_attribute"||e.name==="style_\
|
|
593
|
+
blocks"){const o=e.arguments&&typeof e.arguments=="object"?e.arguments:{},r=typeof o.attribute=="string"&&o.attribute.trim().length>0?o.attribute.trim():"attribute";return(typeof o.operation=="string"&&
|
|
594
|
+
o.operation.trim().length>0?o.operation.trim():"set")==="remove"?`No document mutation occurred; ${r} was already removed on ${n}.`:`No document mutation occurred; ${r} was already set on ${n}.`}return e.
|
|
595
|
+
name==="clear_formatting"?`No document mutation occurred; formatting was already clear on ${n}.`:e.name==="replace_block"?`No document mutation occurred; replacing ${n} produced no document change. Th\
|
|
596
|
+
is result does not prove that the requested content is present; verify the current block before deciding no change is needed.`:e.name==="replace"||e.name==="replace_all"||e.name==="replace_many"?`No d\
|
|
597
|
+
ocument mutation occurred; the replacement on ${n} produced no document change. This result does not prove that the requested content is present; verify the current block before deciding no change is \
|
|
598
|
+
needed.`:"No document mutation occurred; the document already matched the requested update."}function Rs(e){const t=qs(e);return{id:e.id,name:t,arguments:is(t,e.arguments)}}function Ns(e){return e.replace(
|
|
599
|
+
/<[^>]*>/g," ").replace(/ /gi," ").replace(/&/gi,"&").replace(/</gi,"<").replace(/>/gi,">").replace(/"/gi,'"').replace(/'|'/gi,"'").replace(/\s+/g," ").trim()}function qo(e){
|
|
600
|
+
return e.replace(/\s+/g," ").trim()}function Vt(e){const t=new Set;for(const n of[e.lastReadBlockIds,e.requestedBlockIds])if(n)for(const o of n)t.add(o);for(const n of e.docContextLedger?.delivered.keys()??
|
|
601
|
+
[])t.add(n);return t.size>0?t:null}function Ms(e){const t=[],n=new Set;for(const o of e)for(const r of He(o.arguments))n.has(r)||(n.add(r),t.push(r));return t}function Do(e,t){const n=new Set(t),o=new Set(
|
|
602
|
+
t),r=i=>{const a="id"in i?i.id:void 0;let l=!!(a&&n.has(a));if("children"in i)for(const c of i.children)r(c)&&(l=!0);return l&&a&&o.add(a),l};for(const i of[...e.children,...e.chrome??[],...e.notes??[]])
|
|
603
|
+
r(i);return o}function Bs(e,t){if(e.length===1)return`block ${e[0]}`;if(e.length>1){const n=e.slice(0,4).join(", "),o=e.length>4?` (+${e.length-4} more)`:"";return`blocks ${n}${o}`}return t?`block ${t}`:
|
|
604
|
+
"the target block"}function Os(e){if(e.length===0)return"";const t=Array.from(new Set(e.map(r=>`${r.fromBlockId}->${r.toBlockId}`))).map(r=>{const[i,a]=r.split("->");return`${i} -> ${a}`}),n=t.slice(0,
|
|
605
|
+
4).join(", "),o=t.length>4?` (+${t.length-4} more)`:"";return`Retargeted ${e.length} replacement ${e.length===1?"operation":"operations"} to the unique loaded-context block match${e.length===1?"":"es"}\
|
|
606
|
+
: ${n}${o}.`}function js(e,t,n){if(typeof e!="number"||!Number.isFinite(e))return t;const o=Math.floor(e);return o<=0?t:Math.min(o,n)}function it(e,t){if(typeof e!="number"||!Number.isFinite(e))return t;
|
|
607
|
+
const n=Math.floor(e);return Math.max(0,n)}function Po(e,t,n,o,r,i){let a=[...i?.targetBlockIds??o];if(a.length===0&&e.arguments&&typeof e.arguments=="object"&&typeof e.arguments.id=="string"&&(a=[e.arguments.
|
|
608
|
+
id.trim()].filter(Boolean)),a.length===1&&e.name==="remove_block"&&e.arguments&&typeof e.arguments=="object"){const I=a[0],C=js(e.arguments.count,1,50),q=Ae(t,I);q!==-1&&C>1&&(a=t.children.slice(q,q+C).
|
|
609
|
+
map(J=>J.id).filter(J=>typeof J=="string"&&J.length>0))}const l=e.arguments&&typeof e.arguments=="object"&&typeof e.arguments.search_result_id=="string"?e.arguments.search_result_id:null,c=l!==null||a.
|
|
610
|
+
length>Me,d=!c&&e.name!=="replace"&&e.name!=="replace_many"&&e.name!=="replace_all"&&a.length>0?a.flatMap(I=>{const C=re(t,I);if(!C)return[];const q=e.arguments??{};if(C.type==="table"&&/^(insert|remove)_table_(row|column)$/.
|
|
611
|
+
test(e.name)){if(e.name.endsWith("_row")){const j=typeof q.referenceRowId=="string"?C.children.find(oe=>oe.id===q.referenceRowId):C.children[Number(q.rowIndex??q.referenceIndex)];return j?[{id:j.id,html:ae.
|
|
612
|
+
renderTableRow(C,j,t)}]:[]}const J=Ce(C),z=Number(q.columnIndex??q.referenceIndex);return J.cells.filter(j=>j.col<=z&&j.col+j.colSpan>z).map(({cell:j})=>({id:j.id,html:ae.renderSubtree(j,t)}))}if(C.type===
|
|
613
|
+
"table"&&C.id!==I){const J=C.children.find(z=>z.id===I);if(J)return[{id:I,html:ae.renderTableRow(C,J,t)}]}return[{id:I,html:ae.renderSubtree(C,t)}]}):[],u=[],f=[];let b=0;for(const I of d)b+I.html.length+
|
|
614
|
+
1>8e3?f.push(I.id):(u.push(I.html),b+=I.html.length+1);const y=u.join(`
|
|
615
|
+
`),N=a.filter(I=>re(t,I)&&!re(n,I)),L=i?.changedBlockIds??a.filter(I=>{const C=re(t,I),q=re(n,I);return JSON.stringify(C??null)!==JSON.stringify(q??null)}),O=new Set,T=I=>{for(const C of I)"id"in C&&C.
|
|
616
|
+
id&&O.add(C.id),"children"in C&&T(C.children)};T(_e(t));const D=[],A=I=>{for(const C of I)"id"in C&&C.id&&!O.has(C.id)?D.push(C.id):"children"in C&&A(C.children)};A(_e(n));const M=(I,C,q=!1)=>c||q&&C.
|
|
617
|
+
length>Me?{[`${I}_sample`]:C.slice(0,Me),[`${I}_omitted_count`]:Math.max(0,C.length-Me)}:{[I]:C};return JSON.stringify({tool:e.name,...l?{target_reference:l}:{},...r?{summary:r}:{},...i?{style_outcome:i.
|
|
618
|
+
outcome,attribute_effects:i.attributes.map(I=>({name:I.name,applied_target_count:I.appliedBlockIds.length,skipped_target_count:new Set(I.skipped.map(C=>C.blockId)).size,...M("applied_block_ids",I.appliedBlockIds,
|
|
619
|
+
!0),skipped:I.skipped.slice(0,Me),skipped_omitted_count:Math.max(0,I.skipped.length-Me)}))}:{},effect:{...i?M("affected_block_ids",i.affectedBlockIds,!0):{},requested_target_count:a.length,changed_target_count:L.
|
|
620
|
+
length,removed_target_count:N.length,inserted_block_count:D.length,...M("target_block_ids",a),...M("changed_block_ids",L),...M("removed_block_ids",N),...M("inserted_block_ids",D),top_level_blocks_before:_e(
|
|
621
|
+
t).length,top_level_blocks_after:_e(n).length},...!c&&(y.trim()||f.length)?{before_block:y,...f.length?{before_block_truncated:!0,before_block_omitted_ids:f.slice(0,20),before_block_omitted_count:f.length,
|
|
622
|
+
before_block_recovery:"This is a partial lookback, not a complete replacement source. For pending edits use rollback_agent_suggestions with the appropriate request/turn, then reread. Accepted content \
|
|
623
|
+
requires historical edit evidence; never reconstruct it from this partial snapshot."}:{}}:{}})}function _e(e){return[...e.children,...e.notes??[]]}function Xt(e,t){return ae.extractSpecificBlocks(e,[t],
|
|
624
|
+
void 0,ze).foundBlocks[0]?.blockIndex??-1}function Es(e){return`(${e} ${e===1?"block":"blocks"} omitted...)`}function Qt(e,t){const n=_e(e)[t];return n?.id?ae.extractSpecificBlocks(e,[n.id],void 0,ze).
|
|
625
|
+
foundBlocks[0]??null:null}function xt(e){if(e.length===0)return 0;let t=`Showing ${e.length} block(s):
|
|
626
|
+
|
|
627
|
+
`.length+e[0].html.length;for(let n=1;n<e.length;n+=1){const o=e[n-1],r=e[n],i=r.blockIndex-o.blockIndex-1;i>0&&(t+=1+Es(i).length),t+=1+r.html.length}return t}function Ro(e){const{doc:t,startIndex:n,
|
|
628
|
+
maxTokens:o}=e,r=[];let i=0,a=n-1,l=!1;for(let c=n;c<_e(t).length;c+=1){const d=Qt(t,c);if(!d)continue;const u=xt([...r,d]),f=u>o;if(f&&r.length>0){l=!0;break}if(r.push(d),i=u,a=d.blockIndex,f){l=!0;break}}
|
|
629
|
+
return{blockIds:r.map(c=>c.id),endIndex:a,estimatedTokens:i,reachedTokenBudget:l}}function Ls(e){const{doc:t,requestedBlockIds:n,maxTokens:o}=e,r=[],i=new Set,a=new Map,l=(b,y)=>(a.has(b)||a.set(b,Qt(
|
|
630
|
+
t,y)),a.get(b)??null),c=[];let d=0,u=!1,f=0;for(const b of n){const y=Xs(t,b);if(!y){f+=1;continue}if(i.has(y.topLevelBlockId))continue;const N=l(y.topLevelBlockId,y.topLevelIndex);if(!N){f+=1;continue}
|
|
631
|
+
const L=xt([...c,N]),O=L>o;if(O&&r.length>0){u=!0;break}if(r.push(y.topLevelBlockId),i.add(y.topLevelBlockId),c.push(N),d=L,O){u=!0;break}}return{blockIds:r,estimatedTokens:d,reachedTokenBudget:u,missingRequestedBlocks:f}}
|
|
632
|
+
function No(e){const{doc:t,results:n,pageSize:o,maxTokens:r}=e;if(n.length===0)return[];const i=new Map,a=b=>(i.has(b.blockId)||i.set(b.blockId,Qt(t,b.blockIndex)),i.get(b.blockId)??null),l=[];let c=[],
|
|
633
|
+
d=[],u=0;const f=b=>{c.length!==0&&(l.push({results:c,startResultIndex:u,endResultIndexExclusive:b,estimatedTokens:xt(d)}),c=[],d=[])};for(let b=0;b<n.length;b+=1){const y=n[b],N=a(y);if(!N)continue;c.
|
|
634
|
+
length===0&&(u=b);const L=xt([...d,N]),O=c.length>=o,T=L>r;c.length>0&&(O||T)&&(f(b),u=b),c=[...c,y],d=[...d,N]}return f(n.length),l}function Mo(e){if(e.length===0)return[];const t=[...e].sort((i,a)=>i-
|
|
635
|
+
a),n=[];let o=t[0],r=t[0];for(let i=1;i<t.length;i+=1){const a=t[i];if(a<=r+1){r=a;continue}n.push({start:o,end:r}),o=a,r=a}return n.push({start:o,end:r}),n}function Zt(e,t){const n=new Set;for(const o of t){
|
|
636
|
+
const r=Xt(e,o);r!==-1&&n.add(r)}return Array.from(n).sort((o,r)=>o-r)}function st(e,t){const n=Ye(t,e.toolState.tableContext,e.turnState.requestedBlockIds??new Set),o=Zt(t,n),r=Mo(o),i=o.length,a=!e.
|
|
637
|
+
toolState.tableContext?.scopedTableIds?.some(l=>!n.has(l))&&(e.toolState.everReadFullDocument||_e(t).length>0&&i>=_e(t).length);return{requestedBlockCount:i,readBlocksThisTurn:e.turnState.readBudgetBlockIds?.
|
|
638
|
+
size??0,readTokenBudgetMax:We,requestedRanges:r,fullDocumentLoaded:a}}function at(e){return JSON.stringify({kind:"read_context",tool:e.tool,loaded:e.loaded,next:e.next??null,endOfDocument:e.endOfDocument,
|
|
639
|
+
coverage:e.coverage})}function Bo(e){return JSON.stringify({kind:"search_context",tool:e.tool,...e.queries?{queries:e.queries}:{},...e.color?{color:e.color}:{},totalMatches:e.totalMatches,...e.searchResultId?
|
|
640
|
+
{search_result_id:e.searchResultId}:{},page:{current:e.currentPage,total:e.totalPages,startResult:e.pageStart+1,endResult:e.pageEnd},nextPage:e.nextPage,matches:e.pageResults.map(t=>({blockId:t.blockId,
|
|
641
|
+
blockIndex:t.blockIndex,...t.matchedQueries?{matchedQueries:t.matchedQueries}:{},...t.matchedColors?{matchedColors:t.matchedColors}:{}})),coverage:e.coverage})}function Us(e){return e==="account"||e===
|
|
642
|
+
"folder"?e:"current_folder"}function Ge(e){return e.getAuthToken?.().trim()??""}function Oo(e){return typeof e.document_id=="string"?e.document_id.trim():""}function jo(e){return e.replaceAll("-","").
|
|
643
|
+
toLowerCase()}function Ie(e,t){const n=Oo(e);if(!n)return"";const o=t.getCurrentDocumentId?.().trim()??"";return o&&jo(n)===jo(o)?"":n}async function Fs(e){const t=e.scope==="folder"?e.folderId:e.currentFolderId,
|
|
644
|
+
n=no({query:e.query,page:e.page+1,limit:10,currentFolderId:e.scope==="account"?void 0:t}),o=await fetch(`${Kt}/documents/search?${n.toString()}`,{headers:{Authorization:`Bearer ${e.token}`}});if(!o.ok)
|
|
645
|
+
throw new Error(`Document search failed with ${o.status}`);return oo(await o.json(),10)}async function zs(e){const t=no({includeFolders:!0,page:e.page+1,limit:e.limit,parentFolderId:e.parentFolderId}),
|
|
646
|
+
n=await fetch(`${Kt}/documents?${t.toString()}`,{headers:{Authorization:`Bearer ${e.token}`}});if(!n.ok)throw new Error(`Document listing failed with ${n.status}`);return oo(await n.json(),e.limit)}async function St(e){
|
|
647
|
+
const t=await fetch(`${Kt}/documents/${encodeURIComponent(e.documentId)}?includeTailUpdates=1&trackAccess=0`,{headers:{Authorization:`Bearer ${e.token}`}});if(!t.ok)throw new Error(`Document open fail\
|
|
648
|
+
ed with ${t.status}`);const n=await t.json(),o=Pi({content:n.content,yjsState:n.yjsState,yjsUpdates:n.yjsUpdates,source:`agent read document ${e.documentId}`})??{type:"doc",children:[]};return o.title=
|
|
649
|
+
n.title||o.title||"Untitled",{id:n.id||e.documentId,title:n.title||"Untitled",canonicalPath:n.canonicalPath,parentFolderId:n.parentFolderId??null,content:o}}function Js(e){return JSON.stringify({kind:"\
|
|
650
|
+
account_document_search",query:e.query,scope:e.scope,searchedCurrentFolder:e.searchedCurrentFolder,folderId:e.folderId??null,page:{current:e.page,total:e.totalPages},totalMatches:e.totalCount,results:e.
|
|
651
|
+
results.map(t=>({itemType:t.itemType==="folder"?"folder":"document",...t.itemType==="folder"?{folderId:t.id}:{documentId:t.id},title:t.title,canonicalPath:t.canonicalPath||`/${t.title||t.id}`,snippet:t.
|
|
652
|
+
snippet||"",href:t.itemType==="folder"?`/docs/folders/${t.id}`:`/docs/${t.id}`,parentFolderId:t.parentFolderId??null}))})}function Ws(e){return JSON.stringify({kind:"document_tree_listing",parentFolderId:e.
|
|
653
|
+
parentFolderId,page:{current:e.page,total:e.totalPages},totalItems:e.totalCount,hasMore:e.hasMore,items:e.items.map(t=>({type:t.itemType==="folder"?"folder":"document",id:t.id,title:t.title||t.name||"\
|
|
654
|
+
Untitled",name:t.name||t.title||"Untitled",canonicalPath:t.canonicalPath||`/${t.title||t.name||t.id}`,href:t.itemType==="folder"?`/docs?folder=${t.id}`:`/docs/${t.id}`,parentFolderId:t.parentFolderId??
|
|
655
|
+
null,childCount:typeof t.childCount=="number"?t.childCount:void 0,updatedAt:t.updatedAt}))})}function Yt(e){return{editable:!1,editInstructions:`Read-only source. Mutation tools only edit the active d\
|
|
656
|
+
ocument. To edit this source, give the user a clickable link to /docs/${e} and ask them to open it and continue there. Never use these block IDs to edit the active document.`}}function en(e){return JSON.
|
|
657
|
+
stringify({kind:"document_read",document:{documentId:e.documentId,title:e.title,canonicalPath:e.canonicalPath||`/${e.title}`,href:`/docs/${e.documentId}`,...Yt(e.documentId)},loaded:{startIndex:e.startIndex,
|
|
658
|
+
endIndex:e.endIndex,estimatedTokens:e.estimatedTokens},next:e.nextIndex===null?null:{index:e.nextIndex},endOfDocument:e.endOfDocument,documentContent:e.content})}function Eo(e,t){if(e==="search_docume\
|
|
659
|
+
nt"){const o=Array.isArray(t.queries)?t.queries.filter(i=>typeof i=="string"):[],r=typeof t.document_id=="string"&&t.document_id.trim().length>0?t.document_id.trim():null;return JSON.stringify({documentId:r,
|
|
660
|
+
queries:o})}const n=typeof t.color=="string"&&t.color.trim().length>0?t.color.trim().toLowerCase():null;return JSON.stringify({color:n})}function Hs(e){const t=new Map;for(const n of e)for(const o of n.
|
|
661
|
+
matchedColors??[])t.set(o,(t.get(o)??0)+1);return t.size===0?"":Array.from(t.entries()).sort((n,o)=>o[1]-n[1]||n[0].localeCompare(o[0])).map(([n,o])=>`${o} ${n}`).join(", ")}function Gs(e,t){let n=0;for(;n<
|
|
662
|
+
e.length&&n<t.length&&e[n]===t[n];)n+=1;let o=e.length-1,r=t.length-1;for(;o>=n&&r>=n&&e[o]===t[r];)o-=1,r-=1;const i=Math.max(0,o-n+1),a=Math.max(0,r-n+1);return Math.max(i,a)}function Ks(e,t){if(e.name!==
|
|
663
|
+
"replace_block"||!e.arguments||typeof e.arguments!="object")return null;const n=e.arguments.id,o=e.arguments.content,r=e.arguments.count;if(typeof n!="string"||typeof r=="number"&&Number.isFinite(r)&&
|
|
664
|
+
Math.floor(r)>1||!Array.isArray(o)||o.length!==1||typeof o[0]!="string")return null;const i=t.children.find(f=>f.id===n);if(!i)return null;const a=qo(Le(i)),l=qo(Ns(o[0]));if(!a||!l||a===l)return null;
|
|
665
|
+
const c=Gs(a,l),d=Math.max(a.length,l.length);if(d<=0)return null;const u=c/d;return c>us||u>ms?null:`WARNING: replace_block only changed a small span (~${c} chars, ${(u*100).toFixed(0)}% of block). P\
|
|
666
|
+
refer replace for typo, punctuation, and wording edits; reserve replace_block for full rewrites.`}function $t(e,t,n){if(!n||n.size===0)return!1;if(n.has(t))return!0;const o=ht(e,t);if(o&&n.has(o))return!0;
|
|
667
|
+
const r=Ae(e,t),i=r>=0?e.children[r]?.id:void 0;return typeof i=="string"&&n.has(i)}function Vs(e,t,n){if(e.name!=="replace_block"&&e.name!=="remove_block")return{toolCall:e};if(!e.arguments||typeof e.
|
|
668
|
+
arguments!="object")return{toolCall:e};const o=e.arguments.id;if(typeof o!="string"||o.trim().length===0)return{toolCall:e};const r=e.arguments.count;if(r!==void 0&&(typeof r!="number"||!Number.isFinite(
|
|
669
|
+
r)||Math.floor(r)<1))return{toolCall:e};const i=r===void 0?1:Math.floor(r);if(i<=1)return{toolCall:e};const a=vn(t,o),l=a&&"children"in a?lr(a,o):-1;if(!a||l===-1)return{toolCall:e};const c=e.name==="\
|
|
670
|
+
remove_block"?"remove_blocks":e.name,d=a.children[Math.min(l+i,a.children.length)-1]?.id??o;if(!n||n.size===0)return{toolCall:e,error:`${c} range '${o}' through '${d}' needs those blocks in request-le\
|
|
671
|
+
vel document context. Read the complete range first, then retry with the same range.`};const u=new Set(Array.from(n).map(y=>Ae(t,y)).filter(y=>y!==-1));let f=0;for(let y=l;y<a.children.length;y++){const N=a.
|
|
672
|
+
children[y]?.id;if(typeof N!="string"||N.length===0)break;const L=Ae(t,N);if(L===-1||!u.has(L))break;f+=1}if(f<=0)return{toolCall:e,error:`${e.name} targets block '${o}', which is outside the loaded <\
|
|
673
|
+
document_content> context. Read that block first, then retry.`};if(f>=i)return{toolCall:e};const b=a.children[l+f]?.id??d;return{toolCall:e,error:`${c} range '${o}' through '${d}' includes block '${b}\
|
|
674
|
+
', which was not read in this request. Read ${b===d?`'${d}'`:`'${b}' through '${d}'`}, then retry with the same range; no partial mutation was applied.`}}function Xs(e,t){const n=Xt(e,t);if(n===-1)return null;
|
|
675
|
+
const o=_e(e)[n];return o?.id?{block:o,topLevelBlockId:o.id,topLevelIndex:n}:null}function Qs(e){const t=e.toolState.editedBlockIds.size;if(t===0)return{loadedBlockCount:0,editedBlockCount:0};const n=e.
|
|
676
|
+
getLatestDocument(),o=n.children.length,r=new Set;for(const c of e.toolState.editedBlockIds){const d=Ae(n,c);d!==-1&&r.add(d)}const i=new Set;for(const c of r)for(let d=Math.max(0,c-xo);d<=Math.min(o-
|
|
677
|
+
1,c+xo);d++)i.add(d);const a=[],l=Array.from(i).sort((c,d)=>c-d);for(const c of l){const d=n.children[c];d?.id&&a.push(d.id)}e.turnState.requestedBlockIds||(e.turnState.requestedBlockIds=new Set);for(const c of a)
|
|
678
|
+
e.turnState.requestedBlockIds.add(c);return e.turnState.documentRequested=!0,{loadedBlockCount:a.length,editedBlockCount:t}}async function Zs(e){const t=await Mi(e);if(t)return{id:t.id,type:t.type,content:t.
|
|
679
|
+
content,preview:t.preview,charCount:t.charCount,...t.fileName?{fileName:t.fileName}:{},...t.mimeType?{mimeType:t.mimeType}:{},...t.fileSize?{fileSize:t.fileSize}:{},...t.urls?{urls:t.urls}:{},...t.dimensions?
|
|
680
|
+
{dimensions:t.dimensions}:{}}}function Ys(e){const t=e.loadAttachment??Zs,n=e.metrics??kr;if(!e.toolState.foreignBlockSources){e.toolState.foreignBlockSources=new Map;for(const I of e.getConversationHistory?.()??
|
|
681
|
+
[])if(!(!I.toolResult?.success||!I.toolResult.output))try{const C=JSON.parse(I.toolResult.output),q=C.document?.documentId;if(typeof q!="string"||!["document_read","document_search_context"].includes(
|
|
682
|
+
C.kind)||typeof C.documentContent!="string"||!Ie({document_id:q},e))continue;const J=new DOMParser().parseFromString(C.documentContent,"text/html");for(const z of J.querySelectorAll("[id]"))e.toolState.
|
|
683
|
+
foreignBlockSources.set(z.id,q)}catch{}}const o=e.toolState.foreignBlockSources,r=(I,C,q)=>{const J=z=>{if(z.id&&q(z.id),"children"in z&&Array.isArray(z.children))for(const j of z.children)"id"in j&&J(
|
|
684
|
+
j)};for(const z of C){const j=re(I,z);j&&J(j)}},i=(I,C,q)=>r(I,C,J=>o.set(J,q)),a=I=>{const C=e.tryAddRequestedBlocks(I);return(!C||C.code===Io)&&r(e.getLatestDocument(),I,q=>o.delete(q)),C},l=I=>{const C=a(
|
|
685
|
+
I);return C&&C.code!==Io?{error:C,reread:!1}:(e.redeliverReadBlocks?.(I),{error:null,reread:!!C})},c=" These blocks were already in context; their latest content is re-sent in the next document snapsh\
|
|
686
|
+
ot.";let d=e.turnState.currentTurn??0,u=0,f=0,b=0;const y=new Map;let N=1;const L=async()=>{e.getDocumentSession()||await e.waitForDocumentSession?.();const I=e.getDocumentSession(),C=I?.getDocumentId?.(),
|
|
687
|
+
q=e.getCurrentDocumentId?.();return I&&(!C||!q||Ie({document_id:C},e)==="")?I:null},O=I=>v(I,yo,Wi),T=new Set(["read_table","read_blocks","read_blocks_from_index","read_specific_blocks","search_docume\
|
|
688
|
+
nt","find_highlights","measure_document","measure_blocks","view_image","render_document_pages"]),D=new Set(["read_blocks","read_blocks_from_index","read_specific_blocks","search_document"]),A=()=>{const I=e.
|
|
689
|
+
turnState.currentTurn??0;I!==d&&(d=I,u=0,f=0,b=0)},M={requestId:-1,ids:new Set};return async I=>{var C,q,J,z,j;const oe=Rs(I);let h=oe.name==="remove_blocks"?{...oe,name:"remove_block"}:oe.name==="rem\
|
|
690
|
+
ove_table_rows"?{...oe,name:"remove_table_row"}:oe;const $=h.name,we=e.getExecutionPolicy?.(),pe=we?ds(we,$):null;if(pe)return v(h,pe.message,pe.code);if(e.allowCrossDocumentReads===!1&&(Oo(h.arguments??
|
|
691
|
+
{}).length>0||$==="list_documents"||$==="search_documents"))return v(h,"This host only permits the supplied document. document_id routing is unavailable.","agent_tool_not_allowed");if(A(),(T.has($)||D.
|
|
692
|
+
has($))&&(b+=1),$==="move_blocks"){const s=h.arguments??{};let m=s.reference_id;if(typeof m=="string"){const p=m.trim();if(m=p,p.startsWith("[")||p.startsWith('"'))try{m=JSON.parse(p)}catch{m=null}}if(Array.
|
|
693
|
+
isArray(m)&&m.length===1&&(m=m[0]),typeof m!="string"||!/^[A-Za-z0-9_-]+$/.test(m.trim())||!Array.isArray(s.block_ids)||s.block_ids.length===0||s.block_ids.length>100||!s.block_ids.every(p=>typeof p==
|
|
694
|
+
"string"&&/^[A-Za-z0-9_-]+$/.test(p.trim()))||!["before","after"].includes(s.position))return v(h,'move_blocks requires block_ids as an array of source ID strings, reference_id as ONE plain block ID s\
|
|
695
|
+
tring (for example "d5BLVe", not a stringified array), and position "before" or "after". Correct the arguments; rereading does not fix their shape.',"invalid_move_arguments");h={...h,arguments:{...s,block_ids:s.
|
|
696
|
+
block_ids.map(p=>p.trim()),reference_id:m.trim()}}}if($==="create_plan"||$==="update_plan"){if(!e.getPlanState||!e.setPlanState)return v(h,"This host does not support task plans.","plan_unavailable");
|
|
697
|
+
try{const s=jn(e.getPlanState(),$,h.arguments??{});return e.setPlanState(s),e.markConversationDirty(),H(h,Mn(h.arguments??{})?`${JSON.stringify(s.plan)}
|
|
698
|
+
${Bn}`:JSON.stringify(s.plan),void 0,!0,JSON.stringify({kind:"task_plan",plan:s.plan}))}catch(s){return v(h,s instanceof Error?s.message:String(s),"invalid_plan_update")}}if(e.mutationTools.includes($)||
|
|
699
|
+
$==="remove_block"){const s=Ie(h.arguments??{},e),m=He(h.arguments).filter(w=>o.has(w)&&Ie({document_id:o.get(w)},e)!==""),p=s||(m.length?o.get(m[0]):void 0);if(p){if(!s&&m.every(k=>re(e.getLatestDocument(),
|
|
700
|
+
k)))return{...v(h,`These IDs occur in both the source and active documents. If this edit is intended for the source, do not edit here: give the user a clickable link to /docs/${p} and ask them to open\
|
|
701
|
+
it. Only if the edit belongs in the active document, re-read the target IDs without document_id before editing.`,"foreign_document_id_collision"),sourceDocumentId:p};const w=e.turnState.currentRequestId??
|
|
702
|
+
0;e.toolState.foreignTargetFailureState?.requestId!==w&&(e.toolState.foreignTargetFailureState={requestId:w,count:0});const g=++e.toolState.foreignTargetFailureState.count;return{...v(h,`These edits t\
|
|
703
|
+
arget a read-only source document. Open /docs/${p} and continue there to edit it. The active document has not been changed by this call. Do not retry these IDs with another mutation tool. To edit the \
|
|
704
|
+
active document instead, read its target blocks without document_id first.`,g>=2?"foreign_document_target_repeated":"foreign_document_target"),sourceDocumentId:p}}}const lt=di($,h.arguments);if(lt)return v(
|
|
705
|
+
h,lt,li);const At=e.getLockedSelection?.()??null;if(At?.length){const s=e.getLatestDocument(),m=si(s,At,ii(s,$,h.arguments)),p=e.turnState.currentRequestId??0;M.requestId!==p&&(M.requestId=p,M.ids.clear());
|
|
706
|
+
const w=m.filter(g=>!M.ids.has(g));if(w.length)return w.forEach(g=>M.ids.add(g)),v(h,`${w.map(g=>`'${g}'`).join(", ")} ${w.length===1?"is":"are"} outside the user's selection (${JSON.stringify(ai(At))}\
|
|
707
|
+
). This request refers to the selected content, so leave other content unchanged and mention it in chat instead; nothing was changed by this call. Only if the user explicitly asked to change content b\
|
|
708
|
+
eyond the selection, send the same call again.`,ti)}const Wo=D.has($)&&Ie(h.arguments??{},e)!=="";if(e.requireDocumentSessionForReads&&T.has($)&&!Wo&&!await L())return O(h);if($==="import_attachment_i\
|
|
709
|
+
nto_document"){const s=typeof h.arguments?.attachment_id=="string"?h.arguments.attachment_id.trim():"";if(!s)return v(h,"attachment_id is required.");const m=h.arguments?.after_block_id;if(m!=null&&typeof m!=
|
|
710
|
+
"string")return v(h,"after_block_id must be a block ID string.");const p=typeof m=="string"&&m.trim()||void 0,w=e.getAllAttachments().get(s)??await t(s);if(!w)return v(h,`Attachment "${s}" was not fou\
|
|
711
|
+
nd.`);if(w.type!=="docx"&&w.type!=="pdf")return v(h,"Only DOCX and PDF attachments can be imported into the document.");if(!e.importAttachmentIntoDocument)return v(h,"Attachment import is unavailable \
|
|
712
|
+
in this document.");try{e.toolState.statusMessage=`Importing ${w.fileName||"attachment"}…`,e.notifyListeners();const g=await e.importAttachmentIntoDocument(w,p);return e.toolState.editedBlockIds.clear(),
|
|
713
|
+
e.toolState.hasImportedAttachment=!0,e.turnState.documentRequested=!1,e.turnState.requestedBlockIds=null,e.turnState.lastReadBlockIds=null,e.toolState.everReadFullDocument=!1,e.toolState.statusMessage=
|
|
714
|
+
null,e.markConversationDirty(),e.notifyListeners(),H(h,`Imported "${g.fileName}" into the current document (${g.blockCount} blocks)${p?` after block "${p}"`:""}. The URL stayed the same. Continue the \
|
|
715
|
+
user's request by reading the imported content, then edit it.`)}catch(g){return e.toolState.statusMessage=null,e.notifyListeners(),v(h,g instanceof Error?g.message:"Attachment import failed.")}}if(ws.
|
|
716
|
+
has($)){if(!Ps(h.arguments))return v(h,'context_notes is required on every read/search call. Use "N/A" if nothing from the previous context needs to carry forward.');if(u>=1)return v(h,'Use at most on\
|
|
717
|
+
e read/search tool call per turn. Continue with edits in this turn, then read/search again in the next turn with context_notes or "N/A".',fs);u+=1}if($==="measure_document"){const s=h.arguments||{},m=s.
|
|
718
|
+
include_sections===!0,p=Number(s.section_offset),w=Number.isFinite(p)&&p>0?Math.floor(p):0,g=Number(s.section_limit),k=Number.isFinite(g)&&g>0?Math.min(Math.floor(g),ps):hs,S=(Array.isArray(s.heading_levels)?
|
|
719
|
+
s.heading_levels:[]).map(se=>typeof se=="number"?se:typeof se=="string"?Number.parseInt(se,10):Number.NaN).filter(se=>se===1||se===2||se===3),R=e.getLatestDocument(),_=bo(R,{includeSections:m,...S.length>
|
|
720
|
+
0?{headingLevels:S}:{}}),x=e.getDocumentSession()?.getDocumentWithoutPendingSuggestions(),P=x&&x!==R?bo(x,{includeSections:!1}):null,E=P&&(P.wordCount!==_.wordCount||P.characterCount!==_.characterCount)?
|
|
721
|
+
{wordCount:P.wordCount,characterCount:P.characterCount,paragraphCount:P.paragraphCount,pageCount:P.pageCount}:void 0,K=_.sections??[],F=K.length,U=Math.min(w,F),Z=m?K.slice(U,U+k):void 0,W=Z?.length??
|
|
722
|
+
0,le=m&&U+W<F,ee=JSON.stringify({kind:"document_measurement",tool:"measure_document",measurementBasis:"pending_suggestions_applied",..._,...E?{originalReviewProjection:E}:{},...m?{sections:Z,sectionCount:F,
|
|
723
|
+
sectionOffset:U,sectionLimit:k,returnedSectionCount:W,hasMoreSections:le,...le?{nextSectionOffset:U+W}:{}}:{}});n.count("agent.measure.call",1,{tool_name:$}),n.distribution("agent.measure.sections",F,
|
|
724
|
+
void 0,{tool_name:$});const ie=m?`Measured document totals and ${F} heading section(s).`:"Measured document totals.",ge=m&&F>0?` Returned sections ${U+1}-${U+W} of ${F}.${le?` Use section_offset=${U+W}\
|
|
725
|
+
to continue.`:""}`:"",te=m?"heading titles, counts, and page ranges only; it does not include body document text":"counts and page ranges only; it does not include document text",Q=E?` The primary to\
|
|
726
|
+
tals treat pending suggestions as accepted. The original review projection has ${E.wordCount} words and ${E.characterCount} characters because it excludes pending suggestions; use the projection match\
|
|
727
|
+
ing the user's editor view when reconciling a reported count.`:"";return{toolCall:h,success:!0,toolOutput:ee,agentFeedback:`${ie}${ge}${Q} The result includes ${te}.`,control:{shouldContinue:!0}}}if($===
|
|
728
|
+
"measure_blocks"){const s=h.arguments||{},m=typeof s.mode=="string"?s.mode.trim():"inclusive";if(m!==""&&m!=="inclusive")return v(h,'measure_blocks only supports mode="inclusive".');const p=Array.isArray(
|
|
729
|
+
s.ranges)?s.ranges:[];if(p.length===0)return v(h,"measure_blocks requires at least one range.");const w=p.map(x=>{const P=x&&typeof x=="object"?x:{};return{startBlockId:typeof P.start_block_id=="strin\
|
|
730
|
+
g"?P.start_block_id:"",endBlockId:typeof P.end_block_id=="string"?P.end_block_id:void 0}}),g=zi(e.getLatestDocument(),w),k=g.ranges.length,S=g.errors.length,R=JSON.stringify({kind:"document_measuremen\
|
|
731
|
+
t",tool:"measure_blocks",...g});if(n.count("agent.measure.call",1,{tool_name:$}),n.distribution("agent.measure.ranges",k,void 0,{tool_name:$}),k===0){const x=g.errors.map(P=>P.error).join(" ")||"No va\
|
|
732
|
+
lid inclusive ranges were measured.";return v(h,x,De)}const _=S>0?`Measured ${k} inclusive block range(s); ${S} range(s) had errors.`:`Measured ${k} inclusive block range(s).`;return H(h,_,void 0,void 0,
|
|
733
|
+
R)}if($==="read_table"){const s=e.getLatestDocument(),m=h.arguments??{};if(typeof m.context_notes!="string")return v(h,"context_notes is required (use N/A when there is no prior context to preserve).");
|
|
734
|
+
const p=Et(s,m,x=>ae.renderSubtree(x,s));if(p.error)return v(h,p.error);const w=vi(e.getTableTaskState?.()??e.toolState.tableTasks??Zn(),s,m,{requestId:e.turnState.currentRequestId??0,chatHistory:e.getConversationHistory?.()??
|
|
735
|
+
[],attachmentExists:x=>e.getAllAttachments().has(x)});let g;if("error"in w){const x=(e.getTableTaskState?.()??e.toolState.tableTasks)?.task;g={accepted:!1,reason:w.error,retained_scope:x&&x.tableId===
|
|
736
|
+
p.table_id?{task_kind:x.kind,scope_row_start:x.declaredRowStart,scope_row_count:x.rowIds.length,scope_columns:x.columns}:null,note:x?"The existing task scope still applies; finish all of it unless the\
|
|
737
|
+
user narrows it.":"No task scope is recorded for this table; no table task status will be reported until a valid declaration."}}else e.toolState.tableTasks=w.state,w.declared&&e.setTableTaskState?.(w.
|
|
738
|
+
state);const k=(C=e.toolState).tableContext??(C.tableContext=Un());m.mode!=="cell_text"&&(k.geometries??(k.geometries={}),k.geometries[p.table_id]=p.revision),k.scopedTableIds=[...new Set([...k.scopedTableIds??
|
|
739
|
+
[],p.table_id])],k.requestedCells??(k.requestedCells={}),k.requestedCells[p.table_id]=[...new Set([...k.requestedCells[p.table_id]??[],...p.rows.flatMap(x=>x.cells.map(P=>P.id).filter(Boolean))])];const S=!!e.
|
|
740
|
+
turnState.docContextLedger;S?(k.pendingReadCells??(k.pendingReadCells={}),k.pendingReadCells[p.table_id]=[...new Set([...k.pendingReadCells[p.table_id]??[],...p.rows.flatMap(x=>x.cells.map(P=>P.id).filter(
|
|
741
|
+
Boolean))])],(q=e.turnState).requestedBlockIds??(q.requestedBlockIds=new Set),e.turnState.requestedBlockIds.add(p.table_id),(J=e.turnState).lastReadBlockIds??(J.lastReadBlockIds=new Set),e.turnState.lastReadBlockIds.
|
|
742
|
+
add(p.table_id),e.turnState.documentRequested=!0):_t(s,k,p.table_id,p.complete_cell_ids),e.markConversationDirty();const R=p.rows.flatMap(x=>x.cells.filter(P=>P.id&&P.kind!=="covered"&&!p.complete_cell_ids.
|
|
743
|
+
includes(P.id)).map(P=>{const E=re(s,P.id),K=E?.type==="table-cell"?E.children.map(F=>F.id):[];return{row_id:x.row_id,column:P.column,cell_id:P.id,...P.truncated&&P.text?{note:P.text}:{},...K.length?{
|
|
744
|
+
nested_block_ids:K.length>40?[...K.slice(0,40),`+${K.length-40} more`]:K}:{}}})),_=S&&m.mode!=="cell_text"?{...p,rows:void 0,complete_cell_ids:void 0,delivered_rows:p.rows.map(x=>({row_id:x.row_id,columns:x.
|
|
745
|
+
cells.filter(P=>p.complete_cell_ids.includes(P.id)).map(P=>P.column)})),delivered_cell_count:p.complete_cell_ids.length,...R.length?{undelivered_cells:R}:{},delivery:R.length?"Delivered cells arrive i\
|
|
746
|
+
n the next document snapshot; undelivered_cells will not, so follow each one's note. Summary/preview alone is not edit authorization.":"Requested cells arrive in the next document snapshot. Summary/pr\
|
|
747
|
+
eview alone is not edit authorization.",...g?{task_scope_update:g}:{}}:{...p,...g?{task_scope_update:g}:{}};return H(h,g?"Table context read. The task scope declaration was rejected (see task_scope_up\
|
|
748
|
+
date); the existing scope is unchanged.":m.mode==="cell_text"?"Cell text page read. cell_text is read-only: each block's text starts with its [[block_id]] marker (not document text). To edit a passage\
|
|
749
|
+
, read that block with read_specific_blocks, then target its block ID.":"Table context read. Use fill counts to include gaps in earlier rows.",void 0,void 0,JSON.stringify(_))}if($==="read_blocks"){const s=h.
|
|
750
|
+
arguments||{},m=Ie(s,e),p=s.from_id,w=m?Ge(e):"";if(m&&!w&&!e.loadRemoteDocument)return v(h,"Cross-document access is only available for signed-in documents.");let g=null;try{g=m?await(e.loadRemoteDocument?.(
|
|
751
|
+
m)??St({token:w,documentId:m})):null}catch(F){return v(h,F instanceof Error?F.message:"Document read failed.")}const k=g?.content??e.getLatestDocument(),S=_e(k),R=S.length,_=typeof p=="string"?Xt(k,p):
|
|
752
|
+
-1;if(_===-1)return v(h,`Block ID "${p}" not found`,De);if(_>=R)return v(h,`Start index ${_} is out of range for ${R} blocks.`);const x=Ro({doc:k,startIndex:_,maxTokens:We});if(x.blockIds.length===0||
|
|
753
|
+
x.endIndex<_)return v(h,`No readable blocks found from index ${_}.`);if(g){i(k,x.blockIds,g.id);const F=ae.extractSpecificBlocks(k,x.blockIds,void 0,ze),U=ae.formatSpecificBlocks(F),Z=x.endIndex+1<R?x.
|
|
754
|
+
endIndex+1:null,W=en({documentId:g.id,title:g.title,canonicalPath:g.canonicalPath,startIndex:_,endIndex:x.endIndex,estimatedTokens:x.estimatedTokens,content:U,nextIndex:Z,endOfDocument:Z===null}),le=x.
|
|
755
|
+
reachedTokenBudget?" Reached per-call token budget.":"";return H(h,`Read ${x.blockIds.length} blocks from "${g.title}" (index ${_}-${x.endIndex}). Serialized characters: ~${x.estimatedTokens}.${le}${Z!==
|
|
756
|
+
null?` Next: read_blocks_from_index(document_id="${g.id}", index=${Z}).`:" End of document."}`,void 0,void 0,W)}const P=l(x.blockIds);if(P.error)return v(h,P.error.message,P.error.code);e.turnState.documentRequested=
|
|
757
|
+
!0,n.count("agent.read.call",1,{tool_name:$}),n.distribution("agent.read.blocks_loaded",x.blockIds.length,void 0,{tool_name:$}),n.distribution("agent.read.tokens_loaded_estimate",x.estimatedTokens,void 0,
|
|
758
|
+
{tool_name:$}),x.reachedTokenBudget&&n.count("agent.read.token_budget_reached",1,{tool_name:$});const E=st(e,k);if(x.endIndex+1<R){const F=x.endIndex+1,U=S[F]?.id,Z=at({tool:$,loaded:{count:x.blockIds.
|
|
759
|
+
length,startIndex:_,endIndex:x.endIndex,estimatedTokens:x.estimatedTokens},next:{index:F,...U?{blockId:U}:{}},endOfDocument:!1,coverage:E}),W=x.reachedTokenBudget?" Reached per-call token budget.":"",
|
|
760
|
+
le=U?` Next block ID: ${U}.`:"";return H(h,`Read ${x.blockIds.length} blocks (index ${_}-${x.endIndex}). Serialized characters: ~${x.estimatedTokens}.${W} Next: read_blocks_from_index(index=${F}).${le}${P.
|
|
761
|
+
reread?c:""}`,void 0,P.reread,Z)}const K=at({tool:$,loaded:{count:x.blockIds.length,startIndex:_,endIndex:x.endIndex,estimatedTokens:x.estimatedTokens},endOfDocument:!0,coverage:E});return H(h,`Read ${x.
|
|
762
|
+
blockIds.length} blocks (index ${_}-${x.endIndex}). Serialized characters: ~${x.estimatedTokens}. End of document.${P.reread?c:""}`,void 0,P.reread,K)}if($==="read_blocks_from_index"){const s=h.arguments||
|
|
763
|
+
{},m=Ie(s,e),p=it(s.index,0),w=m?Ge(e):"";if(m&&!w&&!e.loadRemoteDocument)return v(h,"Cross-document access is only available for signed-in documents.");let g=null;try{g=m?await(e.loadRemoteDocument?.(
|
|
764
|
+
m)??St({token:w,documentId:m})):null}catch(K){return v(h,K instanceof Error?K.message:"Document read failed.")}const k=g?.content??e.getLatestDocument(),S=_e(k),R=S.length;if(g&&R===0&&p===0)return H(
|
|
765
|
+
h,`Read 0 blocks from "${g.title}". End of document.`,void 0,void 0,en({documentId:g.id,title:g.title,canonicalPath:g.canonicalPath,startIndex:0,endIndex:-1,estimatedTokens:0,content:"",nextIndex:null,
|
|
766
|
+
endOfDocument:!0}));if(p>=R)return v(h,`Start index ${p} is out of range for ${R} blocks${g?` in "${g.title}"`:""}.`);const _=Ro({doc:k,startIndex:p,maxTokens:We});if(_.blockIds.length===0||_.endIndex<
|
|
767
|
+
p)return v(h,`No readable blocks found from index ${p}.`);if(g){i(k,_.blockIds,g.id);const K=ae.extractSpecificBlocks(k,_.blockIds,void 0,ze),F=ae.formatSpecificBlocks(K),U=_.endIndex+1<R?_.endIndex+1:
|
|
768
|
+
null,Z=en({documentId:g.id,title:g.title,canonicalPath:g.canonicalPath,startIndex:p,endIndex:_.endIndex,estimatedTokens:_.estimatedTokens,content:F,nextIndex:U,endOfDocument:U===null}),W=_.reachedTokenBudget?
|
|
769
|
+
" Reached per-call token budget.":"";return n.count("agent.read.call",1,{tool_name:$}),n.distribution("agent.read.blocks_loaded",_.blockIds.length,void 0,{tool_name:$}),H(h,`Read ${_.blockIds.length} \
|
|
770
|
+
blocks from "${g.title}" (index ${p}-${_.endIndex}). Serialized characters: ~${_.estimatedTokens}.${W}${U!==null?` Next: read_blocks_from_index(document_id="${g.id}", index=${U}).`:" End of document."}`,
|
|
771
|
+
void 0,void 0,Z)}const x=l(_.blockIds);if(x.error)return v(h,x.error.message,x.error.code);e.turnState.documentRequested=!0,n.count("agent.read.call",1,{tool_name:$}),n.distribution("agent.read.blocks\
|
|
772
|
+
_loaded",_.blockIds.length,void 0,{tool_name:$}),n.distribution("agent.read.tokens_loaded_estimate",_.estimatedTokens,void 0,{tool_name:$}),_.reachedTokenBudget&&n.count("agent.read.token_budget_reach\
|
|
773
|
+
ed",1,{tool_name:$});const P=st(e,k);if(_.endIndex+1<R){const K=_.endIndex+1,F=S[K]?.id,U=at({tool:$,loaded:{count:_.blockIds.length,startIndex:p,endIndex:_.endIndex,estimatedTokens:_.estimatedTokens},
|
|
774
|
+
next:{index:K,...F?{blockId:F}:{}},endOfDocument:!1,coverage:P}),Z=_.reachedTokenBudget?" Reached per-call token budget.":"",W=F?` Next block ID: ${F}.`:"";return H(h,`Read ${_.blockIds.length} blocks\
|
|
775
|
+
(index ${p}-${_.endIndex}). Serialized characters: ~${_.estimatedTokens}.${Z} Next: read_blocks_from_index(index=${K}).${W}${x.reread?c:""}`,void 0,x.reread,U)}const E=at({tool:$,loaded:{count:_.blockIds.
|
|
776
|
+
length,startIndex:p,endIndex:_.endIndex,estimatedTokens:_.estimatedTokens},endOfDocument:!0,coverage:P});return H(h,`Read ${_.blockIds.length} blocks (index ${p}-${_.endIndex}). Serialized characters:\
|
|
777
|
+
~${_.estimatedTokens}. End of document.${x.reread?c:""}`,void 0,x.reread,E)}if($==="search_document"){const s=h.arguments||{},m=Ie(s,e),p=s.queries,w=Array.isArray(p)?p.filter(ne=>typeof ne=="string"&&
|
|
778
|
+
ne.length>0):typeof p=="string"&&p.length>0?[p]:[];if(w.length===0)return v(h,'search_document requires "queries": a non-empty array of search strings.');const g=typeof s.page=="number"?s.page:0,k=m?Ge(
|
|
779
|
+
e):"";if(m&&!k&&!e.loadRemoteDocument)return v(h,"Cross-document access is only available for signed-in documents.");let S=null;try{S=m?await(e.loadRemoteDocument?.(m)??St({token:k,documentId:m})):null}catch(ne){
|
|
780
|
+
return v(h,ne instanceof Error?ne.message:"Document search failed.")}const R=S?.content??e.getLatestDocument(),_=e.searchPageSize,x=Eo("search_document",s);let P;g>0&&e.toolState.lastSearchState&&e.toolState.
|
|
781
|
+
lastSearchState.toolName==="search_document"&&e.toolState.lastSearchState.requestKey===x?P=e.toolState.lastSearchState.allResults:P=ae.searchDocument(R,w);let E;if(!S&&P.length>0){const ne=g>0&&e.toolState.
|
|
782
|
+
lastSearchState?.requestKey===x?e.toolState.lastSearchState.resultSetId:void 0;if(ne&&y.has(ne))E=ne;else{E=`search_result_${N++}`;const be=Array.from(new Set(P.map($e=>$e.blockId)));y.set(E,{id:E,blockIds:be,
|
|
783
|
+
blockHashes:Dt(R,be)})}}const K=No({doc:R,results:P,pageSize:_,maxTokens:We}),F=Math.max(1,K.length),U=Math.min(g,Math.max(0,F-1)),Z=K[U]??{results:[],startResultIndex:0,endResultIndexExclusive:0},W=Z.
|
|
784
|
+
startResultIndex,le=Z.endResultIndexExclusive,ee=Z.results,ie=ee.map(ne=>ne.blockId),ge=S||ie.length===0?null:a(ie);e.toolState.lastSearchState={toolName:"search_document",requestKey:x,allResults:P,currentPage:U,
|
|
785
|
+
totalPages:F,...E?{resultSetId:E}:{}};let te;P.length===0?te=`No matches found${S?` in "${S.title}"`:""} for: ${w.join(", ")}`:(te=`Found ${P.length} matching blocks${S?` in "${S.title}"`:""}. Showing\
|
|
786
|
+
page ${U+1}/${F} (results ${W+1}-${le} of ${P.length}).`,!S&&E&&(te+=` The full unpaginated result set is saved as ${E}; pass search_result_id="${E}" to replace, replace_block, style_blocks, or remov\
|
|
787
|
+
e_blocks to target all ${P.length} matches in one call.`),U<F-1&&S&&(te+=S?` Call search_document with document_id="${S.id}" and page=${U+1} to see next page.`:` Call search_document with page=${U+1} \
|
|
788
|
+
to see next page.`));const Q=ge?.code==="no_new_read_context";if(ge&&!Q){if(P.length>0){let ne=`Found ${P.length} matching blocks. Showing page ${U+1}/${F} (blocks ${W+1}-${le} of ${P.length}). Matchi\
|
|
789
|
+
ng blocks could not be loaded this turn.`;return U<F-1&&(ne+=` Call search_document with page=${U+1} to see next page.`),v(h,`${ge.message} ${ne}`,ge.code)}return v(h,`${ge.message} ${te}`,ge.code)}if(Q&&
|
|
790
|
+
P.length>0&&(te+=" Matching block content is already available in this request's cached context."),!S){const ne=mr(R.chrome??[]).filter(be=>w.some($e=>be.toLowerCase().includes($e.toLowerCase())));ne.
|
|
791
|
+
length>0&&(te+=` Also found in page headers/footers (not body blocks; change them with set_header_footer):
|
|
792
|
+
${ne.map(be=>`- ${be}`).join(`
|
|
793
|
+
`)}`)}if(S){i(R,ie,S.id);const ne=ae.extractSpecificBlocks(R,ie,void 0,ze),be=ae.formatSpecificBlocks(ne),$e=JSON.stringify({kind:"document_search_context",tool:"search_document",document:{documentId:S.
|
|
794
|
+
id,title:S.title,canonicalPath:S.canonicalPath||`/${S.title}`,href:`/docs/${S.id}`,...Yt(S.id)},queries:w,totalMatches:P.length,page:{current:U,total:F,startResult:W+1,endResult:le},nextPage:U<F-1?U+1:
|
|
795
|
+
null,matches:ee.map(Ee=>({blockId:Ee.blockId,blockIndex:Ee.blockIndex,matchedQueries:Ee.matchedQueries??[]})),documentContent:be});return n.count("agent.read.search_call",1,{tool_name:$}),n.distribution(
|
|
796
|
+
"agent.read.blocks_loaded",ie.length,void 0,{tool_name:$}),H(h,te,void 0,void 0,$e)}e.turnState.documentRequested=!0,n.count("agent.read.search_call",1,{tool_name:$}),n.distribution("agent.read.blocks\
|
|
797
|
+
_loaded",ie.length,void 0,{tool_name:$});const se=Bo({tool:"search_document",queries:w,totalMatches:P.length,currentPage:U,totalPages:F,pageStart:W,pageEnd:le,pageResults:ee,nextPage:U<F-1?U+1:null,...E?
|
|
798
|
+
{searchResultId:E}:{},coverage:st(e,e.getLatestDocument())});return H(h,te,void 0,void 0,se)}if($==="list_documents"){const s=h.arguments||{},m=typeof s.parent_folder_id=="string"&&s.parent_folder_id.
|
|
799
|
+
trim().length>0?s.parent_folder_id.trim():null,p=it(s.page,0),w=Ge(e);if(!w)return v(h,"Document tree listing is only available for signed-in documents.");try{const g=await zs({token:w,parentFolderId:m,
|
|
800
|
+
page:p,limit:50}),k=g.hasMore?` Call list_documents with page=${p+1} for more.`:"",S=g.items.filter(P=>P.itemType==="folder").length,R=g.items.length-S,_=g.totalCount===0?`No items found in ${m?"that \
|
|
801
|
+
folder":"the account root"}.`:`Listed ${g.items.length} of ${g.totalCount} items in ${m?"the folder":"the account root"} (${S} folders, ${R} documents).${k}`,x=Ws({parentFolderId:m,page:p,totalCount:g.
|
|
802
|
+
totalCount,totalPages:Math.max(1,g.totalPages),hasMore:g.hasMore,items:g.items});return n.count("agent.read.document_tree_list",1,{tool_name:$}),H(h,_,void 0,void 0,x)}catch(g){return v(h,g instanceof
|
|
803
|
+
Error?g.message:"Document listing failed.")}}if($==="search_documents"){const s=h.arguments||{},m=typeof s.query=="string"?s.query.trim():"";if(!m)return v(h,"search_documents requires a query.");const p=Ge(
|
|
804
|
+
e);if(!p)return v(h,"Cross-document search is only available for signed-in documents.");const w=Us(s.scope),g=e.getCurrentFolderId?.()??null,k=typeof s.folder_id=="string"&&s.folder_id.trim().length>0?
|
|
805
|
+
s.folder_id.trim():null,S=w==="current_folder"&&!g||w==="folder"&&!k?"account":w,R=it(s.page,0);try{const _=await Fs({token:p,query:m,scope:S,page:R,currentFolderId:g,folderId:k}),x=S==="current_folde\
|
|
806
|
+
r"&&!!g,P=S==="folder"&&k?"the selected folder tree":x?"the current folder tree":"the account",E=R+1<_.totalPages?` Call search_documents with page=${R+1} for more.`:"",K=_.totalCount===0?`No document\
|
|
807
|
+
s found for "${m}" in ${P}.`:`Found ${_.totalCount} documents for "${m}" in ${P}. Showing page ${R+1}/${Math.max(1,_.totalPages)}.${E}`,F=Js({query:m,scope:S,searchedCurrentFolder:x,folderId:S==="fold\
|
|
808
|
+
er"?k:null,page:R,totalCount:_.totalCount,totalPages:Math.max(1,_.totalPages),results:_.items});return n.count("agent.read.account_search_call",1,{tool_name:$}),H(h,K,void 0,void 0,F)}catch(_){return v(
|
|
809
|
+
h,_ instanceof Error?_.message:"Document search failed.")}}if($==="find_highlights"){const s=h.arguments||{},m=typeof s.color=="string"&&s.color.trim().length>0?s.color.trim().toLowerCase():void 0,p=typeof s.
|
|
810
|
+
page=="number"?s.page:0,w=e.getLatestDocument(),g=e.searchPageSize,k=Eo("find_highlights",s);let S;p>0&&e.toolState.lastSearchState&&e.toolState.lastSearchState.toolName==="find_highlights"&&e.toolState.
|
|
811
|
+
lastSearchState.requestKey===k?S=e.toolState.lastSearchState.allResults:S=ae.findHighlights(w,m);const R=No({doc:w,results:S,pageSize:g,maxTokens:We}),_=Math.max(1,R.length),x=Math.min(p,Math.max(0,_-
|
|
812
|
+
1)),P=R[x]??{results:[],startResultIndex:0,endResultIndexExclusive:0},E=P.startResultIndex,K=P.endResultIndexExclusive,F=P.results,U=F.map(te=>te.blockId),Z=U.length===0?null:a(U);e.toolState.lastSearchState=
|
|
813
|
+
{toolName:"find_highlights",requestKey:k,allResults:S,currentPage:x,totalPages:_};const W=m?`${m} highlight`:"highlighted content",le=m||S.length===0?"":` Colors: ${Hs(S)}.`;let ee;S.length===0?ee=`No\
|
|
814
|
+
blocks found with ${W}.`:(ee=`Found ${S.length} blocks with ${W}. Showing page ${x+1}/${_} (results ${E+1}-${K} of ${S.length}).${le}`,x<_-1&&(ee+=` Call find_highlights with page=${x+1} to see next \
|
|
815
|
+
page.`));const ie=Z?.code==="no_new_read_context";if(Z&&!ie){if(S.length>0){let te=`Found ${S.length} blocks with ${W}. Showing page ${x+1}/${_} (blocks ${E+1}-${K} of ${S.length}). Matching blocks co\
|
|
816
|
+
uld not be loaded this turn.`;return x<_-1&&(te+=` Call find_highlights with page=${x+1} to see next page.`),v(h,`${Z.message} ${te}`,Z.code)}return v(h,`${Z.message} ${ee}`,Z.code)}ie&&S.length>0&&(ee+=
|
|
817
|
+
" Matching block content is already available in this request's cached context."),e.turnState.documentRequested=!0,n.count("agent.read.search_call",1,{tool_name:$}),n.distribution("agent.read.blocks_l\
|
|
818
|
+
oaded",U.length,void 0,{tool_name:$});const ge=Bo({tool:"find_highlights",color:m??null,totalMatches:S.length,currentPage:x,totalPages:_,pageStart:E,pageEnd:K,pageResults:F,nextPage:x<_-1?x+1:null,coverage:st(
|
|
819
|
+
e,e.getLatestDocument())});return H(h,ee,void 0,void 0,ge)}if($==="read_specific_blocks"){const s=h.arguments||{},m=Ie(s,e),p=s.block_ids,w=Array.isArray(p)?p.filter(W=>typeof W=="string"&&W.length>0):
|
|
820
|
+
typeof p=="string"&&p.length>0?[p]:[];if(w.length===0)return v(h,"No block IDs provided");const g=m?Ge(e):"";if(m&&!g&&!e.loadRemoteDocument)return v(h,"Cross-document access is only available for sig\
|
|
821
|
+
ned-in documents.");let k=null;try{k=m?await(e.loadRemoteDocument?.(m)??St({token:g,documentId:m})):null}catch(W){return v(h,W instanceof Error?W.message:"Document read failed.")}const S=k?.content??e.
|
|
822
|
+
getLatestDocument();if(!k&&e.toolState.tableContext?.scopedTableIds?.length){const W=[];Ue(S,ee=>W.push(ee));const le=ee=>[...W].reverse().find(ie=>(ie.children.length>=Vo||e.toolState.tableContext.scopedTableIds.
|
|
823
|
+
includes(ie.id))&&ue(ie).includes(ee));if(w.some(ee=>le(ee))){const ee=[];let ie=0;const ge=[...new Set(w.map(Q=>{const se=re(S,Q);return se?.type==="list"&&se.children.some(ne=>ne.id===Q)?se.id:Q}))];
|
|
824
|
+
for(const Q of ge){const se=re(S,Q),ne=le(Q);if(!se||se.id!==Q)return v(h,`Unknown or structural block '${Q}'. Use read_table with table_id and row_ids for table rows.`);let be=!1;if(Ue(se,()=>{be=!0}),
|
|
825
|
+
be)return v(h,`Block '${Q}' contains a table. Use read_table(table_id="${ne?.id??W.find(Go=>ue(se).includes(Go.id))?.id}") for bounded row windows.`);const $e=ae.renderSubtree(se,S),Ee=JSON.stringify(
|
|
826
|
+
{id:Q,html:$e}).length;if(ie+Ee>24e3)return v(h,"Requested nested content exceeds 24000 serialized characters. Read fewer blocks; for a huge cell use read_table mode=cell_text. No new edit rights were\
|
|
827
|
+
granted.");ie+=Ee,ee.push({id:Q,html:$e,table_id:ne?.id})}const te=e.toolState.tableContext;for(const Q of ee)Q.table_id&&(te.scopedTableIds=[...new Set([...te.scopedTableIds??[],Q.table_id])],Ln(S,te,
|
|
828
|
+
Q.table_id,Q.id),e.turnState.docContextLedger&&(te.pendingReadBlocks??(te.pendingReadBlocks={}),te.pendingReadBlocks[Q.id]=te.blocks[Q.id]),re(S,Q.id)?.type==="table-cell"&&_t(S,te,Q.table_id,[Q.id])),
|
|
829
|
+
(z=e.turnState).requestedBlockIds??(z.requestedBlockIds=new Set),e.turnState.requestedBlockIds.add(Q.id);return e.turnState.documentRequested=!0,e.markConversationDirty(),H(h,`Read ${ee.length} exact \
|
|
830
|
+
nested blocks. Ancestors and sibling cells remain unread. During context recovery, only blocks repeated in the next <table_recovery_window> stay editable; any it omits are listed there and are not edi\
|
|
831
|
+
table.`,void 0,void 0,JSON.stringify({blocks:ee,serialized_characters:ie}))}}const{blockIds:R,estimatedTokens:_,reachedTokenBudget:x,missingRequestedBlocks:P}=Ls({doc:S,requestedBlockIds:w,maxTokens:We});
|
|
832
|
+
if(R.length===0)return P>0?v(h,"None of the requested block IDs were found in the document.",De):v(h,"No readable blocks could be loaded.");if(k){i(S,R,k.id);const W=ae.extractSpecificBlocks(S,R,void 0,
|
|
833
|
+
ze),le=ae.formatSpecificBlocks(W),ee=Zt(S,new Set(R)),ie=JSON.stringify({kind:"document_read",tool:$,document:{documentId:k.id,title:k.title,canonicalPath:k.canonicalPath||`/${k.title}`,href:`/docs/${k.
|
|
834
|
+
id}`,...Yt(k.id)},loaded:{count:R.length,blockIds:R,blockIndices:ee,estimatedTokens:_},reachedTokenBudget:x,documentContent:le});return n.count("agent.read.call",1,{tool_name:$}),n.distribution("agent\
|
|
835
|
+
.read.blocks_loaded",R.length,void 0,{tool_name:$}),H(h,`Read ${R.length} specific blocks from "${k.title}". Serialized characters: ~${_}.${x?" Reached per-call token budget.":""}`,void 0,void 0,ie)}const E=l(
|
|
836
|
+
R);if(E.error)return v(h,E.error.message,E.error.code);e.turnState.documentRequested=!0,n.count("agent.read.call",1,{tool_name:$}),n.distribution("agent.read.blocks_loaded",R.length,void 0,{tool_name:$}),
|
|
837
|
+
n.distribution("agent.read.tokens_loaded_estimate",_,void 0,{tool_name:$}),x&&n.count("agent.read.token_budget_reached",1,{tool_name:$});const K=Zt(S,new Set(R)),F=at({tool:$,loaded:{count:R.length,requestedCount:w.
|
|
838
|
+
length,estimatedTokens:_,ranges:Mo(K)},endOfDocument:!1,coverage:st(e,S)}),U=x?` Reached per-call token budget; loaded ${R.length}/${w.length} requested blocks.`:"",Z=P>0?` ${P} requested block IDs we\
|
|
839
|
+
re not found.`:"";return H(h,`Loaded ${R.length} specific blocks.${U}${Z} Serialized characters: ~${_}.${E.reread?c:""}`,void 0,E.reread,F)}if($==="get_attachment"){const s=(h.arguments||{}).attachment_id;
|
|
840
|
+
if(!s)return v(h,"No attachment_id provided");let m=e.getAllAttachments().get(s);return m||(m=await t(s),m&&e.getAllAttachments().set(s,m)),m?m.content?.trim()??""?H(h,`Loaded attachment "${m.id}" (${m.
|
|
841
|
+
charCount} chars).`,void 0,void 0,`<attachment id="${m.id}" type="${m.type}"${m.fileName?` filename="${m.fileName}"`:""} chars="${m.charCount}">
|
|
842
|
+
${m.content}
|
|
843
|
+
</attachment>`):H(h,`Attachment "${m.id}" has no text content to retrieve; it is a hosted file already visible in the conversation history.`):v(h,`Attachment "${s}" not found. Available attachments: ${Array.
|
|
844
|
+
from(e.getAllAttachments().keys()).join(", ")||"none"}`)}if($==="view_image"){const s=(h.arguments||{}).block_id;if(!s)return v(h,"No block_id provided");const m=e.getLatestDocument(),p=Ao(m.children,
|
|
845
|
+
s);if(!p)return v(h,`Image block "${s}" not found in document`,De);const w={id:`view_image_${s}`,type:"image",content:"",preview:"",charCount:0,fileName:p.alt||`image_${s}`,urls:[p.src],dimensions:[{width:p.
|
|
846
|
+
width,height:p.height}]};return H(h,`Image retrieved: ${p.alt?`"${p.alt}" `:""}(${p.width}x${p.height}px)${p.sourceUrl?` Source: ${p.sourceUrl}`:""}`,w)}if($==="render_document_pages"){if(!e.renderDocumentPages)
|
|
847
|
+
return v(h,"Rendered page inspection is unavailable until the document canvas is ready.");const s=h.arguments||{},m=it(s.start_page,1),p=it(s.page_count,1),w=s.mode==="layout"?"layout":"appearance";let g=s.
|
|
848
|
+
quality==="compact"?"compact":"detailed";const k=s.view===void 0||s.view===null?Rt:s.view;if(!sr(k))return v(h,`view must be one of ${ar.join(", ")}. Use show-tracked-changes unless you specifically n\
|
|
849
|
+
eed the accepted or before preview.`,"invalid_view");if(m<1)return v(h,"start_page must be 1 or greater.");const S=g==="detailed"&&p>2;S&&p<=4&&(g="compact");const R=g==="compact"?4:2;if(p<1||p>R)return v(
|
|
850
|
+
h,`page_count must be between 1 and ${R} for ${g} quality.`);try{const _=await e.renderDocumentPages({startPage:m,pageCount:p,mode:w,quality:g,view:k}),x=_.view??Rt;if(x!==k)return v(h,`This document \
|
|
851
|
+
surface cannot render the ${k} view (it rendered ${x}). Use show-tracked-changes, or inspect the accepted text with a read tool.`,"render_view_unsupported");if(_.placeholderImageCount||_.failedImageCount||
|
|
852
|
+
_.mathPlaceholderCount)return{...v(h,`Visual inspection is incomplete: ${_.placeholderImageCount} image placeholders, ${_.failedImageCount} failed images, and ${_.mathPlaceholderCount} formula placeho\
|
|
853
|
+
lders. Resolve the unavailable resources before a retry: allow pending resources to finish loading, re-upload broken images, or correct unsupported formulas. Repeating this call without fixing them wi\
|
|
854
|
+
ll not verify the document.`,"visual_resource_unavailable"),failure:{code:"visual_resource_unavailable",phase:"verification",retryable:!1,mutationOutcome:"unchanged"}};const P=_.pages.length===1?`page\
|
|
855
|
+
${_.pages[0]}`:`pages ${_.pages[0]}-${_.pages[_.pages.length-1]}`,E={id:`render_document_pages_${h.id}`,type:"image",content:"",preview:"",charCount:0,fileName:`Rendered document ${P} (${w}, ${g}, ${k}\
|
|
856
|
+
)`,mimeType:_.dataUrl.startsWith("data:image/png")?"image/png":"image/jpeg",urls:[_.dataUrl],dimensions:[{width:_.width,height:_.height}],visionDetail:g==="compact"?"low":"high"};return H(h,`Rendered ${P}\
|
|
857
|
+
of ${_.totalPages} in ${w} mode at ${g} quality, ${k} view.${k===Rt?"":` This is an isolated preview with ${_.snapshot?`all ${_.snapshot.pendingSuggestionCount}`:"all"} pending suggestions ${k==="sho\
|
|
858
|
+
w-with-tracked-changes-accepted"?"accepted":"rejected"}; no suggestion was accepted or rejected in the document, and the page count is for this view.`}${_.snapshot?.description?` ${_.snapshot.description}`:
|
|
859
|
+
""}${S?" The request was downgraded from detailed to compact quality so all requested pages fit in one bounded render.":""}`,E,void 0,JSON.stringify({pages:_.pages,totalPages:_.totalPages,mode:w,quality:g,
|
|
860
|
+
view:k,..._.snapshot?{snapshot:_.snapshot}:{},placeholderImageCount:_.placeholderImageCount,failedImageCount:_.failedImageCount,mathPlaceholderCount:_.mathPlaceholderCount}))}catch(_){return v(h,_ instanceof
|
|
861
|
+
Error?_.message:"Document page rendering failed.",_ instanceof Error&&"code"in _?String(_.code):void 0)}}if($==="set_status"){const s=Ds(h.arguments);return e.toolState.statusMessage=s,e.markConversationDirty(),
|
|
862
|
+
e.notifyListeners(),H(h,s?`Status set to "${s}".`:"Status updated.")}if($==="request_user_input"){const s=h.arguments??{},m=typeof s.chat_response=="string"?s.chat_response.trim():"";return!m||Co(m)?v(
|
|
863
|
+
h,"request_user_input requires a concrete user-facing question, not only a status update.",$o):!Array.isArray(s.suggested_next_prompts)&&!Array.isArray(s.followups)?v(h,"request_user_input requires su\
|
|
864
|
+
ggested_next_prompts as an array."):H(h,"User input requested.")}if($===ys)return!e.skipSameTurnCompletionGuard&&f>0?v(h,`${$} cannot be used in the same tool batch as document edits. Inspect the succ\
|
|
865
|
+
essful mutation results on the next turn, then call end_agent_run if the request is complete.`,Gt):H(h,"Legacy completion handoff acknowledged. Call end_agent_run on the next turn.");if(ks($)){if(!e.skipSameTurnCompletionGuard&&
|
|
866
|
+
f>0)return v(h,`${$} cannot be used in the same tool batch as document edits. Inspect the successful mutation results on the next turn, then continue concrete work or call end_agent_run if the request\
|
|
867
|
+
is complete.`,Gt);if(!e.skipSameTurnCompletionGuard&&b>0)return v(h,`${$} cannot be used in the same tool batch as reads, searches, or measurements: their results arrive on the next turn. Use those r\
|
|
868
|
+
esults there, then call end_agent_run.`,Gt);const s=h.arguments??{},m=typeof s.chat_response=="string"?s.chat_response.trim():"";if(!m)return v(h,`${$} requires a non-empty chat_response.`);if(Co(m))return v(
|
|
869
|
+
h,`${$} requires a final user-facing response, not only a status update.`,$o);if(!Array.isArray(s.suggested_next_prompts)&&!Array.isArray(s.followups))return v(h,`${$} requires suggested_next_prompts \
|
|
870
|
+
as an array.`);let p;if(s.completed_plan_item_ids!=null||s.completed_plan_steps!=null){if(!e.getPlanState||!e.setPlanState)return v(h,"This host does not support task plans.","plan_unavailable");const w=s.
|
|
871
|
+
completed_plan_item_ids??[];if(!Array.isArray(w)||w.some(k=>typeof k!="string"))return v(h,"completed_plan_item_ids must be an array of current-plan item IDs.","invalid_plan_update");const g=s.completed_plan_steps??
|
|
872
|
+
[];if(!Array.isArray(g)||g.some(k=>typeof k!="string"||!k.trim()))return v(h,"completed_plan_steps must be an array of new non-empty requirements.","invalid_plan_update");if(w.length>0||g.length>0)try{
|
|
873
|
+
const k=e.getPlanState(),S=jn(k,"update_plan",{plan_id:k.plan?.id,updates:w.map(R=>({item_id:R,status:"completed"})),add_steps:g});for(const R of S.plan.items.slice(k.plan.items.length))R.status="comp\
|
|
874
|
+
leted";p=()=>{e.getPlanState()===k&&(e.setPlanState(S),e.markConversationDirty())}}catch(k){return v(h,k instanceof Error?k.message:String(k),"invalid_plan_update")}}return{...H(h,"Final response reco\
|
|
875
|
+
rded."),...p?{commitPlanCompletion:p}:{}}}const me=await L();if(!me)return O(h);const V=e.getLatestDocument();if($==="rollback_agent_suggestions"){const s=h.arguments??{},m=s.request_id==null?void 0:s.
|
|
876
|
+
request_id,p=s.turn==null?void 0:s.turn;if(m!==void 0&&(!Number.isInteger(m)||Number(m)<1))return v(h,"request_id must be a positive integer.");if(p!==void 0&&(!Number.isInteger(p)||Number(p)<1))return v(
|
|
877
|
+
h,"turn must be a positive integer.");if(p!==void 0&&m===void 0)return v(h,"turn requires request_id.");const w=e.turnState.currentRequestId??0,g=e.turnState.currentTurn??0;if(m!==void 0&&Number(m)>w)
|
|
878
|
+
return v(h,`request_id ${m} is in the future; the current request is ${w}.`);const k=e.getConversationId?.().trim()??"";if(!k)return v(h,"This conversation has no stable ID, so its suggestions cannot \
|
|
879
|
+
be rolled back safely.");const S=me.getDocumentWithPendingSuggestionsApplied(),R=me.rollbackAgentSuggestions({agentConversationId:k,requestId:m===void 0?void 0:Number(m),turn:p===void 0?void 0:Number(
|
|
880
|
+
p),currentRequestId:w,currentTurn:g});if(R.resolvedCount===0){const E=R.requestId===void 0?"any prior request":`request ${R.requestId}${R.turn===void 0?"":` turn ${R.turn}`}`;return H(h,`No still-pend\
|
|
881
|
+
ing suggestions from this conversation matched ${E}. Accepted edits and other authors' work were left untouched. Recover omitted text from historical_edit_evidence or earlier before_block snapshots, t\
|
|
882
|
+
hen propose a targeted correction against the current document while preserving later edits. Searching the current document cannot recover text that was deleted.`,void 0,!0)}const _=me.getDocumentWithPendingSuggestionsApplied(),
|
|
883
|
+
x=new Map(S.children.map(E=>[E.id,E])),P=new Map(_.children.map(E=>[E.id,E]));for(const E of new Set([...x.keys(),...P.keys()]))JSON.stringify(x.get(E))!==JSON.stringify(P.get(E))&&e.toolState.editedBlockIds.
|
|
884
|
+
add(E);return e.turnState.hasMutatedSinceLastRead=!0,f+=1,e.markConversationDirty(),e.notifyListeners(),H(h,`Rolled back ${R.resolvedCount} pending suggestion${R.resolvedCount===1?"":"s"} ${R.turn===void 0?
|
|
885
|
+
`to before request ${R.requestId}`:`from request ${R.requestId} turn ${R.turn}`}. The rollback is one user-undoable history item. Now make the corrected edits; do not ask the user to reject the old su\
|
|
886
|
+
ggestions.`)}if($==="leave_comment"){const s=Cs(h,e,me,V);return s.success&&(f+=1),s}if(($==="insert_block"||$==="insert_table_row"||$==="insert_table_column")&&h.arguments?.position!=="before"&&h.arguments?.
|
|
887
|
+
position!=="after")return v(h,`${$} has invalid "position" ${JSON.stringify(h.arguments?.position??null)}; use "before" or "after".`);if($==="set_header_footer"&&h.arguments?.side!=="header"&&h.arguments?.
|
|
888
|
+
side!=="footer")return v(h,`set_header_footer has invalid "side" ${JSON.stringify(h.arguments?.side??null)}; use "header" or "footer".`);const Oe=Ye(V,e.toolState.tableContext,Vt(e.turnState)??new Set);
|
|
889
|
+
if($==="move_blocks"){const s=He(h.arguments),m=new Set([...V.children.map(g=>g.id),...e.getDocumentSession()?.getWorkingDocument().children.map(g=>g.id)??[]]),p=s.filter(g=>!m.has(g));if(p.length){const g=V.
|
|
890
|
+
children.length<=30?V.children.filter(k=>Oe.has(k.id)).map(k=>({id:k.id,text:Le(k).slice(0,80)})):[];return v(h,`Move targets are not current top-level block IDs: ${p.map(k=>JSON.stringify(k)).join(",\
|
|
891
|
+
")}. Use current IDs from the document; read the relevant range if IDs are stale. This is an invalid target, not an unread-block error.${g.length?` Current already-read blocks in document order: ${JSON.
|
|
892
|
+
stringify(g)}.`:""}`,"invalid_move_target")}const w=s.filter(g=>!$t(V,g,Oe));if(w.length)return v(h,`Move targets were not read in this request: ${w.slice(0,10).join(", ")}. Read the source range and \
|
|
893
|
+
destination before moving.`,Be)}const ct=qi({toolCall:h,docBefore:V});if(ct?.error)return v(h,ct.error,"invalid_block_range");const xe=$i({toolCall:ct?.toolCall??h,docBefore:V,isTargetAllowed:s=>$t(V,
|
|
894
|
+
s,Oe)});if(xe?.error)return v(h,xe.error,xe.errorCode);const tn=xe?.toolCall??ct?.toolCall??h,nn=new Set(Oe??[]);for(const s of xe?.targetBlockIds??[])nn.add(s);const de=Xo({toolCall:tn,docBefore:V,resultSets:y});
|
|
895
|
+
if(de?.error)return v(h,de.error,de.errorCode);const je=Vs(tn,V,nn);if(je.error)return v(h,je.error,Be);const B=je.toolCall;if(B.name==="replace"&&B.arguments&&Array.isArray(B.arguments.replacements)&&
|
|
896
|
+
Object.prototype.hasOwnProperty.call(B.arguments,"comment"))return v(B,'replace comment belongs on each operation inside "replacements", alongside find, replace, and occurrence.');const Ho=new Set(V.children.
|
|
897
|
+
map(s=>s.id)),Ke=new Set(Oe??[]);for(const s of xe?.targetBlockIds??[])Ke.add(s);for(const s of de?.targetBlockIds??[])Ke.add(s);const dt=Ci(B,V,s=>$t(V,s,Ke));if(dt.error)return v(B,dt.error,dt.error.
|
|
898
|
+
includes("request-level document context")?Be:void 0);const ce=(j=e.toolState).tableContext??(j.tableContext=Un()),on={responseTurn:e.turnState.currentTurn,hasForeignSuggestion:s=>{const m=me.getDocumentMutator(),
|
|
899
|
+
p=re(me.getWorkingDocument(),s.id);return p?m.getLiveSuggestionIdsForBlock(p).some(w=>{const g=m.getLiveSuggestion(w),k=e.getConversationId?.();return!ce.ownedSuggestionIds?.includes(w)&&!(k&&g?.agentConversationId===
|
|
900
|
+
k)}):!1}},Y=B.name==="edit_table_cells"?zn(V,ce,B.arguments,on):null,rn=s=>{const m=s.filter(g=>g.reason.includes("not delivered"));if(!m.length)return{};const p=m[0].column,w=[...new Set(m.filter(g=>g.
|
|
901
|
+
column===p).map(g=>g.row_id))].slice(0,50);return{recovery_read:{name:"read_table",arguments:{table_id:B.arguments?.table_id,mode:"rows",row_ids:w,column_start:p,column_count:1,context_notes:"Refresh \
|
|
902
|
+
this failed cell batch; preserve the original task and exact requested values."}},recovery_instruction:"Read this window, then edit only its fully delivered target cells before reading another window.\
|
|
903
|
+
Compaction can retire older read windows. Preserve the original task and continue until its full scope is complete.",remaining_unread_target_count:m.length-w.length}};if(Y?.errors.length)return{...v(
|
|
904
|
+
B,"No cells changed. Resolve every listed target error and retry the batch.",So),toolOutput:JSON.stringify({errors:Y.errors,...rn(Y.errors),skipped:Y.skipped,changed_count:0})};const Se=Y?{actions:Y.actions.
|
|
905
|
+
map((s,m)=>({...s,id:`${B.id}-${m}`})),blockId:void 0,error:void 0}:de?{actions:de.actions,blockId:void 0,error:void 0}:B.name==="remove_block"&&Array.isArray(B.arguments?.ids)?{actions:dt.actions,blockId:void 0,
|
|
906
|
+
error:void 0}:Qo(B,{doc:V,loadedBlockIds:Ke});if(Se.error){const s="failure"in Se?Se.failure:void 0;return{...v(B,Se.error,s?.code),failure:s}}if(Se.actions.length===0)return Y?H(B,"No cells changed; \
|
|
907
|
+
inspect skipped and unchanged targets before continuing.",void 0,!0,JSON.stringify({changed_count:0,skipped:Y.skipped,unchanged:Y.unchanged})):H(B,`${To(B)} Continue with the remaining work; do not re\
|
|
908
|
+
peat this unchanged operation.`,void 0,!0);const Tt=Y?{actions:Se.actions,retargets:[]}:Zo({actions:Se.actions,doc:V,loadedBlockIds:Ke}),Pe=Tt.actions,he=Array.from(new Set([...de?.targetBlockIds??[],
|
|
909
|
+
...xe?.targetBlockIds??[],...Ms(Pe)])),sn=s=>{if(!e.toolState.tableContext?.scopedTableIds?.length||B.name==="edit_table_cells"||["style_blocks","clear_formatting"].includes(B.name))return;const m=e.toolState.
|
|
910
|
+
tableContext.scopedTableIds;if(["insert_table_row","insert_table_column","remove_table_row","remove_table_column"].includes(B.name))return Kr(s,e.toolState.tableContext,B.name,B.arguments)?void 0:v(B,
|
|
911
|
+
B.name==="remove_table_row"?As(s,B.arguments):"Table geometry changed or cells affected by this deletion were not fully read. Reread the table summary for insertions, or every affected row/column cell\
|
|
912
|
+
for deletions.",Be);const p=Ye(s,e.toolState.tableContext,Vt(e.turnState)??new Set);for(const w of he){if(xe?.targetBlockIds.includes(w))continue;const g=re(s,w);if(m.some(k=>{const S=re(s,k);return S&&
|
|
913
|
+
ue(S).includes(w)||g&&ue(g).includes(k)})&&!p.has(w)){let k=!1;g&&Ue(g,()=>k=!0);const S=g&&!k&&!["table-row","table-cell"].includes(g.type)?`Read it with read_specific_blocks(block_ids=["${w}"]), the\
|
|
914
|
+
n retry`:"Use read_table for its cells";return v(B,`Target '${w}' was not fully read. ${S}; a table preview or cell_text page does not authorize edits.`,Be)}}if(!he.length&&!["set_title","set_notes","\
|
|
915
|
+
set_page_layout","set_header_footer","insert_block"].includes(B.name))return v(B,"This broad operation includes partially read tables. Read their cells or target fully delivered block IDs explicitly.",
|
|
916
|
+
Be)},an=sn(V);if(an)return an;const ln=["insert_table_row","remove_table_row","insert_table_column","remove_table_column"].includes(B.name),cn=new Map;if((B.name==="replace_block"||B.name==="move_bloc\
|
|
917
|
+
ks"||B.name==="remove_block"||ln&&!e.toolState.tableContext?.scopedTableIds?.includes(String(B.arguments.tableId)))&&e.turnState.promptBlockContentHashes)for(const s of Do(V,he)){const m=re(V,s),p=m?new Set(
|
|
918
|
+
ue(m)):new Set,w=he.filter(k=>p.has(k));if(w.length&&w.every(k=>(ce.scopedTableIds??[]).some(S=>{const R=re(V,S);return R&&ue(R).includes(k)})))continue;const g=e.turnState.promptBlockContentHashes.get(
|
|
919
|
+
s);g&&cn.set(s,g)}const dn=s=>{for(const[m,p]of cn){const w=Pt(s,m);if(w!==null&&w!==p)return v(B,`Block '${m}' was edited (likely by the user) after you last read it. Re-read the block and re-apply y\
|
|
920
|
+
our change against its current content.`,De)}},un=dn(V);if(un)return un;const mn=B.id||`tool-${Date.now()}`,Re=await(e.rehostImages??Pn)(Pe);if(Re.failedUrls.length>0){const s=Re.failedUrls.length===1?
|
|
921
|
+
"1 external image":`${Re.failedUrls.length} external images`,m=Re.failures.some(g=>g.status===429),p=Re.failures.length===1?Re.failures[0]:void 0,w=p?` Reason: ${p.message}${p.status?` (HTTP ${p.status}\
|
|
922
|
+
)`:""}.`:"";return v(B,`${s} could not be copied into Revise storage, so no document changes were applied.${w} ${m?"Do not attempt more external image insertions in this request. Keep any earlier succ\
|
|
923
|
+
essful changes and tell the user which image remains incomplete.":"Do not retry this URL. Use a different verified direct raster image URL or upload the image before trying again."}`,Re.unavailable?"a\
|
|
924
|
+
gent_tool_not_allowed":void 0)}const ye=e.getLatestDocument(),hn=sn(ye);if(hn)return hn;if(Y){const s=zn(ye,ce,B.arguments,on);if(s.errors.length||JSON.stringify(s.targets)!==JSON.stringify(Y.targets))
|
|
925
|
+
return{...v(B,"Table targets changed while preparing this batch; no cells changed. Reread and retry.",So),toolOutput:JSON.stringify({errors:s.errors,...rn(s.errors),skipped:s.skipped,changed_count:0})}}
|
|
926
|
+
const pn=dn(ye);if(pn)return pn;let G;const Ve=B.name==="remove_block"?[...new Set(Pe.map(s=>typeof s.arguments?.id=="string"?ht(V,s.arguments.id):null).filter(s=>s!==null))]:[];if(Ve.length>0&&Pe.some(
|
|
927
|
+
s=>s.arguments?.count!=null&&s.arguments.count!==1||typeof s.arguments?.id!="string"||!ht(V,s.arguments.id)))return v(B,"To remove footnotes/endnotes, pass their exact note IDs in ids, or one note ID \
|
|
928
|
+
as id. Remove main-document blocks separately.");for(const s of Pe){if(s.name!=="replace_block")continue;const m=ye.notes?.find(p=>p.id===s.arguments?.id);if(m&&yn(ye,m.id)===m.id)return v(B,`Note '${m.
|
|
929
|
+
id}' contains multiple body blocks or no single editable text block. Use replace_block with an exact body block ID (${m.children.map(p=>p.id).join(", ")}) instead of replacing the note wrapper.`)}if(Ve.
|
|
930
|
+
length>0){const s=me.getDocumentMutator(),m=new Set(s.getLiveSuggestionIds()),p=s.suggestingMode;s.suggestingMode=!0;let w=!1;try{const{result:k}=s.withSuggestionMetadata({source:"agent",authorType:"a\
|
|
931
|
+
i",agentName:Je(e),...e.getAgentModel?{agentModel:e.getAgentModel()}:{},agentConversationId:e.getConversationId?.(),agentRequestId:e.turnState.currentRequestId,agentTurn:e.turnState.currentTurn,commentThreadId:e.
|
|
932
|
+
commentThreadId,historyOrigin:`live-suggestions:${mn}`},()=>Ve.every(S=>s.removeFootnote(S)));w=k}finally{s.suggestingMode=p}const g=s.getLiveSuggestionIds().filter(k=>!m.has(k));G=w?{success:!0,suggestionIds:g,
|
|
933
|
+
agentFeedback:`Removed footnote/endnote blocks ${Ve.join(", ")} and their inline references.`}:{success:!1,error:`Footnote/endnote blocks '${Ve.join(", ")}' could not be removed.`}}else G=me.applyAgentActions(
|
|
934
|
+
{message:"AI Assistant",actions:Pe.map(s=>{if((s.name==="replace"||s.name==="replace_all"||s.name==="replace_block")&&typeof s.arguments?.id=="string"){const m=yn(ye,s.arguments.id);if(m&&m!==s.arguments.
|
|
935
|
+
id)return{...s,arguments:{...s.arguments,id:m}}}return s}),agentName:Je(e),agentModel:e.getAgentModel?.(),agentConversationId:e.getConversationId?.(),agentRequestId:e.turnState.currentRequestId,agentTurn:e.
|
|
936
|
+
turnState.currentTurn,commentThreadId:e.commentThreadId},mn,{optimizeStyleFormatting:e.getOptimizeStyleFormatting?.()??!1,applyBlockMovesDirectly:e.toolState.directMode,directMode:e.toolState.directMode});
|
|
937
|
+
if(G.resultCode==="already_satisfied")return H(B,(G.styleEffects||$==="move_blocks")&&G.agentFeedback?G.agentFeedback:"Verified that the requested state is already satisfied; no document mutation occu\
|
|
938
|
+
rred. "+To(B),void 0,!0,JSON.stringify({code:"already_satisfied",mutationOutcome:"unchanged",...$==="move_blocks"&&G.agentFeedback?{summary:G.agentFeedback}:{},...G.styleEffects?JSON.parse(Po(B,V,V,G.
|
|
939
|
+
styleEffects.targetBlockIds,G.agentFeedback,G.styleEffects)):{}}));if(G.success!==!1&&G.styleEffects){const s=new Set([...G.styleEffects.changedBlockIds,...G.styleEffects.affectedBlockIds]);s.size<=Me&&
|
|
940
|
+
he.splice(0,he.length,...s)}const fe=G.success!==!1;let X=G.agentFeedback,ut;if(fe&&de?.resultSet){const s=de.resultSet,m=de.targetBlockIds.length,p=m===s.blockIds.length?`Applied ${B.name} to all ${s.
|
|
941
|
+
blockIds.length} blocks in ${s.id}.`:`Applied ${B.name} to the ${m} of ${s.blockIds.length} blocks in ${s.id} that contain its find text; the other ${s.blockIds.length-m} were left unchanged.`;X=X?.includes(
|
|
942
|
+
p)?X:X?`${p}
|
|
943
|
+
${X}`:p}if(fe&&(B.name==="replace_many"||B.name==="replace"&&Array.isArray(B.arguments?.replacements))){const s=Pe.length,m=Bs(he,Se.blockId),p=`Applied ${s} replacement ${s===1?"operation":"operation\
|
|
944
|
+
s"} in ${m}.`;X=X?.includes(p)?X:X?`${p}
|
|
945
|
+
${X}`:p}if(fe&&je.feedback&&(X=X?`${X}
|
|
946
|
+
${je.feedback}`:je.feedback),fe&&Tt.retargets.length>0){const s=Os(Tt.retargets);s&&(X=X?`${X}
|
|
947
|
+
${s}`:s)}if(fe&&((G.commentedSuggestionIds?.length??0)>0||(G.commentAttachmentFailureCount??0)>0)){const s=G.attachedCommentIds??[],m=G.commentAttachmentFailureCount??0,p=s.length>0?`Attached ${s.length===
|
|
948
|
+
1?"comment":`${s.length} separate comments`} to the resulting ${s.length===1?"suggestion":"suggestions"} (${s.join(", ")}).${m>0?` ${m} requested ${m===1?"comment":"comments"} could not be anchored; d\
|
|
949
|
+
o not repeat the edits.`:""}`:"The edits were suggested, but their requested comments could not be anchored. Do not repeat the edits; use leave_comment on the affected text instead.";X=X?`${X}
|
|
950
|
+
${p}`:p}const mt=G.commentOnRestoredTextCount??0;if(fe&&mt>0){const s=`${mt===1?"One edit":`${mt} edits`} put back the original text, undoing part of an earlier pending suggestion, so ${mt===1?"its co\
|
|
951
|
+
mment was":"their comments were"} not added: no change remains there to explain. This is done; do not repeat the edit or comment on the unchanged text.`;X=X?`${X}
|
|
952
|
+
${s}`:s}if(fe){const s=Ks(B,V);s&&(X=X?`${X}
|
|
953
|
+
${s}`:s)}if(e.toolState.directMode&&fe){const s=new Set(G.commentedSuggestionIds??[]),m=(G.suggestionIds??[]).filter(p=>!s.has(p));if(m.length>0&&me.acceptLiveSuggestions(m),m.length>0&&s.size===0){const p=me.
|
|
954
|
+
getDocumentMutator();p?.resetToolCallHistory&&p.resetToolCallHistory()}}if(fe){e.mutationTools.includes($)&&(f+=1);const s=me.getDocumentWithPendingSuggestionsApplied();if($==="move_blocks"&&s.children.
|
|
955
|
+
length<=30){const m=new Set(V.children.map(w=>w.id)),p=s.children.filter(w=>Oe.has(w.id)||!m.has(w.id)).map(w=>({id:w.id,text:Le(w).slice(0,80)}));X=`${X??"Move completed."} Current already-read block\
|
|
956
|
+
s in document order: ${JSON.stringify(p)}.`}if(ln&&typeof B.arguments.tableId=="string"){const m=Et(s,{table_id:B.arguments.tableId,mode:"summary"});m.error||(ce.geometries??(ce.geometries={}),ce.geometries[m.
|
|
957
|
+
table_id]=m.revision)}if(!Y){const m=Ye(ye,ce,new Set);for(const p of Object.values(ce.cells))m.has(p.cellId)&&p.blockIds.some(w=>he.includes(w))&&_t(s,ce,p.tableId,[p.cellId]);for(const[p,w]of Object.
|
|
958
|
+
entries(ce.blocks??{}))m.has(p)&&w.blockIds.some(g=>he.includes(g))&&Ln(s,ce,w.tableId,p)}if(de?.resultSet&&(de.resultSet.blockHashes=Dt(s,de.resultSet.blockIds)),ut=Y?void 0:Po(B,V,s,he,X,G.styleEffects),
|
|
959
|
+
Y){const m=String(B.arguments.table_id);_t(s,ce,m,Y.targets.map(S=>S.cellId));const p=e.turnState.currentTurn??0;ce.responseClaims={turn:p,cellIds:[...ce.responseClaims?.turn===p?ce.responseClaims.cellIds:
|
|
960
|
+
[],...Y.targets.map(S=>S.cellId)]},ce.ownedSuggestionIds=[...ce.ownedSuggestionIds??[],...G.suggestionIds??[]];const w=Ii(e.getTableTaskState?.()??e.toolState.tableTasks??Zn(),{requestId:e.turnState.currentRequestId??
|
|
961
|
+
0,tableId:m,cellIds:Y.targets.map(S=>S.cellId)});e.toolState.tableTasks=w,e.setTableTaskState?.(w);const g=[];let k=0;if(B.arguments.mode==="replace")for(const S of Y.targets){const R=re(ye,S.paragraphId),
|
|
962
|
+
_=R?.type==="paragraph"?R.children.map(P=>P.type==="text"?P.text:"").join(""):null,x={row_id:S.row_id,column:S.column,previous_text:_??""};_===null||JSON.stringify([...g,x]).length>8e3?k++:g.push(x)}ut=
|
|
963
|
+
JSON.stringify({tool:"edit_table_cells",...B.arguments.mode==="replace"?{previous_cells:g,omitted_previous_cells:k,...k?{previous_values_recovery:"Some prior values were omitted from this bounded look\
|
|
964
|
+
back. For pending edits use rollback_agent_suggestions for the relevant request/turn, then reread. Accepted edits require earlier historical edit evidence; do not reconstruct missing prior text from t\
|
|
965
|
+
he current document."}:{}}:{},table_id:m,proposed_cell_count:Y.targets.length,changed_count:Y.targets.length,rows:[...new Set(Y.targets.map(S=>S.row_id))],skipped:Y.skipped,unchanged:Y.unchanged,remaining_empty_in_working_document:Et(
|
|
966
|
+
s,{table_id:m,mode:"summary"}).columns.filter(S=>Y.targets.some(R=>R.column===S.column)),status:e.toolState.directMode?"applied":"proposed_pending_review"})}if(e.turnState.hasMutatedSinceLastRead=!0,e.
|
|
967
|
+
mutationTools.includes($)&&$!=="set_title"&&$!=="set_notes"&&$!=="set_page_layout"){if(!de)for(const m of he)e.toolState.editedBlockIds.add(m);if(!de)for(const m of s.children)m.id&&!Ho.has(m.id)&&e.toolState.
|
|
968
|
+
editedBlockIds.add(m.id);if(e.turnState.promptBlockContentHashes){const m=Do(ye,he);for(const p of m){const w=e.turnState.promptBlockContentHashes.get(p);if(w&&Pt(ye,p)!==w||!w&&!he.includes(p))continue;
|
|
969
|
+
const g=Pt(s,p);g!==null?e.turnState.promptBlockContentHashes.set(p,g):e.turnState.promptBlockContentHashes.delete(p)}}de||Qs(e)}}const gn=Ts(G.error);return{toolCall:B,success:fe,error:G.error,failure:G.
|
|
970
|
+
failure,...G.failure?{errorCode:G.failure.code}:{},...!fe&&gn?{errorCode:gn}:{},documentStateAfter:me.getDocumentWithPendingSuggestionsApplied(),agentFeedback:X,...ut?{toolOutput:ut}:{}}}}const Lo={read_table:[
|
|
971
|
+
"task_kind","scope_row_start","scope_row_count","scope_columns","source_attachment_id","deliberate_blanks"]};function ea(e){const t=Lo[e.name];if(!t)return e;const n=e.inputSchema;return{...e,description:e.
|
|
972
|
+
description.split(/(?<=\.)\s+/).filter(o=>!t.some(r=>o.includes(r))&&!/task scope/i.test(o)).join(" "),inputSchema:{...e.inputSchema,properties:Object.fromEntries(Object.entries(n.properties??{}).filter(
|
|
973
|
+
([o])=>!t.includes(o))),...n.required?{required:n.required.filter(o=>!t.includes(o))}:{}}}}const ta=wo.map(e=>ea(e));function na(e){const t=Lo[e.name],n=e.arguments;if(!t||!n||typeof n!="object"||Array.
|
|
974
|
+
isArray(n))return{toolCall:e};const o=t.filter(r=>vt(n[r]));return o.length?{error:`${e.name} does not accept ${o.join(", ")} in the embedded SDK: task declarations are tracked only by the native Revi\
|
|
975
|
+
se agent. Omit them; reading and editing table cells works without them. Nothing was read.`}:{toolCall:{...e,arguments:Object.fromEntries(Object.entries(n).filter(([r])=>!t.includes(r)))}}}function Uo(e){
|
|
976
|
+
return e.replace(/^Failed operation: [\w-]+: (?:\w*Error: )?/,"").replaceAll("Please only reference IDs you see inside <document_content>.","Use a block ID from a read or search result.").replaceAll("\
|
|
977
|
+
outside the loaded <document_content> context","outside what has been read").replaceAll("<document_content>","the read results")}function oa(e,t){return e.success?{ok:!0,value:{callId:e.toolCallId,tool:e.
|
|
978
|
+
name,message:e.agentFeedback===void 0||e.agentFeedback===null?null:Uo(e.agentFeedback),data:e.output??null,context:e.documentContent?{format:"revise-html",html:e.documentContent}:null,suggestionIds:t}}:
|
|
979
|
+
{ok:!1,error:{callId:e.toolCallId,tool:e.name,code:e.errorCode??"tool_failed",message:Uo(e.error??e.agentFeedback??`${e.name} failed.`),...e.output!==void 0?{details:e.output}:{}}}}function ra(e){if(e)
|
|
980
|
+
try{return JSON.parse(e)}catch{return e}}class ia{constructor(t){this.options=t,this.toolState={editedBlockIds:new Set,hasImportedAttachment:!1,everReadFullDocument:!1,lastSearchState:null,statusMessage:null,
|
|
981
|
+
directMode:!1,directModeForced:!1},this.turnState={currentTurn:0,requestedBlockIds:null,readBudgetBlockIds:null,lastReadBlockIds:null,promptBlockContentHashes:new Map,documentRequested:!1,hasMutatedSinceLastRead:!1},
|
|
982
|
+
this.deliveredBlockIds=[],this.handler=null}async run(t,n={}){this.turnState.currentTurn+=1,this.deliveredBlockIds=[];const o=na(t);if("error"in o)return{toolCall:t,success:!1,error:o.error,errorCode:"\
|
|
983
|
+
unsupported_argument"};t=o.toolCall;const r=this.handler??(this.handler=this.createHandler()),i=this.toolState.directMode,a=this.toolState.directModeForced;n.directMode!==void 0&&(this.toolState.directMode=
|
|
984
|
+
n.directMode,this.toolState.directModeForced=!0);try{return await r(t)}finally{this.toolState.directMode=i,this.toolState.directModeForced=a}}buildResult(t,n,o){const r=o.success&&this.deliveredBlockIds.
|
|
985
|
+
length>0?ae.formatSpecificBlocks(ae.extractSpecificBlocks(this.options.getDocumentSession().getDocumentWithPendingSuggestionsApplied(),this.deliveredBlockIds)):void 0;return{toolCallId:t,name:n,success:o.
|
|
986
|
+
success,...o.error?{error:o.error}:{},...o.errorCode?{errorCode:o.errorCode}:{},...o.agentFeedback?{agentFeedback:o.agentFeedback}:{},...o.toolOutput?{output:ra(o.toolOutput)}:{},...r?{documentContent:r}:
|
|
987
|
+
{}}}createHandler(){return Ys({toolState:this.toolState,turnState:this.turnState,getAllAttachments:()=>new Map,getFlaggedAttachmentIds:()=>new Set,getLatestDocument:()=>this.options.getDocumentSession().
|
|
988
|
+
getDocumentWithPendingSuggestionsApplied(),getDocumentSession:()=>this.options.getDocumentSession(),markConversationDirty:()=>{},notifyListeners:()=>{},tryAddRequestedBlocks:t=>{const n=this.turnState.
|
|
989
|
+
requestedBlockIds??new Set,o=this.turnState.readBudgetBlockIds??new Set;for(const i of t)n.add(i),o.add(i);this.turnState.requestedBlockIds=n,this.turnState.readBudgetBlockIds=o,this.turnState.lastReadBlockIds=
|
|
990
|
+
new Set(t);const r=this.options.getDocumentSession().getDocumentWithPendingSuggestionsApplied();for(const[i,a]of Dt(r,t))this.turnState.promptBlockContentHashes.set(i,a);return this.deliveredBlockIds=
|
|
991
|
+
[...t],null},mutationTools:[...this.options.mutationTools],searchPageSize:this.options.searchPageSize??25,getAgentAuthorName:()=>this.options.getAgentName?.(),...this.options.rehostImages?{rehostImages:this.
|
|
992
|
+
options.rehostImages}:{}})}}const sa="N/A";function Fo(e,t,n){if(t.context_notes!==void 0)return t;const o=n.find(r=>r.name===e)?.inputSchema?.required;return!Array.isArray(o)||!o.includes("context_no\
|
|
993
|
+
tes")?t:{...t,context_notes:sa}}const zo=new Set(["get_selection","view_image"]),aa=new Set(["remove_block","remove_table_row"]),la=["document_id","search_documents",...zo];function ca(e){const t=structuredClone(
|
|
994
|
+
e),n=t.properties;return delete n?.document_id,Array.isArray(t.required)&&(t.required=t.required.filter(o=>o!=="document_id")),t}function da(e){return e.split(/(?<=\.)\s+/).filter(t=>!la.some(n=>t.includes(
|
|
995
|
+
n))).join(" ")}const Ct=ta.filter(e=>!zo.has(e.name)).map(e=>({name:e.name,description:da(e.description),inputSchema:ca(e.inputSchema)})),Jo=new WeakSet;function ua(e){Jo.add(e)}function ma(e,t){if(!t.
|
|
996
|
+
documentId.trim())throw new Error("Revise: documentId is required for a server session.");const n=new Ko(t.documentId,e,void 0,{disableHistory:!0,disableProposalPersistence:!0}),o=new Set(Bt);let r=t.
|
|
997
|
+
mode??"suggesting";n.setSuggestingMode(r==="suggesting"),n.setDocxRoundTripRequired(Jo.has(e));const i=Er(t.images),a=new ia({getDocumentSession:()=>n,mutationTools:Array.from(Bt),searchPageSize:t.searchPageSize,
|
|
998
|
+
getAgentName:()=>t.agentName,rehostImages:T=>Pn(T,i)});let l=1,c=!1,d=Promise.resolve();const u=()=>{if(c)throw new Error("Revise: server document session is disposed.")},f=(T,D,A,M)=>({ok:!1,error:{callId:T,
|
|
999
|
+
tool:D,code:A,message:M}}),b=async(T,D,A,M)=>{u();const I=`server-tool-${l++}`;if(!Ct.some(q=>q.name===T)&&!aa.has(T))return f(I,T,"unknown_tool",`Unknown or unavailable server document tool: ${T}`);if("\
|
|
1000
|
+
document_id"in D)return f(I,T,"document_id_not_supported","document_id is not accepted: a server document session is bound to one document. Omit it and retry.");await hr(),u(),n.setSuggestingMode(M===
|
|
1001
|
+
"suggesting");const C=o.has(T)?new Set(n.getDocumentMutator().getLiveSuggestionIds()):null;try{const q=await a.run({id:I,name:T,arguments:D},{directMode:A.directMode??M==="editing"}),J=a.buildResult(I,
|
|
1002
|
+
T,q);return oa(J,C?n.getDocumentMutator().getLiveSuggestionIds().filter(z=>!C.has(z)):null)}catch(q){return f(I,T,"internal_error",q instanceof Error?q.message:String(q))}finally{n.setSuggestingMode(r===
|
|
1003
|
+
"suggesting")}},y=(T,D,A)=>{const M=r,I=d.then(()=>b(T,D,A,M));return d=I.then(()=>{},()=>{}),I},N={getDefinitions:()=>(u(),Ct.map(T=>({...T,inputSchema:structuredClone(T.inputSchema)}))),execute:(T,...D)=>{
|
|
1004
|
+
const[A={},M={}]=D;return y(T,Fo(T,A,Ct),M)},executeDynamic:(T,D={},A={})=>y(T,D,A),call:async(T,...D)=>{const[A={},M={}]=D,I=await y(T,Fo(T,A,Ct),M);if(!I.ok)throw new wr(I.error);return I.value}},L=()=>{
|
|
1005
|
+
u();const T=n.getDocumentMutator();return T.getLiveSuggestionIds().map(D=>{const A=T.getLiveSuggestion(D),M=T.getInlineSuggestionMetadataFromDocument(D),I=A&&"blockId"in A?A.blockId:A?.type==="paragra\
|
|
1006
|
+
ph-merge"?A.firstBlockId:void 0,C={id:D,...A?.type?{type:A.type}:{},...I?{blockId:I}:{},...A?.type==="table-change"?{tableId:A.tableId}:{}};for(const q of["authorType","agentName","agentModel","source",
|
|
1007
|
+
"label","createdAt"]){const J=M?.[q]??A?.[q];J!==void 0&&Object.assign(C,{[q]:J})}return C})},O=(T,D)=>{u();const A=Array.from(new Set(D.filter(z=>typeof z=="string"&&z.trim().length>0))),M=n.getDocumentMutator(),
|
|
1008
|
+
I=new Set(M.getLiveSuggestionIds()),C=A.filter(z=>!I.has(z)),q=A.filter(z=>I.has(z));q.length>0&&(T==="accept"?n.acceptLiveSuggestions(q):n.rejectLiveSuggestions(q));const J=new Set(M.getLiveSuggestionIds());
|
|
1009
|
+
return{resolved:q.filter(z=>!J.has(z)),missing:C,unresolved:q.filter(z=>J.has(z))}};return{getMode:()=>(u(),r),setSuggestingMode:()=>{u(),r="suggesting"},setEditingMode:()=>{u(),r="editing"},tools:N,getPendingSuggestionIds:()=>(u(),
|
|
1010
|
+
n.getDocumentMutator().getLiveSuggestionIds()),listSuggestions:L,acceptSuggestions:T=>O("accept",T),rejectSuggestions:T=>O("reject",T),acceptAllSuggestions:()=>(u(),O("accept",n.getDocumentMutator().getLiveSuggestionIds())),
|
|
1011
|
+
rejectAllSuggestions:()=>(u(),O("reject",n.getDocumentMutator().getLiveSuggestionIds())),dispose:()=>{c||(c=!0,n.dispose())}}}export{ma as createServerDocumentSession,ua as requireDocxRoundTrip};
|