refactor(session): eliminate Effect.promise roundtrips for sync MessageV2.stream (#21973)
This commit is contained in:
@@ -29,7 +29,7 @@ import type { Provider } from "@/provider/provider"
|
|||||||
import { Permission } from "@/permission"
|
import { Permission } from "@/permission"
|
||||||
import { Global } from "@/global"
|
import { Global } from "@/global"
|
||||||
import type { LanguageModelV2Usage } from "@ai-sdk/provider"
|
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"
|
import { makeRuntime } from "@/effect/run-service"
|
||||||
|
|
||||||
export namespace Session {
|
export namespace Session {
|
||||||
@@ -352,6 +352,11 @@ export namespace Session {
|
|||||||
field: string
|
field: string
|
||||||
delta: string
|
delta: string
|
||||||
}) => Effect.Effect<void>
|
}) => 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") {}
|
export class Service extends Context.Service<Service, Interface>()("@opencode/Session") {}
|
||||||
@@ -636,6 +641,17 @@ export namespace Session {
|
|||||||
yield* bus.publish(MessageV2.Event.PartDelta, input)
|
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({
|
return Service.of({
|
||||||
create,
|
create,
|
||||||
fork,
|
fork,
|
||||||
@@ -657,6 +673,7 @@ export namespace Session {
|
|||||||
updatePart,
|
updatePart,
|
||||||
getPart,
|
getPart,
|
||||||
updatePartDelta,
|
updatePartDelta,
|
||||||
|
findMessage,
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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 lastModel = Effect.fnUntraced(function* (sessionID: SessionID) {
|
||||||
const model = yield* Effect.promise(async () => {
|
const match = yield* sessions.findMessage(sessionID, (m) => m.info.role === "user" && !!m.info.model)
|
||||||
for await (const item of MessageV2.stream(sessionID)) {
|
if (Option.isSome(match) && match.value.info.role === "user") return match.value.info.model
|
||||||
if (item.info.role === "user" && item.info.model) return item.info.model
|
|
||||||
}
|
|
||||||
})
|
|
||||||
if (model) return model
|
|
||||||
return yield* provider.defaultModel()
|
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) =>
|
const lastAssistant = Effect.fnUntraced(function* (sessionID: SessionID) {
|
||||||
Effect.promise(async () => {
|
const match = yield* sessions.findMessage(sessionID, (m) => m.info.role !== "user")
|
||||||
let latest: MessageV2.WithParts | undefined
|
if (Option.isSome(match)) return match.value
|
||||||
for await (const item of MessageV2.stream(sessionID)) {
|
const msgs = yield* sessions.messages({ sessionID, limit: 1 })
|
||||||
latest ??= item
|
if (msgs.length > 0) return msgs[0]
|
||||||
if (item.info.role !== "user") return item
|
throw new Error("Impossible")
|
||||||
}
|
})
|
||||||
if (latest) return latest
|
|
||||||
throw new Error("Impossible")
|
|
||||||
})
|
|
||||||
|
|
||||||
const runLoop: (sessionID: SessionID) => Effect.Effect<MessageV2.WithParts> = Effect.fn("SessionPrompt.run")(
|
const runLoop: (sessionID: SessionID) => Effect.Effect<MessageV2.WithParts> = Effect.fn("SessionPrompt.run")(
|
||||||
function* (sessionID: SessionID) {
|
function* (sessionID: SessionID) {
|
||||||
|
|||||||
Reference in New Issue
Block a user