refactor(core): simplify session runner loop and pending input scopes (#38602)

This commit is contained in:
Kit Langton 2026-07-24 10:27:23 -04:00 committed by GitHub
commit 0f3c30118c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 283 additions and 242 deletions

View file

@ -195,9 +195,9 @@ describe("SessionV2.create", () => {
text: "First",
resume: false,
})
yield* SessionPending.promoteSteers(db, events, parent.id)
yield* SessionPending.promote(db, events, parent.id, "steer")
yield* session.synthetic({ sessionID: parent.id, text: "parent note", resume: false })
yield* SessionPending.promoteSteers(db, events, parent.id)
yield* SessionPending.promote(db, events, parent.id, "steer")
const forked = yield* session.fork({ sessionID: parent.id })
const parentContext = yield* session.context(parent.id)
@ -232,13 +232,13 @@ describe("SessionV2.create", () => {
text: "Parent changed",
resume: false,
})
yield* SessionPending.promoteSteers(db, events, parent.id)
yield* SessionPending.promote(db, events, parent.id, "steer")
yield* session.prompt({
sessionID: forked.id,
text: "Child continues",
resume: false,
})
yield* SessionPending.promoteSteers(db, events, forked.id)
yield* SessionPending.promote(db, events, forked.id, "steer")
expect((yield* session.context(parent.id)).map((message) => message.type)).toEqual(["user", "synthetic", "user"])
expect((yield* session.context(forked.id)).map((message) => message.type)).toEqual(["user", "synthetic", "user"])
@ -263,13 +263,13 @@ describe("SessionV2.create", () => {
text: "First",
resume: false,
})
yield* SessionPending.promoteSteers(db, events, parent.id)
yield* SessionPending.promote(db, events, parent.id, "steer")
const second = yield* session.prompt({
sessionID: parent.id,
text: "Second",
resume: false,
})
yield* SessionPending.promoteSteers(db, events, parent.id)
yield* SessionPending.promote(db, events, parent.id, "steer")
const assistantMessageID = SessionMessage.ID.create()
const model = ModelV2.Ref.make({ id: ModelV2.ID.make("model"), providerID: ProviderV2.ID.make("provider") })
yield* events.publish(SessionEvent.Step.Started, {
@ -414,7 +414,7 @@ describe("SessionV2.create", () => {
text: "Hello",
resume: false,
})
yield* SessionPending.promoteSteers(db, events, created.id)
yield* SessionPending.promote(db, events, created.id, "steer")
expect(
Array.from(yield* logEvents(session, created.id, true).pipe(Stream.take(2), Stream.runCollect)),
@ -440,7 +440,7 @@ describe("SessionV2.create", () => {
text: "Replay lifecycle",
resume: false,
})
yield* SessionPending.promoteSteers(sourceDb, sourceEvents, created.id)
yield* SessionPending.promote(sourceDb, sourceEvents, created.id, "steer")
const serialized = (yield* sourceDb
.select()
.from(EventTable)

View file

@ -216,7 +216,7 @@ describe("SessionV2.prompt", () => {
text: "boundary",
resume: false,
})
yield* SessionPending.promoteSteers(db, events, sessionID)
yield* SessionPending.promote(db, events, sessionID, "steer")
const stale = SessionMessage.ID.make("msg_stale_assistant")
yield* db.insert(SessionMessageTable).values(assistantRow(stale, 100)).run().pipe(Effect.orDie)
yield* events.publish(SessionEvent.RevertEvent.Staged, {
@ -248,7 +248,7 @@ describe("SessionV2.prompt", () => {
text: "boundary",
resume: false,
})
yield* SessionPending.promoteSteers(db, events, sessionID)
yield* SessionPending.promote(db, events, sessionID, "steer")
yield* events.publish(SessionEvent.RevertEvent.Staged, {
sessionID,
revert: { messageID: boundary.id, files: [] },
@ -448,7 +448,7 @@ describe("SessionV2.prompt", () => {
yield* session.prompt({ sessionID, text: "First", resume: false })
yield* session.prompt({ sessionID, text: "Second", resume: false })
yield* SessionPending.promoteSteers(db, events, sessionID)
yield* SessionPending.promote(db, events, sessionID, "steer")
const streamed = Array.from(yield* Fiber.join(fiber))
expect(streamed.map((event): [number | undefined, string] => [event.durable?.seq, event.type])).toEqual([
@ -625,7 +625,7 @@ describe("SessionV2.prompt", () => {
})
yield* Effect.all(
[SessionPending.promoteSteers(db, events, sessionID), SessionPending.promoteSteers(db, events, sessionID)],
[SessionPending.promote(db, events, sessionID, "steer"), SessionPending.promote(db, events, sessionID, "steer")],
{ concurrency: "unbounded" },
)
@ -855,7 +855,7 @@ describe("SessionV2.prompt", () => {
},
})
yield* SessionPending.promoteSteers(db, events, sessionID)
yield* SessionPending.promote(db, events, sessionID, "steer")
expect(yield* session.messages({ sessionID })).toMatchObject([
{
@ -880,7 +880,7 @@ describe("SessionV2.prompt", () => {
const entries = yield* Effect.all([session.synthetic(input), session.synthetic(input)], {
concurrency: "unbounded",
})
yield* SessionPending.promoteSteers(database.db, events, sessionID)
yield* SessionPending.promote(database.db, events, sessionID, "steer")
const promotedRetry = yield* session.synthetic(input)
const failure = yield* session.synthetic({ ...input, text: "Different completion" }).pipe(Effect.flip)
@ -892,7 +892,7 @@ describe("SessionV2.prompt", () => {
}),
)
it.effect("keeps synthetic queue input pending until the queue boundary", () =>
it.effect("keeps queued input pending until the idle boundary", () =>
Effect.gen(function* () {
yield* setup
const session = yield* SessionV2.Service
@ -907,9 +907,15 @@ describe("SessionV2.prompt", () => {
})
expect(input.delivery).toBe("queue")
expect(yield* SessionPending.promoteSteers(db, events, sessionID)).toBe(0)
expect(yield* SessionPending.has(db, sessionID, "input")).toBe(true)
expect(
yield* SessionPending.promote(db, events, sessionID, "steer"),
).toBe(0)
expect(yield* session.messages({ sessionID })).toEqual([])
expect(yield* SessionPending.promoteNextQueued(db, events, sessionID)).toBe(true)
expect(
yield* SessionPending.promote(db, events, sessionID, "input"),
).toBe(1)
expect(yield* SessionPending.has(db, sessionID, "input")).toBe(false)
expect(yield* session.messages({ sessionID })).toMatchObject([
{ id: input.id, type: "synthetic", text: "Queued completion" },
])
@ -935,7 +941,7 @@ describe("SessionV2.prompt", () => {
resume: false,
})
yield* SessionPending.promoteSteers(db, events, sessionID)
yield* SessionPending.promote(db, events, sessionID, "steer")
expect(
(yield* session.messages({ sessionID, order: "asc" })).map((message) =>
@ -978,10 +984,14 @@ describe("SessionV2.pending", () => {
{ id: second.id, type: "user", delivery: "steer" },
])
yield* SessionPending.promoteSteers(db, events, sessionID)
expect(
yield* SessionPending.promote(db, events, sessionID, "input"),
).toBe(2)
expect(yield* session.pending(sessionID)).toMatchObject([{ id: queued.id, type: "synthetic" }])
yield* SessionPending.promoteNextQueued(db, events, sessionID)
expect(
yield* SessionPending.promote(db, events, sessionID, "input"),
).toBe(1)
expect(yield* session.pending(sessionID)).toEqual([])
}),
)
@ -993,9 +1003,12 @@ describe("SessionV2.pending", () => {
const { db } = yield* Database.Service
const barrier = yield* session.compact({ sessionID })
expect(yield* SessionPending.has(db, sessionID, "any")).toBe(true)
expect(yield* SessionPending.has(db, sessionID, "input")).toBe(false)
expect(yield* session.pending(sessionID)).toMatchObject([{ id: barrier.id, type: "compaction" }])
yield* SessionPending.settleCompaction(db, { sessionID })
expect(yield* SessionPending.has(db, sessionID, "any")).toBe(false)
expect(yield* session.pending(sessionID)).toEqual([])
}),
)

View file

@ -3099,7 +3099,7 @@ describe("SessionRunnerLLM", () => {
streamFailure = undefined
streamGate = undefined
streamStarted = undefined
yield* Effect.yieldNow
yield* session.wait(sessionID)
expect(requests).toHaveLength(2)
expect(userTexts(requests[1]!)).toEqual(["Start working", "Recover with this"])
@ -3111,7 +3111,7 @@ describe("SessionRunnerLLM", () => {
const session = yield* setup
const events = yield* EventV2.Service
yield* admit(session, "Recover interrupted tool")
yield* SessionPending.promoteSteers((yield* Database.Service).db, events, sessionID)
yield* SessionPending.promote((yield* Database.Service).db, events, sessionID, "steer")
const assistantMessageID = SessionMessage.ID.create()
yield* events.publish(SessionEvent.Step.Started, {
sessionID,
@ -3168,7 +3168,7 @@ describe("SessionRunnerLLM", () => {
const session = yield* setup
const events = yield* EventV2.Service
yield* admit(session, "Recover interrupted hosted tool")
yield* SessionPending.promoteSteers((yield* Database.Service).db, events, sessionID)
yield* SessionPending.promote((yield* Database.Service).db, events, sessionID, "steer")
const assistantMessageID = SessionMessage.ID.create()
yield* events.publish(SessionEvent.Step.Started, {
sessionID,
@ -3219,7 +3219,7 @@ describe("SessionRunnerLLM", () => {
const session = yield* setup
const events = yield* EventV2.Service
yield* admit(session, "Recover interrupted tool input")
yield* SessionPending.promoteSteers((yield* Database.Service).db, events, sessionID)
yield* SessionPending.promote((yield* Database.Service).db, events, sessionID, "steer")
const assistantMessageID = SessionMessage.ID.create()
yield* events.publish(SessionEvent.Step.Started, {
sessionID,
@ -4220,7 +4220,7 @@ describe("SessionRunnerLLM", () => {
}),
)
it.effect("retries a physical attempt without consuming the logical agent step", () =>
it.effect("retries a model call without consuming the logical agent step", () =>
Effect.gen(function* () {
const session = yield* setup
const agents = yield* AgentV2.Service

View file

@ -406,7 +406,7 @@ describe("SubagentTool", () => {
},
})
const database = yield* Database.Service
yield* SessionPending.promoteSteers(database.db, events, parent.id)
yield* SessionPending.promote(database.db, events, parent.id, "steer")
const synthetic = (yield* sessions.context(parent.id)).filter((message) => message.type === "synthetic")
expect(synthetic).toHaveLength(1)
expect(synthetic[0]?.text).toContain(`<subagent id="${childID}" state="completed"`)