Skip to content

Commit e0a4cbf

Browse files
committed
refactor(session): simplify LLM event adapter
1 parent 2b1a6bf commit e0a4cbf

2 files changed

Lines changed: 35 additions & 22 deletions

File tree

packages/llm/src/schema/events.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,9 +256,15 @@ export const LLMEvent = Object.assign(llmEventTagged, {
256256
toolResult: (input: WithID<ToolResult, ToolCallID>) => ToolResult.make({ ...input, id: toolCallID(input.id) }),
257257
toolError: (input: WithID<ToolError, ToolCallID>) => ToolError.make({ ...input, id: toolCallID(input.id) }),
258258
stepFinish: (input: WithUsage<StepFinish>) =>
259-
StepFinish.make({ ...input, usage: input.usage instanceof Usage ? input.usage : new Usage(input.usage ?? {}) }),
259+
StepFinish.make({
260+
...input,
261+
usage: input.usage === undefined ? undefined : input.usage instanceof Usage ? input.usage : new Usage(input.usage),
262+
}),
260263
requestFinish: (input: WithUsage<RequestFinish>) =>
261-
RequestFinish.make({ ...input, usage: input.usage instanceof Usage ? input.usage : new Usage(input.usage ?? {}) }),
264+
RequestFinish.make({
265+
...input,
266+
usage: input.usage === undefined ? undefined : input.usage instanceof Usage ? input.usage : new Usage(input.usage),
267+
}),
262268
providerError: ProviderErrorEvent.make,
263269
is: {
264270
requestStart: llmEventTagged.guards["request-start"],

packages/opencode/src/session/llm-ai-sdk.ts

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ContentBlockID, FinishReason, LLMEvent, ProviderMetadata, ToolCallID, ToolResultValue, Usage } from "@opencode-ai/llm"
1+
import { FinishReason, LLMEvent, ProviderMetadata, ToolResultValue } from "@opencode-ai/llm"
22
import { Effect, Schema } from "effect"
33
import { type streamText } from "ai"
44
import { errorMessage } from "@/util/error"
@@ -11,15 +11,12 @@ export function adapterState() {
1111
step: 0,
1212
text: 0,
1313
reasoning: 0,
14-
currentTextID: undefined as ContentBlockID | undefined,
15-
currentReasoningID: undefined as ContentBlockID | undefined,
14+
currentTextID: undefined as string | undefined,
15+
currentReasoningID: undefined as string | undefined,
1616
toolNames: {} as Record<string, string>,
1717
}
1818
}
1919

20-
const contentBlockID = (value: string) => ContentBlockID.make(value)
21-
const toolCallID = (value: string) => ToolCallID.make(value)
22-
2320
function finishReason(value: string | undefined): FinishReason {
2421
return Schema.is(FinishReason)(value) ? value : "unknown"
2522
}
@@ -28,7 +25,7 @@ function providerMetadata(value: unknown): ProviderMetadata | undefined {
2825
return Schema.is(ProviderMetadata)(value) ? value : undefined
2926
}
3027

31-
function usage(value: unknown): Usage | undefined {
28+
function usage(value: unknown) {
3229
if (!value || typeof value !== "object") return undefined
3330
const item = value as {
3431
inputTokens?: number
@@ -49,7 +46,17 @@ function usage(value: unknown): Usage | undefined {
4946
cacheWriteInputTokens: item.inputTokenDetails?.cacheWriteTokens,
5047
}).filter((entry) => entry[1] !== undefined),
5148
)
52-
return new Usage(result)
49+
return result
50+
}
51+
52+
function currentTextID(state: ReturnType<typeof adapterState>, id: string | undefined) {
53+
state.currentTextID = id ?? state.currentTextID ?? `text-${state.text++}`
54+
return state.currentTextID
55+
}
56+
57+
function currentReasoningID(state: ReturnType<typeof adapterState>, id: string | undefined) {
58+
state.currentReasoningID = id ?? state.currentReasoningID ?? `reasoning-${state.reasoning++}`
59+
return state.currentReasoningID
5360
}
5461

5562
export function toLLMEvents(
@@ -86,7 +93,7 @@ export function toLLMEvents(
8693

8794
case "text-start":
8895
return Effect.sync(() => {
89-
state.currentTextID = contentBlockID(event.id ?? `text-${state.text++}`)
96+
state.currentTextID = currentTextID(state, event.id)
9097
return [
9198
LLMEvent.textStart({
9299
id: state.currentTextID,
@@ -98,22 +105,22 @@ export function toLLMEvents(
98105
case "text-delta":
99106
return Effect.succeed([
100107
LLMEvent.textDelta({
101-
id: event.id ? contentBlockID(event.id) : (state.currentTextID ?? contentBlockID(`text-${state.text++}`)),
108+
id: currentTextID(state, event.id),
102109
text: event.text,
103110
}),
104111
])
105112

106113
case "text-end":
107114
return Effect.succeed([
108115
LLMEvent.textEnd({
109-
id: event.id ? contentBlockID(event.id) : (state.currentTextID ?? contentBlockID(`text-${state.text++}`)),
116+
id: currentTextID(state, event.id),
110117
providerMetadata: providerMetadata(event.providerMetadata),
111118
}),
112119
])
113120

114121
case "reasoning-start":
115122
return Effect.sync(() => {
116-
state.currentReasoningID = contentBlockID(event.id)
123+
state.currentReasoningID = currentReasoningID(state, event.id)
117124
return [
118125
LLMEvent.reasoningStart({
119126
id: state.currentReasoningID,
@@ -125,14 +132,14 @@ export function toLLMEvents(
125132
case "reasoning-delta":
126133
return Effect.succeed([
127134
LLMEvent.reasoningDelta({
128-
id: event.id ? contentBlockID(event.id) : (state.currentReasoningID ?? contentBlockID(`reasoning-${state.reasoning++}`)),
135+
id: currentReasoningID(state, event.id),
129136
text: event.text,
130137
}),
131138
])
132139

133140
case "reasoning-end":
134141
return Effect.sync(() => {
135-
const id = contentBlockID(event.id)
142+
const id = currentReasoningID(state, event.id)
136143
state.currentReasoningID = undefined
137144
return [
138145
LLMEvent.reasoningEnd({
@@ -147,7 +154,7 @@ export function toLLMEvents(
147154
state.toolNames[event.id] = event.toolName
148155
return [
149156
LLMEvent.toolInputStart({
150-
id: toolCallID(event.id),
157+
id: event.id,
151158
name: event.toolName,
152159
providerMetadata: providerMetadata(event.providerMetadata),
153160
}),
@@ -157,7 +164,7 @@ export function toLLMEvents(
157164
case "tool-input-delta":
158165
return Effect.succeed([
159166
LLMEvent.toolInputDelta({
160-
id: toolCallID(event.id),
167+
id: event.id,
161168
name: state.toolNames[event.id] ?? "unknown",
162169
text: event.delta ?? "",
163170
}),
@@ -166,7 +173,7 @@ export function toLLMEvents(
166173
case "tool-input-end":
167174
return Effect.succeed([
168175
LLMEvent.toolInputEnd({
169-
id: toolCallID(event.id),
176+
id: event.id,
170177
name: state.toolNames[event.id] ?? "unknown",
171178
}),
172179
])
@@ -176,7 +183,7 @@ export function toLLMEvents(
176183
state.toolNames[event.toolCallId] = event.toolName
177184
return [
178185
LLMEvent.toolCall({
179-
id: toolCallID(event.toolCallId),
186+
id: event.toolCallId,
180187
name: event.toolName,
181188
input: event.input,
182189
providerExecuted: "providerExecuted" in event ? event.providerExecuted : undefined,
@@ -191,7 +198,7 @@ export function toLLMEvents(
191198
delete state.toolNames[event.toolCallId]
192199
return [
193200
LLMEvent.toolResult({
194-
id: toolCallID(event.toolCallId),
201+
id: event.toolCallId,
195202
name,
196203
result: ToolResultValue.make(event.output),
197204
providerExecuted: "providerExecuted" in event ? event.providerExecuted : undefined,
@@ -205,7 +212,7 @@ export function toLLMEvents(
205212
delete state.toolNames[event.toolCallId]
206213
return [
207214
LLMEvent.toolError({
208-
id: toolCallID(event.toolCallId),
215+
id: event.toolCallId,
209216
name,
210217
message: errorMessage(event.error),
211218
}),

0 commit comments

Comments
 (0)