chore: merge dev into v2 (#34788)
Co-authored-by: Brendan Allan <14191578+Brendonovich@users.noreply.github.com> Co-authored-by: Kit Langton <kit.langton@gmail.com> Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com> Co-authored-by: Affan Ali <93028901+affanali2k3@users.noreply.github.com> Co-authored-by: affanali2k3 <affanalikhanxx@gmail.com> Co-authored-by: Frank <frank@anoma.ly> Co-authored-by: opencode-agent[bot] <219766164+opencode-agent[bot]@users.noreply.github.com> Co-authored-by: 𝓛𝓲𝓽𝓽𝓵𝓮 𝓕𝓻𝓪𝓷𝓴 <little-frank@opencord.local> Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> Co-authored-by: Jay V <air@live.ca> Co-authored-by: Dax Raad <d@ironbay.co> Co-authored-by: Aarav Sareen <96787824+arvsrn@users.noreply.github.com> Co-authored-by: OpeOginni <107570612+OpeOginni@users.noreply.github.com> Co-authored-by: Luke Parker <10430890+Hona@users.noreply.github.com> Co-authored-by: Ben Guthrie <benjee.012@gmail.com> Co-authored-by: Dax <mail@thdxr.com> Co-authored-by: Filip <34747899+neriousy@users.noreply.github.com> Co-authored-by: Max Anderson <max.a.anderson95@gmail.com> Co-authored-by: Brendan Allan <git@brendonovich.dev> Co-authored-by: Jack <jack@anoma.ly> Co-authored-by: Shoubhit Dash <shoubhit2005@gmail.com> Co-authored-by: Dustin Deus <deusdustin@gmail.com> Co-authored-by: starptech <starptech@starptechs-MBP.fritz.box> Co-authored-by: Aiden Cline <aidenpcline@gmail.com> Co-authored-by: usrnk1 <7547651+usrnk1@users.noreply.github.com> Co-authored-by: Jay <53023+jayair@users.noreply.github.com> Co-authored-by: runvip <164729189+runvip@users.noreply.github.com> Co-authored-by: opencode <opencode@sst.dev> Co-authored-by: Julian Coy <julian@ex-machina.co> Co-authored-by: Vladimir Glafirov <vglafirov@gitlab.com>
This commit is contained in:
@@ -9,13 +9,10 @@ import { InstanceRef } from "../../src/effect/instance-ref"
|
||||
import { HttpClientRequest, HttpClientResponse } from "effect/unstable/http"
|
||||
import z from "zod"
|
||||
import { LLM } from "../../src/session/llm"
|
||||
import { LLMClient, RequestExecutor, WebSocketExecutor } from "@opencode-ai/llm/route"
|
||||
import { Auth } from "@/auth"
|
||||
import { Config } from "@/config/config"
|
||||
import { LLMClient, RequestExecutor } from "@opencode-ai/llm/route"
|
||||
import { Provider } from "@/provider/provider"
|
||||
import { ProviderTransform } from "@/provider/transform"
|
||||
import { ModelsDev } from "@opencode-ai/core/models-dev"
|
||||
import { Plugin } from "@/plugin"
|
||||
|
||||
import { testEffect } from "../lib/effect"
|
||||
import type { Agent } from "../../src/agent/agent"
|
||||
@@ -27,6 +24,9 @@ import { LLMAISDK } from "@/session/llm/ai-sdk"
|
||||
import { Session as SessionNs } from "@/session/session"
|
||||
import { ProviderV2 } from "@opencode-ai/core/provider"
|
||||
import { ModelV2 } from "@opencode-ai/core/model"
|
||||
import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
|
||||
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
||||
import { LayerNodePlatform } from "@opencode-ai/core/effect/app-node-platform"
|
||||
|
||||
type ConfigModel = NonNullable<NonNullable<ConfigV1.Info["provider"]>[string]["models"]>[string]
|
||||
|
||||
@@ -52,15 +52,13 @@ const openAIConfig = (model: ModelsDev.Provider["models"][string], baseURL: stri
|
||||
}
|
||||
}
|
||||
|
||||
const it = testEffect(Layer.mergeAll(LLM.defaultLayer, Provider.defaultLayer))
|
||||
const it = testEffect(AppNodeBuilder.build(LayerNode.group([LLM.node, Provider.node])))
|
||||
|
||||
// LLM.stream returns a Stream, not an Effect, so we can't use the serviceUse proxy.
|
||||
const drain = (input: LLM.StreamInput) => LLM.Service.use((svc) => svc.stream(input).pipe(Stream.runDrain))
|
||||
|
||||
// drainWith builds an isolated runtime so the custom layer fully owns LLM and
|
||||
// its transitive deps — `Effect.provide(layer)` over an existing runtime layers
|
||||
// the new services on top, but transitive Service overrides (e.g. RequestExecutor)
|
||||
// resolved through the outer LLM.defaultLayer leak through.
|
||||
// drainWith builds an isolated runtime so custom replacements fully own LLM and
|
||||
// its transitive deps.
|
||||
const drainWith = (layer: Layer.Layer<LLM.Service>, input: LLM.StreamInput) =>
|
||||
Effect.gen(function* () {
|
||||
const ctx = yield* InstanceRef
|
||||
@@ -75,15 +73,16 @@ const drainWith = (layer: Layer.Layer<LLM.Service>, input: LLM.StreamInput) =>
|
||||
)
|
||||
})
|
||||
|
||||
function llmLayerWithExecutor(executor: Layer.Layer<RequestExecutor.Service>, flags: Partial<RuntimeFlags.Info> = {}) {
|
||||
return LLM.layer.pipe(
|
||||
Layer.provide(Auth.defaultLayer),
|
||||
Layer.provide(Config.defaultLayer),
|
||||
Layer.provide(Provider.defaultLayer),
|
||||
Layer.provide(Plugin.defaultLayer),
|
||||
Layer.provide(LLMClient.layer.pipe(Layer.provide(Layer.mergeAll(executor, WebSocketExecutor.layer)))),
|
||||
Layer.provide(RuntimeFlags.layer(flags)),
|
||||
)
|
||||
function llmLayerWithExecutor(
|
||||
options: {
|
||||
executor?: Layer.Layer<RequestExecutor.Service>
|
||||
flags?: Partial<RuntimeFlags.Info>
|
||||
} = {},
|
||||
) {
|
||||
return AppNodeBuilder.build(LLM.node, [
|
||||
[RuntimeFlags.node, RuntimeFlags.layer(options.flags)],
|
||||
...(options.executor ? ([[LayerNodePlatform.requestExecutor, options.executor]] as const) : []),
|
||||
])
|
||||
}
|
||||
|
||||
describe("session.llm.hasToolCalls", () => {
|
||||
@@ -1129,14 +1128,10 @@ describe("session.llm.stream", () => {
|
||||
} satisfies Agent.Info
|
||||
|
||||
yield* drainWith(
|
||||
LLM.layer.pipe(
|
||||
Layer.provide(Auth.defaultLayer),
|
||||
Layer.provide(Config.defaultLayer),
|
||||
Layer.provide(Provider.defaultLayer),
|
||||
Layer.provide(Plugin.defaultLayer),
|
||||
Layer.provide(failingNativeClient),
|
||||
Layer.provide(RuntimeFlags.layer({ experimentalNativeLlm: false })),
|
||||
),
|
||||
AppNodeBuilder.build(LLM.node, [
|
||||
[LayerNodePlatform.llmClient, failingNativeClient],
|
||||
[RuntimeFlags.node, RuntimeFlags.layer({ experimentalNativeLlm: false })],
|
||||
]),
|
||||
{
|
||||
user: {
|
||||
id: MessageID.make("msg_user-native-flag-off"),
|
||||
@@ -1199,7 +1194,7 @@ describe("session.llm.stream", () => {
|
||||
temperature: 0.2,
|
||||
} satisfies Agent.Info
|
||||
|
||||
yield* drainWith(llmLayerWithExecutor(RequestExecutor.defaultLayer, { experimentalNativeLlm: true }), {
|
||||
yield* drainWith(llmLayerWithExecutor({ flags: { experimentalNativeLlm: true } }), {
|
||||
user: {
|
||||
id: MessageID.make("msg_user-native"),
|
||||
sessionID,
|
||||
@@ -1282,7 +1277,7 @@ describe("session.llm.stream", () => {
|
||||
permission: [{ permission: "*", pattern: "*", action: "allow" }],
|
||||
} satisfies Agent.Info
|
||||
|
||||
yield* drainWith(llmLayerWithExecutor(executor, { experimentalNativeLlm: true }), {
|
||||
yield* drainWith(llmLayerWithExecutor({ executor, flags: { experimentalNativeLlm: true } }), {
|
||||
user: {
|
||||
id: MessageID.make("msg_user-native-injected-tool"),
|
||||
sessionID,
|
||||
@@ -1371,7 +1366,7 @@ describe("session.llm.stream", () => {
|
||||
permission: [{ permission: "*", pattern: "*", action: "allow" }],
|
||||
} satisfies Agent.Info
|
||||
|
||||
yield* drainWith(llmLayerWithExecutor(RequestExecutor.defaultLayer, { experimentalNativeLlm: true }), {
|
||||
yield* drainWith(llmLayerWithExecutor({ flags: { experimentalNativeLlm: true } }), {
|
||||
user: {
|
||||
id: MessageID.make("msg_user-native-tool"),
|
||||
sessionID,
|
||||
|
||||
Reference in New Issue
Block a user