fix(tui): reconcile session state after reconnect (#35262)

This commit is contained in:
Kit Langton 2026-07-04 11:05:41 -04:00 committed by GitHub
commit 9daa4d85a4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 207 additions and 34 deletions

View file

@ -28,23 +28,24 @@ export function createSessionRows(sessionID: Accessor<string>) {
function reduce() {
const messages = data.session.message.list(sessionID())
const boundary = revertBoundary()
return reduceSessionRows(boundary ? messages.filter((message) => message.id < boundary) : messages)
const rows = reduceSessionRows(boundary ? messages.filter((message) => message.id < boundary) : messages)
partitionPending(rows, pendingPermissions())
return rows
}
createEffect(() => {
const pending = new Set(
function pendingPermissions() {
return new Set(
(data.session.permission.list(sessionID()) ?? []).flatMap((request) =>
request.source?.type === "tool" ? [request.source.callID] : [],
),
)
}
createEffect(() => {
const pending = pendingPermissions()
setRows(
produce((draft) => {
draft.forEach((row) => {
if (row.type !== "group") return
const refs = [...row.refs, ...row.pending]
row.refs = refs.filter((ref) => !pending.has(ref.partID))
row.pending = refs.filter((ref) => pending.has(ref.partID))
})
partitionPending(draft, pending)
}),
)
})
@ -69,6 +70,20 @@ export function createSessionRows(sessionID: Accessor<string>) {
}),
)
createEffect(
on(
() =>
data.session.message
.list(sessionID())
.flatMap((message) =>
message.type === "user"
? [{ id: message.id, created: message.time.created, queued: message.metadata?.queued === true }]
: [],
),
() => setRows(reconcile(reduce())),
),
)
const appendMessage = (messageID: string) =>
setRows(
produce((draft) => {
@ -134,7 +149,6 @@ export function createSessionRows(sessionID: Accessor<string>) {
}
const subscriptions = [
data.on("session.prompt.admitted", input),
data.on("session.prompt.promoted", input),
data.on("session.context.updated", message),
data.on("session.synthetic", (event) => {
if (event.data.sessionID === sessionID() && event.data.description?.trim())
@ -225,6 +239,15 @@ function completePrevious(rows: SessionRow[], index = rows.length) {
if (previous?.type === "group") previous.completed = true
}
function partitionPending(rows: SessionRow[], pending: Set<string>) {
rows.forEach((row) => {
if (row.type !== "group") return
const refs = [...row.refs, ...row.pending]
row.refs = refs.filter((ref) => !pending.has(ref.partID))
row.pending = refs.filter((ref) => pending.has(ref.partID))
})
}
function exploration(name: string) {
return ["read", "glob", "grep"].includes(name.toLowerCase())
}