fix(session): hide pending admission sequence
This commit is contained in:
parent
9554f9a16e
commit
2a85c861e0
17 changed files with 32 additions and 48 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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<SessionInfo>; cursor: { previous?: string | null; next?: string | null } }
|
||||
|
||||
export type SessionPendingUser = {
|
||||
admittedSeq: number
|
||||
id: string
|
||||
sessionID: string
|
||||
timeCreated: number
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -53,7 +53,6 @@ export class LifecycleConflict extends Schema.TaggedErrorClass<LifecycleConflict
|
|||
|
||||
const fromRow = (row: typeof SessionPendingTable.$inferSelect): Info => {
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -484,7 +484,6 @@ describe("Session.create", () => {
|
|||
type: "user",
|
||||
data: { text: "Replay lifecycle" },
|
||||
delivery: "steer",
|
||||
admittedSeq: 1,
|
||||
})
|
||||
expect(yield* store.context(created.id)).toEqual([])
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)({
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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<Sessio
|
|||
}
|
||||
|
||||
const syncPending = () => {
|
||||
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<Sessio
|
|||
if (event.type === "session.input.admitted") {
|
||||
if (event.data.input.type !== "user") return
|
||||
mergePending({
|
||||
admittedSeq: event.durable.seq,
|
||||
id: event.data.inputID,
|
||||
sessionID: event.data.sessionID,
|
||||
timeCreated: event.created,
|
||||
|
|
|
|||
|
|
@ -88,7 +88,6 @@ export type FooterQueuedPrompt = {
|
|||
messageID: string
|
||||
prompt: RunPrompt
|
||||
delivery: "steer" | "queue"
|
||||
admittedSeq: number
|
||||
}
|
||||
|
||||
export type RunAgent = {
|
||||
|
|
|
|||
|
|
@ -1346,14 +1346,12 @@ test("restores queued compaction from durable pending input", async () => {
|
|||
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" },
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -77,7 +77,6 @@ function durable(sessionID: string, seq = 0, version: 1 | 2 = 1) {
|
|||
|
||||
function promptAdmission(input: Parameters<OpenCodeClient["session"]["prompt"]>[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,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue