@@ -90,6 +90,16 @@ export const REDIS_ORIGIN = Symbol('file-doc-redis')
9090 */
9191export const REDIS_SNAPSHOT_ORIGIN = Symbol ( 'file-doc-redis-snapshot' )
9292
93+ /**
94+ * Origin for an AGENT-STREAMED frame applied from the stream (a copilot output token relayed via
95+ * {@link FILE_DOC_MESSAGE_TYPE.SYNC_NO_PERSIST}). A peer task tails these to stay live mid-stream, but
96+ * they are transient preview content the copilot's durable `edit_content` write reconciles — so the
97+ * relay's edit-tracker must NOT mark the doc edited on them (a startup-race duplicate between two stream
98+ * leaders would otherwise become eligible for a peer task's persist). Behaves like {@link REDIS_ORIGIN}
99+ * otherwise (already in the stream — never re-published).
100+ */
101+ export const REDIS_AGENT_ORIGIN = Symbol ( 'file-doc-redis-agent' )
102+
93103const STREAM_PREFIX = 'filedoc:stream:'
94104/** Cluster-wide "durable version the live doc is synced to" (the persist If-Match token). */
95105const SYNC_VERSION_PREFIX = 'filedoc:syncver:'
@@ -103,6 +113,9 @@ const UPDATE_FIELD = 'u'
103113/** Marks a stream entry as a compaction SNAPSHOT (folds seed + edits), so the tailer applies it with
104114 * {@link REDIS_SNAPSHOT_ORIGIN}. Present only on snapshot entries. */
105115const SNAPSHOT_FIELD = 's'
116+ /** Marks a stream entry as an AGENT-STREAMED preview frame, so the tailer applies it with
117+ * {@link REDIS_AGENT_ORIGIN} (never marks the doc edited). Present only on agent-frame entries. */
118+ const AGENT_FIELD = 'a'
106119
107120/** Sentinel token a DISABLED store returns from a lock acquire, so single-replica callers proceed
108121 * without special-casing; {@link FileDocStore.releaseLock} treats it as a no-op. Not a real UUID, so it
@@ -264,12 +277,14 @@ export class FileDocStore {
264277 * an edit from the shared log. Only the `xAdd` is retried; the TTL refresh + compaction check are
265278 * post-write best-effort and never re-trigger the append. Throws if the append ultimately fails.
266279 */
267- private async appendUpdate ( name : string , update : Uint8Array ) : Promise < void > {
280+ private async appendUpdate ( name : string , update : Uint8Array , agent = false ) : Promise < void > {
268281 if ( ! this . write ) return
269282 const encoded = Buffer . from ( update ) . toString ( 'base64' )
283+ const fields : Record < string , string > = { [ UPDATE_FIELD ] : encoded }
284+ if ( agent ) fields [ AGENT_FIELD ] = '1'
270285 for ( let attempt = 0 ; attempt <= PUBLISH_MAX_RETRIES ; attempt ++ ) {
271286 try {
272- await this . write . xAdd ( streamKey ( name ) , '*' , { [ UPDATE_FIELD ] : encoded } )
287+ await this . write . xAdd ( streamKey ( name ) , '*' , fields )
273288 break
274289 } catch ( error ) {
275290 if ( attempt === PUBLISH_MAX_RETRIES ) {
@@ -288,11 +303,12 @@ export class FileDocStore {
288303
289304 /**
290305 * Fire-and-forget append for the hot keystroke path (`doc.on('update')`): converges peers without
291- * blocking the relay. Retries internally; never throws. No-op when disabled.
306+ * blocking the relay. Retries internally; never throws. No-op when disabled. Pass `agent: true` for
307+ * a copilot preview frame so peer tasks tail it as {@link REDIS_AGENT_ORIGIN} and never persist it.
292308 */
293- publish ( name : string , update : Uint8Array ) : void {
309+ publish ( name : string , update : Uint8Array , agent = false ) : void {
294310 if ( ! this . enabled || ! this . write ) return
295- void this . appendUpdate ( name , update ) . catch ( ( ) => { } ) // already logged inside appendUpdate
311+ void this . appendUpdate ( name , update , agent ) . catch ( ( ) => { } ) // already logged inside appendUpdate
296312 }
297313
298314 /**
@@ -515,8 +531,13 @@ export class FileDocStore {
515531 private applyEntry ( room : StoreRoom , id : string , message : Record < string , string > ) : void {
516532 room . lastId = id
517533 // A compaction snapshot folds seed + edits into one frame; stamp it so the relay's edit-tracker
518- // treats a fresh catch-up from it as edited (a snapshot only exists once real edits accumulated).
519- const origin = message [ SNAPSHOT_FIELD ] ? REDIS_SNAPSHOT_ORIGIN : REDIS_ORIGIN
534+ // treats a fresh catch-up from it as edited (a snapshot only exists once real edits accumulated). An
535+ // agent-streamed preview frame is stamped separately so the tracker NEVER marks it edited.
536+ const origin = message [ SNAPSHOT_FIELD ]
537+ ? REDIS_SNAPSHOT_ORIGIN
538+ : message [ AGENT_FIELD ]
539+ ? REDIS_AGENT_ORIGIN
540+ : REDIS_ORIGIN
520541 applyEntryToDoc ( room . doc , id , message , origin )
521542 }
522543
0 commit comments