Skip to content

Commit 91938e2

Browse files
committed
core: fix reasoning tracking for multiple blocks per response
Enable proper handling of multiple reasoning blocks within a single assistant response by assigning unique reasoningIDs to each block. Previously, reasoning blocks could get mixed up when multiple reasoning steps occurred in one turn, causing deltas and completion events to apply to the wrong block.
1 parent 51b0b6f commit 91938e2

4 files changed

Lines changed: 20 additions & 5 deletions

File tree

packages/opencode/src/session/processor.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ export const layer: Layer.Layer<
226226
if (value.id in ctx.reasoningMap) return
227227
SyncEvent.run(SessionEvent.Reasoning.Started.Sync, {
228228
sessionID: ctx.sessionID,
229+
reasoningID: value.id,
229230
timestamp: DateTime.makeUnsafe(Date.now()),
230231
})
231232
ctx.reasoningMap[value.id] = {
@@ -242,6 +243,12 @@ export const layer: Layer.Layer<
242243

243244
case "reasoning-delta":
244245
if (!(value.id in ctx.reasoningMap)) return
246+
SyncEvent.run(SessionEvent.Reasoning.Delta.Sync, {
247+
sessionID: ctx.sessionID,
248+
reasoningID: value.id,
249+
delta: value.text,
250+
timestamp: DateTime.makeUnsafe(Date.now()),
251+
})
245252
ctx.reasoningMap[value.id].text += value.text
246253
if (value.providerMetadata) ctx.reasoningMap[value.id].metadata = value.providerMetadata
247254
yield* session.updatePartDelta({
@@ -257,6 +264,7 @@ export const layer: Layer.Layer<
257264
if (!(value.id in ctx.reasoningMap)) return
258265
SyncEvent.run(SessionEvent.Reasoning.Ended.Sync, {
259266
sessionID: ctx.sessionID,
267+
reasoningID: value.id,
260268
text: ctx.reasoningMap[value.id].text,
261269
timestamp: DateTime.makeUnsafe(Date.now()),
262270
})

packages/opencode/src/v2/session-entry-stepper.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,10 @@ export function stepWith<Result>(adapter: Adapter<Result>, event: SessionEvent.E
6060
const latestText = (assistant: DraftAssistant | undefined) =>
6161
assistant?.content.findLast((item): item is DraftText => item.type === "text")
6262

63-
const latestReasoning = (assistant: DraftAssistant | undefined) =>
64-
assistant?.content.findLast((item): item is DraftReasoning => item.type === "reasoning")
63+
const latestReasoning = (assistant: DraftAssistant | undefined, reasoningID: string) =>
64+
assistant?.content.findLast(
65+
(item): item is DraftReasoning => item.type === "reasoning" && item.reasoningID === reasoningID,
66+
)
6567

6668
SessionEvent.All.match(event, {
6769
"session.next.prompted": (event) => {
@@ -203,12 +205,13 @@ export function stepWith<Result>(adapter: Adapter<Result>, event: SessionEvent.E
203205
)
204206
}
205207
},
206-
"session.next.reasoning.started": () => {
208+
"session.next.reasoning.started": (event) => {
207209
if (currentAssistant) {
208210
adapter.updateAssistant(
209211
produce(currentAssistant, (draft) => {
210212
draft.content.push({
211213
type: "reasoning",
214+
reasoningID: event.data.reasoningID,
212215
text: "",
213216
})
214217
}),
@@ -219,7 +222,7 @@ export function stepWith<Result>(adapter: Adapter<Result>, event: SessionEvent.E
219222
if (currentAssistant) {
220223
adapter.updateAssistant(
221224
produce(currentAssistant, (draft) => {
222-
const match = latestReasoning(draft)
225+
const match = latestReasoning(draft, event.data.reasoningID)
223226
if (match) match.text += event.data.delta
224227
}),
225228
)
@@ -229,7 +232,7 @@ export function stepWith<Result>(adapter: Adapter<Result>, event: SessionEvent.E
229232
if (currentAssistant) {
230233
adapter.updateAssistant(
231234
produce(currentAssistant, (draft) => {
232-
const match = latestReasoning(draft)
235+
const match = latestReasoning(draft, event.data.reasoningID)
233236
if (match) match.text = event.data.text
234237
}),
235238
)

packages/opencode/src/v2/session-entry.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ export class AssistantText extends Schema.Class<AssistantText>("Session.Entry.As
107107

108108
export class AssistantReasoning extends Schema.Class<AssistantReasoning>("Session.Entry.Assistant.Reasoning")({
109109
type: Schema.Literal("reasoning"),
110+
reasoningID: Schema.String,
110111
text: Schema.String,
111112
}) {}
112113

packages/opencode/src/v2/session-event.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ export namespace Reasoning {
117117
schema: {
118118
timestamp: Schema.DateTimeUtcFromMillis,
119119
sessionID: SessionID,
120+
reasoningID: Schema.String,
120121
},
121122
})
122123
export type Started = Schema.Schema.Type<typeof Started>
@@ -127,6 +128,7 @@ export namespace Reasoning {
127128
schema: {
128129
timestamp: Schema.DateTimeUtcFromMillis,
129130
sessionID: SessionID,
131+
reasoningID: Schema.String,
130132
delta: Schema.String,
131133
},
132134
})
@@ -138,6 +140,7 @@ export namespace Reasoning {
138140
schema: {
139141
timestamp: Schema.DateTimeUtcFromMillis,
140142
sessionID: SessionID,
143+
reasoningID: Schema.String,
141144
text: Schema.String,
142145
},
143146
})

0 commit comments

Comments
 (0)