From 2a85c861e02f484576013542fd8ff88b41749268 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Tue, 28 Jul 2026 22:32:06 -0400 Subject: [PATCH] fix(session): hide pending admission sequence --- packages/app/src/utils/server-compat.test.ts | 1 - packages/app/src/utils/server-compat.ts | 3 --- packages/cli/test/run/noninteractive.test.ts | 2 +- .../client/src/promise/generated/types.ts | 10 +------- packages/client/test/effect.test.ts | 2 -- packages/client/test/promise.test.ts | 4 ---- packages/core/src/session/pending.ts | 5 ---- packages/core/test/plugin/promise.test.ts | 1 - packages/core/test/session-create.test.ts | 1 - packages/schema/src/session-pending.ts | 3 +-- packages/schema/test/contract-hygiene.test.ts | 23 +++++++++++++++++++ packages/tui/src/context/data.tsx | 2 -- packages/tui/src/mini/stream-v2.transport.ts | 4 +--- packages/tui/src/mini/types.ts | 1 - packages/tui/test/cli/tui/data.test.tsx | 3 --- packages/tui/test/mini/footer.view.test.tsx | 2 -- .../tui/test/mini/stream-v2.transport.test.ts | 13 ++++------- 17 files changed, 32 insertions(+), 48 deletions(-) diff --git a/packages/app/src/utils/server-compat.test.ts b/packages/app/src/utils/server-compat.test.ts index 52e5ec6e3b..1330f846ec 100644 --- a/packages/app/src/utils/server-compat.test.ts +++ b/packages/app/src/utils/server-compat.test.ts @@ -26,7 +26,6 @@ function setup( return new Response(undefined, { status: 204 }) if (request.method === "POST" && request.url.endsWith("/prompt")) { return Response.json({ - admittedSeq: 1, id: "msg_1", sessionID: "ses_1", timeCreated: 1, diff --git a/packages/app/src/utils/server-compat.ts b/packages/app/src/utils/server-compat.ts index 1df1338b71..b37bf6db48 100644 --- a/packages/app/src/utils/server-compat.ts +++ b/packages/app/src/utils/server-compat.ts @@ -229,7 +229,6 @@ function createV1Api(input: CompatibleInput): CompatibleApi { ], }) return { - admittedSeq: 0, id: value.id ?? "", sessionID: value.sessionID, timeCreated: Date.now(), @@ -255,7 +254,6 @@ function createV1Api(input: CompatibleInput): CompatibleApi { })), }) return { - admittedSeq: 0, id: value.id ?? "", sessionID: value.sessionID, timeCreated: Date.now(), @@ -280,7 +278,6 @@ function createV1Api(input: CompatibleInput): CompatibleApi { modelID: value.model.modelID, }) return { - admittedSeq: 0, id: value.id ?? "", sessionID: value.sessionID, timeCreated: Date.now(), diff --git a/packages/cli/test/run/noninteractive.test.ts b/packages/cli/test/run/noninteractive.test.ts index 8527bcaa57..c8a57d3637 100644 --- a/packages/cli/test/run/noninteractive.test.ts +++ b/packages/cli/test/run/noninteractive.test.ts @@ -267,7 +267,7 @@ async function run(input: { values.push(...input.turn(messageID)) wake?.() wake = undefined - return ok({ admittedSeq: 1, id: messageID, sessionID: "ses_1", timeCreated: 1 }) as never + return ok({ id: messageID, sessionID: "ses_1", timeCreated: 1 }) as never }) await runNonInteractivePrompt({ client: sdk, diff --git a/packages/client/src/promise/generated/types.ts b/packages/client/src/promise/generated/types.ts index fcd25cc09b..4f6dad595b 100644 --- a/packages/client/src/promise/generated/types.ts +++ b/packages/client/src/promise/generated/types.ts @@ -43,13 +43,7 @@ export type PromptMention = { start: number; end: number; text: string } export type SessionPendingSyntheticData = { text: string; description?: string; metadata?: { [x: string]: JsonValue } } -export type SessionPendingCompaction = { - admittedSeq: number - id: string - sessionID: string - timeCreated: number - type: "compaction" -} +export type SessionPendingCompaction = { id: string; sessionID: string; timeCreated: number; type: "compaction" } export type SessionMessageAgentSelected = { id: string @@ -1210,7 +1204,6 @@ export type PromptFileAttachment = { export type PromptAgentAttachment = { name: string; mention?: PromptMention } export type SessionPendingSynthetic = { - admittedSeq: number id: string sessionID: string timeCreated: number @@ -1966,7 +1959,6 @@ export type AgentInfo = { export type SessionsResponse = { data: Array; cursor: { previous?: string | null; next?: string | null } } export type SessionPendingUser = { - admittedSeq: number id: string sessionID: string timeCreated: number diff --git a/packages/client/test/effect.test.ts b/packages/client/test/effect.test.ts index b52d86d382..eee0d2d08a 100644 --- a/packages/client/test/effect.test.ts +++ b/packages/client/test/effect.test.ts @@ -268,7 +268,6 @@ const session = { const admission = { data: { - admittedSeq: 0, id: "msg_test", sessionID: "ses_test", type: "user", @@ -281,7 +280,6 @@ const admission = { const compactionAdmission = { data: { type: "compaction", - admittedSeq: 1, id: "msg_compaction", sessionID: "ses_test", timeCreated: 1_717_171_717_000, diff --git a/packages/client/test/promise.test.ts b/packages/client/test/promise.test.ts index c3c0512f17..b38b141cbc 100644 --- a/packages/client/test/promise.test.ts +++ b/packages/client/test/promise.test.ts @@ -304,7 +304,6 @@ test("session.pending.list uses the public HTTP contract", async () => { const requests: Array<{ method: string; url: string }> = [] const pending = [ { - admittedSeq: 3, id: "msg_pending", sessionID: "ses_test", timeCreated: 1_717_171_717_000, @@ -547,7 +546,6 @@ const session = { const admission = { data: { - admittedSeq: 0, id: "msg_test", sessionID: "ses_test", type: "user", @@ -559,7 +557,6 @@ const admission = { const syntheticAdmission = { data: { - admittedSeq: 1, id: "msg_synthetic", sessionID: "ses_test", type: "synthetic", @@ -572,7 +569,6 @@ const syntheticAdmission = { const compactionAdmission = { data: { type: "compaction", - admittedSeq: 1, id: "msg_compaction", sessionID: "ses_test", timeCreated: 1_717_171_717_000, diff --git a/packages/core/src/session/pending.ts b/packages/core/src/session/pending.ts index 47d74d0abf..986d624a6f 100644 --- a/packages/core/src/session/pending.ts +++ b/packages/core/src/session/pending.ts @@ -53,7 +53,6 @@ export class LifecycleConflict extends Schema.TaggedErrorClass { const base = { - admittedSeq: row.admitted_seq, id: SessionMessage.ID.make(row.id), sessionID: SessionSchema.ID.make(row.session_id), timeCreated: DateTime.makeUnsafe(row.time_created), @@ -134,7 +133,6 @@ const promotedFromHistory = Effect.fn("SessionPending.promotedFromHistory")(func const decoded = decodeAdmittedEvent(row.data) if (decoded._tag !== "Some" || decoded.value.inputID !== id) continue const base = { - admittedSeq: row.seq, id, sessionID, timeCreated: DateTime.makeUnsafe(row.created), @@ -172,10 +170,7 @@ export const admit = Effect.fn("SessionPending.admit")(function* ( }) .pipe( Effect.flatMap((event) => { - if (event.durable === undefined) - return Effect.die(new Error("Session input admission event is missing aggregate sequence")) const base = { - admittedSeq: event.durable.seq, id: request.id, sessionID: request.sessionID, timeCreated: event.created, diff --git a/packages/core/test/plugin/promise.test.ts b/packages/core/test/plugin/promise.test.ts index 064e083ac7..f63c7f3eca 100644 --- a/packages/core/test/plugin/promise.test.ts +++ b/packages/core/test/plugin/promise.test.ts @@ -62,7 +62,6 @@ describe("fromPromise", () => { seen = value return Effect.succeed( SessionPending.Synthetic.make({ - admittedSeq: 1, id: SessionMessage.ID.make(input.id), sessionID: Session.ID.make(input.sessionID), timeCreated: DateTime.makeUnsafe(0), diff --git a/packages/core/test/session-create.test.ts b/packages/core/test/session-create.test.ts index ae048e228b..968cb94713 100644 --- a/packages/core/test/session-create.test.ts +++ b/packages/core/test/session-create.test.ts @@ -484,7 +484,6 @@ describe("Session.create", () => { type: "user", data: { text: "Replay lifecycle" }, delivery: "steer", - admittedSeq: 1, }) expect(yield* store.context(created.id)).toEqual([]) diff --git a/packages/schema/src/session-pending.ts b/packages/schema/src/session-pending.ts index 215c13c299..f687c4ecf2 100644 --- a/packages/schema/src/session-pending.ts +++ b/packages/schema/src/session-pending.ts @@ -3,7 +3,7 @@ export * as SessionPending from "./session-pending.js" import { Schema } from "effect" import { optional } from "./schema.js" import { Prompt } from "./prompt.js" -import { DateTimeUtcFromMillis, NonNegativeInt } from "./schema.js" +import { DateTimeUtcFromMillis } from "./schema.js" import { SessionDelivery } from "./session-delivery.js" import { SessionID } from "./session-id.js" import { SessionMessage } from "./session-message.js" @@ -45,7 +45,6 @@ export const Message = Schema.Union([UserMessage, SyntheticMessage]).pipe( export type Message = typeof Message.Type const Admitted = { - admittedSeq: NonNegativeInt, id: SessionMessage.ID, sessionID: SessionID, timeCreated: DateTimeUtcFromMillis, diff --git a/packages/schema/test/contract-hygiene.test.ts b/packages/schema/test/contract-hygiene.test.ts index f9b379e8e0..ba5496e660 100644 --- a/packages/schema/test/contract-hygiene.test.ts +++ b/packages/schema/test/contract-hygiene.test.ts @@ -54,6 +54,29 @@ describe("contract hygiene", () => { ).toEqual({ text: "completed" }) }) + test("pending session items omit the internal admission sequence", () => { + expect( + Schema.encodeSync(SessionPending.Info)( + Schema.decodeUnknownSync(SessionPending.Info)({ + admittedSeq: 3, + id: "msg_pending", + sessionID: "ses_pending", + timeCreated: 1, + type: "user", + data: { text: "hello" }, + delivery: "steer", + }), + ), + ).toEqual({ + id: "msg_pending", + sessionID: "ses_pending", + timeCreated: 1, + type: "user", + data: { text: "hello" }, + delivery: "steer", + }) + }) + test("forms require at least one field", () => { expect(() => Schema.decodeUnknownSync(Form.Info)({ diff --git a/packages/tui/src/context/data.tsx b/packages/tui/src/context/data.tsx index 01a60f57f1..5880275790 100644 --- a/packages/tui/src/context/data.tsx +++ b/packages/tui/src/context/data.tsx @@ -407,7 +407,6 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({ addPending({ id: event.data.inputID, sessionID: event.data.sessionID, - admittedSeq: event.durable.seq, timeCreated: event.created, ...event.data.input, }) @@ -702,7 +701,6 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({ addPending({ id: event.data.inputID, sessionID: event.data.sessionID, - admittedSeq: event.durable.seq, timeCreated: event.created, type: "compaction", }) diff --git a/packages/tui/src/mini/stream-v2.transport.ts b/packages/tui/src/mini/stream-v2.transport.ts index 09462654e3..e58811ec20 100644 --- a/packages/tui/src/mini/stream-v2.transport.ts +++ b/packages/tui/src/mini/stream-v2.transport.ts @@ -186,7 +186,6 @@ function pendingPrompt(item: SessionPendingInfo): FooterQueuedPrompt | undefined messageID: item.id, prompt: { messageID: item.id, text: item.data.text, parts: [] }, delivery: item.delivery, - admittedSeq: item.admittedSeq, } } @@ -517,7 +516,7 @@ export async function createSessionTransport(input: StreamInput): Promise { - const prompts = [...state.pending.values()].toSorted((left, right) => left.admittedSeq - right.admittedSeq) + const prompts = [...state.pending.values()] input.trace?.write("ui.patch", { pending: prompts.length }) input.footer.event({ type: "queued.prompts", prompts }) } @@ -905,7 +904,6 @@ export async function createSessionTransport(input: StreamInput): Promise { const sessionID = "session-compaction-queued" let pending = [ { - admittedSeq: 3, id: "message-compaction-queued", sessionID, timeCreated: 1, type: "compaction" as const, }, { - admittedSeq: 4, id: "message-compaction-later", sessionID, timeCreated: 2, @@ -2474,7 +2472,6 @@ test("renders admitted prompts immediately and tracks them until promoted", asyn { id: messageID, sessionID, - admittedSeq: 0, timeCreated: 0, type: "user", data: { text: "hello" }, diff --git a/packages/tui/test/mini/footer.view.test.tsx b/packages/tui/test/mini/footer.view.test.tsx index 8e44e01eba..50e81d168d 100644 --- a/packages/tui/test/mini/footer.view.test.tsx +++ b/packages/tui/test/mini/footer.view.test.tsx @@ -919,7 +919,6 @@ test("direct pending panel shows durable delivery without edit actions", async ( messageID: "m-1", prompt: { text: "fix the auth test", parts: [] }, delivery: "queue" as const, - admittedSeq: 1, }, ]) @@ -1284,7 +1283,6 @@ test("direct footer shows authoritative pending work while running", async () => messageID: "m-queued", prompt: { text: "follow up", parts: [] }, delivery: "queue", - admittedSeq: 1, }, ]} theme={() => RUN_THEME_FALLBACK} diff --git a/packages/tui/test/mini/stream-v2.transport.test.ts b/packages/tui/test/mini/stream-v2.transport.test.ts index f3c25ea52c..2a1f828e28 100644 --- a/packages/tui/test/mini/stream-v2.transport.test.ts +++ b/packages/tui/test/mini/stream-v2.transport.test.ts @@ -77,7 +77,6 @@ function durable(sessionID: string, seq = 0, version: 1 | 2 = 1) { function promptAdmission(input: Parameters[0], sessionID = "ses_1") { return { - admittedSeq: 1, id: input.id ?? "msg_prompt", sessionID, type: "user" as const, @@ -659,7 +658,6 @@ describe("V2 mini transport", () => { pending: { ses_1: [ { - admittedSeq: 1, id: "msg_queued", sessionID: "ses_1", timeCreated: 1, @@ -680,9 +678,9 @@ describe("V2 mini transport", () => { const pending = () => ui.events .findLast((item) => item.type === "queued.prompts") - ?.prompts.map((item) => [item.messageID, item.delivery, item.admittedSeq]) + ?.prompts.map((item) => [item.messageID, item.delivery]) - expect(pending()).toEqual([["msg_queued", "queue", 1]]) + expect(pending()).toEqual([["msg_queued", "queue"]]) events.push({ id: "evt_promoted", created: 2, @@ -697,7 +695,7 @@ describe("V2 mini transport", () => { ) expect(pending()).toEqual([]) const prompt = spyOn(client.session, "prompt").mockImplementation( - (request) => ok({ ...promptAdmission(request), admittedSeq: 2 }) as never, + (request) => ok(promptAdmission(request)) as never, ) await transport.queuePromptTurn({ agent: "review", @@ -726,8 +724,8 @@ describe("V2 mini transport", () => { await Bun.sleep(0) } expect(pending()).toEqual([ - ["msg_earlier", "steer", 1], - ["msg_next", "queue", 2], + ["msg_next", "queue"], + ["msg_earlier", "steer"], ]) await transport.close() }) @@ -2694,7 +2692,6 @@ describe("V2 mini transport", () => { }) }) return ok({ - admittedSeq: 1, id: input.id ?? "msg_cmd", sessionID: "ses_1", type: "user" as const,