summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorKit Langton <[email protected]>2026-04-10 23:18:13 -0400
committerGitHub <[email protected]>2026-04-10 23:18:13 -0400
commitcd004cf0b28aa49344da2d5947a78703d30bcaf1 (patch)
tree0d850b47659a77f86a905213babcfb132dbdbee0
parent19ae8c88b0bfdbd66b81c96c1ca142b19463287c (diff)
downloadopencode-cd004cf0b28aa49344da2d5947a78703d30bcaf1.tar.gz
opencode-cd004cf0b28aa49344da2d5947a78703d30bcaf1.zip
refactor(session): eliminate Effect.promise roundtrips for sync MessageV2.stream (#21973)
-rw-r--r--packages/opencode/src/session/index.ts19
-rw-r--r--packages/opencode/src/session/prompt.ts25
2 files changed, 27 insertions, 17 deletions
diff --git a/packages/opencode/src/session/index.ts b/packages/opencode/src/session/index.ts
index d28a1988d..55532a794 100644
--- a/packages/opencode/src/session/index.ts
+++ b/packages/opencode/src/session/index.ts
@@ -29,7 +29,7 @@ import type { Provider } from "@/provider/provider"
import { Permission } from "@/permission"
import { Global } from "@/global"
import type { LanguageModelV2Usage } from "@ai-sdk/provider"
-import { Effect, Layer, Context } from "effect"
+import { Effect, Layer, Option, Context } from "effect"
import { makeRuntime } from "@/effect/run-service"
export namespace Session {
@@ -352,6 +352,11 @@ export namespace Session {
field: string
delta: string
}) => Effect.Effect<void>
+ /** Finds the first message matching the predicate, searching newest-first. */
+ readonly findMessage: (
+ sessionID: SessionID,
+ predicate: (msg: MessageV2.WithParts) => boolean,
+ ) => Effect.Effect<Option.Option<MessageV2.WithParts>>
}
export class Service extends Context.Service<Service, Interface>()("@opencode/Session") {}
@@ -636,6 +641,17 @@ export namespace Session {
yield* bus.publish(MessageV2.Event.PartDelta, input)
})
+ /** Finds the first message matching the predicate, searching newest-first. */
+ const findMessage = Effect.fn("Session.findMessage")(function* (
+ sessionID: SessionID,
+ predicate: (msg: MessageV2.WithParts) => boolean,
+ ) {
+ for (const item of MessageV2.stream(sessionID)) {
+ if (predicate(item)) return Option.some(item)
+ }
+ return Option.none<MessageV2.WithParts>()
+ })
+
return Service.of({
create,
fork,
@@ -657,6 +673,7 @@ export namespace Session {
updatePart,
getPart,
updatePartDelta,
+ findMessage,
})
}),
)
diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts
index de26e0328..2b092fc8f 100644
--- a/packages/opencode/src/session/prompt.ts
+++ b/packages/opencode/src/session/prompt.ts
@@ -902,12 +902,8 @@ NOTE: At any point in time through this workflow you should feel free to ask the
})
const lastModel = Effect.fnUntraced(function* (sessionID: SessionID) {
- const model = yield* Effect.promise(async () => {
- for await (const item of MessageV2.stream(sessionID)) {
- if (item.info.role === "user" && item.info.model) return item.info.model
- }
- })
- if (model) return model
+ const match = yield* sessions.findMessage(sessionID, (m) => m.info.role === "user" && !!m.info.model)
+ if (Option.isSome(match) && match.value.info.role === "user") return match.value.info.model
return yield* provider.defaultModel()
})
@@ -1290,16 +1286,13 @@ NOTE: At any point in time through this workflow you should feel free to ask the
},
)
- const lastAssistant = (sessionID: SessionID) =>
- Effect.promise(async () => {
- let latest: MessageV2.WithParts | undefined
- for await (const item of MessageV2.stream(sessionID)) {
- latest ??= item
- if (item.info.role !== "user") return item
- }
- if (latest) return latest
- throw new Error("Impossible")
- })
+ const lastAssistant = Effect.fnUntraced(function* (sessionID: SessionID) {
+ const match = yield* sessions.findMessage(sessionID, (m) => m.info.role !== "user")
+ if (Option.isSome(match)) return match.value
+ const msgs = yield* sessions.messages({ sessionID, limit: 1 })
+ if (msgs.length > 0) return msgs[0]
+ throw new Error("Impossible")
+ })
const runLoop: (sessionID: SessionID) => Effect.Effect<MessageV2.WithParts> = Effect.fn("SessionPrompt.run")(
function* (sessionID: SessionID) {