chore: generate

This commit is contained in:
opencode-agent[bot] 2026-06-27 07:43:42 +00:00
commit 6861fedd09
4 changed files with 28 additions and 41 deletions

View file

@ -61,7 +61,6 @@ describe("coalesceServerEvents", () => {
expect(result.map((event) => event.payload.id)).toEqual(["1", "2", "3"]) expect(result.map((event) => event.payload.id)).toEqual(["1", "2", "3"])
}) })
}) })
describe("enqueueServerEvent", () => { describe("enqueueServerEvent", () => {

View file

@ -26,10 +26,7 @@ const coalescedKey = (event: QueuedServerEvent) => {
return undefined return undefined
} }
export function enqueueServerEvent( export function enqueueServerEvent(queue: QueuedServerEvent[], event: QueuedServerEvent) {
queue: QueuedServerEvent[],
event: QueuedServerEvent,
) {
const key = coalescedKey(event) const key = coalescedKey(event)
const previous = queue[queue.length - 1] const previous = queue[queue.length - 1]
if (key && previous && coalescedKey(previous) === key) { if (key && previous && coalescedKey(previous) === key) {

View file

@ -264,7 +264,9 @@ describe("server session", () => {
const message = userMessage("message") const message = userMessage("message")
const stale = textPart(message.id, { id: "stale", text: "stale" }) const stale = textPart(message.id, { id: "stale", text: "stale" })
const part = textPart(message.id, { id: "optimistic", text: "optimistic" }) const part = textPart(message.id, { id: "optimistic", text: "optimistic" })
const store = createServerSession(messageClient(response([{ info: message, parts: [] }]), pending.promise, response())) const store = createServerSession(
messageClient(response([{ info: message, parts: [] }]), pending.promise, response()),
)
await store.sync("child") await store.sync("child")
const refreshing = store.sync("child", { force: true }) const refreshing = store.sync("child", { force: true })
@ -372,10 +374,7 @@ describe("server session", () => {
const updated = { ...confirmed, text: "updated" } const updated = { ...confirmed, text: "updated" }
const pendingPart = textPart(message.id, { id: "pending", text: "pending" }) const pendingPart = textPart(message.id, { id: "pending", text: "pending" })
const store = createServerSession( const store = createServerSession(
messageClient( messageClient(response([{ info: message, parts: [confirmed] }]), response([{ info: message, parts: [updated] }])),
response([{ info: message, parts: [confirmed] }]),
response([{ info: message, parts: [updated] }]),
),
) )
store.optimistic.add({ sessionID: "child", message, parts: [confirmed, pendingPart] }) store.optimistic.add({ sessionID: "child", message, parts: [confirmed, pendingPart] })
await store.sync("child") await store.sync("child")

View file

@ -53,10 +53,7 @@ type MessageLoadState = {
clearedMessageParts: Set<string> clearedMessageParts: Set<string>
} }
function mergeOptimisticPage( function mergeOptimisticPage(page: MessagePage, items: OptimisticItem[]) {
page: MessagePage,
items: OptimisticItem[],
) {
if (items.length === 0) return { ...page, observed: [] as { messageID: string; parts: Part[] }[] } if (items.length === 0) return { ...page, observed: [] as { messageID: string; parts: Part[] }[] }
const session = [...page.session] const session = [...page.session]
const part = new Map(page.part.map((item) => [item.id, item.part])) const part = new Map(page.part.map((item) => [item.id, item.part]))
@ -157,7 +154,10 @@ export function createServerSession(client: OpencodeClient, options?: { retry?:
const orphanParts = new Map<string, Set<string>>() const orphanParts = new Map<string, Set<string>>()
const removedMessages = new Map<string, Set<string>>() const removedMessages = new Map<string, Set<string>>()
const deltaBases = new Map<string, { base: string; sessionID: string }>() const deltaBases = new Map<string, { base: string; sessionID: string }>()
const deleteMessageParts = (cache: { part: Record<string, Part[] | undefined>; part_text_accum_delta: Record<string, string | undefined> }, messageID: string) => { const deleteMessageParts = (
cache: { part: Record<string, Part[] | undefined>; part_text_accum_delta: Record<string, string | undefined> },
messageID: string,
) => {
for (const part of cache.part[messageID] ?? []) { for (const part of cache.part[messageID] ?? []) {
delete cache.part_text_accum_delta[part.id] delete cache.part_text_accum_delta[part.id]
deltaBases.delete(part.id) deltaBases.delete(part.id)
@ -253,10 +253,7 @@ export function createServerSession(client: OpencodeClient, options?: { retry?:
) )
generations.delete(sessionID) generations.delete(sessionID)
} }
void request.then( void request.then(cleanup, cleanup)
cleanup,
cleanup,
)
return request return request
} }
@ -339,7 +336,8 @@ export function createServerSession(client: OpencodeClient, options?: { retry?:
if (!load) return if (!load) return
// A part event keeps an existing parent when the fetched page omits it without overriding fetched metadata. // A part event keeps an existing parent when the fetched page omits it without overriding fetched metadata.
const messages = data.message[sessionID] const messages = data.message[sessionID]
if (messages && Binary.search(messages, messageID, (message) => message.id).found) load.retainedMessages.add(messageID) if (messages && Binary.search(messages, messageID, (message) => message.id).found)
load.retainedMessages.add(messageID)
const parts = load.touchedParts.get(messageID) const parts = load.touchedParts.get(messageID)
if (parts) { if (parts) {
parts.add(partID) parts.add(partID)
@ -504,11 +502,7 @@ export function createServerSession(client: OpencodeClient, options?: { retry?:
for (const partID of load?.carriedDeltaParts.get(item.id) ?? []) { for (const partID of load?.carriedDeltaParts.get(item.id) ?? []) {
if (!fetchedIDs.has(partID)) touched.delete(partID) if (!fetchedIDs.has(partID)) touched.delete(partID)
} }
const parts = reconcileFetched( const parts = reconcileFetched(fetched, data.part[item.id] ?? [], { touched })
fetched,
data.part[item.id] ?? [],
{ touched },
)
if (!parts.length) { if (!parts.length) {
orphanParts.get(sessionID)?.delete(item.id) orphanParts.get(sessionID)?.delete(item.id)
setData(produce((draft) => deleteMessageParts(draft, item.id))) setData(produce((draft) => deleteMessageParts(draft, item.id)))
@ -542,19 +536,12 @@ export function createServerSession(client: OpencodeClient, options?: { retry?:
merged.observed.forEach((item) => { merged.observed.forEach((item) => {
if (!load?.clearedMessageParts.has(item.messageID)) confirmOptimistic(sessionID, item.messageID, item.parts) if (!load?.clearedMessageParts.has(item.messageID)) confirmOptimistic(sessionID, item.messageID, item.parts)
}) })
const touchedMessages = new Set([ const touchedMessages = new Set([...(load?.touchedMessages ?? []), ...(removedMessages.get(sessionID) ?? [])])
...(load?.touchedMessages ?? []), const messages = reconcileFetched(merged.session, data.message[sessionID] ?? [], {
...(removedMessages.get(sessionID) ?? []), touched: touchedMessages,
]) retained: load?.retainedMessages,
const messages = reconcileFetched( preserveUnfetched,
merged.session, })
data.message[sessionID] ?? [],
{
touched: touchedMessages,
retained: load?.retainedMessages,
preserveUnfetched,
},
)
batch(() => { batch(() => {
const messageIDs = replaceMessages(sessionID, messages) const messageIDs = replaceMessages(sessionID, messages)
replaceParts(sessionID, merged.part, messageIDs, load) replaceParts(sessionID, merged.part, messageIDs, load)
@ -785,7 +772,9 @@ export function createServerSession(client: OpencodeClient, options?: { retry?:
// Outside a page load, accepting a part without its ordered parent event would create an unbounded orphan. // Outside a page load, accepting a part without its ordered parent event would create an unbounded orphan.
if ( if (
missing && missing &&
(!load || load.clearedMessageParts.has(part.messageID) || removedMessages.get(part.sessionID)?.has(part.messageID)) (!load ||
load.clearedMessageParts.has(part.messageID) ||
removedMessages.get(part.sessionID)?.has(part.messageID))
) )
return return
if (missing) { if (missing) {
@ -1003,7 +992,9 @@ export function createServerSession(client: OpencodeClient, options?: { retry?:
}, },
optimistic: { optimistic: {
add(input: { sessionID: string; message: Message; parts: Part[] }) { add(input: { sessionID: string; message: Message; parts: Part[] }) {
const parts = input.parts.filter((part) => !!part?.id && !SKIP_PARTS.has(part.type)).sort((a, b) => cmp(a.id, b.id)) const parts = input.parts
.filter((part) => !!part?.id && !SKIP_PARTS.has(part.type))
.sort((a, b) => cmp(a.id, b.id))
const load = messageLoads.get(input.sessionID) const load = messageLoads.get(input.sessionID)
if (load?.clearedMessageParts.has(input.message.id)) { if (load?.clearedMessageParts.has(input.message.id)) {
const touched = load.touchedParts.get(input.message.id) ?? new Set<string>() const touched = load.touchedParts.get(input.message.id) ?? new Set<string>()
@ -1019,7 +1010,8 @@ export function createServerSession(client: OpencodeClient, options?: { retry?:
removedMessagesForSession?.delete(input.message.id) removedMessagesForSession?.delete(input.message.id)
if (removedMessagesForSession?.size === 0) removedMessages.delete(input.sessionID) if (removedMessagesForSession?.size === 0) removedMessages.delete(input.sessionID)
if (items) items.set(input.message.id, { ...input, parts, confirmedParts: [] }) if (items) items.set(input.message.id, { ...input, parts, confirmedParts: [] })
if (!items) optimistic.set(input.sessionID, new Map([[input.message.id, { ...input, parts, confirmedParts: [] }]])) if (!items)
optimistic.set(input.sessionID, new Map([[input.message.id, { ...input, parts, confirmedParts: [] }]]))
setData("message", input.sessionID, (messages = []) => merge(messages, [input.message])) setData("message", input.sessionID, (messages = []) => merge(messages, [input.message]))
setData( setData(
"part_text_accum_delta", "part_text_accum_delta",