(args: RunPipelineArgs)
| 3427 | } |
| 3428 | |
| 3429 | async function runPipeline(args: RunPipelineArgs): Promise<RunPipelineResult> { |
| 3430 | let executedWorkThisPass = false; |
| 3431 | let historyWasConsumedThisPass = false; |
| 3432 | let materializationSatisfiedThisPass = false; |
| 3433 | let pendingOpsAppliedThisPass = false; |
| 3434 | let pendingOpsDidMutate = false; |
| 3435 | let heuristicOrReasoningDidMutate = false; |
| 3436 | let didMutateFromFlushedStatuses = false; |
| 3437 | let droppedCount = 0; |
| 3438 | const droppedTokens = 0; |
| 3439 | let emergency = false; |
| 3440 | let autoReclaimDidMutateThisPass = false; |
| 3441 | let suppressDeferredHistoryDrain = false; |
| 3442 | let casLost = false; |
| 3443 | const deferredHistoryWasPendingAtPassStart = |
| 3444 | deferredHistoryRefreshSessions.has(args.sessionId); |
| 3445 | |
| 3446 | // 0. Inject temporal `<!-- +Xm -->` markers into user messages |
| 3447 | // BEFORE tagging so the §N§ tag prefix wraps around our marker on |
| 3448 | // re-tagging. Idempotent: existing markers are detected by regex |
| 3449 | // and skipped. Same invariants as OpenCode's `injectTemporalMarkers` |
| 3450 | // at transform.ts:648 — runs on every pass, deterministic from |
| 3451 | // timestamps, retroactive when the flag flips. |
| 3452 | if (args.temporalAwareness) { |
| 3453 | const tTemporal = performance.now(); |
| 3454 | try { |
| 3455 | const injected = injectPiTemporalMarkers(args.messages); |
| 3456 | if (injected > 0) { |
| 3457 | sessionLog( |
| 3458 | args.sessionId, |
| 3459 | `temporal-awareness: injected ${injected} gap markers`, |
| 3460 | ); |
| 3461 | } |
| 3462 | } catch (err) { |
| 3463 | sessionLog( |
| 3464 | args.sessionId, |
| 3465 | `temporal-awareness failed (continuing): ${err instanceof Error ? err.message : String(err)}`, |
| 3466 | ); |
| 3467 | } |
| 3468 | logTransformTiming(args.sessionId, "injectTemporalMarkers", tTemporal); |
| 3469 | } |
| 3470 | |
| 3471 | // Pass entryIds so the transcript tags each message under its real SessionEntry |
| 3472 | // id (position-independent) instead of the index-based pi-msg-* id that drifts |
| 3473 | // when the visible array shifts (compaction trim / custom_message inserts), |
| 3474 | // orphaning tags/source_contents/caveman/drop-state. Positional entryIds is |
| 3475 | // exactly aligned here: tagging runs at transcript-build time, before any splice. |
| 3476 | const transcript = createPiTranscript( |
| 3477 | args.messages, |
| 3478 | args.sessionId, |
| 3479 | args.entryIds, |
| 3480 | ); |
| 3481 | // Reasoning clearing/replay mutate `part.thinking` in place. They MUST target |
| 3482 | // the transcript's `working` array (the channel commit() flushes), not the |
| 3483 | // original `args.messages`: tagging/drops/caveman reassign working[idx] to |
| 3484 | // fresh objects, so a reasoning mutation written to args.messages[idx] (a |
| 3485 | // now-divergent object) would be discarded when commit() does |
| 3486 | // source[idx] = working[idx], leaving the cleared-reasoning watermark ahead |
no test coverage detected