refactor: centralize client identity (#38148)
This commit is contained in:
parent
dd6c95fdc7
commit
9c38358197
13 changed files with 102 additions and 94 deletions
|
|
@ -10,6 +10,7 @@ import { llmClient } from "../effect/app-node-platform"
|
|||
import { SessionEvent } from "./event"
|
||||
import type { SessionMessage } from "./message"
|
||||
import { SessionModelHeaders } from "./model-headers"
|
||||
import { Client } from "@opencode-ai/util/client"
|
||||
import { SessionRunnerModel } from "./runner/model"
|
||||
import { SessionSchema } from "./schema"
|
||||
import { toSessionError } from "./to-session-error"
|
||||
|
|
@ -60,7 +61,7 @@ type Settings = {
|
|||
}
|
||||
|
||||
type Dependencies = {
|
||||
readonly headers?: SessionModelHeaders.Options
|
||||
readonly client: string
|
||||
readonly events: EventV2.Interface
|
||||
readonly llm: {
|
||||
readonly stream: (request: LLMRequest) => Stream.Stream<LLMEvent, LLMError>
|
||||
|
|
@ -259,7 +260,7 @@ const make = (dependencies: Dependencies) => {
|
|||
.stream(
|
||||
LLM.request({
|
||||
model: plan.model,
|
||||
http: { headers: SessionModelHeaders.make(plan.session, dependencies.headers) },
|
||||
http: { headers: SessionModelHeaders.make(plan.session, dependencies.client) },
|
||||
messages: [Message.user(plan.prompt)],
|
||||
tools: [],
|
||||
}),
|
||||
|
|
@ -391,23 +392,20 @@ const make = (dependencies: Dependencies) => {
|
|||
})
|
||||
}
|
||||
|
||||
export const layer = (options?: SessionModelHeaders.Options) => Layer.effect(
|
||||
export const layer = Layer.effect(
|
||||
Service,
|
||||
Effect.gen(function* () {
|
||||
const events = yield* EventV2.Service
|
||||
const llm = yield* LLMClient.Service
|
||||
const config = yield* Config.Service
|
||||
const models = yield* SessionRunnerModel.Service
|
||||
return make({ events, llm, models, config: settings(yield* config.entries()), headers: options })
|
||||
const client = yield* Client.Name
|
||||
return make({ events, llm, models, config: settings(yield* config.entries()), client })
|
||||
}),
|
||||
)
|
||||
|
||||
export function configured(options?: SessionModelHeaders.Options) {
|
||||
return makeLocationNode({
|
||||
service: Service,
|
||||
layer: layer(options),
|
||||
deps: [EventV2.node, llmClient, Config.node, SessionRunnerModel.node],
|
||||
})
|
||||
}
|
||||
|
||||
export const node = configured()
|
||||
export const node = makeLocationNode({
|
||||
service: Service,
|
||||
layer,
|
||||
deps: [EventV2.node, llmClient, Config.node, SessionRunnerModel.node, Client.node],
|
||||
})
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { LLM, LLMClient, Message, SystemPart } from "@opencode-ai/ai"
|
|||
import { Effect, Layer } from "effect"
|
||||
import { Database } from "../database/database"
|
||||
import { makeLocationNode } from "@opencode-ai/util/effect/app-node"
|
||||
import { Client } from "@opencode-ai/util/client"
|
||||
import { llmClient } from "../effect/app-node-platform"
|
||||
import { PluginHooks } from "../plugin/hooks"
|
||||
import { SessionContext } from "./context"
|
||||
|
|
@ -14,7 +15,7 @@ import { SessionRunnerModel } from "./runner/model"
|
|||
import PROMPT_DEFAULT from "./runner/prompt/base.txt"
|
||||
import { toLLMMessages } from "./runner/to-llm-message"
|
||||
|
||||
export const layer = (options?: SessionModelHeaders.Options) => Layer.effect(
|
||||
export const layer = Layer.effect(
|
||||
SessionGenerate.Service,
|
||||
Effect.gen(function* () {
|
||||
const context = yield* SessionContext.Service
|
||||
|
|
@ -22,6 +23,7 @@ export const layer = (options?: SessionModelHeaders.Options) => Layer.effect(
|
|||
const hooks = yield* PluginHooks.Service
|
||||
const llm = yield* LLMClient.Service
|
||||
const models = yield* SessionRunnerModel.Service
|
||||
const client = yield* Client.Name
|
||||
|
||||
return SessionGenerate.Service.of({
|
||||
generate: Effect.fn("SessionGenerate.generate")(function* (input) {
|
||||
|
|
@ -49,7 +51,7 @@ export const layer = (options?: SessionModelHeaders.Options) => Layer.effect(
|
|||
return (yield* llm.generate(
|
||||
LLM.request({
|
||||
model: model.model,
|
||||
http: { headers: SessionModelHeaders.make(selection.session, options) },
|
||||
http: { headers: SessionModelHeaders.make(selection.session, client) },
|
||||
providerOptions: { openai: { promptCacheKey } },
|
||||
system: contextEvent.system,
|
||||
messages: contextEvent.messages,
|
||||
|
|
@ -62,12 +64,8 @@ export const layer = (options?: SessionModelHeaders.Options) => Layer.effect(
|
|||
}),
|
||||
)
|
||||
|
||||
export function configured(options?: SessionModelHeaders.Options) {
|
||||
return makeLocationNode({
|
||||
service: SessionGenerate.Service,
|
||||
layer: layer(options),
|
||||
deps: [SessionContext.node, Database.node, PluginHooks.node, SessionRunnerModel.node, llmClient],
|
||||
})
|
||||
}
|
||||
|
||||
export const node = configured()
|
||||
export const node = makeLocationNode({
|
||||
service: SessionGenerate.Service,
|
||||
layer,
|
||||
deps: [SessionContext.node, Database.node, PluginHooks.node, SessionRunnerModel.node, Client.node, llmClient],
|
||||
})
|
||||
|
|
|
|||
|
|
@ -2,22 +2,13 @@ export * as SessionModelHeaders from "./model-headers"
|
|||
|
||||
import { InstallationVersion } from "@opencode-ai/util/installation/version"
|
||||
import { SessionSchema } from "./schema"
|
||||
import { Schema } from "effect"
|
||||
|
||||
export const Options = Schema.Struct({
|
||||
client: Schema.optional(Schema.String),
|
||||
})
|
||||
export type Options = typeof Options.Type
|
||||
|
||||
export const make = (
|
||||
session: Pick<SessionSchema.Info, "id" | "parentID" | "projectID">,
|
||||
options?: Options,
|
||||
) => ({
|
||||
export const make = (session: Pick<SessionSchema.Info, "id" | "parentID" | "projectID">, client: string) => ({
|
||||
"x-session-affinity": session.id,
|
||||
"X-Session-Id": session.id,
|
||||
...(session.parentID ? { "x-parent-session-id": session.parentID } : {}),
|
||||
"User-Agent": `opencode/${InstallationVersion}`,
|
||||
"x-opencode-project": session.projectID,
|
||||
"x-opencode-session": session.id,
|
||||
"x-opencode-client": options?.client ?? "cli",
|
||||
"x-opencode-client": client,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { LLM, Message, SystemPart, type LLMRequest } from "@opencode-ai/ai"
|
|||
import { SessionError } from "@opencode-ai/schema/session-error"
|
||||
import { Context, Effect, Layer } from "effect"
|
||||
import { makeLocationNode } from "@opencode-ai/util/effect/app-node"
|
||||
import { Client } from "@opencode-ai/util/client"
|
||||
import { PluginHooks } from "../plugin/hooks"
|
||||
import { ToolRegistry } from "../tool/registry"
|
||||
import { SessionContext } from "./context"
|
||||
|
|
@ -39,11 +40,12 @@ export interface Interface {
|
|||
/** Location-scoped outbound model-request preparation. */
|
||||
export class Service extends Context.Service<Service, Interface>()("@opencode/v2/SessionModelRequest") {}
|
||||
|
||||
export const layer = (options?: SessionModelHeaders.Options) => Layer.effect(
|
||||
export const layer = Layer.effect(
|
||||
Service,
|
||||
Effect.gen(function* () {
|
||||
const hooks = yield* PluginHooks.Service
|
||||
const registry = yield* ToolRegistry.Service
|
||||
const client = yield* Client.Name
|
||||
|
||||
const prepare = Effect.fn("SessionModelRequest.prepare")(function* (input: PrepareInput) {
|
||||
const session = input.context.session
|
||||
|
|
@ -81,7 +83,7 @@ export const layer = (options?: SessionModelHeaders.Options) => Layer.effect(
|
|||
const request = LLM.request({
|
||||
model,
|
||||
http: {
|
||||
headers: SessionModelHeaders.make(session, options),
|
||||
headers: SessionModelHeaders.make(session, client),
|
||||
},
|
||||
providerOptions: { openai: { promptCacheKey } },
|
||||
system: contextEvent.system,
|
||||
|
|
@ -112,8 +114,8 @@ export const layer = (options?: SessionModelHeaders.Options) => Layer.effect(
|
|||
}),
|
||||
)
|
||||
|
||||
export function configured(options?: SessionModelHeaders.Options) {
|
||||
return makeLocationNode({ service: Service, layer: layer(options), deps: [PluginHooks.node, ToolRegistry.node] })
|
||||
}
|
||||
|
||||
export const node = configured()
|
||||
export const node = makeLocationNode({
|
||||
service: Service,
|
||||
layer,
|
||||
deps: [PluginHooks.node, ToolRegistry.node, Client.node],
|
||||
})
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { AgentV2 } from "../agent"
|
|||
import { Database } from "../database/database"
|
||||
import { EventV2 } from "../event"
|
||||
import { makeLocationNode } from "@opencode-ai/util/effect/app-node"
|
||||
import { Client } from "@opencode-ai/util/client"
|
||||
import { llmClient } from "../effect/app-node-platform"
|
||||
import { SessionEvent } from "./event"
|
||||
import { SessionHistory } from "./history"
|
||||
|
|
@ -17,7 +18,7 @@ import { SessionUsage } from "./usage"
|
|||
const MAX_LENGTH = 100
|
||||
|
||||
type Dependencies = {
|
||||
readonly headers?: SessionModelHeaders.Options
|
||||
readonly client: string
|
||||
readonly events: EventV2.Interface
|
||||
readonly llm: {
|
||||
readonly stream: (request: LLMRequest) => Stream.Stream<LLMEvent, LLMError>
|
||||
|
|
@ -67,7 +68,7 @@ const make = (dependencies: Dependencies) => {
|
|||
.stream(
|
||||
LLM.request({
|
||||
model: resolved.model,
|
||||
http: { headers: SessionModelHeaders.make(session, dependencies.headers) },
|
||||
http: { headers: SessionModelHeaders.make(session, dependencies.client) },
|
||||
system: agent.system,
|
||||
messages: [Message.user(firstUser.text)],
|
||||
tools: [],
|
||||
|
|
@ -103,7 +104,7 @@ const make = (dependencies: Dependencies) => {
|
|||
return { generateForFirstPrompt }
|
||||
}
|
||||
|
||||
export const layer = (options?: SessionModelHeaders.Options) => Layer.effect(
|
||||
export const layer = Layer.effect(
|
||||
Service,
|
||||
Effect.gen(function* () {
|
||||
const events = yield* EventV2.Service
|
||||
|
|
@ -111,19 +112,16 @@ export const layer = (options?: SessionModelHeaders.Options) => Layer.effect(
|
|||
const agents = yield* AgentV2.Service
|
||||
const models = yield* SessionRunnerModel.Service
|
||||
const database = yield* Database.Service
|
||||
const title = make({ events, llm, agents, models, headers: options })
|
||||
const client = yield* Client.Name
|
||||
const title = make({ events, llm, agents, models, client })
|
||||
return Service.of({
|
||||
generateForFirstPrompt: (session) => title.generateForFirstPrompt(database.db, session),
|
||||
})
|
||||
}),
|
||||
)
|
||||
|
||||
export function configured(options?: SessionModelHeaders.Options) {
|
||||
return makeLocationNode({
|
||||
service: Service,
|
||||
layer: layer(options),
|
||||
deps: [EventV2.node, llmClient, AgentV2.node, SessionRunnerModel.node, Database.node],
|
||||
})
|
||||
}
|
||||
|
||||
export const node = configured()
|
||||
export const node = makeLocationNode({
|
||||
service: Service,
|
||||
layer,
|
||||
deps: [EventV2.node, llmClient, AgentV2.node, SessionRunnerModel.node, Database.node, Client.node],
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue