revise 2.0.0 → 2.0.1
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 +27 -0
- package/assets/{historyMaterializeWorker-CoAX9ZAi.js → historyMaterializeWorker-C4uxcZEh.js} +1 -1
- package/backend.d.ts +22 -0
- package/backend.js +1 -1
- package/chunks/AgentPageRenderer-BIf_Fza8.js +1 -0
- package/chunks/AgentPageRenderer-DT9sNxEn.js +1 -0
- package/chunks/{AttachmentDocumentImporter-dNMtkxrv.js → AttachmentDocumentImporter-BUavYRxO.js} +1 -1
- package/chunks/{AttachmentDocumentImporter-DSic_6At.js → AttachmentDocumentImporter-DGwfDJSH.js} +1 -1
- package/chunks/{BidiText-B4Hzrjg9.js → BidiText-D7LYTAUL.js} +1 -1
- package/chunks/DocumentMutator-CjN7Kk-X.js +31 -0
- package/chunks/DocumentScrubber-C9ZZEcYW.js +1 -0
- package/chunks/DocumentScrubber-DrgzBlx4.js +1 -0
- package/chunks/DocumentScrubber-W0EfGmL-.js +1 -0
- package/chunks/{DocxConverter-COV6CjUM.js → DocxConverter-Be3uPNcD.js} +3 -3
- package/chunks/{DocxConverter-B7P52lw7.js → DocxConverter-CGYMfz-j.js} +6 -6
- package/chunks/{DocxConverter-Cq_zCEJC.js → DocxConverter-DabDLfsu.js} +6 -6
- package/chunks/{DocxGraft-CJ12C9WP.js → DocxGraft-B6W7fbh4.js} +1 -1
- package/chunks/{DocxGraft-DcmFuUkd.js → DocxGraft-Cj7v78BO.js} +1 -1
- package/chunks/DocxGraft-Duvo2cpy.js +1 -0
- package/chunks/FileImporter-CjUX2S4s.js +1 -0
- package/chunks/FileImporter-DtkbI6rF.js +1 -0
- package/chunks/{HtmlConverter-JvRlkQM3.js → HtmlConverter-ikXImzTY.js} +1 -1
- package/chunks/{MarkdownConverter-B-tPY7X3.js → MarkdownConverter-CFrcLyO_.js} +2 -2
- package/chunks/{OdtConverter-DYHnR4E8.js → OdtConverter-BFT_P8SI.js} +1 -1
- package/chunks/OdtConverter-Cnda9T0q.js +1 -0
- package/chunks/OdtConverter-WdwwXKVM.js +1 -0
- package/chunks/PdfConverter-D7UM58vc.js +21 -0
- package/chunks/PdfConverter-TB-QPw29.js +21 -0
- package/chunks/PdfConverter-wVP63986.js +21 -0
- package/chunks/PdfImportService-Dj1-3L2B.js +2 -0
- package/chunks/PdfImportService-OE9G383I.js +2 -0
- package/chunks/{RtfConverter-oIwzoqCD.js → RtfConverter-D-oqPWNl.js} +5 -5
- package/chunks/{RtfConverter-BQGge3K-.js → RtfConverter-D9zhE07-.js} +5 -5
- package/chunks/{RtfConverter-CMfZ4olw.js → RtfConverter-DZgwU-_R.js} +1 -1
- package/chunks/{TableBorders-BLkZYt1k.js → TableBorders-BorZS8aZ.js} +1 -1
- package/chunks/{TxtConverter-C1lp6dBS.js → TxtConverter-BYazsp6P.js} +3 -3
- package/chunks/ar-C8zx2RwP.js +8 -0
- package/chunks/backend-MFpDFVrD.js +1 -0
- package/chunks/base64-BNMNG-lN.js +1 -0
- package/chunks/{browser-module-6b2Fq-5C.js → browser-module-BbaxnHNK.js} +1 -1
- package/chunks/{browser-module-CkO57IPL.js → browser-module-D2ixluMg.js} +1 -1
- package/chunks/capture-qC26xmfy.js +1 -0
- package/chunks/{carrier-WgcRSu7a.js → carrier-BWONvrA7.js} +1 -1
- package/chunks/de-ByQFqecF.js +8 -0
- package/chunks/es-PHpJXv5S.js +8 -0
- package/chunks/{footnoteFlatten-CW-DUcgK.js → footnoteFlatten-Bdnn_bz1.js} +1 -1
- package/chunks/{graftExport-CVg7PO2A.js → graftExport-CP3h2T88.js} +1 -1
- package/chunks/index-CjeGoI2g.js +351 -0
- package/chunks/index-D7V8zn4w.js +36 -0
- package/chunks/index-DyOcu9mD.js +351 -0
- package/chunks/{index.es-DOqegDGr.js → index.es-B97tjxvW.js} +1 -1
- package/chunks/{index.es-tXDO0RMv.js → index.es-mTU7Sl3w.js} +1 -1
- package/chunks/{jspdf.es.min-CzYti8jo.js → jspdf.es.min-DGiD4mlU.js} +1 -1
- package/chunks/{jspdf.es.min-ejWOGhkJ.js → jspdf.es.min-Mykp4BZO.js} +1 -1
- package/chunks/{pseudoLocale-CdBtPHRi.js → pseudoLocale-C90lXrPg.js} +1 -1
- package/chunks/{pseudoLocale-DEVWLkGC.js → pseudoLocale-UA_TkGrH.js} +1 -1
- package/chunks/serverDocumentSession-CRZSb5SO.js +11 -0
- package/chunks/signatures-CsL_TjvW.js +1 -0
- package/full.js +1 -1
- package/index.d.ts +27 -4
- package/index.js +1 -1
- package/package.json +2 -2
- package/root.js +2 -2
- package/style.css +1 -1
- package/chunks/AgentPageRenderer-C0n4EnuW.js +0 -1
- package/chunks/AgentPageRenderer-DURfmiu0.js +0 -1
- package/chunks/DocxGraft-CQpvFcYb.js +0 -1
- package/chunks/FileImporter-DVnYOJHp.js +0 -1
- package/chunks/FileImporter-q9mCch0J.js +0 -1
- package/chunks/OdtConverter-Br81BSoJ.js +0 -1
- package/chunks/OdtConverter-CQjh0vlo.js +0 -1
- package/chunks/PdfConverter-D26rXumc.js +0 -21
- package/chunks/PdfConverter-DGZpUSVf.js +0 -21
- package/chunks/PdfConverter-DZzVP0-B.js +0 -21
- package/chunks/PdfImportService-CBD8TL1k.js +0 -2
- package/chunks/PdfImportService-D6uUKGMf.js +0 -2
- package/chunks/ar-kgSWdrXF.js +0 -8
- package/chunks/backend-Cq-khfdG.js +0 -1
- package/chunks/base64-CfDUyGi8.js +0 -36
- package/chunks/capture-DU3MC7tb.js +0 -1
- package/chunks/de-C2QTHrqo.js +0 -8
- package/chunks/es-BKboUn4q.js +0 -8
- package/chunks/index-CLw_BlSL.js +0 -353
- package/chunks/index-F-kHIwWT.js +0 -353
- package/chunks/serverDocumentSession-DZrYbdpk.js +0 -42
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import{h as Cn,y as fe,i as Ye,d as wt,o as Dn,m as An,r as St,g as xt,a as Tn,t as Pn,R as Bn,b as Rn}from"./backend-MFpDFVrD.js";import{D as Xe,P as qn,i as Ln,f as Ne,e as Ze,A as Z,b as Qe,a as On,c as Un,r as Nn,d as Mt,g as et,h as Ce,j as Fn,l as En,k as jn,m as zn,n as $t,o as Wn,p as Hn,q as Ct,s as Dt,t as Jn,u as Vn}from"./DocumentMutator-CjN7Kk-X.js";import{i as Gn,R as Kn}from"./DocumentStylesheet-byN5dtC6.js";import{s as Yn}from"./carrier-BWONvrA7.js";import*as ce from"yjs";import{f as de,a as ye,c as Xn,b as Zn,d as Qn,e as eo,g as to}from"./index-D7V8zn4w.js";import{b as tt,c as no,a as oo}from"./base64-BNMNG-lN.js";const ro={count:()=>{},gauge:()=>{},distribution:()=>{}};class so{constructor(e=50){this.tasks=new Map,this.intervalId=null,this.tickMs=e}schedule(e,n,o){const r=Date.now();this.tasks.set(e,{id:e,callback:o,delay:n,lastScheduledAt:r}),this.intervalId===null&&(this.intervalId=window.setInterval(()=>this.tick(),this.tickMs))}cancel(e){this.tasks.delete(e)&&this.tasks.size===0&&this.intervalId!==null&&(window.clearInterval(this.intervalId),this.intervalId=null)}tick(){const e=Date.now();for(const n of this.tasks.values())if(e-n.lastScheduledAt>=n.delay){this.tasks.delete(n.id);try{n.callback()}catch(o){console.error("[DebouncedTaskScheduler] Task error",o)}}this.tasks.size===0&&this.intervalId!==null&&(window.clearInterval(this.intervalId),this.intervalId=null)}}const io=new so;function ao(t,e,n){io.schedule(t,e,n)}function At(t){if(typeof atob=="function"){const e=atob(t),n=new Uint8Array(e.length);for(let o=0;o<e.length;o++)n[o]=e.charCodeAt(o);return n}return Uint8Array.from(Buffer.from(t,"base64"))}function Tt(t,e){const n=ce;if(typeof n.applyUpdateV2=="function")try{n.applyUpdateV2(t,e)}catch(o){console.warn("[historyReplay] Failed to apply V2 update:",o)}}function Pt(t,e){try{ce.applyUpdate(t,e),Cn(t)||Tt(t,e)}catch{Tt(t,e)}}function co(t,e,n=-1){const o=new ce.Doc({gc:!1});Pt(o,At(t));const r=n<0?e.length:n;for(let s=0;s<r&&s<e.length;s++)Pt(o,At(e[s]));return o}class lo{constructor(){this.worker=null,this.workerFailed=!1,this.nextRequestId=1,this.pendingRequests=new Map}async init(){if(!(this.worker||this.workerFailed))try{if(typeof window>"u"||typeof Worker>"u"){this.workerFailed=!0;return}this.worker=new Worker(new URL(""+new URL("../assets/historyMaterializeWorker-C4uxcZEh.js",import.meta.url).href,import.meta.url)),this.worker.onmessage=e=>{const n=e.data,o=this.pendingRequests.get(n.id);if(o){if(this.pendingRequests.delete(n.id),!n.success){o.reject(new Error(n.error||"Worker request failed"));return}n.kind==="filterDistinct"?o.resolve(n.distinctIds??[]):n.doc?o.resolve(n.doc):o.reject(new Error("Materialization failed"))}},this.worker.onerror=e=>{console.warn("[HistoryMaterializer] Worker error:",e);for(const[n,o]of this.pendingRequests)o.reject(new Error("Worker error")),this.pendingRequests.delete(n);this.workerFailed=!0,this.worker?.terminate(),this.worker=null}}catch(e){console.warn("[HistoryMaterializer] Failed to create worker:",e),this.workerFailed=!0}}async materialize(e,n,o=-1){if(await this.init(),this.worker&&!this.workerFailed)try{return await this.materializeViaWorker(e,n,o)}catch(r){console.warn("[HistoryMaterializer] Worker materialization failed, falling back:",r)}return this.materializeSync(e,n,o)}async computeDistinctContentIds(e,n){if(n.length===0)return[];if(await this.init(),!this.worker||this.workerFailed)return null;try{return await new Promise((o,r)=>{if(!this.worker){r(new Error("Worker not available"));return}const s=this.nextRequestId++;this.pendingRequests.set(s,{resolve:o,reject:r});const i={id:s,kind:"filterDistinct",segments:e,candidateIds:n};this.worker.postMessage(i),setTimeout(()=>{this.pendingRequests.has(s)&&(this.pendingRequests.delete(s),r(new Error("Worker timeout")))},6e4)})}catch(o){return console.warn("[HistoryMaterializer] Distinct-frame filtering failed:",o),null}}materializeToYDoc(e,n,o=-1){return co(e,n,o)}materializeViaWorker(e,n,o){return new Promise((r,s)=>{if(!this.worker){s(new Error("Worker not available"));return}const i=this.nextRequestId++;this.pendingRequests.set(i,{resolve:r,reject:s});const c={id:i,snapshotB64:e,updatesB64:n,uptoIndex:o};this.worker.postMessage(c),setTimeout(()=>{this.pendingRequests.has(i)&&(this.pendingRequests.delete(i),s(new Error("Worker timeout")))},3e4)})}materializeSync(e,n,o){const r=this.materializeToYDoc(e,n,o);try{return fe(r)}finally{r.destroy()}}dispose(){for(const[,e]of this.pendingRequests)e.reject(new Error("Materializer disposed"));this.pendingRequests.clear(),this.worker?.terminate(),this.worker=null}isWorkerAvailable(){return this.worker!==null&&!this.workerFailed}}const Fe=new lo,nt="https://app-api.revise-sdk.invalid";class uo{constructor(e=20){this.cache=new Map,this.maxSize=e}get(e){const n=this.cache.get(e);return n&&(this.cache.delete(e),this.cache.set(e,n)),n}set(e,n){if(this.cache.size>=this.maxSize&&!this.cache.has(e)){const o=this.cache.keys().next().value;o&&this.cache.delete(o)}this.cache.delete(e),this.cache.set(e,n)}clear(){this.cache.clear()}}class ho{constructor(e,n,o){this.tailDebounceMs=1200,this.docCache=new uo,this.totalUpdates=0,this.segments=[],this.loaded=!1,this.maxEndLoaded=0,this.loadLock=null,this.targetLocks=new Map,this.blobLocks=new Map,this.abortController=null,this.contentIds=[],this.updateTimestamps=new Map,this.contentTimestamps=[],this.chunkEndUpdateIds=[],this.chunkSegIdx=[],this.distinctContentIds=null,this.distinctSignature=null,this.changeObservers=[],this.disposed=!1,this.documentId=e,this.authToken=o?.authToken,this.tailTaskId=`history-tail-${Math.random().toString(36).slice(2)}`,this.abortController=new AbortController}onChange(e){return this.changeObservers.push(e),()=>{const n=this.changeObservers.indexOf(e);n>=0&&this.changeObservers.splice(n,1)}}async ensureLoaded(){if(this.loaded)return!0;if(this.disposed)return!1;if(!this.supportsServerHistory())return this.loaded=!0,!0;try{const e=`${nt}/documents/${this.documentId}/history`,n=await this.fetchJson(e);return this.totalUpdates=this.readTotalUpdates(n),this.segments=this.parseFrames(n.frames),this.loaded=!0,this.recomputeDerivedData(),this.notifyChange(),!0}catch(e){return console.error("[UpdateHistoryManager] Failed to load update history:",{documentId:this.documentId,error:e instanceof Error?e.message:String(e)}),!1}}notifyDocUpdated(){this.disposed||!this.loaded||ao(this.tailTaskId,this.tailDebounceMs,()=>{this.refreshNewSegments()})}dispose(){this.disposed=!0,this.abortController?.abort(),this.abortController=null,this.changeObservers=[],this.docCache.clear(),this.segments=[],this.updateTimestamps.clear()}getTotalUpdates(){const e=this.segments[this.segments.length-1],n=this.contentIds[this.contentIds.length-1]??0;return Math.max(this.totalUpdates,e?.endUpdateId??0,n)}getContentCount(){return this.contentIds.length}getContentUpdateIds(){return this.contentIds.slice()}getDistinctContentUpdateIds(){return this.distinctContentIds&&this.distinctSignature===this.contentIdsSignature()?this.distinctContentIds.slice():null}contentIdsSignature(){const e=this.contentIds;return`${e.length}:${e[e.length-1]??0}`}async ensureDistinctFramesComputed(){}getWorkChunkCount(){return this.chunkEndUpdateIds.length}getWorkChunkEndUpdateIds(){return this.chunkEndUpdateIds.slice()}getTimestampForUpdateId(e){const n=this.updateTimestamps.get(Math.floor(e));return n&&Number.isFinite(n)&&n>0?n:null}getContentTimeline(){return{count:this.contentIds.length,timestamps:this.contentTimestamps.slice()}}getTimeAxisTicks(){let e;if(this.contentTimestamps.length>0?e=this.contentTimestamps.filter(L=>Number.isFinite(L)&&L>0):(e=Array.from(this.updateTimestamps.values()).filter(L=>Number.isFinite(L)&&L>0),e.sort((L,z)=>L-z)),e.length===0)return null;const n=e[0],o=e[e.length-1],r=o-n;if(r<=0)return{startTs:n,endTs:o,ticksTs:[]};const s=6e4,i=60*s,c=24*i,l=7*c;let u;r<i?u=5*s:r<c?u=i:r<30*c?u=c:u=l;const _=Math.floor(n/u)*u,T=[];let M=0,B=0;for(let L=_+u;L<o;L+=u){const z=L-u;for(;M<e.length&&e[M]<=z;)M++;for(B=Math.max(B,M);B<e.length&&e[B]<=L;)B++;B>M&&L>n&&T.push(L)}return{startTs:n,endTs:o,ticksTs:T}}getPauseMarkersForContent(e,n=10){const o=this.contentTimestamps;if(o.length<=1)return[];const r=Math.max(0,o[o.length-1]-o[0]);if(r<=0||e<=0)return[];const s=r*Math.max(1,n)/Math.max(1,e),i=[];let c=-1/0;for(let l=0;l<o.length-1;l++)o[l+1]-o[l]>=s&&o[l]-c>=s&&(i.push(l+1),c=o[l]);return i}async findLatestUpdateIdBeforeTimestamp(e){if(!await this.ensureLoaded()||!Number.isFinite(e)||e<=0||this.updateTimestamps.size===0)return null;const n=Array.from(this.updateTimestamps.entries()).filter(([,i])=>i>0).sort((i,c)=>i[1]-c[1]);if(n.length===0)return null;let o=0,r=n.length-1,s=null;for(;o<=r;){const i=o+r>>1;n[i][1]<=e?(s=n[i][0],o=i+1):r=i-1}return s??n[0][0]}async materializeAtContentIndex(e,n){if(!await this.ensureLoaded()||this.contentIds.length===0)return null;const o=Math.max(1,Math.min(this.contentIds.length,e));return this.materializeAt(this.contentIds[o-1],n)}async materializeAt(e,n){if(!await this.ensureLoaded()||this.segments.length===0)return null;const o=n?.excludePendingSuggestions===!0;e=Math.max(1,Math.min(this.getTotalUpdates(),e));const r=o?`update-${e}-accepted-only`:`update-${e}`,s=this.docCache.get(r);if(s)return s;await this.ensureHasSegmentFor(e);let i=this.getPlanForUpdateId(e);if(!i)return null;if(await this.ensureBlobsForSegmentStart(i.seg.startUpdateId),i=this.getPlanForUpdateId(e),!i?.seg.snapshotB64)return console.warn("[UpdateHistoryManager] Missing snapshot for segment",i?.seg.startUpdateId),null;const{seg:c}=i;try{const l=Math.min(c.updatesB64.length,c.frameOnly?c.updatesB64.length:e-c.startUpdateId+1);let u;if(o){const _=Fe.materializeToYDoc(c.snapshotB64,c.updatesB64,l);try{const T=Xe.createSuggestionProjectionFromYDoc(_,"reject");try{u=T.doc}finally{T.ydoc.destroy()}}finally{_.destroy()}}else u=await Fe.materialize(c.snapshotB64,c.updatesB64,l);return u&&this.docCache.set(r,u),u}catch(l){return console.error("[UpdateHistoryManager] Materialize failed:",{updateId:e,segmentRange:`${c.startUpdateId}-${c.endUpdateId}`,error:l instanceof Error?l.message:String(l)}),null}}async materializeChunkEnd(e,n){if(!await this.ensureLoaded()||this.chunkSegIdx.length===0)return null;const o=Math.max(0,Math.min(this.chunkSegIdx.length-1,Math.floor(e)-1)),r=n?.excludePendingSuggestions===!0?`chunk-end-${e}-accepted-only`:`chunk-end-${e}`,s=this.docCache.get(r);if(s)return s;const i=this.segments[this.chunkSegIdx[o]];await this.ensureBlobsForSegmentStart(i.startUpdateId);const c=await this.materializeAt(i.endUpdateId,n);return c&&this.docCache.set(r,c),c}async materializeChunkSnapshot(e,n){if(!await this.ensureLoaded()||this.chunkSegIdx.length===0)return null;const o=Math.max(0,Math.min(this.chunkSegIdx.length-1,Math.floor(e)-1)),r=this.segments[this.chunkSegIdx[o]];if(await this.ensureBlobsForSegmentStart(r.startUpdateId),!r.snapshotB64)return null;if(n?.excludePendingSuggestions){const s=Fe.materializeToYDoc(r.snapshotB64,[],0);try{const i=Xe.createSuggestionProjectionFromYDoc(s,"reject");try{return i.doc}finally{i.ydoc.destroy()}}finally{s.destroy()}}return Fe.materialize(r.snapshotB64,[],0)}async materializeChunkPair(e,n){if(!await this.ensureLoaded()||this.chunkSegIdx.length===0)return null;const o=Math.max(0,Math.min(this.chunkSegIdx.length-1,Math.floor(e)-1)),r=this.segments[this.chunkSegIdx[o]];await this.ensureBlobsForSegmentStart(r.startUpdateId);const s=await this.materializeAt(r.endUpdateId,n);if(!s)return null;if(o>0){const c=this.segments[this.chunkSegIdx[o-1]];await this.ensureBlobsForSegmentStart(c.startUpdateId);const l=await this.materializeAt(c.endUpdateId,n);if(l)return{base:l,target:s}}if(!r.snapshotB64)return null;const i=await this.materializeChunkSnapshot(e,n);return i?{base:i,target:s}:null}__getPlanForTest(e){return this.getPlanForUpdateId(e)}supportsServerHistory(){return this.documentId.length>8}async fetchJson(e){if(this.disposed)throw new Error("Manager disposed");const n={};this.authToken&&(n.Authorization=`Bearer ${this.authToken}`);const o=await fetch(e,{headers:n,credentials:"omit",signal:this.abortController?.signal});if(!o.ok)throw new Error(`HTTP ${o.status}`);return o.json()}readTotalUpdates(e){const n=Number(e.totalUpdates);return!Number.isFinite(n)||n<=0?this.totalUpdates:n}parseFrames(e){return e?e.filter(n=>Number.isFinite(n.updateId)&&Number.isFinite(n.sourceId)&&(n.source==="legacy"||n.source==="delta")).map(n=>({startUpdateId:Number(n.updateId),endUpdateId:Number(n.updateId),snapshotB64:"",updatesB64:[],meta:[{ts:Number(n.timestamp||0),content:!0,userId:n.userId??null,agentName:n.agentName??null}],frameSource:n.source,frameSourceId:Number(n.sourceId),frameOnly:!0})).sort((n,o)=>n.startUpdateId-o.startUpdateId):[]}async refreshNewSegments(){!this.supportsServerHistory()||this.disposed||!this.loaded||await this.withLoadLock(async()=>{const e=`${nt}/documents/${this.documentId}/history`;try{const n=await this.fetchJson(e);this.totalUpdates=this.readTotalUpdates(n),this.segments=this.parseFrames(n.frames),this.recomputeDerivedData(),this.notifyChange()}catch(n){n.name!=="AbortError"&&console.warn("[UpdateHistoryManager] Failed to refresh segments:",n)}})}async ensureHasSegmentFor(e){if(!this.supportsServerHistory()||this.disposed||this.segments.some(r=>r.startUpdateId<=e&&e<=r.endUpdateId))return;const n=this.targetLocks.get(e);if(n)return n;const o=this.fetchSegmentContaining(e).finally(()=>{this.targetLocks.delete(e)});this.targetLocks.set(e,o),await o}async fetchSegmentContaining(e){if(this.disposed)return;const n=this.getPlanForUpdateId(e)?.seg;if(!n?.frameSource||n.frameSourceId==null)return;const o=new URLSearchParams({source:n.frameSource,sourceId:String(n.frameSourceId)});n.frameSource==="legacy"&&o.set("targetUpdateId",String(e));const r=`${nt}/documents/${this.documentId}/history/frame?${o.toString()}`;try{const s=await this.fetchJson(r);n.snapshotB64=s.snapshotB64||"",n.updatesB64=s.updatesB64||[]}catch(s){s.name!=="AbortError"&&console.warn("[UpdateHistoryManager] Failed to fetch segment:",{updateId:e,error:s})}}async ensureBlobsForSegmentStart(e){const n=this.segments.find(r=>r.startUpdateId===e);if(n?.snapshotB64&&Array.isArray(n.updatesB64))return;let o=this.blobLocks.get(e);o||(o=this.fetchSegmentContaining(e).finally(()=>{this.blobLocks.delete(e)}),this.blobLocks.set(e,o)),await o}async withLoadLock(e){if(this.loadLock)return this.loadLock;this.loadLock=e();try{await this.loadLock}finally{this.loadLock=null}}mergeInSegments(e){if(e.length===0)return;const n=new Map;for(const o of this.segments)n.set(o.startUpdateId,o);for(const o of e){const r=n.get(o.startUpdateId);if(!r){n.set(o.startUpdateId,o);continue}n.set(o.startUpdateId,{startUpdateId:r.startUpdateId,endUpdateId:Math.max(r.endUpdateId,o.endUpdateId),snapshotB64:r.snapshotB64||o.snapshotB64,updatesB64:(o.updatesB64?.length||0)>=(r.updatesB64?.length||0)?o.updatesB64:r.updatesB64,meta:(o.meta?.length||0)>=(r.meta?.length||0)?o.meta:r.meta,frameSource:o.frameSource||r.frameSource,frameSourceId:o.frameSourceId??r.frameSourceId,frameOnly:o.frameOnly||r.frameOnly})}this.segments=Array.from(n.values()).sort((o,r)=>o.startUpdateId-r.startUpdateId),this.maxEndLoaded=0;for(const o of this.segments)o.endUpdateId>this.maxEndLoaded&&(this.maxEndLoaded=o.endUpdateId)}getPlanForUpdateId(e){if(this.segments.length===0)return null;let n=this.segments.find(r=>r.startUpdateId<=e&&e<=r.endUpdateId);if(!n){const r=this.segments[0],s=this.segments[this.segments.length-1];if(e<r.startUpdateId)n=r;else if(e>s.endUpdateId)n=s;else for(let i=0;i<this.segments.length-1;i++)if(e>this.segments[i].endUpdateId&&e<this.segments[i+1].startUpdateId){n=this.segments[i];break}}if(!n)return null;const o=Math.max(0,Math.min(n.updatesB64.length,e-n.startUpdateId+1));return{seg:n,upto:o}}recomputeDerivedData(){this.docCache.clear(),this.recomputeContentIds(),this.recomputeTimestamps(),this.recomputeChunks()}recomputeContentIds(){const e=[];for(let n=0;n<this.segments.length;n++){const o=this.segments[n];if(o.frameOnly){e.push(o.startUpdateId);continue}const r=o.meta,s=Math.max(o.updatesB64.length,r?.length||0),i=n<2;for(let c=0;c<s;c++)(r?.[c]?.content||i&&c===0)&&e.push(o.startUpdateId+c)}this.contentIds=e}recomputeTimestamps(){this.updateTimestamps.clear();for(const e of this.segments){const n=e.meta;if(n)for(let o=0;o<n.length;o++){const r=e.startUpdateId+o,s=Number(n[o]?.ts||0);s>0&&this.updateTimestamps.set(r,s)}}this.contentTimestamps=this.contentIds.map(e=>this.updateTimestamps.get(e)||0)}recomputeChunks(){const e=this.segments.length;if(e===0){this.chunkSegIdx=[],this.chunkEndUpdateIds=[];return}const n=[];for(let r=0;r<e;r++){if(this.segments[r].frameOnly){n.push(r);continue}const s=this.segments[r].meta,i=Array.isArray(s)&&s.some(l=>l?.content),c=r<2;(i||c)&&n.push(r)}const o=e-1;(n.length===0||n[n.length-1]!==o)&&n.push(o),this.chunkSegIdx=n,this.chunkEndUpdateIds=n.map(r=>this.segments[r].endUpdateId)}notifyChange(){if(!this.disposed)for(const e of this.changeObservers.slice())try{e()}catch(n){console.error("[UpdateHistoryManager] Observer error:",n)}}}const go=()=>{},mo=async()=>{},po=new Set;function ot(t,e){for(const n of po)try{n(t,e)}catch{}}const fo=new Proxy({track:(t,e)=>ot(t,e),trackAgentToolInvoked:(t,e,n,o=!1)=>ot("Agent Tool Invoked",{tool:t,documentId:e??void 0,directMode:o}),trackDocumentExported:(t,e,n)=>ot("Document Exported",{documentId:t,format:e,source:n}),getCheckoutAttribution:()=>null,flush:mo},{get(t,e){return e in t?t[e]:go}});class mt{constructor(e,n,o,r){this.isViewingRevision=!1,this.documentChangeObservers=[],this.isReadOnly=!1,this.timeTravelActive=!1,this.viewModeObservers=[],this.historyOpen=!1,this.historyDiffEnabled=!0,this.historySelection={start:null,end:null},this.historyObservers=[],this.notesObservers=[],this.notesValue="",this.cleanupCallbacks=[],this.disposed=!1,this.historyManager=null,this.sharedWriteAccess=null,this.autocorrectEnabled=!0,this.suggestionDecisionsAllowed=!0,this.documentId=e,this.sharedStyleMigrationPermit=r?.sharedStyleMigrationPermit,this.authToken=r?.authToken,this.onTitleChange=o;const s=r?.disableProposalPersistence??!!r?.authToken;if(this.preprocessorSession=new qn,Ye(n)){const l=n;if(this.ydoc=wt(l,this.sharedStyleMigrationPermit?{sharedStyles:this.sharedStyleMigrationPermit.formatGateConfirmed===!0&&this.sharedStyleMigrationPermit.exclusive===!0}:void 0),l.pendingDocxCarrier){const u=l.pendingDocxCarrier;delete l.pendingDocxCarrier,Yn(this.ydoc,u.bytes,{hash:u.hash})}l.pageless!==void 0&&this.ydoc.getMap("metadata").set("pageless",l.pageless),this.currentDocument=this.cloneDoc(l)}else{this.ydoc=n;const l=fe(this.ydoc);this.currentDocument=this.cloneDoc(l)}Ln(this.ydoc),Ye(n)&&(this.sharedWriteAccess=!0),this.documentMutator=new Xe(fe(this.ydoc),(l,u)=>this.updateWorkingDocument(l,u),this.onTitleChange,this.ydoc,e,s,this.preprocessorSession,{canRepairIdentity:()=>this.sharedWriteAccess===!0,deferIdentityRepair:!Ye(n)}),this.documentMutator.identityRepairedOnConstruct&&(this.currentDocument=this.cloneDoc(fe(this.ydoc))),this.notesValue=this.documentMutator.getDocumentNotes();try{this.documentMutator.backfillLiveSuggestionTreeRecords(),this.documentMutator.reconcileFootnotes(),this.documentMutator.migrateChromeOutOfContent(),this.documentMutator.migrateNotesOutOfContent(),this.documentMutator.migrateLegacyHeaderFooterMetadata(),this.documentMutator.migrateLegacyPageNumbers()}catch{}this.backfillStylesheetSidecar(),this.cleanupCallbacks.push(Dn(this.ydoc,l=>{console.warn(`[DocumentSession] repaired a duplicate seed: removed ${l.removedBlocks} blocks from ${l.losingClaims} losing seed(s)`)}));const i=this.ydoc.getMap("metadata"),c=l=>{if(l.keysChanged.has("notes")){const u=this.documentMutator.getDocumentNotes();u!==this.notesValue&&(this.notesValue=u,this.notifyNotesObservers())}};if(i.observe(c),this.cleanupCallbacks.push(()=>i.unobserve(c)),!r?.disableHistory){this.historyManager=new ho(this.documentId,this.ydoc,{authToken:this.authToken});const l=()=>{this.historyManager?.notifyDocUpdated()};this.ydoc.on("update",l),this.cleanupCallbacks.push(()=>this.ydoc.off("update",l))}}static fromDocRoot(e,n){return new mt("no-id",e,n)}getDocumentId(){return this.documentId}dispose(){if(!this.disposed){this.disposed=!0;for(const e of this.cleanupCallbacks.splice(0))e();this.documentMutator.dispose(),this.historyManager?.dispose(),this.historyManager=null,this.documentChangeObservers=[],this.viewModeObservers=[],this.historyObservers=[],this.notesObservers=[]}}setReadOnly(){this.isReadOnly=!0}setReadWrite(){this.isReadOnly=!1}setSharedWriteAccess(e){const n=e&&this.sharedWriteAccess!==!0;this.sharedWriteAccess=e,n&&this.documentMutator.repairDocumentIdentity()&&this.notifyDocumentChange(this.documentMutator.getDocument(),{origin:"local"}),n&&this.sharedStyleMigrationPermit&&(An(this.ydoc,this.sharedStyleMigrationPermit),this.sharedStyleMigrationPermit=void 0)}setSuggestingMode(e){this.documentMutator.setSuggestingMode(e)}isSuggestingMode(){return this.documentMutator.isSuggestingMode()}getWorkingDocument(){return this.documentMutator.getDocument()}getDocumentWithoutPendingSuggestions(){return this.documentMutator.getLiveSuggestionIds().length>0?this.documentMutator.getDocumentWithRejectedSuggestions():this.getWorkingDocument()}getWorkingDocumentBeforePendingReview(){return this.getDocumentWithoutPendingSuggestions()}getDocumentWithPendingSuggestionsApplied(e){if(e?.conversationId!==void 0&&this.documentMutator.setDetachedSuggestionConversation(e.conversationId??null,e.serverDetachedSuggestions),this.documentMutator.getLiveSuggestionIds().length>0)return this.documentMutator.getDocumentWithAcceptedSuggestions();const n=this.documentMutator.getDetachedSuggestionStore(),o=n.getPendingSuggestions();if(o.size===0)return this.getWorkingDocument();const r=Array.from(o.keys()),s=n.materializeWithSuggestions(r);return fe(s)}getCurrentDocument(){return this.currentDocument}updateWorkingDocument(e,n={origin:"unknown"}){!this.isViewingRevision&&!this.historyOpen&&(this.currentDocument=e),this.logUnresolvableLiveSuggestions(n),this.notifyDocumentChange(this.currentDocument,n)}logUnresolvableLiveSuggestions(e){const n=this.documentMutator.getLiveSuggestionIds();if(n.length===0)return;const o=this.documentMutator.getUnresolvableLiveSuggestionRecords(),r=o.filter(s=>s.source==="agent");this.documentId,e.origin,n.length,o.length,r.length}countPrunedByKey(e,n){return e.reduce((o,r)=>{const s=r[n]||"unknown";return o[s]=(o[s]??0)+1,o},{})}trackPrunedUnresolvableLiveSuggestions(e,n,o){const r=this.documentMutator.takeLastPrunedUnresolvableLiveSuggestions();if(r.length===0)return;const s=r.filter(c=>c.source==="agent").length,i={Document:this.documentId,Action:e,RequestedSuggestionCount:new Set(n).size,ResolvedSuggestionCount:o,PrunedSuggestionCount:r.length,PrunedAgentSuggestionCount:s,PrunedSuggestionTypes:this.countPrunedByKey(r,"type"),PrunedSuggestionSources:this.countPrunedByKey(r,"source"),PrunedSuggestions:r};fo.track("Live Suggestions Pruned",i)}onDocumentChange(e){return this.documentChangeObservers.push(e),()=>{const n=this.documentChangeObservers.indexOf(e);n>-1&&this.documentChangeObservers.splice(n,1)}}notifyDocumentChange(e,n={origin:"unknown"}){const o=e??this.getCurrentDocument();this.documentChangeObservers.forEach(r=>{try{r(o,n)}catch(s){console.error("Error in document change observer:",s)}})}exitRevisionView(){this.isViewingRevision=!1,this.currentDocument=this.getWorkingDocument(),this.notifyViewModeChange(),this.notifyDocumentChange()}getDocumentMutator(){return this.documentMutator}async getDocumentSnapshotAtOrBefore(e){if(!this.historyManager||!Number.isFinite(e)||e<=0)return null;const n=await this.historyManager.findLatestUpdateIdBeforeTimestamp(e);return n===null?null:this.historyManager.materializeAt(n,{excludePendingSuggestions:!0})}getDocumentNotes(){return this.notesValue}setDocumentNotes(e){if(this.isReadOnly)return;const n=typeof e=="string"?e:String(e??"");n!==this.notesValue&&(this.notesValue=n,this.documentMutator.setNotes(n),this.notifyNotesObservers())}onNotesChange(e){return this.notesObservers.push(e),()=>{const n=this.notesObservers.indexOf(e);n>=0&&this.notesObservers.splice(n,1)}}getPreprocessorSession(){return this.preprocessorSession}getRevisionManager(){return null}getYDoc(){return this.ydoc}registerRemoteOrigin(e){this.documentMutator.registerRemoteOrigin(e)}unregisterRemoteOrigin(e){this.documentMutator.unregisterRemoteOrigin(e)}setTimeTravelActive(e){this.timeTravelActive=!!e}isTimeTravelActive(){return this.timeTravelActive}onViewModeChange(e){return this.viewModeObservers.push(e),()=>{const n=this.viewModeObservers.indexOf(e);n>=0&&this.viewModeObservers.splice(n,1)}}openHistory(){this.historyOpen=!0,this.notifyHistoryChange()}closeHistory(){this.historyOpen=!1,this.notifyHistoryChange()}isHistoryOpen(){return this.historyOpen}setDiffEnabled(e){this.historyDiffEnabled=!!e,this.notifyHistoryChange()}isDiffEnabled(){return this.historyDiffEnabled}setSelection(e){this.historySelection={start:e.start??null,end:e.end??null},this.notifyHistoryChange()}getSelection(){return{...this.historySelection}}onHistoryStateChange(e){return this.historyObservers.push(e),()=>{const n=this.historyObservers.indexOf(e);n>=0&&this.historyObservers.splice(n,1)}}notifyHistoryChange(){for(const e of this.historyObservers.slice())try{e()}catch(n){console.error("[DocumentSession] History observer error:",n)}}backfillStylesheetSidecar(){try{const e=this.ydoc.getMap("metadata"),n=e.get("stylesXml");if(typeof n!="string"||n.length===0||e.get("stylesheet")!==void 0)return;import("./DocxConverter-Be3uPNcD.js").then(({DocxConverter:o})=>{if(this.isReadOnly||this.isViewingRevision||e.get("stylesheet")!==void 0)return;const r=o.resolveStylesheetFromStylesXml(n,this.currentDocument.pageLayout);r&&this.ydoc.transact(()=>{e.set("stylesheet",r)})}).catch(()=>{})}catch{}}notifyNotesObservers(){const e=this.getDocumentNotes();for(const n of this.notesObservers.slice())try{n(e)}catch(o){console.error("[DocumentSession] Notes observer error:",o)}}async applySelection(e){const n=this.historyManager;if(!n||!e)return;const o=this.historyDiffEnabled,r=this.historySelection;await n.ensureLoaded();const s=n.getTotalUpdates?.()||0;if(s<=0)return;const i=y=>Math.max(1,Math.min(s,Math.floor(y))),c=async y=>await n.materializeAt?.(i(y),{excludePendingSuggestions:!0}),l=()=>this.getDocumentWithoutPendingSuggestions(),u=y=>{try{e.getEditor?.()?.setDisplayDocument?.(y)}catch(k){console.error("[DocumentSession] Failed to set display document:",k)}},_=async y=>{const k=await c(y);if(k){try{e.clearDiffPresentation?.()}catch(D){console.error("[DocumentSession] Failed to clear diff presentation:",D)}u(k)}},T=async(y,k)=>{const D=await c(y),R=await c(k);!D||!R||(e.showDiffBetweenDocuments?.(D,R),u(R))},M=async y=>{const k=await c(y),D=l();!k||!D||(e.showDiffBetweenDocuments?.(k,D),u(D))},B=r.start,L=r.end;if(B!=null&&L!=null&&B!==L){const y=i(B),k=i(L),D=Math.min(y,k),R=Math.max(y,k);o?await T(D,R):await _(R);return}const z=typeof B=="number"?B:null;if(z==null)return;const $=i(z);if($<=1){await _(1);return}if(o)if($===s)try{const y=await c(s),k=l();JSON.stringify(y)===JSON.stringify(k)?s>1?await T(s-1,s):await _(1):await M(s)}catch{await M(s)}else $>1?await T($-1,$):await _($);else await _($)}async showDiffBetweenHistoryUpdates(e,n,o){const r=this.historyManager;if(!r||!e)return!1;const s=Math.min(n,o),i=Math.max(n,o);if(!Number.isFinite(s)||!Number.isFinite(i)||s<=0||i<=s||!await r.ensureLoaded())return!1;const c=r.getTotalUpdates?.()??0;return i>c?!1:(this.openHistory(),this.setDiffEnabled(!0),this.setSelection({start:s,end:i}),await this.applySelection(e),!0)}notifyViewModeChange(){const e=this.isViewingRevision;this.viewModeObservers.forEach(n=>{try{n(e)}catch{}})}getStorageType(){return this.ydoc.getMap("metadata").get("storageType")}getParentFolderId(){const e=this.ydoc.getMap("metadata").get("parentFolderId");return typeof e=="string"&&e.length>0?e:null}getHistoryManager(){return this.historyManager}attachDemoHistoryManager(e){this.historyManager=e}async jumpToUpdateId(e){const n=await this.historyManager?.materializeAt(e,{excludePendingSuggestions:!0});return n?(this.currentDocument=this.cloneDoc(n),this.notifyDocumentChange(),!0):!1}async jumpToContentIndex(e){const n=this.historyManager;if(!n?.materializeAtContentIndex)return!1;const o=await n.materializeAtContentIndex(e,{excludePendingSuggestions:!0});return o?(this.currentDocument=this.cloneDoc(o),this.notifyDocumentChange(),!0):!1}cloneDoc(e){return JSON.parse(JSON.stringify(e))}getPagelessMode(){return this.documentMutator.getPagelessMode()}setPagelessMode(e){this.documentMutator.setPagelessMode(e)}getPageLayoutSettings(){return this.documentMutator.getPageLayoutSettings()}setPageLayoutSettings(e){this.documentMutator.setPageLayoutSettings(e)}getIndentStepPx(){return this.documentMutator.getIndentStepPx()}setAutocorrectEnabled(e){this.autocorrectEnabled=e}isAutocorrectEnabled(){return this.autocorrectEnabled}insertText(e,n,o,r){return this.documentMutator.insertText(e,n,o,r)}getAfterOperationSelection(){return this.documentMutator.getAfterOperationSelection()}insertFormattedText(e,n,o,r,s){return this.documentMutator.insertFormattedText(e,n,o,r,s)}deleteText(e,n,o,r){return this.documentMutator.deleteText(e,n,o,r)}deleteSelection(e,n,o,r){return this.documentMutator.deleteSelection(e,n,o,r)}deleteBlock(e,n,o){return this.documentMutator.deleteBlock(e,n,o)}deleteBlockById(e,n,o){return this.documentMutator.deleteBlockById(e,n,o)}insertBlock(e,n,o,r){return this.documentMutator.insertBlock(e,n,o,r)}insertBlockAfterId(e,n,o,r){return this.documentMutator.insertBlockAfterId(e,n,o,r)}insertBlockBeforeId(e,n,o,r){return this.documentMutator.insertBlockBeforeId(e,n,o,r)}insertBlockIntoParent(e,n,o,r){return this.documentMutator.insertBlockIntoParent(e,n,o,r)}insertBlockAtStart(e,n,o){return this.documentMutator.insertBlockAtStart(e,n,o)}insertBlockAtEnd(e,n,o){return this.documentMutator.insertBlockAtEnd(e,n,o)}updateBlock(e,n,o,r){return this.documentMutator.updateBlock(e,n,o,r)}updateBlockById(e,n,o,r){return this.documentMutator.updateBlockById(e,n,o,r)}replaceParagraphById(e,n,o,r){return this.documentMutator.replaceParagraphById(e,n,o,r)}toggleTodoItem(e,n,o,r,s){return this.documentMutator.toggleTodoItem(e,n,o,r,s)}toggleTodoItemById(e,n,o,r,s){return this.documentMutator.toggleTodoItemById(e,n,o,r,s)}setListItemIndent(e,n,o,r,s){return this.documentMutator.setListItemIndent(e,n,o,r,s)}splitParagraph(e,n){return this.documentMutator.splitParagraph(e,n)}applyFormatting(e,n,o,r,s){return this.documentMutator.applyFormatting(e,n,o,r,s)}setSelectionAfterOperation(e){this.documentMutator.setSelectionAfterOperation(e)}setFontFamily(e,n,o,r){return this.documentMutator.setFontFamily(e,n,o,r)}setFontSize(e,n,o,r){return this.documentMutator.setFontSize(e,n,o,r)}setLetterSpacing(e,n,o,r){return this.documentMutator.setLetterSpacing(e,n,o,r)}setTextColor(e,n,o,r){return this.documentMutator.setTextColor(e,n,o,r)}setBackgroundColor(e,n,o,r){return this.documentMutator.setBackgroundColor(e,n,o,r)}clearFormatting(e,n,o){return this.documentMutator.clearFormatting(e,n,o)}setLink(e,n,o,r){return this.documentMutator.setLink(e,n,o,r)}setCodeBlockLanguage(e,n){return this.documentMutator.setCodeBlockLanguage(e,n)}setCodeBlockRenderDiagram(e,n){return this.documentMutator.setCodeBlockRenderDiagram(e,n)}setCodeBlockShowDiagramSource(e,n){return this.documentMutator.setCodeBlockShowDiagramSource(e,n)}setMathBlockContent(e,n){return this.documentMutator.setMathBlockContent(e,n)}setMathBlockDisplayMode(e,n){return this.documentMutator.setMathBlockDisplayMode(e,n)}setMathBlockAlign(e,n){return this.documentMutator.setMathBlockAlign(e,n)}replaceParagraph(e,n,o,r){return this.documentMutator.replaceParagraph(e,n,o,r)}pasteParagraphs(e,n,o,r={}){return this.documentMutator.pasteParagraphs(e,n,o,r)}canUndo(){return this.documentMutator.canUndo()}canRedo(){return this.documentMutator.canRedo()}undo(){return this.documentMutator.undo()}redo(e){return this.documentMutator.redo(e)}getLiveSuggestionIdsBySource(e){return this.documentMutator.getLiveSuggestionIdsBySource(e)}getLiveSuggestionIdsByCommentThread(e){return this.documentMutator.getLiveSuggestionIdsByCommentThread(e)}getInlineSuggestionMetadataFromDocument(e){return this.documentMutator.getInlineSuggestionMetadataFromDocument(e)}setSuggestionDecisionsAllowed(e){this.suggestionDecisionsAllowed=e}canDecideSuggestions(){return this.suggestionDecisionsAllowed}refusedDecision(e){return{decision:e.decision,scope:e.scope,resolvedCount:0,initialSuggestionIds:[],attemptedSuggestionIds:[],attemptedSuggestionIdCount:0,prunedSuggestions:[]}}decideLiveSuggestions(e){return this.suggestionDecisionsAllowed?this.decideLiveSuggestionsUnchecked(e):this.refusedDecision(e)}decideLiveSuggestionsUnchecked(e){const n=this.documentMutator.decideLiveSuggestions(e);return this.trackPrunedUnresolvableLiveSuggestions(e.decision,n.attemptedSuggestionIds,n.resolvedCount),n}acceptLiveSuggestions(e){return this.decideLiveSuggestions({decision:"accept",scope:{kind:"ids",suggestionIds:e}}).resolvedCount}acceptLiveSuggestionsBySource(e){return this.decideLiveSuggestions({decision:"accept",scope:{kind:"source",source:e}})}nativeAgentLiveSuggestionIds(){return this.documentMutator.getLiveSuggestionIdsBySource("agent").filter(e=>Gn(this.documentMutator.getInlineSuggestionMetadataFromDocument(e)?.agentName??this.documentMutator.getLiveSuggestion(e)?.agentName))}rollbackAgentSuggestions(e){const n=this.nativeAgentLiveSuggestionIds().map(i=>{const c=this.documentMutator.getInlineSuggestionMetadataFromDocument(i),l=this.documentMutator.getLiveSuggestion(i);return{suggestionId:i,agentConversationId:c?.agentConversationId??l?.agentConversationId,agentRequestId:c?.agentRequestId??l?.agentRequestId,agentTurn:c?.agentTurn??l?.agentTurn}}).filter(i=>i.agentConversationId===e.agentConversationId&&typeof i.agentRequestId=="number"&&typeof i.agentTurn=="number"),o=e.requestId??n.reduce((i,c)=>{const l=c.agentRequestId;return l>=e.currentRequestId?i:i===void 0||l>i?l:i},void 0);if(o===void 0)return{suggestionIds:[],resolvedCount:0};const r=n.filter(i=>e.turn===void 0&&i.agentRequestId>=o||e.turn!==void 0&&i.agentRequestId===o&&i.agentTurn===e.turn).map(i=>i.suggestionId);if(r.length===0)return{requestId:o,turn:e.turn,suggestionIds:[],resolvedCount:0};const s=this.decideLiveSuggestionsUnchecked({decision:"reject",scope:{kind:"ids",suggestionIds:r},historyOrigin:`agent-suggestion-rollback:${e.agentConversationId}:${o}:${e.turn??"all"}:by-${e.currentRequestId}:${e.currentTurn}`});return{requestId:o,turn:e.turn,suggestionIds:r,resolvedCount:s.resolvedCount}}setSuggestionAuthorName(e){this.documentMutator.setDefaultSuggestionAuthorName(e)}acceptLiveSuggestionsByAuthor(e){return this.suggestionDecisionsAllowed?this.documentMutator.acceptLiveSuggestionsByAuthor(e):this.refusedDecision({decision:"accept",scope:{kind:"author",authorName:e}})}rejectLiveSuggestionsByAuthor(e){return this.suggestionDecisionsAllowed?this.documentMutator.rejectLiveSuggestionsByAuthor(e):this.refusedDecision({decision:"reject",scope:{kind:"author",authorName:e}})}acceptLiveSuggestionsByKind(e){return this.suggestionDecisionsAllowed?this.documentMutator.acceptLiveSuggestionsByKind(e):this.refusedDecision({decision:"accept",scope:{kind:"suggestion-kind",suggestionKind:e}})}rejectLiveSuggestionsByKind(e){return this.suggestionDecisionsAllowed?this.documentMutator.rejectLiveSuggestionsByKind(e):this.refusedDecision({decision:"reject",scope:{kind:"suggestion-kind",suggestionKind:e}})}acceptAgentSuggestions(){return this.decideLiveSuggestions({decision:"accept",scope:{kind:"ids",suggestionIds:this.nativeAgentLiveSuggestionIds()}})}rejectLiveSuggestions(e){return this.decideLiveSuggestions({decision:"reject",scope:{kind:"ids",suggestionIds:e}}).resolvedCount}rejectLiveSuggestionsBySource(e){return this.decideLiveSuggestions({decision:"reject",scope:{kind:"source",source:e}})}rejectAgentSuggestions(){return this.decideLiveSuggestions({decision:"reject",scope:{kind:"ids",suggestionIds:this.nativeAgentLiveSuggestionIds()}})}beginGroup(e){this.documentMutator.beginGroup(e)}endGroup(){this.documentMutator.endGroup()}clearHistory(){this.documentMutator.clearHistory()}getHistoryInfo(){return this.documentMutator.getHistoryInfo()}setCurrentDocument(e){this.currentDocument=this.cloneDoc(e),this.notifyDocumentChange()}hasUncommittedChanges(){return!1}getDetachedSuggestionStore(){return this.documentMutator.getDetachedSuggestionStore()}clearLegacyDetachedSuggestionState(){this.documentMutator.clearLegacyDetachedSuggestionState()}migrateLegacyDetachedSuggestionsToLiveSuggestions(e){return this.documentMutator.migrateLegacyDetachedSuggestionsToLiveSuggestions(e)}applyAgentActions(e,n,o){return o?.startNewTurn!==!1&&this.preprocessorSession.startNewTurn(),this.documentMutator.applyAgentActions(e,n,{optimizeStyleFormatting:o?.optimizeStyleFormatting})}}const rt=new Set(["import_attachment_into_document","insert_block","insert_footnote","replace_block","set_block_attribute","style_blocks","clear_formatting","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","set_page_layout","set_header_footer","insert_table_row","remove_table_row","insert_table_column","remove_table_column"]),Bt=[{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 pending 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_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 or 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,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 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 the user to open it and continue there.",type:"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 document. 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 before 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 replace, 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 document. 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 tool 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:"string"},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 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; prefix regex patterns with 'regex:'.",items:{type:"string"},type:"array"}},required:["queries","page","context_notes"],type:"object"}},{name:"find_highlights",description:'Find highlighted text blocks, optionally 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 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:{additionalProperties:!1,properties:{color:{description:"Optional color filter.",enum:["yellow","orange","green","blue","purple","pink","gray"],type:"string"},context_notes:{description:"Plain-text notes 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:"object"}},{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 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:"Block 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"},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 the user to open it and continue there.",type:"string"}},required:["block_ids","context_notes"],type:"object"}},{name:"measure_document",description:"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 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. 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 include 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. Default 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,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:"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 counts, 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:["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:"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_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; 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,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 HTML. A reference may be nested inside a table cell; inserting <img> (bare or wrapped by a paragraph/presentational span) next to 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-source-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 while 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 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; direction: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 inserted 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).',inputSchema:{additionalProperties:!1,properties:{content:{description:'HTML block elements to insert, e.g. <p>, <h1>, <ul>, <img>, <toc levels="3"></toc> (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 direct 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 is 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 for it.',items:{type:"string"},type:"array"},position:{description:"Insert before or after reference block.",enum:["before","after"],type:"string"},referenceId:{description:"Current reference 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, use an existing block ID.",type:"string"}},required:["content","position","referenceId"],type:"object"}},{name:"insert_footnote",description:"Insert a footnote: a numbered superscript reference placed 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 with 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:"Anchor 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:"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","endnote"],type:"string"},text:{description:"Footnote body text.",type:"string"}},required:["id","find","text"],type:"object"}},{name:"remove_blocks",description:"Remove native footnotes/endnotes by targeting the note ID or its body block ID with id + count=1; this removes the entire note and all its inline references while preserving the surrounding paragraph. To remove multiple notes, use ids containing only note/body IDs (do not mix with main-document block IDs or use a count range). For notes found by search, use their explicit IDs rather than search_result_id. Remove one or more blocks by a direct target (id, optionally with count), an explicit tail range (id + through_end=true), an exact nonconsecutive ID batch (ids), or every block in a 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 must 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 context. Prefer search_result_id for large or sparse match sets; search discovers candidates but never deletes them implicitly.",inputSchema:{additionalProperties:!1,properties:{count:{description:"Number of consecutive blocks. Only count blocks available in the current document context; never use the document total block count.",minimum:1,type:"integer"},id:{description:"First block ID to remove.",type:"string"},ids:{description:"Exact nonconsecutive block IDs to remove. Each ID must have appeared in document 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_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 is unavailable or stale.",type:"string"},through_end:{description:"Set true with id to remove that top-level block and the entire document tail after it. Mutually exclusive with count, ids, and search_result_id. Omit unless the whole 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:{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 the first occurrence of substring; second paragraph starts there.",inputSchema:{additionalProperties:!1,properties:{id:{description:"Paragraph ID.",type:"string"},substring:{description:"Substring where 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 appended 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:{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 inline-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 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"],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_document 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 for 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 and 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 alignment 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-source-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="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 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 is 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 for it.',items:{type:"string"},type:"array"},count:{description:"Number of consecutive sibling blocks to replace. Only count blocks available in the current document context; never use the document total block count.",minimum:1,type:"integer"},id:{description:"First block ID to replace.",type:"string"},search_result_id:{description:"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 reference is 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_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 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, 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 hex 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 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. Table-cell selectors apply text styles, alignment, and spacing to their descendant 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":"fontWeight","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"] 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, 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 durable document equivalents; feedback lists approximations and unsupported values. Null resets.",items:{additionalProperties:!1,properties:{name:{description:"Attribute/style name, e.g. fontSize, font-size, 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","value"],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 unpaginated 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: * (also 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, 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, #blockId *, #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"},{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): bold, italic, underline, code, LaTeX, superscript/subscript, background highlight, and links. Preserve font family, font size, text color, and paragraph attributes.",inputSchema:{additionalProperties:!1,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:"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_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 inherited 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 every 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 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 normal 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:{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 target 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 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 page 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", "3cm", "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 (examples: "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, 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 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 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"},noteMode:{description:"Bulk-convert existing 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 native 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:["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 the 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:{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"}},required:["style","color","widthPt","spacePt"],type:"object"},display:{enum:["allPages","firstPage","notFirstPage"],type:"string"},left:{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"},widthPt:{maximum:12,minimum:.25,type:"number"}},required:["style","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,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"},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"},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:"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 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, and exports. Use sectionIndex for front matter.",enum:["decimal","lowerRoman","upperRoman"],type:"string"},pageNumberPosition:{description:"Page number position.",enum:["top-left","top-right","bottom-left","bottom-right"],type:"string"},pageNumberRestart:{description:"Section numbering mode (use with sectionIndex, including the final section): true restarts at pageNumberStart (default 1); false continues 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 it 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","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 in/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 overrides.",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 section.",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 pageNumberPosition). 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 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 page count, anywhere in any zone (e.g. right: "Page {PAGE} of {PAGES}"). An empty string clears a zone; clear=true removes the whole header or footer. For a plain bottom-right page number, set_page_layout with showPageNumbers also works.',inputSchema:{properties:{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 entirely.",type:"boolean"},left:{description:"Left zone text ({PAGE}/{PAGES} tokens allowed). Omit 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"},side:{description:"Which band to edit.",enum:["header","footer"],type:"string"},slot:{description:"Which pages this applies to (Word slot model). Default: all pages.",enum:["default","first","even"],type:"string"}},required:["side"],type:"object"}},{name:"replace",description:"Preferred/default tool for editing text inside an existing block, 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 preserves 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 across 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 that 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/text 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. 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 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 in the same block.",items:{additionalProperties:!1,properties:{comment:{description:"Optional comment explaining this operation. It is attached separately to every resulting suggestion from this operation, 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 allowed 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 (default 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 differ 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:"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 reference is unavailable or stale.",type:"string"}},required:["replacements"],type:"object"}},{name:"leave_comment",description:"Leave granular review feedback on the current document without changing 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: 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 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 <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,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 genuinely 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:"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 or 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</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 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 text 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:["start_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:"object"}]},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"},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, 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 the 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> 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 (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 dimensions 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"},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:"integer"},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:["tableId","position","content"],type:"object"}},{name:"remove_table_row",description:"Remove a row 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 it is not loaded.",inputSchema:{additionalProperties:!1,properties:{rowIndex:{description:"The index of the row to remove (0-based)",type:"integer"},tableId:{description:"The table block ID",type:"string"}},required:["tableId","rowIndex"],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 loaded 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 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 dimensions are rejected without changing 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:"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"}},{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 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:"string"}},required:["tableId","columnIndex"],type:"object"}}],Rt=50,yo="out_of_context_edit";function bo(t){const{toolCall:e,docBefore:n,isTargetAllowed:o}=t;if(e.name!=="remove_block")return null;const r=e.arguments;if(!r||typeof r!="object")return null;const s=r.through_end;if(s==null||s===!1)return null;if(s!==!0)return{toolCall:e,targetBlockIds:[],error:"remove_blocks through_end must be true when provided."};const i=r.id,c=r.count,l=r.ids,u=r.search_result_id;if(typeof i!="string"||i.trim().length===0)return{toolCall:e,targetBlockIds:[],error:"remove_blocks through_end requires a non-empty top-level id."};if(c!=null||l!=null||u!=null)return{toolCall:e,targetBlockIds:[],error:"remove_blocks through_end is mutually exclusive with count, ids, and search_result_id."};const _=i.trim(),T=de(n,_);if(T<0||n.children[T]?.id!==_)return{toolCall:e,targetBlockIds:[],error:`remove_blocks through_end target '${_}' must be a current top-level block.`};if(!o(_))return{toolCall:e,targetBlockIds:[],error:`remove_blocks through_end start '${_}' is outside the request-level document context. Read or search for that boundary block first, then retry.`,errorCode:yo};const M=n.children.slice(T).map(B=>B.id).filter(B=>typeof B=="string"&&B.length>0);return{toolCall:{...e,arguments:{id:_,count:M.length}},targetBlockIds:M}}function ko(t,e,n){if(t.name!=="remove_block")return{actions:[t]};const o=t.arguments;if(!o||typeof o!="object")return{actions:[],error:"remove_blocks requires object arguments"};const r=o.ids;if(r==null)return{actions:[t]};if(typeof o.id=="string")return{actions:[],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>Rt)return{actions:[],error:`remove_blocks supports at most ${Rt} exact IDs per call`};const s=[],i=new Set;for(const l of r){if(typeof l!="string"||l.trim().length===0)return{actions:[],error:"remove_blocks ids must all be non-empty strings"};const u=l.trim();if(!i.has(u)){if(!ye(e,u))return{actions:[],error:`remove_blocks target '${u}' was not found`};if(!n(u))return{actions:[],error:`remove_blocks target '${u}' is outside the request-level document context. Read or search for that block first, then retry the exact ID batch.`};i.add(u),s.push(u)}}const c=s.filter(l=>Ne(e,l)).length;return c>0&&c<s.length?{actions:[],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:s.map((l,u)=>({id:`${t.id||"remove_block"}-${u+1}`,name:"remove_block",arguments:{id:l,count:1}}))}}function qt(t){const e=new URLSearchParams;t.query!==void 0&&e.set("q",t.query),e.set("includeContent","false");for(const n of["page","limit","currentFolderId","parentFolderId","sortBy","order"]){const o=t[n];o!=null&&o!==""&&e.set(n,String(o))}return t.includeFolders&&e.set("includeFolders","1"),e}function Lt(t,e=10){const n=t,o=Array.isArray(n?.items)?n.items:[],r=s=>typeof s=="number"&&Number.isFinite(s)&&s>=0;return{items:o,totalCount:r(n?.pagination?.totalCount)?n.pagination.totalCount:o.length,totalPages:r(n?.pagination?.totalPages)?n.pagination.totalPages:Math.max(1,Math.ceil(o.length/Math.max(1,e))),hasMore:n?.pagination?.hasMore===!0}}function Ot(t){return typeof t=="object"&&t!==null&&t.type==="doc"&&Array.isArray(t.children)}function vo(t,e=[]){const n=new ce.Doc;ce.applyUpdate(n,tt(t));for(const o of e)o&&ce.applyUpdate(n,tt(o));return fe(n)}function Io({content:t,yjsState:e,yjsUpdates:n,source:o}){const r=Array.isArray(n)?n.filter(s=>s.length>0):[];if(typeof e=="string"&&e.length>0||r.length>0)try{if(typeof e=="string"&&e.length>0)return vo(e,r);const s=Ot(t)?wt(t):new ce.Doc;if(r.length>0){for(const i of r)ce.applyUpdate(s,tt(i));return fe(s)}}catch(s){console.error(`[resolveDocRootFromSerializedState] Failed to decode yjs updates${o?` for ${o}`:""}`,s)}return Ot(t)?t:null}const _o="revise_conversations",wo=2,Ut="conversations",De="attachments";let le=null;function Nt(){return typeof indexedDB<"u"}function Ft(t){return le||(le=new Promise((e,n)=>{if(!Nt()){n(new Error("IndexedDB not available"));return}const o=indexedDB.open(_o,t??wo);o.onerror=()=>{le=null,n(o.error)},o.onblocked=()=>{console.warn("[LocalConversationStorage] Database upgrade blocked - close other tabs")},o.onsuccess=()=>{const r=o.result;if(!r.objectStoreNames.contains(De)){if(t!==void 0){r.close(),le=null,n(new Error("Attachments store still missing after version bump"));return}console.warn("[LocalConversationStorage] Attachments store missing, bumping version to create it");const s=r.version+1;r.close(),le=null,Ft(s).then(e).catch(n);return}r.onclose=()=>{le=null},r.onerror=()=>{le=null},e(r)},o.onupgradeneeded=r=>{const s=r.target.result;if(!s.objectStoreNames.contains(Ut)){const i=s.createObjectStore(Ut,{keyPath:"id"});i.createIndex("documentId","documentId",{unique:!1}),i.createIndex("updatedAt","updatedAt",{unique:!1})}s.objectStoreNames.contains(De)||s.createObjectStore(De,{keyPath:"id"}).createIndex("conversationId","conversationId",{unique:!1})}}),le)}async function So(t){if(!Nt())return null;try{const e=await Ft();return new Promise((n,o)=>{const r=e.transaction(De,"readonly").objectStore(De).get(t);r.onsuccess=()=>{n(r.result??null)},r.onerror=()=>o(r.error)})}catch(e){return console.warn("[LocalConversationStorage] Failed to get attachment:",e),null}}const st=/(<img\b[^>]*?\bsrc\s*=\s*)(["'])([\s\S]*?)\2/gi,Et=/(!\[[^\]]*\]\(\s*)(<[^>]+>|[^)\s]+)((?:\s+(?:"[^"]*"|'[^']*'|\([^)]*\)))?\s*\))/g;function Ee(t){const e=t.trim();return e.startsWith("<")&&e.endsWith(">")?e.slice(1,-1).trim():e}function xo(t){const e=new Set(["images.revise.io"]);for(const n of t.flatMap(o=>(o??"").split(",")))if(n.trim())try{e.add(new URL(n.includes("://")?n.trim():"https://"+n.trim()).host)}catch{}return e}function Mo(t,e,n){try{const o=new URL(Ee(t),n);return!["http:","https:"].includes(o.protocol)||e.has(o.host)?!1:!n||o.origin!==new URL(n).origin}catch{return!1}}function $o(t,e,n,o=!1){for(const r of t.matchAll(st)){const s=Ee(r[3]);n(s)&&e.add(s)}if(o)for(const r of t.matchAll(Et)){const s=Ee(r[2]);n(s)&&e.add(s)}}function Co(t){try{const e=new URL(t);if(e.hostname!=="upload.wikimedia.org")return t;const n=e.pathname.split("/");return n.length<8||n[1]!=="wikipedia"||n[2]!=="commons"||n[3]!=="thumb"?t:(e.pathname=["","wikipedia","commons",...n.slice(4,-1)].join("/"),e.toString())}catch{return t}}function Do(t){return t.replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<").replace(/>/g,">")}function Ao(t,e){return t.replace(/<img\b[^>]*>/gi,n=>{const o=Array.from(n.matchAll(st))[0];if(!o)return n;const r=o[3].trim(),s=e.get(r);if(!s)return n;let i=n.replace(st,(l,u,_)=>`${u}${_}${s.url}${_}`);const c=[];return/\bdata-source-url\s*=/i.test(i)||c.push(`data-source-url="${Do(r)}"`),s.naturalWidth&&s.naturalHeight&&!/\bdata-revise-natural-(?:width|height)\s*=/i.test(i)&&c.push(`data-revise-natural-width="${s.naturalWidth}"`,`data-revise-natural-height="${s.naturalHeight}"`),c.length>0&&(i=i.replace(/\s*\/?>$/,l=>` ${c.join(" ")}${l}`)),i})}function jt(t,e,n=!1){const o=n?t.replace(Et,(r,s,i,c)=>{const l=e.get(Ee(i));return l?s+"<"+l.url+">"+c:r}):t;return Ao(o,e)}const To="https://app-api.revise-sdk.invalid";function Po(t){return Mo(t,xo([""]),typeof window<"u"?window.location.href:void 0)}function zt(t){return typeof t=="number"&&Number.isInteger(t)&&t>0?t:void 0}async function Bo(t){try{const e=await fetch(`${To}/uploads/images/rehost`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({url:Co(t)}),signal:AbortSignal.timeout(3e4)});if(!e.ok){let s=`Image copy request failed (HTTP ${e.status}).`;try{const i=await e.json();typeof i.error=="string"&&i.error.trim().length>0&&(s=i.error.trim())}catch{}return{ok:!1,failure:{url:t,status:e.status,message:s}}}const n=await e.json();if(typeof n.fileUrl!="string"||!n.fileUrl)return{ok:!1,failure:{url:t,status:e.status,message:"Image copy response did not include a file URL."}};const o=zt(n.width),r=zt(n.height);return{ok:!0,image:{url:n.fileUrl,...o&&r?{naturalWidth:o,naturalHeight:r}:{}}}}catch{return{ok:!1,failure:{url:t,message:"Image copy request could not reach Revise storage."}}}}const Wt=new Set(["insert_block","replace_block"]);function Ro(t){const e=new Set;for(const n of t??[]){if(!n?.name||!Wt.has(n.name))continue;const o=n.arguments?.content;for(const r of Array.isArray(o)?o:[o])typeof r=="string"&&$o(r,e,Po)}return e}async function qo(t){const e={attempted:0,rehosted:0,failedUrls:[],failures:[]};if(!Array.isArray(t)||t.length===0)return e;const n=Ro(t);if(n.size===0)return e;const o=new Map,r=[];await Promise.all([...n].map(async i=>{const c=await Bo(i);c.ok?o.set(i,c.image):r.push(c.failure)}));const s=[...n].filter(i=>!o.has(i));if(o.size===0)return{attempted:n.size,rehosted:0,failedUrls:s,failures:r};for(const i of t){if(!i?.name||!Wt.has(i.name))continue;const c=i.arguments;c&&(typeof c.content=="string"?c.content=jt(c.content,o):Array.isArray(c.content)&&(c.content=c.content.map(l=>typeof l=="string"?jt(l,o):l)))}return{attempted:n.size,rehosted:o.size,failedUrls:s,failures:r}}function Lo(t,e){const n=t.children.flatMap((o,r)=>o.type==="paragraph"&&o.heading?[{index:r,level:o.heading,blockId:o.id,title:Ze(o).replace(/\s+/g," ").trim()}]:[]);return n.filter(o=>o.level<=e?.maxDepth).map(o=>({...o,endIndex:(n.find(r=>r.index>o.index&&(e?.flat||r.level<=o.level))?.index??t.children.length)-1}))}const Oo=new Set([8203,8204,8205,8288,65279]);function Uo(){return{wordCount:0,paragraphCount:0,characterCount:0,hasVisibleText:!1,inWord:!1}}function Ht(t,e){for(let n=0;n<t.length;n+=1){const o=t.codePointAt(n);if(o===void 0||(o>65535&&(n+=1),Oo.has(o)))continue;const r=String.fromCodePoint(o);if(e.characterCount+=r.length,/\s/.test(r)){e.inWord=!1;continue}e.hasVisibleText=!0,e.inWord||(e.wordCount+=1,e.inWord=!0)}}function Jt(t,e){if(!t||typeof t!="object")return;const n=t;if(n.type==="text"&&typeof n.text=="string"){Ht(n.text,e);return}if(n.type==="paragraph"&&(e.paragraphCount+=1),(n.type==="code"||n.type==="math")&&typeof n.content=="string"){Ht(n.content,e),e.inWord=!1;return}if(n.type==="placeholder"||n.type==="image"||n.type==="page-break"||n.type==="section-break"){e.inWord=!1;return}if(Array.isArray(n.children))for(const o of n.children)Jt(o,e),o&&typeof o=="object"&&"type"in o&&o.type!=="text"&&(e.inWord=!1)}function No(t){const e=Uo();for(const o of t)Jt(o,e),e.inWord=!1;const n={parts:[],paragraphCount:0,containsSentinel:!1};for(const o of t)Vt(o,n),n.parts.push(" ");return e.wordCount=Qn(n.parts.join("")),e}const Ae="\0";function Vt(t,e){if(!t||typeof t!="object")return;const n=t;if(n.type==="text"&&typeof n.text=="string"){n.text.includes(Ae)&&(e.containsSentinel=!0),e.parts.push(n.text);return}if(n.type==="paragraph"&&(e.paragraphCount+=1),(n.type==="code"||n.type==="math")&&typeof n.content=="string"){n.content.includes(Ae)&&(e.containsSentinel=!0),e.parts.push(n.content,Ae);return}if(n.type==="placeholder"||n.type==="image"||n.type==="page-break"||n.type==="section-break"){e.parts.push(Ae);return}if(Array.isArray(n.children))for(const o of n.children)Vt(o,e),o&&typeof o=="object"&&"type"in o&&o.type!=="text"&&e.parts.push(Ae)}function Gt(t){return No(t)}function Kt(t){const e=St(t.pageLayout),n=Tn(e);return{layout:Zn({pageWidth:n.pageWidth,pageHeight:n.pageHeight,pageMargin:e.marginLeftPx,pageMarginTop:e.marginTopPx,pageMarginRight:e.marginRightPx,pageMarginBottom:e.marginBottomPx,pageMarginLeft:e.marginLeftPx,availableWidth:Math.max(1,n.pageWidth-e.marginLeftPx-e.marginRightPx),textStartY:e.marginTopPx,indentStepPx:e.indentStepPx,blockSpacingPx:e.blockSpacingPx,hyphenationEnabled:e.hyphenationEnabled,lineNumbering:e.lineNumbering,columnCount:e.columnCount,columnGapPx:Pn(e.columnGapTwips),pageless:t.pageless===!0}),resolved:e}}function Yt(t){if(typeof document>"u")return null;const e=document.createElement("canvas").getContext("2d");if(!e)return null;const n=Xn(e),{layout:o}=Kt(t);return no(t,n,o)}function Xt(t,e){const n=new Map;if(!e||t.pageless===!0)return new Map;const o=(i,c)=>{if(!i||typeof c!="number"||!Number.isFinite(c))return;const l=Math.max(1,Math.floor(c)),u=n.get(i);if(!u){n.set(i,{min:l,max:l});return}u.min=Math.min(u.min,l),u.max=Math.max(u.max,l)};for(const i of e.fragments)o(i.blockId,i.pageNumber);for(const i of e.blocks)o(i.blockId,i.pageNumber);const r=St(t.pageLayout),s=new Map;for(const[i,c]of n)s.set(i,{pageStart:xt(r,c.min-1),pageEnd:xt(r,c.max-1)});return s}function Fo(t,e){let n,o;for(const r of t){const s=e.get(r);s&&(n=n===void 0?s.pageStart:Math.min(n,s.pageStart),o=o===void 0?s.pageEnd:Math.max(o,s.pageEnd))}return n!==void 0&&o!==void 0?{pageStart:n,pageEnd:o}:void 0}function Zt(t,e,n,o){const r=Math.max(0,Math.min(e,t.children.length-1)),s=Math.max(0,Math.min(n,t.children.length-1));if(r>s||t.children.length===0)return null;const i=t.children.slice(r,s+1),c=t.children[r],l=t.children[s];if(!c?.id||!l?.id)return null;const u=Gt(i),_=i.map(M=>M.id).filter(Boolean),T=Fo(_,o);return{startIndex:r,endIndex:s,startBlockId:c.id,endBlockId:l.id,inclusive:!0,blockCount:i.length,wordCount:u.wordCount,paragraphCount:u.paragraphCount,characterCount:u.characterCount,...T?{pageStart:T.pageStart,pageEnd:T.pageEnd}:{}}}function Eo(t,e,n){const o=[],r=n?new Set(n):null;for(const s of Lo(t,{maxDepth:3})){const i=s.index,c=s.endIndex,l=s.level;if(r&&!r.has(l))continue;const u=Zt(t,i,c,e);u&&o.push({startIndex:u.startIndex,endIndex:u.endIndex,startBlockId:u.startBlockId,endBlockId:u.endBlockId,headingLevel:l,title:s.title,wordCount:u.wordCount,paragraphCount:u.paragraphCount,characterCount:u.characterCount,...u.pageStart!==void 0?{pageStart:u.pageStart,pageEnd:u.pageEnd}:{}})}return o}function Qt(t,e){const n=e&&"layout"in e?e.layout??null:t.pageless===!0?null:Yt(t),o=Gt(t.children),r=t.pageless===!0?null:n,s=e?.includeSections===!0?Xt(t,n):new Map;return{inclusive:!0,totalBlocks:t.children.length,wordCount:o.wordCount,paragraphCount:o.paragraphCount,characterCount:o.characterCount,...r?{pageCount:r.pageCount}:{},...e?.includeFractionalPageCount===!0&&r?{fractionalPageCount:jo(t,r)}:{},...e?.includeSections===!0?{sections:Eo(t,s,e.headingLevels).map(i=>({...i,inclusive:!0,blockCount:i.endIndex-i.startIndex+1}))}:{}}}function jo(t,e){const{layout:n}=Kt(t);return oo(n,e)}function en(t){return typeof t!="string"?"":t.trim().replace(/^#+/,"")}function zo(t,e,n){const o=Yt(t),r=Xt(t,o),s=new Map;for(let l=0;l<t.children.length;l+=1){const u=t.children[l]?.id;u&&s.set(u,l)}const i=[],c=[];for(const l of e){const u=en(l.startBlockId),_=en(l.endBlockId??u),T=s.get(u),M=s.get(_);if(!u){c.push({error:"start_block_id is required."});continue}if(T===void 0){c.push({startBlockId:u,endBlockId:_,error:`start_block_id "${u}" was not found.`});continue}if(M===void 0){c.push({startBlockId:u,endBlockId:_,error:`end_block_id "${_}" was not found.`});continue}if(M<T){c.push({startBlockId:u,endBlockId:_,error:`end_block_id "${_}" comes before start_block_id "${u}". Ranges must be forward and inclusive.`});continue}const B=Zt(t,T,M,r);if(!B){c.push({startBlockId:u,endBlockId:_,error:`Could not measure inclusive range "${u}"-"${_}".`});continue}i.push(B)}return{inclusive:!0,totalBlocks:t.children.length,ranges:i,errors:c}}const Wo="The agent had trouble completing this request. Please try again.",tn="Document session unavailable after waiting for document load",Ho="document_session_unavailable";class Jo extends Error{constructor(e){super("Open the source document linked in the conversation to continue these edits."),this.sourceDocumentId=e,this.name="ForeignDocumentTargetError"}}const Vo="InvalidAssistantResponseError",Go="Couldn't reach the server. Please check your connection and try again.",Ko=["aborted without reason","bodystreambuffer was aborted","client.timeout","connection reset by peer","context canceled","context cancellation","context cancelled","context deadline exceeded","econnreset","etimedout","failed to fetch","failed 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 timeout","while reading body"],Yo=["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 error: 400"],Xo=["server_error","service_unavailable","server_is_overloaded","503 service unavailable","error in input stream"],Zo=["context_length_exceeded","input token count exceeds","exceeds the context window","maximum number of tokens","maximum context length","prompt is too long","too many input tokens"],Qo=['attachment "',"attachment not found","unable to download the file","failed to fetch attachment","expected a valid url","invalid 'input","image_url"],er=['block id "',"document changed while","reference block","not found in document","not found in the document","insert_block"];function tr(t){const e=t.toLowerCase();return e.includes("network")||Ko.some(n=>e.includes(n))}function nr(t){if(t?.name==="AbortError"||t instanceof DOMException&&t.code===20)return{isAbort:!0,isRateLimited:!1,isNetworkError:!1,kind:"abort",rawMessage:"",message:"",shouldRetryWithStableModel:!1,shouldTrackConversationError:!1};const e=t instanceof Error?t.message:typeof t?.toString=="function"?t.toString():String(t??""),n=e.toLowerCase(),o=e==="RATE_LIMITED"||t?.message==="RATE_LIMITED",r=t instanceof TypeError||tr(e),s=t instanceof Error&&t.name===Vo,i=u=>u.some(_=>n.includes(_)),c=t instanceof Jo?"document_target":o?"rate_limited":s?"invalid_assistant_response":e.trim().length===0?"unknown_empty":i(Zo)?"context_limit":i(Qo)?"attachment":n.includes(tn.toLowerCase())?"document_loading":i(er)?"document_state":i(Yo)?"provider_protocol":i(Xo)?"provider_transient":r?"connection":"unknown";let l;return o?l="Rate limit reached":s?l="The agent sent an invalid response. Please try again.":c==="connection"?l=Go:c==="provider_protocol"||c==="provider_transient"?l="The model service had trouble completing this request. Please try again.":c==="context_limit"?l="This request is too large for the model. Try a smaller request or attach fewer files.":c==="attachment"?l="The agent could not read one of the attached files.":c==="document_loading"?l="The document is still loading. Please wait a moment and try again.":c==="document_target"?l=e:c==="document_state"?l="Document state changed during the request.":c==="unknown_empty"?l="The agent stopped unexpectedly. Your prompt is saved.":l=Wo,{isAbort:!1,isRateLimited:o,isNetworkError:r,kind:c,rawMessage:e,message:l,shouldRetryWithStableModel:c==="provider_protocol"||c==="provider_transient",shouldTrackConversationError:c!=="rate_limited"&&c!=="connection"&&c!=="document_loading"}}const or=new Map(Bt.map(t=>[t.name,t.inputSchema]));function it(t){return t!==null&&typeof t=="object"&&!Array.isArray(t)}function nn(t,e){return Object.prototype.hasOwnProperty.call(t,e)}function rr(t,e){switch(e){case"null":return t===null;case"object":return it(t);case"array":return Array.isArray(t);case"string":return typeof t=="string";case"number":return typeof t=="number"&&Number.isFinite(t);case"integer":return typeof t=="number"&&Number.isInteger(t);case"boolean":return typeof t=="boolean";default:return!0}}function _e(t,e){return!(t.const!==void 0&&!Object.is(t.const,e)||t.enum&&!t.enum.some(n=>Object.is(n,e))||t.type&&!(Array.isArray(t.type)?t.type:[t.type]).some(n=>rr(e,n))||t.allOf?.some(n=>!_e(n,e))||t.anyOf&&!t.anyOf.some(n=>_e(n,e))||t.oneOf&&t.oneOf.filter(n=>_e(n,e)).length!==1||t.not&&_e(t.not,e)||it(e)&&t.required&&!t.required.every(n=>nn(e,n)))}function Te(t,e){let n=t;if(Array.isArray(n)&&e.items)n=n.map(o=>Te(o,e.items));else if(it(n)&&e.properties){const o=new Set(e.required??[]),r={...n};for(const[s,i]of Object.entries(e.properties))if(nn(r,s)){if(r[s]===null&&!o.has(s)&&!_e(i,null)){delete r[s];continue}r[s]=Te(r[s],i)}n=r}for(const o of e.allOf??[])n=Te(n,o);for(const o of[e.anyOf,e.oneOf]){const r=o?.filter(s=>_e(s,n));r?.length===1&&(n=Te(n,r[0]))}return n}function sr(t,e){const n=or.get(t);return n?Te(e,n):e}const ir="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 comments; do not invent facts or ask for clarification or approval.",ar=new Set(["read_blocks","read_blocks_from_index","read_specific_blocks","search_document","find_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_response","ready_for_verification"]),cr=new Set(["missed_requirements","verification_passed"]);function on(t){const e=t.trim();return e==="remove_blocks"?"remove_block":e}function dr(t){return Array.from(new Set(t.map(on).filter(Boolean)))}function lr(t,e){const n=on(e);return cr.has(n)?{code:"agent_tool_not_allowed",message:"This legacy verification tool is unavailable. Continue supported work or finish with end_agent_run."}:n==="request_user_input"&&t.interaction==="best_effort"?{code:"agent_interaction_not_allowed",message:ir}:t.allowedTools!=null&&!dr(t.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."}:rt.has(n)?t.documentAccess==="edit"||t.documentAccess==="comment"&&n==="leave_comment"?null:{code:"agent_document_access_denied",message:"This request does not permit this document mutation. Continue within the granted document access and explain any work that could not be completed."}:ar.has(n)?null:{code:"agent_tool_not_allowed",message:"This tool has no execution-policy classification and cannot run. Continue using permitted tools."}}const je="no_new_read_context",be={scanDocumentFontFamily:!1};function we(t){return t.getAgentAuthorName?.()?.trim()||Kn}const rn=2,ur=48,hr=.4,ke=10,gr=100,mr=100,Se=48e3,at="out_of_context_edit",ue="document_state_changed",pr="duplicate_comment_anchor",fr="one_read_search_per_turn",sn="terminal_tool_requires_turn_two_continuation",an="terminal_response_status_only",yr="end_agent_run",br="finish_response",kr="ready_for_verification",vr=new Set(["read_blocks","read_blocks_from_index","read_specific_blocks","search_document","search_documents","find_highlights","render_document_pages"]);function Ir(t){return t===yr||t===br}function cn(t){return t.replace(/<status\b[^>]*>[\s\S]*?<\/status>/gi,"").trim().length===0}const ct="https://app-api.revise-sdk.invalid";function _r(t){if(t&&typeof t=="object"&&!Array.isArray(t))return t;if(typeof t!="string")return null;const e=t.trim();if(!e)return null;if(!e.startsWith("{")||!e.endsWith("}"))return{text:e};try{const n=JSON.parse(e);return n&&typeof n=="object"&&!Array.isArray(n)?n:null}catch{return null}}function wr(t){const e=Ce(t.doc,t.requestedBlockId);if(!e||!Array.isArray(e.children))return null;const n=[],o=r=>{if(!(!r||typeof r!="object")&&(r.id!==t.requestedBlockId&&typeof r.id=="string"&&Vn(r)&&n.push({blockId:r.id,text:Ze(r),html:Dt(t.anchorText)?Ct(r):void 0}),Array.isArray(r.children)))for(const s of r.children)o(s)};return o(e),$t(n,t.anchorText)}function Sr(t){return!t.loadedBlockIds||t.loadedBlockIds.size===0?null:$t(Wn(t.doc).filter(e=>e.blockId!==t.requestedBlockId&&Hn(e,t.loadedBlockIds)).map(e=>({...e,html:Dt(t.anchorText)?Ct(Ce(t.doc,e.blockId)):void 0})),t.anchorText)}function xr(t,e,n,o,r,s,i){if(i.hasBlockId||i.hasAnchor)return f(t,"A reply inherits its thread's anchor: pass reply_to_comment_id and comment alone, without id or anchor.");const c=jn(o,r);if(!c)return f(t,`Comment '${r}' was not found. Reply only to a <comment-thread> id you can see in loaded document content.`,ue);if(c.resolved===!0)return f(t,`Comment thread '${c.id}' is resolved. Leave a new anchored comment instead of replying to a settled thread.`);const l=n.getDocumentMutator(),u=zn(o,l,c.id,s,{author:we(e),authorType:"ai",agentName:we(e),...e.getAgentModel?{agentModel:e.getAgentModel()}:{}}).commentId;if(!u)return f(t,`Could not reply to comment thread '${c.id}'.`);const _=Mr(o,c);return _&&e.toolState.editedBlockIds.add(_),e.turnState.hasMutatedSinceLastRead=!0,e.metrics?.count("agent.comment.reply",1),N(t,`Replied ${u} in comment thread ${c.id}.`,void 0,void 0,JSON.stringify({commentId:u,threadId:c.id,mode:"reply",..._?{blockId:_}:{}}))}function Mr(t,e){if(e.anchorBlockId){const n=de(t,e.anchorBlockId);return n>=0?t.children[n]?.id??e.anchorBlockId:e.anchorBlockId}for(const n of t.children)if(n.id&&Jn(n).has(e.id))return n.id;return null}function $r(t,e,n,o){const r=t.arguments??{};let s=typeof r.id=="string"?r.id.trim():"";const i=typeof r.comment=="string"?r.comment.trim():"",c=_r(r.anchor),l=typeof r.reply_to_comment_id=="string"?r.reply_to_comment_id.trim():"",u=new Set((Array.isArray(r.acknowledge_existing_thread_ids)?r.acknowledge_existing_thread_ids:[]).filter(d=>typeof d=="string").map(d=>d.trim()).filter(Boolean));if(!i)return f(t,"leave_comment requires a non-empty comment.");if(l)return xr(t,e,n,o,l,i,{hasBlockId:!!s,hasAnchor:!!c});if(!s)return f(t,"leave_comment requires id.");if(!c)return f(t,"leave_comment requires an anchor.");let _=Ce(o,s);const T=hn(e.turnState),M=typeof c.text=="string"&&c.text.length>0?c.text:null;if(M&&_){const d=wr({doc:o,requestedBlockId:s,anchorText:M});d&&(s=d,_=Ce(o,s))}if(M&&(!_||Fn(_,M).length===0)){const d=Sr({doc:o,requestedBlockId:s,anchorText:M,loadedBlockIds:T});d&&(s=d,_=Ce(o,s))}if(!_)return f(t,`Block '${s}' was not found.`,ue);const B=de(o,s),L=B>=0?o.children[B]?.id:void 0;if(!T||!T.has(s)&&(!L||!T.has(L)))return f(t,`leave_comment targets block '${s}', which is outside the loaded <document_content> context. Read that block first, then retry.`,at);const z=n.getDocumentMutator(),$={author:we(e),authorType:"ai",agentName:we(e),...e.getAgentModel?{agentModel:e.getAgentModel()}:{}},y=En(n.getWorkingDocument(),o,z,s,i,c,$,Array.from(u));if(!y.success)return y.overlappingThreadIds?.length&&e.metrics?.count("agent.comment.overlap_blocked",1),f(t,y.error??"Could not attach comment.",y.overlappingThreadIds?.length?pr:y.errorCode);const k=y.commentId,D=c.whole_block===!0,R=y.range;return u.size&&e.metrics?.count("agent.comment.overlap_acknowledged",1),e.toolState.editedBlockIds.add(L??s),e.turnState.hasMutatedSinceLastRead=!0,N(t,`Left comment ${k} on block ${s}.`,void 0,void 0,JSON.stringify({commentId:k,blockId:s,anchor:D?{wholeBlock:!0}:R}))}function f(t,e,n){return{toolCall:t,success:!1,error:e,...n?{errorCode:n}:{}}}function Cr(t){return t&&nr(new Error(t)).kind==="document_state"?ue:void 0}function N(t,e,n,o,r){return{toolCall:t,success:!0,agentFeedback:e,...n?{imageAttachment:n}:{},...o?{nonMeaningful:!0}:{},...r?{toolOutput:r}:{}}}function Dr(t){return t.tool||t.name}function Ar(t){if(!t||typeof t!="object")return null;const e=typeof t.status=="string"?t.status:typeof t.message=="string"?t.message:null;if(!e)return null;const n=e.replace(/[\s\n]+/g," ").trim();return n.length>0?n:null}function Tr(t){if(!t||typeof t!="object")return null;const e=typeof t.context_notes=="string"?t.context_notes:null;if(!e)return null;const n=e.trim();return n.length>0?n:null}function dn(t,e){for(const n of t){if(n.type==="image"&&n.id===e)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=dn(n.children,e);if(o)return o}}return null}function Pe(t){if(!t||typeof t!="object")return[];const e=t,n=[],o=new Set,r=i=>{if(typeof i!="string")return;const c=i.trim();!c||o.has(c)||(o.add(c),n.push(c))};if(r(e.id),r(e.referenceId),r(e.firstId),r(e.secondId),r(e.from_id),r(e.block_id),r(e.tableId),r(e.referenceRowId),r(e.after_block_id),Array.isArray(e.id))for(const i of e.id)r(i);if(Array.isArray(e.block_ids))for(const i of e.block_ids)r(i);Array.isArray(e.ids)&&e.ids.forEach(r);const s=Array.isArray(e.selectors)?e.selectors:[e.selectors];for(const i of s)if(typeof i=="string")for(const c of i.split(",")){const l=c.trim().match(/^#([A-Za-z0-9_-]+)(?=$|[\s:>~+])/);l&&r(l[1])}if(e.selector&&typeof e.selector=="object"&&Pe(e.selector).forEach(r),Array.isArray(e.replacements))for(const i of e.replacements)Pe(i).forEach(r);return n}function ln(t){const e=Pe(t.arguments),n=e.length===0?"the target block":e.length===1?`block ${e[0]}`:`${e.length} blocks`;if(t.name==="set_block_attribute"||t.name==="style_blocks"){const o=t.arguments&&typeof t.arguments=="object"?t.arguments:{},r=typeof o.attribute=="string"&&o.attribute.trim().length>0?o.attribute.trim():"attribute";return(typeof o.operation=="string"&&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 t.name==="clear_formatting"?`No document mutation occurred; formatting was already clear on ${n}.`:t.name==="replace_block"?`No document mutation occurred; replacing ${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 needed.`:t.name==="replace"||t.name==="replace_all"||t.name==="replace_many"?`No document 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 needed.`:"No document mutation occurred; the document already matched the requested update."}function Pr(t){const e=Dr(t);return{id:t.id,name:e,arguments:sr(e,t.arguments)}}function Br(t){return t.replace(/<[^>]*>/g," ").replace(/ /gi," ").replace(/&/gi,"&").replace(/</gi,"<").replace(/>/gi,">").replace(/"/gi,'"').replace(/'|'/gi,"'").replace(/\s+/g," ").trim()}function un(t){return t.replace(/\s+/g," ").trim()}function hn(t){const e=new Set;for(const n of[t.lastReadBlockIds,t.requestedBlockIds])if(n)for(const o of n)e.add(o);for(const n of t.docContextLedger?.delivered.keys()??[])e.add(n);return e.size>0?e:null}function Rr(t){const e=[],n=new Set;for(const o of t)for(const r of Pe(o.arguments))n.has(r)||(n.add(r),e.push(r));return e}function gn(t,e){const n=new Set(e),o=new Set(e),r=s=>{const i="id"in s?s.id:void 0;let c=!!(i&&n.has(i));if("children"in s)for(const l of s.children)r(l)&&(c=!0);return c&&i&&o.add(i),c};for(const s of[...t.children,...t.chrome??[],...t.notes??[]])r(s);return o}function qr(t,e){if(t.length===1)return`block ${t[0]}`;if(t.length>1){const n=t.slice(0,4).join(", "),o=t.length>4?` (+${t.length-4} more)`:"";return`blocks ${n}${o}`}return e?`block ${e}`:"the target block"}function Lr(t){if(t.length===0)return"";const e=Array.from(new Set(t.map(r=>`${r.fromBlockId}->${r.toBlockId}`))).map(r=>{const[s,i]=r.split("->");return`${s} -> ${i}`}),n=e.slice(0,4).join(", "),o=e.length>4?` (+${e.length-4} more)`:"";return`Retargeted ${t.length} replacement ${t.length===1?"operation":"operations"} to the unique loaded-context block match${t.length===1?"":"es"}: ${n}${o}.`}function Or(t,e,n){if(typeof t!="number"||!Number.isFinite(t))return e;const o=Math.floor(t);return o<=0?e:Math.min(o,n)}function Be(t,e){if(typeof t!="number"||!Number.isFinite(t))return e;const n=Math.floor(t);return Math.max(0,n)}function mn(t,e,n,o,r,s){let i=[...s?.targetBlockIds??o];if(i.length===0&&t.arguments&&typeof t.arguments=="object"&&typeof t.arguments.id=="string"&&(i=[t.arguments.id.trim()].filter(Boolean)),i.length===1&&t.name==="remove_block"&&t.arguments&&typeof t.arguments=="object"){const y=i[0],k=Or(t.arguments.count,1,50),D=de(e,y);D!==-1&&k>1&&(i=e.children.slice(D,D+k).map(R=>R.id).filter(R=>typeof R=="string"&&R.length>0))}const c=t.arguments&&typeof t.arguments=="object"&&typeof t.arguments.search_result_id=="string"?t.arguments.search_result_id:null,l=c!==null||i.length>ke,u=!l&&t.name!=="replace"&&t.name!=="replace_many"&&t.name!=="replace_all"&&i.length>0?Z.extractSpecificBlocks(e,i,void 0,be).html:"",_=i.filter(y=>ye(e,y)&&!ye(n,y)),T=s?.changedBlockIds??i.filter(y=>{const k=ye(e,y),D=ye(n,y);return JSON.stringify(k??null)!==JSON.stringify(D??null)}),M=new Set,B=y=>{for(const k of y)"id"in k&&k.id&&M.add(k.id),"children"in k&&B(k.children)};B(te(e));const L=[],z=y=>{for(const k of y)"id"in k&&k.id&&!M.has(k.id)?L.push(k.id):"children"in k&&z(k.children)};z(te(n));const $=(y,k,D=!1)=>l||D&&k.length>ke?{[`${y}_sample`]:k.slice(0,ke),[`${y}_omitted_count`]:Math.max(0,k.length-ke)}:{[y]:k};return JSON.stringify({tool:t.name,...c?{target_reference:c}:{},...r?{summary:r}:{},...s?{style_outcome:s.outcome,attribute_effects:s.attributes.map(y=>({name:y.name,applied_target_count:y.appliedBlockIds.length,skipped_target_count:new Set(y.skipped.map(k=>k.blockId)).size,...$("applied_block_ids",y.appliedBlockIds,!0),skipped:y.skipped.slice(0,ke),skipped_omitted_count:Math.max(0,y.skipped.length-ke)}))}:{},effect:{...s?$("affected_block_ids",s.affectedBlockIds,!0):{},requested_target_count:i.length,changed_target_count:T.length,removed_target_count:_.length,inserted_block_count:L.length,...$("target_block_ids",i),...$("changed_block_ids",T),...$("removed_block_ids",_),...$("inserted_block_ids",L),top_level_blocks_before:te(e).length,top_level_blocks_after:te(n).length},...!l&&u.trim()?{before_block:u}:{}})}function te(t){return[...t.children,...t.notes??[]]}function dt(t,e){return Z.extractSpecificBlocks(t,[e],void 0,be).foundBlocks[0]?.blockIndex??-1}function Ur(t){return`(${t} ${t===1?"block":"blocks"} omitted...)`}function lt(t,e){const n=te(t)[e];return n?.id?Z.extractSpecificBlocks(t,[n.id],void 0,be).foundBlocks[0]??null:null}function ze(t){if(t.length===0)return 0;let e=`Showing ${t.length} block(s):
|
|
2
|
+
|
|
3
|
+
`.length+t[0].html.length;for(let n=1;n<t.length;n+=1){const o=t[n-1],r=t[n],s=r.blockIndex-o.blockIndex-1;s>0&&(e+=1+Ur(s).length),e+=1+r.html.length}return e}function pn(t){const{doc:e,startIndex:n,maxTokens:o}=t,r=[];let s=0,i=n-1,c=!1;for(let l=n;l<te(e).length;l+=1){const u=lt(e,l);if(!u)continue;const _=ze([...r,u]),T=_>o;if(T&&r.length>0){c=!0;break}if(r.push(u),s=_,i=u.blockIndex,T){c=!0;break}}return{blockIds:r.map(l=>l.id),endIndex:i,estimatedTokens:s,reachedTokenBudget:c}}function Nr(t){const{doc:e,requestedBlockIds:n,maxTokens:o}=t,r=[],s=new Set,i=new Map,c=(M,B)=>(i.has(M)||i.set(M,lt(e,B)),i.get(M)??null),l=[];let u=0,_=!1,T=0;for(const M of n){const B=Kr(e,M);if(!B){T+=1;continue}if(s.has(B.topLevelBlockId))continue;const L=c(B.topLevelBlockId,B.topLevelIndex);if(!L){T+=1;continue}const z=ze([...l,L]),$=z>o;if($&&r.length>0){_=!0;break}if(r.push(B.topLevelBlockId),s.add(B.topLevelBlockId),l.push(L),u=z,$){_=!0;break}}return{blockIds:r,estimatedTokens:u,reachedTokenBudget:_,missingRequestedBlocks:T}}function fn(t){const{doc:e,results:n,pageSize:o,maxTokens:r}=t;if(n.length===0)return[];const s=new Map,i=M=>(s.has(M.blockId)||s.set(M.blockId,lt(e,M.blockIndex)),s.get(M.blockId)??null),c=[];let l=[],u=[],_=0;const T=M=>{l.length!==0&&(c.push({results:l,startResultIndex:_,endResultIndexExclusive:M,estimatedTokens:ze(u)}),l=[],u=[])};for(let M=0;M<n.length;M+=1){const B=n[M],L=i(B);if(!L)continue;l.length===0&&(_=M);const z=ze([...u,L]),$=l.length>=o,y=z>r;l.length>0&&($||y)&&(T(M),_=M),l=[...l,B],u=[...u,L]}return T(n.length),c}function yn(t){if(t.length===0)return[];const e=[...t].sort((s,i)=>s-i),n=[];let o=e[0],r=e[0];for(let s=1;s<e.length;s+=1){const i=e[s];if(i<=r+1){r=i;continue}n.push({start:o,end:r}),o=i,r=i}return n.push({start:o,end:r}),n}function ut(t,e){const n=new Set;for(const o of e){const r=dt(t,o);r!==-1&&n.add(r)}return Array.from(n).sort((o,r)=>o-r)}function Re(t,e){const n=t.turnState.requestedBlockIds??new Set,o=ut(e,n),r=yn(o),s=o.length,i=t.toolState.everReadFullDocument||te(e).length>0&&s>=te(e).length;return{requestedBlockCount:s,readBlocksThisTurn:t.turnState.readBudgetBlockIds?.size??0,readTokenBudgetMax:Se,requestedRanges:r,fullDocumentLoaded:i}}function qe(t){return JSON.stringify({kind:"read_context",tool:t.tool,loaded:t.loaded,next:t.next??null,endOfDocument:t.endOfDocument,coverage:t.coverage})}function bn(t){return JSON.stringify({kind:"search_context",tool:t.tool,...t.queries?{queries:t.queries}:{},...t.color?{color:t.color}:{},totalMatches:t.totalMatches,...t.searchResultId?{search_result_id:t.searchResultId}:{},page:{current:t.currentPage,total:t.totalPages,startResult:t.pageStart+1,endResult:t.pageEnd},nextPage:t.nextPage,matches:t.pageResults.map(e=>({blockId:e.blockId,blockIndex:e.blockIndex,...e.matchedQueries?{matchedQueries:e.matchedQueries}:{},...e.matchedColors?{matchedColors:e.matchedColors}:{}})),coverage:t.coverage})}function Fr(t){return t==="account"||t==="folder"?t:"current_folder"}function xe(t){return t.getAuthToken?.().trim()??""}function kn(t){return typeof t.document_id=="string"?t.document_id.trim():""}function vn(t){return t.replaceAll("-","").toLowerCase()}function ie(t,e){const n=kn(t);if(!n)return"";const o=e.getCurrentDocumentId?.().trim()??"";return o&&vn(n)===vn(o)?"":n}async function Er(t){const e=t.scope==="folder"?t.folderId:t.currentFolderId,n=qt({query:t.query,page:t.page+1,limit:10,currentFolderId:t.scope==="account"?void 0:e}),o=await fetch(`${ct}/documents/search?${n.toString()}`,{headers:{Authorization:`Bearer ${t.token}`}});if(!o.ok)throw new Error(`Document search failed with ${o.status}`);return Lt(await o.json(),10)}async function jr(t){const e=qt({includeFolders:!0,page:t.page+1,limit:t.limit,parentFolderId:t.parentFolderId}),n=await fetch(`${ct}/documents?${e.toString()}`,{headers:{Authorization:`Bearer ${t.token}`}});if(!n.ok)throw new Error(`Document listing failed with ${n.status}`);return Lt(await n.json(),t.limit)}async function We(t){const e=await fetch(`${ct}/documents/${encodeURIComponent(t.documentId)}?includeTailUpdates=1&trackAccess=0`,{headers:{Authorization:`Bearer ${t.token}`}});if(!e.ok)throw new Error(`Document open failed with ${e.status}`);const n=await e.json(),o=Io({content:n.content,yjsState:n.yjsState,yjsUpdates:n.yjsUpdates,source:`agent read document ${t.documentId}`})??{type:"doc",children:[]};return o.title=n.title||o.title||"Untitled",{id:n.id||t.documentId,title:n.title||"Untitled",canonicalPath:n.canonicalPath,parentFolderId:n.parentFolderId??null,content:o}}function zr(t){return JSON.stringify({kind:"account_document_search",query:t.query,scope:t.scope,searchedCurrentFolder:t.searchedCurrentFolder,folderId:t.folderId??null,page:{current:t.page,total:t.totalPages},totalMatches:t.totalCount,results:t.results.map(e=>({itemType:e.itemType==="folder"?"folder":"document",...e.itemType==="folder"?{folderId:e.id}:{documentId:e.id},title:e.title,canonicalPath:e.canonicalPath||`/${e.title||e.id}`,snippet:e.snippet||"",href:e.itemType==="folder"?`/docs/folders/${e.id}`:`/docs/${e.id}`,parentFolderId:e.parentFolderId??null}))})}function Wr(t){return JSON.stringify({kind:"document_tree_listing",parentFolderId:t.parentFolderId,page:{current:t.page,total:t.totalPages},totalItems:t.totalCount,hasMore:t.hasMore,items:t.items.map(e=>({type:e.itemType==="folder"?"folder":"document",id:e.id,title:e.title||e.name||"Untitled",name:e.name||e.title||"Untitled",canonicalPath:e.canonicalPath||`/${e.title||e.name||e.id}`,href:e.itemType==="folder"?`/docs?folder=${e.id}`:`/docs/${e.id}`,parentFolderId:e.parentFolderId??null,childCount:typeof e.childCount=="number"?e.childCount:void 0,updatedAt:e.updatedAt}))})}function ht(t){return{editable:!1,editInstructions:`Read-only source. Mutation tools only edit the active document. To edit this source, give the user a clickable link to /docs/${t} and ask them to open it and continue there. Never use these block IDs to edit the active document.`}}function gt(t){return JSON.stringify({kind:"document_read",document:{documentId:t.documentId,title:t.title,canonicalPath:t.canonicalPath||`/${t.title}`,href:`/docs/${t.documentId}`,...ht(t.documentId)},loaded:{startIndex:t.startIndex,endIndex:t.endIndex,estimatedTokens:t.estimatedTokens},next:t.nextIndex===null?null:{index:t.nextIndex},endOfDocument:t.endOfDocument,documentContent:t.content})}function In(t,e){if(t==="search_document"){const o=Array.isArray(e.queries)?e.queries.filter(s=>typeof s=="string"):[],r=typeof e.document_id=="string"&&e.document_id.trim().length>0?e.document_id.trim():null;return JSON.stringify({documentId:r,queries:o})}const n=typeof e.color=="string"&&e.color.trim().length>0?e.color.trim().toLowerCase():null;return JSON.stringify({color:n})}function Hr(t){const e=new Map;for(const n of t)for(const o of n.matchedColors??[])e.set(o,(e.get(o)??0)+1);return e.size===0?"":Array.from(e.entries()).sort((n,o)=>o[1]-n[1]||n[0].localeCompare(o[0])).map(([n,o])=>`${o} ${n}`).join(", ")}function Jr(t,e){let n=0;for(;n<t.length&&n<e.length&&t[n]===e[n];)n+=1;let o=t.length-1,r=e.length-1;for(;o>=n&&r>=n&&t[o]===e[r];)o-=1,r-=1;const s=Math.max(0,o-n+1),i=Math.max(0,r-n+1);return Math.max(s,i)}function Vr(t,e){if(t.name!=="replace_block"||!t.arguments||typeof t.arguments!="object")return null;const n=t.arguments.id,o=t.arguments.content,r=t.arguments.count;if(typeof n!="string"||typeof r=="number"&&Number.isFinite(r)&&Math.floor(r)>1||!Array.isArray(o)||o.length!==1||typeof o[0]!="string")return null;const s=e.children.find(T=>T.id===n);if(!s)return null;const i=un(Ze(s)),c=un(Br(o[0]));if(!i||!c||i===c)return null;const l=Jr(i,c),u=Math.max(i.length,c.length);if(u<=0)return null;const _=l/u;return l>ur||_>hr?null:`WARNING: replace_block only changed a small span (~${l} chars, ${(_*100).toFixed(0)}% of block). Prefer replace for typo, punctuation, and wording edits; reserve replace_block for full rewrites.`}function _n(t,e,n){if(!n||n.size===0)return!1;if(n.has(e))return!0;const o=Ne(t,e);if(o&&n.has(o))return!0;const r=de(t,e),s=r>=0?t.children[r]?.id:void 0;return typeof s=="string"&&n.has(s)}function Gr(t,e,n){if(t.name!=="replace_block"&&t.name!=="remove_block")return{toolCall:t};if(!t.arguments||typeof t.arguments!="object")return{toolCall:t};const o=t.arguments.id;if(typeof o!="string"||o.trim().length===0)return{toolCall:t};const r=t.arguments.count;if(r!==void 0&&(typeof r!="number"||!Number.isFinite(r)||Math.floor(r)<1))return{toolCall:t};const s=r===void 0?1:Math.floor(r);if(s<=1)return{toolCall:t};const i=eo(e,o),c=i&&"children"in i?to(i,o):-1;if(!i||c===-1)return{toolCall:t};if(!n||n.size===0)return{toolCall:t,error:`${t.name} requested ${s} consecutive blocks, but no request-level multi-block document context is available. Read the complete range first, then retry without narrowing the count.`};const l=new Set(Array.from(n).map(_=>de(e,_)).filter(_=>_!==-1));let u=0;for(let _=c;_<i.children.length;_++){const T=i.children[_]?.id;if(typeof T!="string"||T.length===0)break;const M=de(e,T);if(M===-1||!l.has(M))break;u+=1}return u<=0?{toolCall:t,error:`${t.name} targets block '${o}', which is outside the loaded <document_content> context. Read that block first, then retry.`}:u>=s?{toolCall:t}:{toolCall:t,error:`${t.name} requested ${s} consecutive blocks, but only ${u} were seen in request-level document context. Read the remaining range and retry; no partial mutation was applied.`}}function Kr(t,e){const n=dt(t,e);if(n===-1)return null;const o=te(t)[n];return o?.id?{block:o,topLevelBlockId:o.id,topLevelIndex:n}:null}function Yr(t){const e=t.toolState.editedBlockIds.size;if(e===0)return{loadedBlockCount:0,editedBlockCount:0};const n=t.getLatestDocument(),o=n.children.length,r=new Set;for(const l of t.toolState.editedBlockIds){const u=de(n,l);u!==-1&&r.add(u)}const s=new Set;for(const l of r)for(let u=Math.max(0,l-rn);u<=Math.min(o-1,l+rn);u++)s.add(u);const i=[],c=Array.from(s).sort((l,u)=>l-u);for(const l of c){const u=n.children[l];u?.id&&i.push(u.id)}t.turnState.requestedBlockIds||(t.turnState.requestedBlockIds=new Set);for(const l of i)t.turnState.requestedBlockIds.add(l);return t.turnState.documentRequested=!0,{loadedBlockCount:i.length,editedBlockCount:e}}async function Xr(t){const e=await So(t);if(e)return{id:e.id,type:e.type,content:e.content,preview:e.preview,charCount:e.charCount,...e.fileName?{fileName:e.fileName}:{},...e.mimeType?{mimeType:e.mimeType}:{},...e.fileSize?{fileSize:e.fileSize}:{},...e.urls?{urls:e.urls}:{},...e.dimensions?{dimensions:e.dimensions}:{}}}function Zr(t){const e=t.loadAttachment??Xr,n=t.metrics??ro;if(!t.toolState.foreignBlockSources){t.toolState.foreignBlockSources=new Map;for(const y of t.getConversationHistory?.()??[])if(!(!y.toolResult?.success||!y.toolResult.output))try{const k=JSON.parse(y.toolResult.output),D=k.document?.documentId;if(typeof D!="string"||!["document_read","document_search_context"].includes(k.kind)||typeof k.documentContent!="string"||!ie({document_id:D},t))continue;const R=new DOMParser().parseFromString(k.documentContent,"text/html");for(const d of R.querySelectorAll("[id]"))t.toolState.foreignBlockSources.set(d.id,D)}catch{}}const o=t.toolState.foreignBlockSources,r=(y,k,D)=>{const R=d=>{if(d.id&&D(d.id),"children"in d&&Array.isArray(d.children))for(const m of d.children)"id"in m&&R(m)};for(const d of k){const m=ye(y,d);m&&R(m)}},s=(y,k,D)=>r(y,k,R=>o.set(R,D)),i=y=>{const k=t.tryAddRequestedBlocks(y);return(!k||k.code===je)&&r(t.getLatestDocument(),y,D=>o.delete(D)),k};let c=t.turnState.currentTurn??0,l=0,u=0;const _=new Map;let T=1;const M=async()=>{t.getDocumentSession()||await t.waitForDocumentSession?.();const y=t.getDocumentSession(),k=y?.getDocumentId?.(),D=t.getCurrentDocumentId?.();return y&&(!k||!D||ie({document_id:k},t)==="")?y:null},B=y=>f(y,tn,Ho),L=new Set(["read_blocks","read_blocks_from_index","read_specific_blocks","search_document","find_highlights","measure_document","measure_blocks","view_image","render_document_pages"]),z=new Set(["read_blocks","read_blocks_from_index","read_specific_blocks","search_document"]),$=()=>{const y=t.turnState.currentTurn??0;y!==c&&(c=y,l=0,u=0)};return async y=>{var k,D;const R=Pr(y),d=R.name==="remove_blocks"?{...R,name:"remove_block"}:R,m=d.name,ne=t.getExecutionPolicy?.(),G=ne?lr(ne,m):null;if(G)return f(d,G.message,G.code);if(t.allowCrossDocumentReads===!1&&(kn(d.arguments??{}).length>0||m==="list_documents"||m==="search_documents"))return f(d,"This host only permits the supplied document. document_id routing is unavailable.","agent_tool_not_allowed");if($(),t.mutationTools.includes(m)||m==="remove_block"){const a=ie(d.arguments??{},t),h=Pe(d.arguments).filter(S=>o.has(S)&&ie({document_id:o.get(S)},t)!==""),g=a||(h.length?o.get(h[0]):void 0);if(g){if(!a&&h.every(x=>ye(t.getLatestDocument(),x)))return{...f(d,`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/${g} and ask them to open 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:g};const S=t.turnState.currentRequestId??0;t.toolState.foreignTargetFailureState?.requestId!==S&&(t.toolState.foreignTargetFailureState={requestId:S,count:0});const b=++t.toolState.foreignTargetFailureState.count;return{...f(d,`These edits target a read-only source document. Open /docs/${g} 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 active document instead, read its target blocks without document_id first.`,b>=2?"foreign_document_target_repeated":"foreign_document_target"),sourceDocumentId:g}}}const xn=z.has(m)&&ie(d.arguments??{},t)!=="";if(t.requireDocumentSessionForReads&&L.has(m)&&!xn&&!await M())return B(d);if(m==="import_attachment_into_document"){const a=typeof d.arguments?.attachment_id=="string"?d.arguments.attachment_id.trim():"";if(!a)return f(d,"attachment_id is required.");const h=d.arguments?.after_block_id;if(h!=null&&typeof h!="string")return f(d,"after_block_id must be a block ID string.");const g=typeof h=="string"&&h.trim()||void 0,S=t.getAllAttachments().get(a)??await e(a);if(!S)return f(d,`Attachment "${a}" was not found.`);if(S.type!=="docx"&&S.type!=="pdf")return f(d,"Only DOCX and PDF attachments can be imported into the document.");if(!t.importAttachmentIntoDocument)return f(d,"Attachment import is unavailable in this document.");try{t.toolState.statusMessage=`Importing ${S.fileName||"attachment"}…`,t.notifyListeners();const b=await t.importAttachmentIntoDocument(S,g);return t.toolState.editedBlockIds.clear(),t.toolState.hasImportedAttachment=!0,t.turnState.documentRequested=!1,t.turnState.requestedBlockIds=null,t.turnState.lastReadBlockIds=null,t.toolState.everReadFullDocument=!1,t.toolState.sequentialReadBlockIds=new Set,t.toolState.statusMessage=null,t.markConversationDirty(),t.notifyListeners(),N(d,`Imported "${b.fileName}" into the current document (${b.blockCount} blocks)${g?` after block "${g}"`:""}. The URL stayed the same. Continue the user's request by reading the imported content, then edit it.`)}catch(b){return t.toolState.statusMessage=null,t.notifyListeners(),f(d,b instanceof Error?b.message:"Attachment import failed.")}}if(vr.has(m)){if(!Tr(d.arguments))return f(d,'context_notes is required on every read/search call. Use "N/A" if nothing from the previous context needs to carry forward.');if(l>=1)return f(d,'Use at most one 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".',fr);l+=1}if(m==="measure_document"){const a=d.arguments||{},h=a.include_sections===!0,g=Number(a.section_offset),S=Number.isFinite(g)&&g>0?Math.floor(g):0,b=Number(a.section_limit),x=Number.isFinite(b)&&b>0?Math.min(Math.floor(b),mr):gr,w=(Array.isArray(a.heading_levels)?a.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),v=t.getLatestDocument(),p=Qt(v,{includeSections:h,...w.length>0?{headingLevels:w}:{}}),I=t.getDocumentSession()?.getDocumentWithoutPendingSuggestions(),C=I&&I!==v?Qt(I,{includeSections:!1}):null,P=C&&(C.wordCount!==p.wordCount||C.characterCount!==p.characterCount)?{wordCount:C.wordCount,characterCount:C.characterCount,paragraphCount:C.paragraphCount,pageCount:C.pageCount}:void 0,J=p.sections??[],q=J.length,A=Math.min(S,q),F=h?J.slice(A,A+x):void 0,O=F?.length??0,W=h&&A+O<q,V=JSON.stringify({kind:"document_measurement",tool:"measure_document",measurementBasis:"pending_suggestions_applied",...p,...P?{originalReviewProjection:P}:{},...h?{sections:F,sectionCount:q,sectionOffset:A,sectionLimit:x,returnedSectionCount:O,hasMoreSections:W,...W?{nextSectionOffset:A+O}:{}}:{}});n.count("agent.measure.call",1,{tool_name:m}),n.distribution("agent.measure.sections",q,void 0,{tool_name:m});const Q=h?`Measured document totals and ${q} heading section(s).`:"Measured document totals.",re=h&&q>0?` Returned sections ${A+1}-${A+O} of ${q}.${W?` Use section_offset=${A+O} to continue.`:""}`:"",X=h?"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",Oe=P?` The primary totals treat pending suggestions as accepted. The original review projection has ${P.wordCount} words and ${P.characterCount} characters because it excludes pending suggestions; use the projection matching the user's editor view when reconciling a reported count.`:"";return{toolCall:d,success:!0,toolOutput:V,agentFeedback:`${Q}${re}${Oe} The result includes ${X}.`,control:{shouldContinue:!0}}}if(m==="measure_blocks"){const a=d.arguments||{},h=typeof a.mode=="string"?a.mode.trim():"inclusive";if(h!==""&&h!=="inclusive")return f(d,'measure_blocks only supports mode="inclusive".');const g=Array.isArray(a.ranges)?a.ranges:[];if(g.length===0)return f(d,"measure_blocks requires at least one range.");const S=g.map(I=>{const C=I&&typeof I=="object"?I:{};return{startBlockId:typeof C.start_block_id=="string"?C.start_block_id:"",endBlockId:typeof C.end_block_id=="string"?C.end_block_id:void 0}}),b=zo(t.getLatestDocument(),S),x=b.ranges.length,w=b.errors.length,v=JSON.stringify({kind:"document_measurement",tool:"measure_blocks",...b});if(n.count("agent.measure.call",1,{tool_name:m}),n.distribution("agent.measure.ranges",x,void 0,{tool_name:m}),x===0){const I=b.errors.map(C=>C.error).join(" ")||"No valid inclusive ranges were measured.";return f(d,I,ue)}const p=w>0?`Measured ${x} inclusive block range(s); ${w} range(s) had errors.`:`Measured ${x} inclusive block range(s).`;return N(d,p,void 0,void 0,v)}if(m==="read_blocks"){const a=d.arguments||{},h=ie(a,t),g=a.from_id,S=h?xe(t):"";if(h&&!S&&!t.loadRemoteDocument)return f(d,"Cross-document access is only available for signed-in documents.");let b=null;try{b=h?await(t.loadRemoteDocument?.(h)??We({token:S,documentId:h})):null}catch(A){return f(d,A instanceof Error?A.message:"Document read failed.")}const x=b?.content??t.getLatestDocument(),w=te(x),v=w.length,p=typeof g=="string"?dt(x,g):-1;if(p===-1)return f(d,`Block ID "${g}" not found`,ue);if(p>=v)return f(d,`Start index ${p} is out of range for ${v} blocks.`);const I=pn({doc:x,startIndex:p,maxTokens:Se});if(I.blockIds.length===0||I.endIndex<p)return f(d,`No readable blocks found from index ${p}.`);if(b){s(x,I.blockIds,b.id);const A=Z.extractSpecificBlocks(x,I.blockIds,void 0,be),F=Z.formatSpecificBlocks(A),O=I.endIndex+1<v?I.endIndex+1:null,W=gt({documentId:b.id,title:b.title,canonicalPath:b.canonicalPath,startIndex:p,endIndex:I.endIndex,estimatedTokens:I.estimatedTokens,content:F,nextIndex:O,endOfDocument:O===null}),V=I.reachedTokenBudget?" Reached per-call token budget.":"";return N(d,`Read ${I.blockIds.length} blocks from "${b.title}" (index ${p}-${I.endIndex}). Estimated tokens: ~${I.estimatedTokens}.${V}${O!==null?` Next: read_blocks_from_index(document_id="${b.id}", index=${O}).`:" End of document."}`,void 0,void 0,W)}const C=(k=t.toolState).sequentialReadBlockIds??(k.sequentialReadBlockIds=new Set);if(C.size>0&&I.blockIds.every(A=>C.has(A)))return f(d,`This sequential read window (index ${p}-${I.endIndex}) contains only blocks already returned by earlier sequential read calls in this request. Do not cycle among previously read indices. Follow the last successful nextIndex, use read_specific_blocks for an intentional exact revisit, make the pending edits, or finish.`,je);const P=i(I.blockIds);if(P)return f(d,P.message,P.code);for(const A of I.blockIds)C.add(A);t.turnState.documentRequested=!0,n.count("agent.read.call",1,{tool_name:m}),n.distribution("agent.read.blocks_loaded",I.blockIds.length,void 0,{tool_name:m}),n.distribution("agent.read.tokens_loaded_estimate",I.estimatedTokens,void 0,{tool_name:m}),I.reachedTokenBudget&&n.count("agent.read.token_budget_reached",1,{tool_name:m});const J=Re(t,x);if(I.endIndex+1<v){const A=I.endIndex+1,F=w[A]?.id,O=qe({tool:m,loaded:{count:I.blockIds.length,startIndex:p,endIndex:I.endIndex,estimatedTokens:I.estimatedTokens},next:{index:A,...F?{blockId:F}:{}},endOfDocument:!1,coverage:J}),W=I.reachedTokenBudget?" Reached per-call token budget.":"",V=F?` Next block ID: ${F}.`:"";return N(d,`Read ${I.blockIds.length} blocks (index ${p}-${I.endIndex}). Estimated tokens: ~${I.estimatedTokens}.${W} Next: read_blocks_from_index(index=${A}).${V}`,void 0,void 0,O)}const q=qe({tool:m,loaded:{count:I.blockIds.length,startIndex:p,endIndex:I.endIndex,estimatedTokens:I.estimatedTokens},endOfDocument:!0,coverage:J});return N(d,`Read ${I.blockIds.length} blocks (index ${p}-${I.endIndex}). Estimated tokens: ~${I.estimatedTokens}. End of document.`,void 0,void 0,q)}if(m==="read_blocks_from_index"){const a=d.arguments||{},h=ie(a,t),g=Be(a.index,0),S=h?xe(t):"";if(h&&!S&&!t.loadRemoteDocument)return f(d,"Cross-document access is only available for signed-in documents.");let b=null;try{b=h?await(t.loadRemoteDocument?.(h)??We({token:S,documentId:h})):null}catch(q){return f(d,q instanceof Error?q.message:"Document read failed.")}const x=b?.content??t.getLatestDocument(),w=te(x),v=w.length;if(!b&&t.toolState.everReadFullDocument)return f(d,"You have already read the entire current document in this request. Continue by making edits if needed. If you need to revisit exact known blocks, use read_specific_blocks instead of restarting a sequential read.",je);if(b&&v===0&&g===0)return N(d,`Read 0 blocks from "${b.title}". End of document.`,void 0,void 0,gt({documentId:b.id,title:b.title,canonicalPath:b.canonicalPath,startIndex:0,endIndex:-1,estimatedTokens:0,content:"",nextIndex:null,endOfDocument:!0}));if(g>=v)return f(d,`Start index ${g} is out of range for ${v} blocks${b?` in "${b.title}"`:""}.`);const p=pn({doc:x,startIndex:g,maxTokens:Se});if(p.blockIds.length===0||p.endIndex<g)return f(d,`No readable blocks found from index ${g}.`);if(b){s(x,p.blockIds,b.id);const q=Z.extractSpecificBlocks(x,p.blockIds,void 0,be),A=Z.formatSpecificBlocks(q),F=p.endIndex+1<v?p.endIndex+1:null,O=gt({documentId:b.id,title:b.title,canonicalPath:b.canonicalPath,startIndex:g,endIndex:p.endIndex,estimatedTokens:p.estimatedTokens,content:A,nextIndex:F,endOfDocument:F===null}),W=p.reachedTokenBudget?" Reached per-call token budget.":"";return n.count("agent.read.call",1,{tool_name:m}),n.distribution("agent.read.blocks_loaded",p.blockIds.length,void 0,{tool_name:m}),N(d,`Read ${p.blockIds.length} blocks from "${b.title}" (index ${g}-${p.endIndex}). Estimated tokens: ~${p.estimatedTokens}.${W}${F!==null?` Next: read_blocks_from_index(document_id="${b.id}", index=${F}).`:" End of document."}`,void 0,void 0,O)}const I=(D=t.toolState).sequentialReadBlockIds??(D.sequentialReadBlockIds=new Set);if(I.size>0&&p.blockIds.every(q=>I.has(q)))return f(d,`This sequential read window (index ${g}-${p.endIndex}) contains only blocks already returned by earlier sequential read calls in this request. Do not cycle among previously read indices. Follow the last successful nextIndex, use read_specific_blocks for an intentional exact revisit, make the pending edits, or finish.`,je);const C=i(p.blockIds);if(C)return f(d,C.message,C.code);for(const q of p.blockIds)I.add(q);t.turnState.documentRequested=!0,n.count("agent.read.call",1,{tool_name:m}),n.distribution("agent.read.blocks_loaded",p.blockIds.length,void 0,{tool_name:m}),n.distribution("agent.read.tokens_loaded_estimate",p.estimatedTokens,void 0,{tool_name:m}),p.reachedTokenBudget&&n.count("agent.read.token_budget_reached",1,{tool_name:m});const P=Re(t,x);if(p.endIndex+1<v){const q=p.endIndex+1,A=w[q]?.id,F=qe({tool:m,loaded:{count:p.blockIds.length,startIndex:g,endIndex:p.endIndex,estimatedTokens:p.estimatedTokens},next:{index:q,...A?{blockId:A}:{}},endOfDocument:!1,coverage:P}),O=p.reachedTokenBudget?" Reached per-call token budget.":"",W=A?` Next block ID: ${A}.`:"";return N(d,`Read ${p.blockIds.length} blocks (index ${g}-${p.endIndex}). Estimated tokens: ~${p.estimatedTokens}.${O} Next: read_blocks_from_index(index=${q}).${W}`,void 0,void 0,F)}const J=qe({tool:m,loaded:{count:p.blockIds.length,startIndex:g,endIndex:p.endIndex,estimatedTokens:p.estimatedTokens},endOfDocument:!0,coverage:P});return N(d,`Read ${p.blockIds.length} blocks (index ${g}-${p.endIndex}). Estimated tokens: ~${p.estimatedTokens}. End of document.`,void 0,void 0,J)}if(m==="search_document"){const a=d.arguments||{},h=ie(a,t),g=a.queries,S=Array.isArray(g)?g.filter(K=>typeof K=="string"&&K.length>0):typeof g=="string"&&g.length>0?[g]:[];if(S.length===0)return f(d,'search_document requires "queries": a non-empty array of search strings.');const b=typeof a.page=="number"?a.page:0,x=h?xe(t):"";if(h&&!x&&!t.loadRemoteDocument)return f(d,"Cross-document access is only available for signed-in documents.");let w=null;try{w=h?await(t.loadRemoteDocument?.(h)??We({token:x,documentId:h})):null}catch(K){return f(d,K instanceof Error?K.message:"Document search failed.")}const v=w?.content??t.getLatestDocument(),p=t.searchPageSize,I=In("search_document",a);let C;b>0&&t.toolState.lastSearchState&&t.toolState.lastSearchState.toolName==="search_document"&&t.toolState.lastSearchState.requestKey===I?C=t.toolState.lastSearchState.allResults:C=Z.searchDocument(v,S);let P;if(!w&&C.length>0){const K=b>0&&t.toolState.lastSearchState?.requestKey===I?t.toolState.lastSearchState.resultSetId:void 0;if(K&&_.has(K))P=K;else{P=`search_result_${T++}`;const Ue=Array.from(new Set(C.map(Ge=>Ge.blockId)));_.set(P,{id:P,blockIds:Ue,blockHashes:Qe(v,Ue)})}}const J=fn({doc:v,results:C,pageSize:p,maxTokens:Se}),q=Math.max(1,J.length),A=Math.min(b,Math.max(0,q-1)),F=J[A]??{results:[],startResultIndex:0,endResultIndexExclusive:0},O=F.startResultIndex,W=F.endResultIndexExclusive,V=F.results,Q=V.map(K=>K.blockId),re=w||Q.length===0?null:i(Q);t.toolState.lastSearchState={toolName:"search_document",requestKey:I,allResults:C,currentPage:A,totalPages:q,...P?{resultSetId:P}:{}};let X;C.length===0?X=`No matches found${w?` in "${w.title}"`:""} for: ${S.join(", ")}`:(X=`Found ${C.length} matching blocks${w?` in "${w.title}"`:""}. Showing page ${A+1}/${q} (results ${O+1}-${W} of ${C.length}).`,!w&&P&&(X+=` The full unpaginated result set is saved as ${P}; pass search_result_id="${P}" to replace, replace_block, style_blocks, or remove_blocks to target all ${C.length} matches in one call.`),A<q-1&&w&&(X+=w?` Call search_document with document_id="${w.id}" and page=${A+1} to see next page.`:` Call search_document with page=${A+1} to see next page.`));const Oe=re?.code==="no_new_read_context";if(re&&!Oe){if(C.length>0){let K=`Found ${C.length} matching blocks. Showing page ${A+1}/${q} (blocks ${O+1}-${W} of ${C.length}). Matching blocks could not be loaded this turn.`;return A<q-1&&(K+=` Call search_document with page=${A+1} to see next page.`),f(d,`${re.message} ${K}`,re.code)}return f(d,`${re.message} ${X}`,re.code)}if(Oe&&C.length>0&&(X+=" Matching block content is already available in this request's cached context."),w){s(v,Q,w.id);const K=Z.extractSpecificBlocks(v,Q,void 0,be),Ue=Z.formatSpecificBlocks(K),Ge=JSON.stringify({kind:"document_search_context",tool:"search_document",document:{documentId:w.id,title:w.title,canonicalPath:w.canonicalPath||`/${w.title}`,href:`/docs/${w.id}`,...ht(w.id)},queries:S,totalMatches:C.length,page:{current:A,total:q,startResult:O+1,endResult:W},nextPage:A<q-1?A+1:null,matches:V.map(Ke=>({blockId:Ke.blockId,blockIndex:Ke.blockIndex,matchedQueries:Ke.matchedQueries??[]})),documentContent:Ue});return n.count("agent.read.search_call",1,{tool_name:m}),n.distribution("agent.read.blocks_loaded",Q.length,void 0,{tool_name:m}),N(d,X,void 0,void 0,Ge)}t.turnState.documentRequested=!0,n.count("agent.read.search_call",1,{tool_name:m}),n.distribution("agent.read.blocks_loaded",Q.length,void 0,{tool_name:m});const se=bn({tool:"search_document",queries:S,totalMatches:C.length,currentPage:A,totalPages:q,pageStart:O,pageEnd:W,pageResults:V,nextPage:A<q-1?A+1:null,...P?{searchResultId:P}:{},coverage:Re(t,t.getLatestDocument())});return N(d,X,void 0,void 0,se)}if(m==="list_documents"){const a=d.arguments||{},h=typeof a.parent_folder_id=="string"&&a.parent_folder_id.trim().length>0?a.parent_folder_id.trim():null,g=Be(a.page,0),S=xe(t);if(!S)return f(d,"Document tree listing is only available for signed-in documents.");try{const b=await jr({token:S,parentFolderId:h,page:g,limit:50}),x=b.hasMore?` Call list_documents with page=${g+1} for more.`:"",w=b.items.filter(C=>C.itemType==="folder").length,v=b.items.length-w,p=b.totalCount===0?`No items found in ${h?"that folder":"the account root"}.`:`Listed ${b.items.length} of ${b.totalCount} items in ${h?"the folder":"the account root"} (${w} folders, ${v} documents).${x}`,I=Wr({parentFolderId:h,page:g,totalCount:b.totalCount,totalPages:Math.max(1,b.totalPages),hasMore:b.hasMore,items:b.items});return n.count("agent.read.document_tree_list",1,{tool_name:m}),N(d,p,void 0,void 0,I)}catch(b){return f(d,b instanceof Error?b.message:"Document listing failed.")}}if(m==="search_documents"){const a=d.arguments||{},h=typeof a.query=="string"?a.query.trim():"";if(!h)return f(d,"search_documents requires a query.");const g=xe(t);if(!g)return f(d,"Cross-document search is only available for signed-in documents.");const S=Fr(a.scope),b=t.getCurrentFolderId?.()??null,x=typeof a.folder_id=="string"&&a.folder_id.trim().length>0?a.folder_id.trim():null,w=S==="current_folder"&&!b||S==="folder"&&!x?"account":S,v=Be(a.page,0);try{const p=await Er({token:g,query:h,scope:w,page:v,currentFolderId:b,folderId:x}),I=w==="current_folder"&&!!b,C=w==="folder"&&x?"the selected folder tree":I?"the current folder tree":"the account",P=v+1<p.totalPages?` Call search_documents with page=${v+1} for more.`:"",J=p.totalCount===0?`No documents found for "${h}" in ${C}.`:`Found ${p.totalCount} documents for "${h}" in ${C}. Showing page ${v+1}/${Math.max(1,p.totalPages)}.${P}`,q=zr({query:h,scope:w,searchedCurrentFolder:I,folderId:w==="folder"?x:null,page:v,totalCount:p.totalCount,totalPages:Math.max(1,p.totalPages),results:p.items});return n.count("agent.read.account_search_call",1,{tool_name:m}),N(d,J,void 0,void 0,q)}catch(p){return f(d,p instanceof Error?p.message:"Document search failed.")}}if(m==="find_highlights"){const a=d.arguments||{},h=typeof a.color=="string"&&a.color.trim().length>0?a.color.trim().toLowerCase():void 0,g=typeof a.page=="number"?a.page:0,S=t.getLatestDocument(),b=t.searchPageSize,x=In("find_highlights",a);let w;g>0&&t.toolState.lastSearchState&&t.toolState.lastSearchState.toolName==="find_highlights"&&t.toolState.lastSearchState.requestKey===x?w=t.toolState.lastSearchState.allResults:w=Z.findHighlights(S,h);const v=fn({doc:S,results:w,pageSize:b,maxTokens:Se}),p=Math.max(1,v.length),I=Math.min(g,Math.max(0,p-1)),C=v[I]??{results:[],startResultIndex:0,endResultIndexExclusive:0},P=C.startResultIndex,J=C.endResultIndexExclusive,q=C.results,A=q.map(X=>X.blockId),F=A.length===0?null:i(A);t.toolState.lastSearchState={toolName:"find_highlights",requestKey:x,allResults:w,currentPage:I,totalPages:p};const O=h?`${h} highlight`:"highlighted content",W=h||w.length===0?"":` Colors: ${Hr(w)}.`;let V;w.length===0?V=`No blocks found with ${O}.`:(V=`Found ${w.length} blocks with ${O}. Showing page ${I+1}/${p} (results ${P+1}-${J} of ${w.length}).${W}`,I<p-1&&(V+=` Call find_highlights with page=${I+1} to see next page.`));const Q=F?.code==="no_new_read_context";if(F&&!Q){if(w.length>0){let X=`Found ${w.length} blocks with ${O}. Showing page ${I+1}/${p} (blocks ${P+1}-${J} of ${w.length}). Matching blocks could not be loaded this turn.`;return I<p-1&&(X+=` Call find_highlights with page=${I+1} to see next page.`),f(d,`${F.message} ${X}`,F.code)}return f(d,`${F.message} ${V}`,F.code)}Q&&w.length>0&&(V+=" Matching block content is already available in this request's cached context."),t.turnState.documentRequested=!0,n.count("agent.read.search_call",1,{tool_name:m}),n.distribution("agent.read.blocks_loaded",A.length,void 0,{tool_name:m});const re=bn({tool:"find_highlights",color:h??null,totalMatches:w.length,currentPage:I,totalPages:p,pageStart:P,pageEnd:J,pageResults:q,nextPage:I<p-1?I+1:null,coverage:Re(t,t.getLatestDocument())});return N(d,V,void 0,void 0,re)}if(m==="read_specific_blocks"){const a=d.arguments||{},h=ie(a,t),g=a.block_ids,S=Array.isArray(g)?g.filter(O=>typeof O=="string"&&O.length>0):typeof g=="string"&&g.length>0?[g]:[];if(S.length===0)return f(d,"No block IDs provided");const b=h?xe(t):"";if(h&&!b&&!t.loadRemoteDocument)return f(d,"Cross-document access is only available for signed-in documents.");let x=null;try{x=h?await(t.loadRemoteDocument?.(h)??We({token:b,documentId:h})):null}catch(O){return f(d,O instanceof Error?O.message:"Document read failed.")}const w=x?.content??t.getLatestDocument(),{blockIds:v,estimatedTokens:p,reachedTokenBudget:I,missingRequestedBlocks:C}=Nr({doc:w,requestedBlockIds:S,maxTokens:Se});if(v.length===0)return C>0?f(d,"None of the requested block IDs were found in the document.",ue):f(d,"No readable blocks could be loaded.");if(x){s(w,v,x.id);const O=Z.extractSpecificBlocks(w,v,void 0,be),W=Z.formatSpecificBlocks(O),V=ut(w,new Set(v)),Q=JSON.stringify({kind:"document_read",tool:m,document:{documentId:x.id,title:x.title,canonicalPath:x.canonicalPath||`/${x.title}`,href:`/docs/${x.id}`,...ht(x.id)},loaded:{count:v.length,blockIds:v,blockIndices:V,estimatedTokens:p},reachedTokenBudget:I,documentContent:W});return n.count("agent.read.call",1,{tool_name:m}),n.distribution("agent.read.blocks_loaded",v.length,void 0,{tool_name:m}),N(d,`Read ${v.length} specific blocks from "${x.title}". Estimated tokens: ~${p}.${I?" Reached per-call token budget.":""}`,void 0,void 0,Q)}const P=i(v);if(P)return f(d,P.message,P.code);t.turnState.documentRequested=!0,n.count("agent.read.call",1,{tool_name:m}),n.distribution("agent.read.blocks_loaded",v.length,void 0,{tool_name:m}),n.distribution("agent.read.tokens_loaded_estimate",p,void 0,{tool_name:m}),I&&n.count("agent.read.token_budget_reached",1,{tool_name:m});const J=ut(w,new Set(v)),q=qe({tool:m,loaded:{count:v.length,requestedCount:S.length,estimatedTokens:p,ranges:yn(J)},endOfDocument:!1,coverage:Re(t,w)}),A=I?` Reached per-call token budget; loaded ${v.length}/${S.length} requested blocks.`:"",F=C>0?` ${C} requested block IDs were not found.`:"";return N(d,`Loaded ${v.length} specific blocks.${A}${F} Estimated tokens: ~${p}.`,void 0,void 0,q)}if(m==="get_attachment"){const a=(d.arguments||{}).attachment_id;if(!a)return f(d,"No attachment_id provided");let h=t.getAllAttachments().get(a);return h||(h=await e(a),h&&t.getAllAttachments().set(a,h)),h?h.content?.trim()??""?N(d,`Loaded attachment "${h.id}" (${h.charCount} chars).`,void 0,void 0,`<attachment id="${h.id}" type="${h.type}"${h.fileName?` filename="${h.fileName}"`:""} chars="${h.charCount}">
|
|
4
|
+
${h.content}
|
|
5
|
+
</attachment>`):N(d,`Attachment "${h.id}" has no text content to retrieve; it is a hosted file already visible in the conversation history.`):f(d,`Attachment "${a}" not found. Available attachments: ${Array.from(t.getAllAttachments().keys()).join(", ")||"none"}`)}if(m==="view_image"){const a=(d.arguments||{}).block_id;if(!a)return f(d,"No block_id provided");const h=t.getLatestDocument(),g=dn(h.children,a);if(!g)return f(d,`Image block "${a}" not found in document`,ue);const S={id:`view_image_${a}`,type:"image",content:"",preview:"",charCount:0,fileName:g.alt||`image_${a}`,urls:[g.src],dimensions:[{width:g.width,height:g.height}]};return N(d,`Image retrieved: ${g.alt?`"${g.alt}" `:""}(${g.width}x${g.height}px)${g.sourceUrl?` Source: ${g.sourceUrl}`:""}`,S)}if(m==="render_document_pages"){if(!t.renderDocumentPages)return f(d,"Rendered page inspection is unavailable until the document canvas is ready.");const a=d.arguments||{},h=Be(a.start_page,1),g=Be(a.page_count,1),S=a.mode==="layout"?"layout":"appearance";let b=a.quality==="compact"?"compact":"detailed";if(h<1)return f(d,"start_page must be 1 or greater.");const x=b==="detailed"&&g>2;x&&g<=4&&(b="compact");const w=b==="compact"?4:2;if(g<1||g>w)return f(d,`page_count must be between 1 and ${w} for ${b} quality.`);try{const v=await t.renderDocumentPages({startPage:h,pageCount:g,mode:S,quality:b});if(v.placeholderImageCount||v.failedImageCount||v.mathPlaceholderCount)return{...f(d,`Visual inspection is incomplete: ${v.placeholderImageCount} image placeholders, ${v.failedImageCount} failed images, and ${v.mathPlaceholderCount} formula placeholders. 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 will not verify the document.`,"visual_resource_unavailable"),failure:{code:"visual_resource_unavailable",phase:"verification",retryable:!1,mutationOutcome:"unchanged"}};const p=v.pages.length===1?`page ${v.pages[0]}`:`pages ${v.pages[0]}-${v.pages[v.pages.length-1]}`,I={id:`render_document_pages_${d.id}`,type:"image",content:"",preview:"",charCount:0,fileName:`Rendered document ${p} (${S}, ${b})`,mimeType:v.dataUrl.startsWith("data:image/png")?"image/png":"image/jpeg",urls:[v.dataUrl],dimensions:[{width:v.width,height:v.height}],visionDetail:b==="compact"?"low":"high"};return N(d,`Rendered ${p} of ${v.totalPages} in ${S} mode at ${b} quality.${x?" The request was downgraded from detailed to compact quality so all requested pages fit in one bounded render.":""}`,I,void 0,JSON.stringify({pages:v.pages,totalPages:v.totalPages,mode:S,quality:b,placeholderImageCount:v.placeholderImageCount,failedImageCount:v.failedImageCount,mathPlaceholderCount:v.mathPlaceholderCount}))}catch(v){return f(d,v instanceof Error?v.message:"Document page rendering failed.",v instanceof Error&&"code"in v?String(v.code):void 0)}}if(m==="set_status"){const a=Ar(d.arguments);return t.toolState.statusMessage=a,t.markConversationDirty(),t.notifyListeners(),N(d,a?`Status set to "${a}".`:"Status updated.")}if(m==="request_user_input"){const a=d.arguments??{},h=typeof a.chat_response=="string"?a.chat_response.trim():"";return!h||cn(h)?f(d,"request_user_input requires a concrete user-facing question, not only a status update.",an):!Array.isArray(a.suggested_next_prompts)&&!Array.isArray(a.followups)?f(d,"request_user_input requires suggested_next_prompts as an array."):N(d,"User input requested.")}if(m===kr)return!t.skipSameTurnCompletionGuard&&u>0?f(d,`${m} cannot be used in the same tool batch as document edits. Inspect the successful mutation results on the next turn, then call end_agent_run if the request is complete.`,sn):N(d,"Legacy completion handoff acknowledged. Call end_agent_run on the next turn.");if(Ir(m)){if(!t.skipSameTurnCompletionGuard&&u>0)return f(d,`${m} 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 is complete.`,sn);const a=d.arguments??{},h=typeof a.chat_response=="string"?a.chat_response.trim():"";return h?cn(h)?f(d,`${m} requires a final user-facing response, not only a status update.`,an):!Array.isArray(a.suggested_next_prompts)&&!Array.isArray(a.followups)?f(d,`${m} requires suggested_next_prompts as an array.`):N(d,"Final response recorded."):f(d,`${m} requires a non-empty chat_response.`)}const ee=await M();if(!ee)return B(d);const H=t.getLatestDocument();if(m==="rollback_agent_suggestions"){const a=d.arguments??{},h=a.request_id==null?void 0:a.request_id,g=a.turn==null?void 0:a.turn;if(h!==void 0&&(!Number.isInteger(h)||Number(h)<1))return f(d,"request_id must be a positive integer.");if(g!==void 0&&(!Number.isInteger(g)||Number(g)<1))return f(d,"turn must be a positive integer.");if(g!==void 0&&h===void 0)return f(d,"turn requires request_id.");const S=t.turnState.currentRequestId??0,b=t.turnState.currentTurn??0;if(h!==void 0&&Number(h)>S)return f(d,`request_id ${h} is in the future; the current request is ${S}.`);const x=t.getConversationId?.().trim()??"";if(!x)return f(d,"This conversation has no stable ID, so its suggestions cannot be rolled back safely.");const w=ee.getDocumentWithPendingSuggestionsApplied(),v=ee.rollbackAgentSuggestions({agentConversationId:x,requestId:h===void 0?void 0:Number(h),turn:g===void 0?void 0:Number(g),currentRequestId:S,currentTurn:b});if(v.resolvedCount===0){const P=v.requestId===void 0?"any prior request":`request ${v.requestId}${v.turn===void 0?"":` turn ${v.turn}`}`;return N(d,`No still-pending suggestions from this conversation matched ${P}. Accepted edits and other authors' work were left untouched. Recover omitted text from historical_edit_evidence or earlier before_block snapshots, then 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 p=ee.getDocumentWithPendingSuggestionsApplied(),I=new Map(w.children.map(P=>[P.id,P])),C=new Map(p.children.map(P=>[P.id,P]));for(const P of new Set([...I.keys(),...C.keys()]))JSON.stringify(I.get(P))!==JSON.stringify(C.get(P))&&t.toolState.editedBlockIds.add(P);return t.turnState.hasMutatedSinceLastRead=!0,u+=1,t.markConversationDirty(),t.notifyListeners(),N(d,`Rolled back ${v.resolvedCount} pending suggestion${v.resolvedCount===1?"":"s"} ${v.turn===void 0?`to before request ${v.requestId}`:`from request ${v.requestId} turn ${v.turn}`}. The rollback is one user-undoable history item. Now make the corrected edits; do not ask the user to reject the old suggestions.`)}if(m==="leave_comment"){const a=$r(d,t,ee,H);return a.success&&(u+=1),a}if((m==="insert_block"||m==="insert_table_row"||m==="insert_table_column")&&d.arguments?.position!=="before"&&d.arguments?.position!=="after")return f(d,`${m} has invalid "position" ${JSON.stringify(d.arguments?.position??null)}; use "before" or "after".`);if(m==="set_header_footer"&&d.arguments?.side!=="header"&&d.arguments?.side!=="footer")return f(d,`set_header_footer has invalid "side" ${JSON.stringify(d.arguments?.side??null)}; use "header" or "footer".`);const He=hn(t.turnState),he=bo({toolCall:d,docBefore:H,isTargetAllowed:a=>_n(H,a,He)});if(he?.error)return f(d,he.error,he.errorCode);const pt=he?.toolCall??d,ft=new Set(He??[]);for(const a of he?.targetBlockIds??[])ft.add(a);const Y=On({toolCall:pt,docBefore:H,resultSets:_});if(Y?.error)return f(d,Y.error,Y.errorCode);const ve=Gr(pt,H,ft);if(ve.error)return f(d,ve.error,at);const U=ve.toolCall;if(U.name==="replace"&&U.arguments&&Array.isArray(U.arguments.replacements)&&Object.prototype.hasOwnProperty.call(U.arguments,"comment"))return f(U,'replace comment belongs on each operation inside "replacements", alongside find, replace, and occurrence.');const Mn=new Set(H.children.map(a=>a.id)),Me=new Set(He??[]);for(const a of he?.targetBlockIds??[])Me.add(a);for(const a of Y?.targetBlockIds??[])Me.add(a);const Le=ko(U,H,a=>_n(H,a,Me));if(Le.error)return f(U,Le.error,Le.error.includes("request-level document context")?at:void 0);const ge=Y?{actions:Y.actions,blockId:void 0,error:void 0}:U.name==="remove_block"&&Array.isArray(U.arguments?.ids)?{actions:Le.actions,blockId:void 0,error:void 0}:Un(U,{doc:H,loadedBlockIds:Me});if(ge.error){const a="failure"in ge?ge.failure:void 0;return{...f(U,ge.error,a?.code),failure:a}}if(ge.actions.length===0)return N(U,`${ln(U)} Continue with the remaining work; do not repeat this unchanged operation.`,void 0,!0);const Je=Nn({actions:ge.actions,doc:H,loadedBlockIds:Me}),me=Je.actions,ae=Array.from(new Set([...Y?.targetBlockIds??[],...he?.targetBlockIds??[],...Rr(me)])),$n=["insert_table_row","remove_table_row","insert_table_column","remove_table_column"].includes(U.name),yt=new Map;if((U.name==="replace_block"||U.name==="remove_block"||$n)&&t.turnState.promptBlockContentHashes)for(const a of gn(H,ae)){const h=t.turnState.promptBlockContentHashes.get(a);h&&yt.set(a,h)}const bt=a=>{for(const[h,g]of yt){const S=et(a,h);if(S!==null&&S!==g)return f(U,`Block '${h}' was edited (likely by the user) after you last read it. Re-read the block and re-apply your change against its current content.`,ue)}},kt=bt(H);if(kt)return kt;const vt=U.id||`tool-${Date.now()}`,pe=await(t.rehostImages??qo)(me);if(pe.failedUrls.length>0){const a=pe.failedUrls.length===1?"1 external image":`${pe.failedUrls.length} external images`,h=pe.failures.some(b=>b.status===429),g=pe.failures.length===1?pe.failures[0]:void 0,S=g?` Reason: ${g.message}${g.status?` (HTTP ${g.status})`:""}.`:"";return f(U,`${a} could not be copied into Revise storage, so no document changes were applied.${S} ${h?"Do not attempt more external image insertions in this request. Keep any earlier successful 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."}`,pe.unavailable?"agent_tool_not_allowed":void 0)}const Ie=t.getLatestDocument(),It=bt(Ie);if(It)return It;let E;const $e=U.name==="remove_block"?[...new Set(me.map(a=>typeof a.arguments?.id=="string"?Ne(H,a.arguments.id):null).filter(a=>a!==null))]:[];if($e.length>0&&me.some(a=>a.arguments?.count!=null&&a.arguments.count!==1||typeof a.arguments?.id!="string"||!Ne(H,a.arguments.id)))return f(U,"To remove footnotes/endnotes, pass their exact note IDs in ids, or one note ID with count 1. Remove main-document blocks separately.");for(const a of me){if(a.name!=="replace_block")continue;const h=Ie.notes?.find(g=>g.id===a.arguments?.id);if(h&&Mt(Ie,h.id)===h.id)return f(U,`Note '${h.id}' contains multiple body blocks or no single editable text block. Use replace_block with an exact body block ID (${h.children.map(g=>g.id).join(", ")}) instead of replacing the note wrapper.`)}if($e.length>0){const a=ee.getDocumentMutator(),h=new Set(a.getLiveSuggestionIds()),g=a.suggestingMode;a.suggestingMode=!0;let S=!1;try{const{result:x}=a.withSuggestionMetadata({source:"agent",authorType:"ai",agentName:we(t),...t.getAgentModel?{agentModel:t.getAgentModel()}:{},agentConversationId:t.getConversationId?.(),agentRequestId:t.turnState.currentRequestId,agentTurn:t.turnState.currentTurn,commentThreadId:t.commentThreadId,historyOrigin:`live-suggestions:${vt}`},()=>$e.every(w=>a.removeFootnote(w)));S=x}finally{a.suggestingMode=g}const b=a.getLiveSuggestionIds().filter(x=>!h.has(x));E=S?{success:!0,suggestionIds:b,agentFeedback:`Removed footnote/endnote blocks ${$e.join(", ")} and their inline references.`}:{success:!1,error:`Footnote/endnote blocks '${$e.join(", ")}' could not be removed.`}}else E=ee.applyAgentActions({message:"AI Assistant",actions:me.map(a=>{if((a.name==="replace"||a.name==="replace_all"||a.name==="replace_block")&&typeof a.arguments?.id=="string"){const h=Mt(Ie,a.arguments.id);if(h&&h!==a.arguments.id)return{...a,arguments:{...a.arguments,id:h}}}return a}),agentName:we(t),agentModel:t.getAgentModel?.(),agentConversationId:t.getConversationId?.(),agentRequestId:t.turnState.currentRequestId,agentTurn:t.turnState.currentTurn,commentThreadId:t.commentThreadId},vt,{optimizeStyleFormatting:t.getOptimizeStyleFormatting?.()??!1});if(E.resultCode==="already_satisfied")return N(U,E.styleEffects&&E.agentFeedback?E.agentFeedback:"Verified that the requested state is already satisfied; no document mutation occurred. "+ln(U),void 0,!0,JSON.stringify({code:"already_satisfied",mutationOutcome:"unchanged",...E.styleEffects?JSON.parse(mn(U,H,H,E.styleEffects.targetBlockIds,E.agentFeedback,E.styleEffects)):{}}));if(E.success!==!1&&E.styleEffects){const a=new Set([...E.styleEffects.changedBlockIds,...E.styleEffects.affectedBlockIds]);a.size<=ke&&ae.splice(0,ae.length,...a)}const oe=E.success!==!1;let j=E.agentFeedback,Ve;if(oe&&Y?.resultSet){const a=Y.resultSet,h=`Applied ${U.name} to all ${a.blockIds.length} blocks in ${a.id}.`;j=j?.includes(h)?j:j?`${h}
|
|
6
|
+
${j}`:h}if(oe&&(U.name==="replace_many"||U.name==="replace"&&Array.isArray(U.arguments?.replacements))){const a=me.length,h=qr(ae,ge.blockId),g=`Applied ${a} replacement ${a===1?"operation":"operations"} in ${h}.`;j=j?.includes(g)?j:j?`${g}
|
|
7
|
+
${j}`:g}if(oe&&ve.feedback&&(j=j?`${j}
|
|
8
|
+
${ve.feedback}`:ve.feedback),oe&&Je.retargets.length>0){const a=Lr(Je.retargets);a&&(j=j?`${j}
|
|
9
|
+
${a}`:a)}if(oe&&((E.commentedSuggestionIds?.length??0)>0||(E.commentAttachmentFailureCount??0)>0)){const a=E.attachedCommentIds??[],h=E.commentAttachmentFailureCount??0,g=a.length>0?`Attached ${a.length===1?"comment":`${a.length} separate comments`} to the resulting ${a.length===1?"suggestion":"suggestions"} (${a.join(", ")}).${h>0?` ${h} requested ${h===1?"comment":"comments"} could not be anchored; do 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.";j=j?`${j}
|
|
10
|
+
${g}`:g}if(oe){const a=Vr(U,H);a&&(j=j?`${j}
|
|
11
|
+
${a}`:a)}if(t.toolState.directMode&&oe){const a=new Set(E.commentedSuggestionIds??[]),h=(E.suggestionIds??[]).filter(g=>!a.has(g));if(h.length>0&&ee.acceptLiveSuggestions(h),h.length>0&&a.size===0){const g=ee.getDocumentMutator();g?.resetToolCallHistory&&g.resetToolCallHistory()}}if(oe){t.mutationTools.includes(m)&&(u+=1);const a=ee.getDocumentWithPendingSuggestionsApplied();if(Y?.resultSet&&(Y.resultSet.blockHashes=Qe(a,Y.resultSet.blockIds)),Ve=mn(U,H,a,ae,j,E.styleEffects),t.turnState.hasMutatedSinceLastRead=!0,t.mutationTools.includes(m)&&m!=="set_title"&&m!=="set_notes"&&m!=="set_page_layout"){if(!Y)for(const h of ae)t.toolState.editedBlockIds.add(h);if(!Y)for(const h of a.children)h.id&&!Mn.has(h.id)&&t.toolState.editedBlockIds.add(h.id);if(t.turnState.promptBlockContentHashes){const h=gn(Ie,ae);for(const g of h){const S=t.turnState.promptBlockContentHashes.get(g);if(S&&et(Ie,g)!==S||!S&&!ae.includes(g))continue;const b=et(a,g);b!==null?t.turnState.promptBlockContentHashes.set(g,b):t.turnState.promptBlockContentHashes.delete(g)}}Y||Yr(t)}}const _t=Cr(E.error);return{toolCall:U,success:oe,error:E.error,failure:E.failure,...E.failure?{errorCode:E.failure.code}:{},...!oe&&_t?{errorCode:_t}:{},documentStateAfter:ee.getDocumentWithPendingSuggestionsApplied(),agentFeedback:j,...Ve?{toolOutput:Ve}:{}}}}function Qr(t,e){return t.success?{ok:!0,value:{callId:t.toolCallId,tool:t.name,message:t.agentFeedback??null,data:t.output??null,context:t.documentContent?{format:"revise-html",html:t.documentContent}:null,suggestionIds:e}}:{ok:!1,error:{callId:t.toolCallId,tool:t.name,code:t.errorCode??"tool_failed",message:t.error??t.agentFeedback??`${t.name} failed.`}}}function es(t){if(t)try{return JSON.parse(t)}catch{return t}}class ts{constructor(e){this.options=e,this.toolState={editedBlockIds:new Set,hasImportedAttachment:!1,everReadFullDocument:!1,lastSearchState:null,statusMessage:null,directMode:!1,directModeForced:!1},this.turnState={currentTurn:0,requestedBlockIds:null,readBudgetBlockIds:null,lastReadBlockIds:null,promptBlockContentHashes:new Map,documentRequested:!1,hasMutatedSinceLastRead:!1},this.deliveredBlockIds=[],this.handler=null}async run(e,n={}){this.turnState.currentTurn+=1,this.deliveredBlockIds=[];const o=this.handler??(this.handler=this.createHandler()),r=this.toolState.directMode,s=this.toolState.directModeForced;n.directMode!==void 0&&(this.toolState.directMode=n.directMode,this.toolState.directModeForced=!0);try{return await o(e)}finally{this.toolState.directMode=r,this.toolState.directModeForced=s}}buildResult(e,n,o){const r=o.success&&this.deliveredBlockIds.length>0?Z.formatSpecificBlocks(Z.extractSpecificBlocks(this.options.getDocumentSession().getDocumentWithPendingSuggestionsApplied(),this.deliveredBlockIds)):void 0;return{toolCallId:e,name:n,success:o.success,...o.error?{error:o.error}:{},...o.errorCode?{errorCode:o.errorCode}:{},...o.agentFeedback?{agentFeedback:o.agentFeedback}:{},...o.toolOutput?{output:es(o.toolOutput)}:{},...r?{documentContent:r}:{}}}createHandler(){return Zr({toolState:this.toolState,turnState:this.turnState,getAllAttachments:()=>new Map,getFlaggedAttachmentIds:()=>new Set,getLatestDocument:()=>this.options.getDocumentSession().getDocumentWithPendingSuggestionsApplied(),getDocumentSession:()=>this.options.getDocumentSession(),markConversationDirty:()=>{},notifyListeners:()=>{},tryAddRequestedBlocks:e=>{const n=this.turnState.requestedBlockIds??new Set,o=this.turnState.readBudgetBlockIds??new Set;for(const s of e)n.add(s),o.add(s);this.turnState.requestedBlockIds=n,this.turnState.readBudgetBlockIds=o,this.turnState.lastReadBlockIds=new Set(e);const r=this.options.getDocumentSession().getDocumentWithPendingSuggestionsApplied();for(const[s,i]of Qe(r,e))this.turnState.promptBlockContentHashes.set(s,i);return this.deliveredBlockIds=[...e],null},mutationTools:[...this.options.mutationTools],searchPageSize:this.options.searchPageSize??25,getAgentAuthorName:()=>this.options.getAgentName?.()})}}const wn=new Set(["get_selection","view_image"]),ns=new Set(["remove_block"]),os=["document_id","search_documents",...wn];function rs(t){const e=structuredClone(t),n=e.properties;return delete n?.document_id,Array.isArray(e.required)&&(e.required=e.required.filter(o=>o!=="document_id")),e}function ss(t){return t.split(/(?<=\.)\s+/).filter(e=>!os.some(n=>e.includes(n))).join(" ")}const Sn=Bt.filter(t=>!wn.has(t.name)).map(t=>({name:t.name,description:ss(t.description),inputSchema:rs(t.inputSchema)}));function is(t,e){if(!e.documentId.trim())throw new Error("Revise: documentId is required for a server session.");const n=new mt(e.documentId,t,void 0,{disableHistory:!0,disableProposalPersistence:!0}),o=new Set(rt);let r=e.mode??"suggesting";n.setSuggestingMode(r==="suggesting");const s=new ts({getDocumentSession:()=>n,mutationTools:Array.from(rt),searchPageSize:e.searchPageSize});let i=1,c=!1,l=Promise.resolve();const u=()=>{if(c)throw new Error("Revise: server document session is disposed.")},_=($,y,k,D)=>({ok:!1,error:{callId:$,tool:y,code:k,message:D}}),T=async($,y,k,D)=>{u();const R=`server-tool-${i++}`;if(!Sn.some(m=>m.name===$)&&!ns.has($))return _(R,$,"unknown_tool",`Unknown or unavailable server document tool: ${$}`);if("document_id"in y)return _(R,$,"document_id_not_supported","document_id is not accepted: a server document session is bound to one document. Omit it and retry.");await Rn(),u(),n.setSuggestingMode(D==="suggesting");const d=o.has($)?new Set(n.getDocumentMutator().getLiveSuggestionIds()):null;try{const m=await s.run({id:R,name:$,arguments:y},{directMode:k.directMode??D==="editing"}),ne=s.buildResult(R,$,m);return Qr(ne,d?n.getDocumentMutator().getLiveSuggestionIds().filter(G=>!d.has(G)):null)}catch(m){return _(R,$,"internal_error",m instanceof Error?m.message:String(m))}finally{n.setSuggestingMode(r==="suggesting")}},M=($,y,k)=>{const D=r,R=l.then(()=>T($,y,k,D));return l=R.then(()=>{},()=>{}),R},B={getDefinitions:()=>(u(),Sn.map($=>({...$,inputSchema:structuredClone($.inputSchema)}))),execute:($,...y)=>{const[k={},D={}]=y;return M($,k,D)},executeDynamic:($,y={},k={})=>M($,y,k),call:async($,...y)=>{const[k={},D={}]=y,R=await M($,k,D);if(!R.ok)throw new Bn(R.error);return R.value}},L=()=>{u();const $=n.getDocumentMutator();return $.getLiveSuggestionIds().map(y=>{const k=$.getLiveSuggestion(y),D=$.getInlineSuggestionMetadataFromDocument(y),R=k&&"blockId"in k?k.blockId:k?.type==="paragraph-merge"?k.firstBlockId:void 0,d={id:y,...k?.type?{type:k.type}:{},...R?{blockId:R}:{},...k?.type==="table-change"?{tableId:k.tableId}:{}};for(const m of["authorType","agentName","agentModel","source","label","createdAt"]){const ne=D?.[m]??k?.[m];ne!==void 0&&Object.assign(d,{[m]:ne})}return d})},z=($,y)=>{u();const k=Array.from(new Set(y.filter(G=>typeof G=="string"&&G.trim().length>0))),D=n.getDocumentMutator(),R=new Set(D.getLiveSuggestionIds()),d=k.filter(G=>!R.has(G)),m=k.filter(G=>R.has(G));m.length>0&&($==="accept"?n.acceptLiveSuggestions(m):n.rejectLiveSuggestions(m));const ne=new Set(D.getLiveSuggestionIds());return{resolved:m.filter(G=>!ne.has(G)),missing:d,unresolved:m.filter(G=>ne.has(G))}};return{getMode:()=>(u(),r),setSuggestingMode:()=>{u(),r="suggesting"},setEditingMode:()=>{u(),r="editing"},tools:B,getPendingSuggestionIds:()=>(u(),n.getDocumentMutator().getLiveSuggestionIds()),listSuggestions:L,acceptSuggestions:$=>z("accept",$),rejectSuggestions:$=>z("reject",$),acceptAllSuggestions:()=>(u(),z("accept",n.getDocumentMutator().getLiveSuggestionIds())),rejectAllSuggestions:()=>(u(),z("reject",n.getDocumentMutator().getLiveSuggestionIds())),dispose:()=>{c||(c=!0,n.dispose())}}}export{is as createServerDocumentSession};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{ag as g,r as h,ab as j,b6 as A,b7 as k}from"./backend-MFpDFVrD.js";const c=2;function s(e){return e===null||typeof e!="object"?JSON.stringify(e)??"null":Array.isArray(e)?`[${e.map(s).join(",")}]`:`{${Object.entries(e).filter(([,t])=>t!==void 0).sort(([t],[r])=>t<r?-1:t>r?1:0).map(([t,r])=>`${JSON.stringify(t)}:${s(r)}`).join(",")}}`}function i(e,t=c){if(e===null||typeof e!="object")return e;if(Array.isArray(e))return e.map(o=>i(o,t));const r=e;if(r.type==="text")return{...r,marks:(t===1?A:k)(r.marks)};const n={};for(const[o,a]of Object.entries(r))o==="indentLevel"&&r.type==="list-item"&&!a||o==="hasHeader"&&r.type==="table"&&!a||o==="footnoteNumber"&&r.type==="footnote"||(n[o]=i(a,t));if(Array.isArray(n.children)){const o=[];for(const a of n.children){const f=o[o.length-1];if(f&&f.type==="text"&&a.type==="text"&&s(f.marks)===s(a.marks)){f.text=`${f.text}${a.text}`;continue}o.push(a)}n.children=o}return n}function u(e){return`${d(e,0).toString(36)}-${d(e,2654435769).toString(36)}`}function d(e,t){let r=3735928559^t,n=1103547991^t;for(let o=0;o<e.length;o++){const a=e.charCodeAt(o);r=Math.imul(r^a,2654435761),n=Math.imul(n^a,1597334677)}return r=Math.imul(r^r>>>16,2246822507),r^=Math.imul(n^n>>>13,3266489909),n=Math.imul(n^n>>>16,2246822507),n^=Math.imul(r^r>>>13,3266489909),4294967296*(2097151&n)+(r>>>0)}function b(e,t=c){return s(i(e,t))}function x(e,t=c){return u(b(e,t))}function O(e){return u(s(h(e.pageLayout)))}function l(e){if(e===null||typeof e!="object")return e;if(Array.isArray(e))return e.map(l);const t=e;if(t.type==="text"&&t.marks&&typeof t.marks=="object"&&"fontFamily"in t.marks){const n={...t.marks};return delete n.fontFamily,{...t,marks:n}}const r={};for(const[n,o]of Object.entries(t))r[n]=l(o);return r}function $(e,t=c){const r=[...e.children.filter(n=>n.type==="footnote"),...e.notes??[]];return u(s(r.map(n=>i(l(n),t))))}function m(e){if(e===null||typeof e!="object")return e;if(Array.isArray(e))return e.map(m);const t={};for(const[r,n]of Object.entries(e))r!=="id"&&(t[r]=m(n));return t}function v(e,t=c){let r=[...e.children.filter(n=>n.type==="header-footer"),...e.chrome??[]];return r.length===0&&(e.headers||e.footers)&&(r=j(e.headers,e.footers)),u(s(i({blocks:r.map(n=>m(n)),watermark:e.watermark??null,chromeImages:e.chromeImages??[]},t)))}function M(e,t=c){const r=n=>[...n].sort((o,a)=>{const f=s(i(o,t)),p=s(i(a,t));return f<p?-1:f>p?1:0});return u(s(i({sdtWrappers:r(e.sdtWrappers??[]),oxmlRanges:r(e.oxmlRanges??[])},t)))}function S(e,t=c){return u(s(i({stylesXml:e.stylesXml??null,stylesheet:e.stylesheet??null},t)))}function y(e){if(e===null||typeof e!="object")return!1;if(Array.isArray(e))return e.some(y);const t=e;if(t.type==="toc")return!0;const r=t.marks;return r&&typeof r=="object"&&typeof r.fieldInstr=="string"?!0:Object.values(t).some(y)}function F(e){const t=[...e.children.filter(n=>n.type==="header-footer"),...e.chrome??[]],r=!!(e.headers?.even||e.footers?.even)||t.some(n=>n.slot==="even"&&g(n));return u(s({autoHyphenation:h(e.pageLayout).hyphenationEnabled,evenAndOddHeaders:r,updateFields:y(e.children)}))}function N(e,t=c){return u(s([...e.comments??[]].sort((r,n)=>r.id<n.id?-1:r.id>n.id?1:0).map(r=>i(r,t))))}function C(e){return u(s(e.coreProperties??{}))}export{c as C,b as a,x as b,M as c,F as d,S as e,v as f,N as g,C as h,i,s as j,$ as n,O as p,u as s};
|
package/full.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{ca as s,c9 as a,cc as e,cf as c,cd as r,cb as o,cc as E,cg as t,ce as R}from"./chunks/index-DyOcu9mD.js";export{s as REVISE_SDK_BUILD,a as REVISE_SDK_VERSION,e as ReviseEditor,c as ReviseRoleError,r as ReviseToolError,o as createEmptyDocx,E as default,t as rolePolicy,R as setAssetBaseUrl};
|
package/index.d.ts
CHANGED
|
@@ -158,6 +158,13 @@ export interface ReviseEditorTools {
|
|
|
158
158
|
): Promise<ReviseToolResponse<Name>>;
|
|
159
159
|
getDefinitions(): ReviseEditorToolDefinition[];
|
|
160
160
|
exportDocx(): Promise<Blob>;
|
|
161
|
+
/**
|
|
162
|
+
* Export the document as a file. `format` defaults to "docx". In
|
|
163
|
+
* "review" mode (the default) a .docx keeps pending tracked changes and
|
|
164
|
+
* comments; other formats show the text with changes accepted. "final"
|
|
165
|
+
* accepts every pending change and drops comments first: a clean copy.
|
|
166
|
+
*/
|
|
167
|
+
export(options?: ReviseExportOptions): Promise<Blob>;
|
|
161
168
|
/** Settle every open suggestion, collaborators' included. Prefer ID-based
|
|
162
169
|
* review.acceptSuggestions() with IDs from mutation results. */
|
|
163
170
|
acceptAllSuggestions(): ReviseSuggestionDecision;
|
|
@@ -229,6 +236,14 @@ export type InlineFormattingCommand =
|
|
|
229
236
|
| "superscript"
|
|
230
237
|
| "subscript";
|
|
231
238
|
|
|
239
|
+
/** File formats `tools.export()` can produce. */
|
|
240
|
+
export type ReviseExportFormat = "docx" | "pdf" | "html" | "markdown" | "txt";
|
|
241
|
+
|
|
242
|
+
export interface ReviseExportOptions {
|
|
243
|
+
format?: ReviseExportFormat;
|
|
244
|
+
mode?: "review" | "final";
|
|
245
|
+
}
|
|
246
|
+
|
|
232
247
|
export type ReviseToolbarMode = "native" | "none";
|
|
233
248
|
export type ReviseZoom = number | "fit-width";
|
|
234
249
|
|
|
@@ -631,10 +646,10 @@ export interface ReviseCollaborationConfig {
|
|
|
631
646
|
* The recommended form: the editor builds the document and awareness with
|
|
632
647
|
* the settings it requires, and this connects them.
|
|
633
648
|
*
|
|
634
|
-
* The editor reserves
|
|
635
|
-
*
|
|
636
|
-
*
|
|
637
|
-
*
|
|
649
|
+
* The editor reserves the top-level keys listed in RESERVED_DOCUMENT_KEYS
|
|
650
|
+
* (content, comments, metadata, and others), so a document built elsewhere
|
|
651
|
+
* may already use those names or hold another schema. Let the editor build
|
|
652
|
+
* its own.
|
|
638
653
|
*/
|
|
639
654
|
connect?: ReviseCollaborationConnect;
|
|
640
655
|
/** A provider that already owns its document. The document is validated
|
|
@@ -790,6 +805,7 @@ export type ReviseDocumentScoped<T> = T & {
|
|
|
790
805
|
export interface ReviseMultiDocumentTools extends ReviseEditorTools {
|
|
791
806
|
forDocument(documentId: string): ReviseEditorTools;
|
|
792
807
|
exportDocx(documentId?: string): Promise<Blob>;
|
|
808
|
+
export(options?: ReviseExportOptions, documentId?: string): Promise<Blob>;
|
|
793
809
|
acceptAllSuggestions(documentId?: string): ReviseSuggestionDecision;
|
|
794
810
|
rejectAllSuggestions(documentId?: string): ReviseSuggestionDecision;
|
|
795
811
|
}
|
|
@@ -909,6 +925,13 @@ export interface ReviseEditorProps {
|
|
|
909
925
|
pageBorderColor?: string;
|
|
910
926
|
toolbarMode?: ReviseToolbarMode;
|
|
911
927
|
fonts?: readonly ReviseFontDefinition[];
|
|
928
|
+
/**
|
|
929
|
+
* Store an image the user inserts, pastes, or drops, and resolve to the URL
|
|
930
|
+
* the document should reference. Without it, images are embedded in the
|
|
931
|
+
* document as data URLs, which export into the .docx like any other image.
|
|
932
|
+
* A rejection shows the user a notice and reaches onError.
|
|
933
|
+
*/
|
|
934
|
+
onImageUpload?: (file: File, documentId: string) => Promise<string>;
|
|
912
935
|
className?: string;
|
|
913
936
|
style?: React.CSSProperties;
|
|
914
937
|
onReady?: (editor: ReviseEditorHandle) => void;
|
package/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{ca as s,c9 as a,cc as e,cf as c,cd as r,cb as o,cc as E,cg as t,ce as R}from"./chunks/index-CjeGoI2g.js";export{s as REVISE_SDK_BUILD,a as REVISE_SDK_VERSION,e as ReviseEditor,c as ReviseRoleError,r as ReviseToolError,o as createEmptyDocx,E as default,t as rolePolicy,R as setAssetBaseUrl};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "revise",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "A word processor for React: DOCX in and out, real pagination, tracked changes, comments, collaboration, and agent tools. Free for evaluation, personal projects, and education.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"docx",
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
"node": ">=18"
|
|
86
86
|
},
|
|
87
87
|
"license": "SEE LICENSE IN LICENSE",
|
|
88
|
-
"homepage": "https://revise.io",
|
|
88
|
+
"homepage": "https://revise.io/sdk",
|
|
89
89
|
"bugs": {
|
|
90
90
|
"email": "sdk@revise.io",
|
|
91
91
|
"url": "https://developer.revise.io/editor-sdk/support"
|
package/root.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const REVISE_SDK_VERSION = "2.0.
|
|
2
|
-
export const REVISE_SDK_BUILD = "
|
|
1
|
+
export const REVISE_SDK_VERSION = "2.0.1";
|
|
2
|
+
export const REVISE_SDK_BUILD = "d2e5b1c73";
|