refactor: isolate legacy flags

This commit is contained in:
Dax Raad 2026-07-20 21:42:02 -04:00
commit 43c08387f1
65 changed files with 282 additions and 147 deletions

View file

@ -60,6 +60,7 @@ type Settings = {
}
type Dependencies = {
readonly headers?: SessionModelHeaders.Options
readonly events: EventV2.Interface
readonly llm: {
readonly stream: (request: LLMRequest) => Stream.Stream<LLMEvent, LLMError>
@ -258,7 +259,7 @@ const make = (dependencies: Dependencies) => {
.stream(
LLM.request({
model: plan.model,
http: { headers: SessionModelHeaders.make(plan.session) },
http: { headers: SessionModelHeaders.make(plan.session, dependencies.headers) },
messages: [Message.user(plan.prompt)],
tools: [],
}),
@ -390,19 +391,23 @@ const make = (dependencies: Dependencies) => {
})
}
export const layer = Layer.effect(
export const layer = (options?: SessionModelHeaders.Options) => 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()) })
return make({ events, llm, models, config: settings(yield* config.entries()), headers: options })
}),
)
export const node = makeLocationNode({
service: Service,
layer,
deps: [EventV2.node, llmClient, Config.node, SessionRunnerModel.node],
})
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()

View file

@ -14,7 +14,7 @@ import { SessionRunnerModel } from "./runner/model"
import PROMPT_DEFAULT from "./runner/prompt/base.txt"
import { toLLMMessages } from "./runner/to-llm-message"
const layer = Layer.effect(
export const layer = (options?: SessionModelHeaders.Options) => Layer.effect(
SessionGenerate.Service,
Effect.gen(function* () {
const context = yield* SessionContext.Service
@ -49,7 +49,7 @@ const layer = Layer.effect(
return (yield* llm.generate(
LLM.request({
model: model.model,
http: { headers: SessionModelHeaders.make(selection.session) },
http: { headers: SessionModelHeaders.make(selection.session, options) },
providerOptions: { openai: { promptCacheKey } },
system: contextEvent.system,
messages: contextEvent.messages,
@ -62,8 +62,12 @@ const layer = Layer.effect(
}),
)
export const node = makeLocationNode({
service: SessionGenerate.Service,
layer,
deps: [SessionContext.node, Database.node, PluginHooks.node, SessionRunnerModel.node, llmClient],
})
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()

View file

@ -1,15 +1,23 @@
export * as SessionModelHeaders from "./model-headers"
import { Flag } from "../flag/flag"
import { InstallationVersion } from "../installation/version"
import { SessionSchema } from "./schema"
import { Schema } from "effect"
export const make = (session: Pick<SessionSchema.Info, "id" | "parentID" | "projectID">) => ({
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,
) => ({
"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": Flag.OPENCODE_CLIENT,
"x-opencode-client": options?.client ?? "cli",
})

View file

@ -39,7 +39,7 @@ export interface Interface {
/** Location-scoped outbound model-request preparation. */
export class Service extends Context.Service<Service, Interface>()("@opencode/v2/SessionModelRequest") {}
const layer = Layer.effect(
export const layer = (options?: SessionModelHeaders.Options) => Layer.effect(
Service,
Effect.gen(function* () {
const hooks = yield* PluginHooks.Service
@ -81,7 +81,7 @@ const layer = Layer.effect(
const request = LLM.request({
model,
http: {
headers: SessionModelHeaders.make(session),
headers: SessionModelHeaders.make(session, options),
},
providerOptions: { openai: { promptCacheKey } },
system: contextEvent.system,
@ -112,8 +112,8 @@ const layer = Layer.effect(
}),
)
export const node = makeLocationNode({
service: Service,
layer,
deps: [PluginHooks.node, ToolRegistry.node],
})
export function configured(options?: SessionModelHeaders.Options) {
return makeLocationNode({ service: Service, layer: layer(options), deps: [PluginHooks.node, ToolRegistry.node] })
}
export const node = configured()

View file

@ -17,6 +17,7 @@ import { SessionUsage } from "./usage"
const MAX_LENGTH = 100
type Dependencies = {
readonly headers?: SessionModelHeaders.Options
readonly events: EventV2.Interface
readonly llm: {
readonly stream: (request: LLMRequest) => Stream.Stream<LLMEvent, LLMError>
@ -66,7 +67,7 @@ const make = (dependencies: Dependencies) => {
.stream(
LLM.request({
model: resolved.model,
http: { headers: SessionModelHeaders.make(session) },
http: { headers: SessionModelHeaders.make(session, dependencies.headers) },
system: agent.system,
messages: [Message.user(firstUser.text)],
tools: [],
@ -102,7 +103,7 @@ const make = (dependencies: Dependencies) => {
return { generateForFirstPrompt }
}
export const layer = Layer.effect(
export const layer = (options?: SessionModelHeaders.Options) => Layer.effect(
Service,
Effect.gen(function* () {
const events = yield* EventV2.Service
@ -110,15 +111,19 @@ export const layer = Layer.effect(
const agents = yield* AgentV2.Service
const models = yield* SessionRunnerModel.Service
const database = yield* Database.Service
const title = make({ events, llm, agents, models })
const title = make({ events, llm, agents, models, headers: options })
return Service.of({
generateForFirstPrompt: (session) => title.generateForFirstPrompt(database.db, session),
})
}),
)
export const node = makeLocationNode({
service: Service,
layer,
deps: [EventV2.node, llmClient, AgentV2.node, SessionRunnerModel.node, Database.node],
})
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()