1import type * as ProviderAdapter from "@t3tools/provider-core/server/ProviderAdapter";
2import { assert, describe, it } from "@effect/vitest";
3import {
4 ContextHandoffId,
5 PROVIDER_SEND_TURN_MAX_ATTACHMENTS,
6 ProviderDriverKind,
7 ProviderInstanceId,
8 ProviderThreadId,
9 RunId,
10 ThreadId,
11 TurnItemId,
12 OrchestrationV2ContextHandoff,
13 type OrchestrationV2HistoricalMessage,
14 type OrchestrationV2ProviderThread,
15} from "@t3tools/contracts";
16import * as DateTime from "effect/DateTime";
17import * as Effect from "effect/Effect";
18import * as Schema from "effect/Schema";
19import {
20 contextUsageForHandoff,
21 handoffBudget,
22 historyCost,
23 historyResponseItems,
24 selectHistory,
25 historicalMessage,
26} from "@t3tools/provider-core/server/handoffBudget";
27import { projectContextHandoffForWire } from "./WireProjection.ts";
28import { deliverContextHandoffs } from "./ContextHandoffDelivery.ts";
29
30const encodeJson = Schema.encodeEffect(Schema.fromJsonString(Schema.Unknown));
31const decodeHandoff = Schema.decodeUnknownSync(OrchestrationV2ContextHandoff);
32
33const now = DateTime.makeUnsafe("2026-09-17T00:00:00Z");
34const threadId = ThreadId.make("thread:handoff");
35const providerThread: OrchestrationV2ProviderThread = {
36 id: ProviderThreadId.make("provider-thread:target"),
37 driver: ProviderDriverKind.make("codex"),
38 providerInstanceId: ProviderInstanceId.make("codex"),
39 providerSessionId: null,
40 appThreadId: threadId,
41 ownerNodeId: null,
42 nativeThreadRef: {
43 driver: ProviderDriverKind.make("codex"),
44 strength: "strong",
45 nativeId: "native:target",
46 },
47 nativeConversationHeadRef: null,
48 status: "idle",
49 firstRunOrdinal: null,
50 lastRunOrdinal: null,
51 handoffIds: [],
52 forkedFrom: null,
53 createdAt: now,
54 updatedAt: now,
55};
56const message = (
57 id: string,
58 role: "user" | "assistant",
59 text: string,
60): OrchestrationV2HistoricalMessage => ({
61 itemId: TurnItemId.make(id),
62 role,
63 text,
64 threadId,
65 runId: RunId.make("run:source"),
66 providerThreadId: ProviderThreadId.make("provider-thread:source"),
67 status: "interrupted",
68 kind: role === "user" ? "user_message" : "assistant_message",
69});
70const messages = [
71 message("item:one", "user", "Preserve every line.\n\n And this indentation.\n"),
72 message("item:two", "assistant", "Partial work: ๆ—ฅๆœฌ่ชž ๐Ÿงช ู…ุฑุญุจุง\n" + "x".repeat(600)),
73];
74const handoff: OrchestrationV2ContextHandoff = {
75 id: ContextHandoffId.make("handoff:one"),
76 threadId,
77 targetRunId: RunId.make("run:target"),
78 fromProviderThreadIds: [],
79 toProviderThreadId: providerThread.id,
80 coveredRunOrdinals: { from: 1, to: 2 },
81 strategy: "full_thread_summary",
82 status: "ready",
83 summaryMessageId: null,
84 summaryText: "",
85 history: {
86 messages,
87 coverage: "Historical context; retrieve thread:handoff with t3_thread_read.",
88 omittedItems: 0,
89 },
90 createdByProviderInstanceId: null,
91 createdAt: now,
92 updatedAt: now,
93};
94
95describe("handoff budget", () => {
96 it("keeps old preview handoffs readable and delivery history off the wire", () => {
97 const projected = projectContextHandoffForWire({
98 ...handoff,
99 summaryText: "private transcript and command output",
100 delivery: {
101 nativeThreadId: "native:target",
102 status: "injected",
103 itemIds: [messages[0]!.itemId],
104 },
105 });
106 assert.equal(projected.summaryText, "");
107 assert.isUndefined(projected.history);
108 assert.isUndefined(projected.delivery);
109 assert.equal(decodeHandoff(projected).id, handoff.id);
110 assert.deepEqual(handoff.history?.messages, messages);
111 });
112 it("carries command outcomes as attributed activity and excludes reasoning", () => {
113 const base = {
114 id: TurnItemId.make("item:command"),
115 threadId,
116 runId: RunId.make("run:source"),
117 nodeId: null,
118 providerThreadId: providerThread.id,
119 providerTurnId: null,
120 nativeItemRef: null,
121 parentItemId: null,
122 ordinal: 1,
123 status: "failed" as const,
124 title: null,
125 startedAt: now,
126 completedAt: now,
127 updatedAt: now,
128 };
129 const command = historicalMessage({
130 ...base,
131 type: "command_execution",
132 input: "vp test",
133 output: "Failure near the end: " + "็•Œ".repeat(300),
134 exitCode: 1,
135 });
136 assert.equal(command?.role, "assistant");
137 assert.equal(command?.kind, "command_execution");
138 assert.include(command!.text, "Exit code: 1");
139 assert.include(command!.text, "็•Œ".repeat(300));
140 assert.isNull(
141 historicalMessage({
142 ...base,
143 type: "reasoning",
144 text: "private reasoning",
145 streaming: false,
146 }),
147 );
148 assert.equal(historyResponseItems([command!], "Activity")[1]?.type, "message");
149 });
150
151 it("retains short conversations verbatim in role and order", () => {
152 const selected = selectHistory({ messages, coverage: "History", budget: 16_000 });
153 assert.deepEqual(selected.messages, messages);
154 const items = historyResponseItems(selected.messages, selected.context);
155 assert.deepEqual(
156 items.map((item) => item.role),
157 ["user", "user", "assistant"],
158 );
159 assert.include(items[1]!.content[0]!.text, messages[0]!.text);
160 assert.include(items[2]!.content[0]!.text, messages[1]!.text);
161 assert.equal(selected.omittedItems, 0);
162 });
163
164 it("omits oversized multilingual items whole, preserves original constraints and recent work", () => {
165 const candidates = [
166 messages[0]!,
167 message("huge", "assistant", "็•Œ๐Ÿงช".repeat(20_000)),
168 message("old", "assistant", "a".repeat(4_000)),
169 messages[1]!,
170 ];
171 const selected = selectHistory({
172 messages: candidates,
173 coverage: "thread:handoff runs 1-4",
174 budget: 3_000,
175 });
176 assert.deepEqual(selected.messages, messages);
177 assert.equal(selected.omittedItems, 2);
178 assert.isAtMost(historyCost(selected.messages, selected.context), 3_000);
179 });
180
181 it("counts JSON escaping and UTF-8 bytes across many messages", () => {
182 const candidates = Array.from({ length: 500 }, (_, i) =>
183 message(`item:${i}`, i % 2 ? "assistant" : "user", '\u0000\\"๐Ÿงช็•Œ'.repeat(15)),
184 );
185 for (const budget of [1_024, 4_000, 16_000]) {
186 const selected = selectHistory({
187 messages: candidates,
188 coverage: "Retrieve omitted history",
189 budget,
190 });
191 assert.isAtMost(historyCost(selected.messages, selected.context), budget);
192 assert.isAbove(selected.omittedItems, 0);
193 }
194 });
195
196 it("fits the final envelope at intermediate selected/omitted digit boundaries", () => {
197 const candidates = Array.from({ length: 20 }, (_, index) =>
198 message(`boundary:${index}`, "user", "Short request"),
199 );
200 for (let budget = 4_000; budget <= 9_000; budget++) {
201 const selected = selectHistory({
202 messages: candidates,
203 coverage: "Recover history",
204 omittedItems: 90,
205 budget,
206 });
207 assert.isAtMost(historyCost(selected.messages, selected.context), budget);
208 }
209 });
210
211 it("subtracts native usage, input, attachments, instructions and space for work", () => {
212 const base = {
213 tokenCap: 16_000,
214 userText: "Continue",
215 attachments: [],
216 providerThread,
217 nativeContextEstimate: 0,
218 modelContextWindow: 32_000,
219 };
220 assert.isBelow(handoffBudget(base), 16_000);
221 assert.isBelow(handoffBudget({ ...base, nativeContextEstimate: 8_000 }), handoffBudget(base));
222 assert.equal(handoffBudget({ ...base, userText: "็•Œ".repeat(30_000) }), 0);
223 assert.equal(
224 handoffBudget({
225 ...base,
226 providerThread: {
227 ...providerThread,
228 contextUsage: { usedTokens: 23_000, maxTokens: 24_000 },
229 },
230 }),
231 0,
232 );
233 for (const sizeBytes of [100_000, 10 * 1024 * 1024]) {
234 const attachments = [
235 {
236 type: "image",
237 id: "attachment",
238 name: "image.png",
239 mimeType: "image/png",
240 sizeBytes,
241 },
242 ];
243 const withImage = handoffBudget({ ...base, attachments });
244 assert.isAbove(withImage, 4_000);
245 assert.isBelow(withImage, handoffBudget(base));
246 assert.equal(handoffBudget({ ...base, attachments: [...attachments, ...attachments] }), 0);
247 assert.equal(
248 handoffBudget({
249 ...base,
250 tokenCap: 64_000,
251 modelContextWindow: 1_000_000,
252 // The history byte cap is independent of both current text and image payloads.
253 userText: "x".repeat(70_000),
254 attachments,
255 providerThread: {
256 ...providerThread,
257 contextUsage: { usedTokens: 0, maxTokens: 1_000_000 },
258 },
259 }),
260 64_000,
261 );
262 }
263 assert.equal(handoffBudget({ ...base, tokenCap: 2_000 }), 2_000);
264 });
265
266 it("keeps measured occupancy across a model change", () => {
267 const previous = {
268 usedTokens: 37_321,
269 maxTokens: 258_400,
270 autoCompactThreshold: 32_000,
271 };
272 assert.isNull(
273 contextUsageForHandoff({
274 sameNativeThread: false,
275 sameSelection: false,
276 reuseTelemetry: false,
277 previousUsage: previous,
278 }),
279 );
280 assert.equal(
281 contextUsageForHandoff({
282 sameNativeThread: true,
283 sameSelection: true,
284 reuseTelemetry: true,
285 previousUsage: previous,
286 }),
287 previous,
288 );
289 assert.deepEqual(
290 contextUsageForHandoff({
291 sameNativeThread: true,
292 sameSelection: false,
293 reuseTelemetry: true,
294 previousUsage: previous,
295 }),
296 { usedTokens: 37_321, maxTokens: 258_400 },
297 );
298 assert.deepEqual(
299 contextUsageForHandoff({
300 sameNativeThread: true,
301 sameSelection: false,
302 reuseTelemetry: false,
303 previousUsage: previous,
304 }),
305 { usedTokens: 37_321, maxTokens: 258_400 },
306 );
307 assert.deepEqual(
308 contextUsageForHandoff({
309 sameNativeThread: true,
310 sameSelection: false,
311 reuseTelemetry: false,
312 previousUsage: { usedTokens: 30_000, maxTokens: 32_000, autoCompactThreshold: 31_000 },
313 knownModelWindow: 1_000_000,
314 }),
315 { usedTokens: 30_000, maxTokens: 1_000_000 },
316 );
317
318 const preserved = contextUsageForHandoff({
319 sameNativeThread: true,
320 sameSelection: false,
321 reuseTelemetry: false,
322 previousUsage: previous,
323 });
324 assert.equal(
325 handoffBudget({
326 tokenCap: 16_000,
327 userText: "Continue work",
328 attachments: [
329 {
330 type: "image",
331 id: "screenshot-a",
332 name: "a.png",
333 mimeType: "image/png",
334 sizeBytes: 100_000,
335 },
336 {
337 type: "image",
338 id: "screenshot-b",
339 name: "b.png",
340 mimeType: "image/png",
341 sizeBytes: 100_000,
342 },
343 ],
344 providerThread: { ...providerThread, contextUsage: preserved },
345 nativeContextEstimate: 0,
346 modelContextWindow: preserved?.maxTokens,
347 }),
348 16_000,
349 );
350 assert.equal(
351 handoffBudget({
352 tokenCap: 16_000,
353 userText: "Continue work",
354 attachments: [],
355 providerThread,
356 nativeContextEstimate: 120_000,
357 }),
358 0,
359 );
360 });
361 it("reserves context for image batches up to the attachment limit, honoring smaller known windows", () => {
362 let previousBudget = 16_000;
363 for (let count = 1; count <= PROVIDER_SEND_TURN_MAX_ATTACHMENTS; count++) {
364 const input = {
365 tokenCap: 16_000,
366 userText: "Compare these screenshots",
367 providerThread,
368 nativeContextEstimate: 0,
369 attachments: Array.from({ length: count }, (_, index) => ({
370 type: "image",
371 id: `image-${index}`,
372 name: "image.png",
373 mimeType: "image/png",
374 sizeBytes: 100_000,
375 })),
376 };
377 const budget = handoffBudget(input);
378 assert.isAtLeast(budget, 0);
379 assert.isAtMost(budget, previousBudget);
380 previousBudget = budget;
381 if (count <= 8) assert.equal(budget, 16_000);
382 if (count === 10) {
383 assert.isAbove(budget, 0);
384 assert.isBelow(budget, 16_000);
385 }
386 if (count === PROVIDER_SEND_TURN_MAX_ATTACHMENTS) assert.equal(budget, 0);
387 if (budget > 0) {
388 const selected = selectHistory({ messages, coverage: "Recover omitted history", budget });
389 assert.isAtMost(historyCost(selected.messages, selected.context), budget);
390 }
391 assert.equal(handoffBudget({ ...input, modelContextWindow: 2_000_000 }), 16_000);
392 assert.equal(handoffBudget({ ...input, modelContextWindow: 20_000 }), 0);
393 assert.equal(
394 handoffBudget({
395 ...input,
396 providerThread: { ...providerThread, contextUsage: { usedTokens: 0, maxTokens: 20_000 } },
397 }),
398 0,
399 );
400 assert.equal(
401 handoffBudget({
402 ...input,
403 modelContextWindow: 1_000_000,
404 providerThread: {
405 ...providerThread,
406 contextUsage: { usedTokens: 0, maxTokens: 1_000_000, autoCompactThreshold: 20_000 },
407 },
408 }),
409 0,
410 );
411 }
412 });
413});
414
415describe("handoff delivery", () => {
416 it.effect.each([
417 { native: true, label: "injected" },
418 { native: false, label: "inline" },
419 ])("records omitted recovery coverage separately from $label text", ({ native }) =>
420 Effect.gen(function* () {
421 const omittedBeforeDelivery = TurnItemId.make("item:omitted-during-preparation");
422 const oversized = message("item:oversized", "user", "x".repeat(20_000));
423 let durable: OrchestrationV2ContextHandoff = {
424 ...handoff,
425 history: {
426 ...handoff.history!,
427 messages: [...messages, oversized],
428 omittedItems: 1,
429 omittedItemIds: [omittedBeforeDelivery],
430 },
431 };
432 const result = yield* deliverContextHandoffs({
433 handoffs: [durable],
434 providerThread,
435 budget: 16_000,
436 alreadyDeliveredItemIds: new Set(),
437 inject: (value) => {
438 assert.include(value.context, "omitted 2 items");
439 assert.notInclude(
440 value.messages.map((item) => item.itemId),
441 oversized.itemId,
442 );
443 return Effect.succeed(native);
444 },
445 persist: (value) =>
446 Effect.sync(() => {
447 durable = value;
448 }),
449 });
450 assert.equal(durable.delivery?.status, native ? "injected" : "pending");
451 yield* result.delivered;
452 assert.equal(durable.delivery?.status, native ? "injected" : "inline");
453 assert.deepEqual(
454 durable.delivery?.itemIds,
455 messages.map((item) => item.itemId),
456 );
457 assert.deepEqual(durable.delivery?.omittedItemIds, [omittedBeforeDelivery, oversized.itemId]);
458 assert.deepEqual(decodeHandoff(durable).delivery, durable.delivery);
459 }),
460 );
461 it.effect("loads the history budget only when a handoff needs delivery", () =>
462 Effect.gen(function* () {
463 let reads = 0;
464 const input = {
465 providerThread,
466 budget: Effect.sync(() => {
467 reads++;
468 return 16_000;
469 }),
470 alreadyDeliveredItemIds: new Set<string>(),
471 persist: () => Effect.void,
472 };
473 yield* deliverContextHandoffs({ ...input, handoffs: [] });
474 yield* deliverContextHandoffs({ ...input, handoffs: [handoff], deferInline: true });
475 yield* deliverContextHandoffs({
476 ...input,
477 handoffs: [
478 {
479 ...handoff,
480 delivery: {
481 nativeThreadId: providerThread.nativeThreadRef!.nativeId!,
482 status: "injected",
483 itemIds: [],
484 },
485 },
486 ],
487 });
488 assert.equal(reads, 0);
489 const result = yield* deliverContextHandoffs({ ...input, handoffs: [handoff] });
490 assert.equal(reads, 1);
491 assert.include(result.context, messages[0]!.text);
492 }),
493 );
494
495 it.effect("persists successful injection before turn start and skips it on retry", () =>
496 Effect.gen(function* () {
497 let durable = handoff;
498 const history: unknown[] = [];
499 const statuses: string[] = [];
500 const input = {
501 providerThread,
502 budget: 16_000,
503 alreadyDeliveredItemIds: new Set<string>(),
504 inject: (value: ProviderAdapter.ProviderAdapterV2HistoricalContext) =>
505 Effect.sync(() => {
506 history.push(...historyResponseItems(value.messages, value.context));
507 return true;
508 }),
509 persist: (value: OrchestrationV2ContextHandoff) =>
510 Effect.sync(() => {
511 durable = value;
512 statuses.push(value.delivery!.status);
513 }),
514 };
515 const first = yield* deliverContextHandoffs({ ...input, handoffs: [durable] });
516 assert.equal(first.context, "");
517 assert.deepEqual(statuses, ["pending", "injected"]);
518 assert.lengthOf(history, 3);
519 // No turn has started. Reconstruct from the durable projection as a retry would.
520 const second = yield* deliverContextHandoffs({ ...input, handoffs: [durable] });
521 assert.equal(second.context, "");
522 assert.lengthOf(history, 3);
523 }),
524 );
525
526 it.effect(
527 "uses the same selection on explicit native fallback, marking only accepted input",
528 () =>
529 Effect.gen(function* () {
530 let durable = handoff;
531 const result = yield* deliverContextHandoffs({
532 handoffs: [handoff],
533 providerThread,
534 budget: 16_000,
535 alreadyDeliveredItemIds: new Set(),
536 inject: () => Effect.succeed(false),
537 persist: (value) =>
538 Effect.sync(() => {
539 durable = value;
540 }),
541 });
542 assert.include(result.context, messages[0]!.text);
543 assert.include(result.context, messages[1]!.text);
544 assert.equal(durable.delivery?.status, "pending");
545 yield* result.delivered;
546 assert.equal(durable.delivery?.status, "inline");
547 }),
548 );
549
550 it.effect(
551 "defers unsupported compaction history until a normal turn without marking delivery uncertain",
552 () =>
553 Effect.gen(function* () {
554 let durable = handoff;
555 const persist = (value: OrchestrationV2ContextHandoff) =>
556 Effect.sync(() => {
557 durable = value;
558 });
559 const compact = yield* deliverContextHandoffs({
560 handoffs: [durable],
561 providerThread,
562 budget: 16_000,
563 alreadyDeliveredItemIds: new Set(),
564 deferInline: true,
565 inject: () => Effect.succeed(false),
566 persist,
567 });
568 yield* compact.delivered;
569 assert.equal(compact.context, "");
570 assert.isUndefined((() => durable.delivery)());
571 const next = yield* deliverContextHandoffs({
572 handoffs: [durable],
573 providerThread,
574 budget: 16_000,
575 alreadyDeliveredItemIds: new Set(),
576 inject: () => Effect.succeed(false),
577 persist,
578 });
579 assert.include(next.context, messages[0]!.text);
580 yield* next.delivered;
581 assert.equal(durable.delivery?.status, "inline");
582 }),
583 );
584
585 it.effect("bounds accumulated recovery markers while keeping omitted history discoverable", () =>
586 Effect.gen(function* () {
587 const many = Array.from({ length: 100 }, (_, index) => ({
588 ...handoff,
589 id: ContextHandoffId.make(`handoff:retry:${index}`),
590 }));
591 let captured: ProviderAdapter.ProviderAdapterV2HistoricalContext | undefined;
592 const result = yield* deliverContextHandoffs({
593 handoffs: many,
594 providerThread,
595 budget: 2_500,
596 alreadyDeliveredItemIds: new Set(),
597 inject: (history) =>
598 Effect.sync(() => {
599 captured = history;
600 return true;
601 }),
602 persist: () => Effect.void,
603 });
604 assert.equal(result.context, "");
605 assert.isDefined(captured);
606 assert.include(captured.context, "detailed coverage references omitted");
607 assert.include(captured.context, "t3_thread_read");
608 assert.include(captured.context, threadId);
609 assert.isAtMost(historyCost(captured.messages, captured.context), 2_500);
610 assert.isAbove(captured.messages.length, 0);
611 }),
612 );
613
614 it.effect("does not redeliver after ambiguous injection failure", () =>
615 Effect.gen(function* () {
616 let durable = handoff;
617 let calls = 0;
618 const input = {
619 providerThread,
620 budget: 16_000,
621 alreadyDeliveredItemIds: new Set<string>(),
622 inject: () =>
623 Effect.sync(() => {
624 calls++;
625 }).pipe(Effect.andThen(Effect.fail("connection lost"))),
626 persist: (value: OrchestrationV2ContextHandoff) =>
627 Effect.sync(() => {
628 durable = value;
629 }),
630 };
631 yield* deliverContextHandoffs({ ...input, handoffs: [durable] }).pipe(Effect.result);
632 assert.equal(durable.delivery?.status, "pending");
633 const retry = yield* deliverContextHandoffs({ ...input, handoffs: [durable] }).pipe(
634 Effect.result,
635 );
636 assert.equal(retry._tag, "Failure");
637 assert.equal(calls, 1);
638 }),
639 );
640
641 it.effect("budgets multiple handoffs together and skips previously delivered items", () =>
642 Effect.gen(function* () {
643 const extra = {
644 ...handoff,
645 id: ContextHandoffId.make("handoff:two"),
646 history: {
647 ...handoff.history!,
648 messages: [...messages, message("item:three", "assistant", "Latest result")],
649 },
650 };
651 let delivered: ReadonlyArray<unknown> = [];
652 yield* deliverContextHandoffs({
653 handoffs: [handoff, extra],
654 providerThread,
655 budget: 2_500,
656 alreadyDeliveredItemIds: new Set(["item:one"]),
657 inject: (value) =>
658 Effect.sync(() => {
659 delivered = historyResponseItems(value.messages, value.context);
660 return true;
661 }),
662 persist: () => Effect.void,
663 });
664 const serialized = yield* encodeJson(delivered);
665 assert.isAtMost(Buffer.byteLength(serialized), 2_500);
666 assert.notInclude(serialized, "Preserve every line");
667 assert.equal(serialized.split("Partial work").length - 1, 1);
668 assert.include(serialized, "Latest result");
669 }),
670 );
671
672 it.effect("fails before delivery when even the coverage marker cannot fit", () =>
673 Effect.gen(function* () {
674 let calls = 0;
675 const result = yield* deliverContextHandoffs({
676 handoffs: [handoff],
677 providerThread,
678 budget: 0,
679 alreadyDeliveredItemIds: new Set(),
680 inject: () =>
681 Effect.sync(() => {
682 calls++;
683 return true;
684 }),
685 persist: () => Effect.void,
686 }).pipe(Effect.result);
687 assert.equal(result._tag, "Failure");
688 assert.equal(calls, 0);
689 }),
690 );
691});