refactor(session): effectify SessionPrompt service (#19483)
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { Provider } from "@/provider/provider"
|
||||
import { Log } from "@/util/log"
|
||||
import { Effect, Layer, ServiceMap } from "effect"
|
||||
import { Cause, Effect, Layer, Record, ServiceMap } from "effect"
|
||||
import * as Queue from "effect/Queue"
|
||||
import * as Stream from "effect/Stream"
|
||||
import { streamText, wrapLanguageModel, type ModelMessage, type Tool, tool, jsonSchema } from "ai"
|
||||
import { mergeDeep, pipe } from "remeda"
|
||||
@@ -28,7 +29,6 @@ export namespace LLM {
|
||||
agent: Agent.Info
|
||||
permission?: Permission.Ruleset
|
||||
system: string[]
|
||||
abort: AbortSignal
|
||||
messages: ModelMessage[]
|
||||
small?: boolean
|
||||
tools: Record<string, Tool>
|
||||
@@ -36,6 +36,10 @@ export namespace LLM {
|
||||
toolChoice?: "auto" | "required" | "none"
|
||||
}
|
||||
|
||||
export type StreamRequest = StreamInput & {
|
||||
abort: AbortSignal
|
||||
}
|
||||
|
||||
export type Event = Awaited<ReturnType<typeof stream>>["fullStream"] extends AsyncIterable<infer T> ? T : never
|
||||
|
||||
export interface Interface {
|
||||
@@ -49,15 +53,32 @@ export namespace LLM {
|
||||
Effect.gen(function* () {
|
||||
return Service.of({
|
||||
stream(input) {
|
||||
return Stream.unwrap(
|
||||
Effect.promise(() => LLM.stream(input)).pipe(
|
||||
Effect.map((result) =>
|
||||
Stream.fromAsyncIterable(result.fullStream, (err) => err).pipe(
|
||||
Stream.mapEffect((event) => Effect.succeed(event)),
|
||||
),
|
||||
),
|
||||
const stream: Stream.Stream<Event, unknown> = Stream.scoped(
|
||||
Stream.unwrap(
|
||||
Effect.gen(function* () {
|
||||
const ctrl = yield* Effect.acquireRelease(
|
||||
Effect.sync(() => new AbortController()),
|
||||
(ctrl) => Effect.sync(() => ctrl.abort()),
|
||||
)
|
||||
const queue = yield* Queue.unbounded<Event, unknown | Cause.Done>()
|
||||
|
||||
yield* Effect.promise(async () => {
|
||||
const result = await LLM.stream({ ...input, abort: ctrl.signal })
|
||||
for await (const event of result.fullStream) {
|
||||
if (!Queue.offerUnsafe(queue, event)) break
|
||||
}
|
||||
Queue.endUnsafe(queue)
|
||||
}).pipe(
|
||||
Effect.catchCause((cause) => Effect.sync(() => void Queue.failCauseUnsafe(queue, cause))),
|
||||
Effect.onInterrupt(() => Effect.sync(() => ctrl.abort())),
|
||||
Effect.forkScoped,
|
||||
)
|
||||
|
||||
return Stream.fromQueue(queue)
|
||||
}),
|
||||
),
|
||||
)
|
||||
return stream
|
||||
},
|
||||
})
|
||||
}),
|
||||
@@ -65,7 +86,7 @@ export namespace LLM {
|
||||
|
||||
export const defaultLayer = layer
|
||||
|
||||
export async function stream(input: StreamInput) {
|
||||
export async function stream(input: StreamRequest) {
|
||||
const l = log
|
||||
.clone()
|
||||
.tag("providerID", input.model.providerID)
|
||||
@@ -322,17 +343,12 @@ export namespace LLM {
|
||||
})
|
||||
}
|
||||
|
||||
async function resolveTools(input: Pick<StreamInput, "tools" | "agent" | "permission" | "user">) {
|
||||
function resolveTools(input: Pick<StreamInput, "tools" | "agent" | "permission" | "user">) {
|
||||
const disabled = Permission.disabled(
|
||||
Object.keys(input.tools),
|
||||
Permission.merge(input.agent.permission, input.permission ?? []),
|
||||
)
|
||||
for (const tool of Object.keys(input.tools)) {
|
||||
if (input.user.tools?.[tool] === false || disabled.has(tool)) {
|
||||
delete input.tools[tool]
|
||||
}
|
||||
}
|
||||
return input.tools
|
||||
return Record.filter(input.tools, (_, k) => input.user.tools?.[k] !== false && !disabled.has(k))
|
||||
}
|
||||
|
||||
// Check if messages contain any tool-call content
|
||||
|
||||
Reference in New Issue
Block a user