fix(core): preserve model capability semantics

This commit is contained in:
Aiden Cline 2026-07-07 23:33:15 -05:00
commit 44a898f3ee
7 changed files with 27 additions and 59 deletions

View file

@ -42,7 +42,6 @@ import { ToolRegistry } from "@opencode-ai/core/tool/registry"
import { QuestionTool } from "@opencode-ai/core/tool/question"
import { ToolOutputStore } from "@opencode-ai/core/tool-output-store"
import { AgentV2 } from "@opencode-ai/core/agent"
import { Catalog } from "@opencode-ai/core/catalog"
import { Config } from "@opencode-ai/core/config"
import { ConfigCompaction } from "@opencode-ai/core/config/compaction"
import { Tool } from "@opencode-ai/core/tool/tool"
@ -236,34 +235,19 @@ const echo = Layer.effectDiscard(
const echoNode = makeLocationNode({ name: "test/session-runner-tools", layer: echo, deps: [ToolRegistry.node] })
let modelResolveHook = Effect.void
let currentModel = model
let modelCapabilities = ModelV2.Capabilities.defaults()
const models = SessionRunnerModel.layerWith((session) =>
modelResolveHook.pipe(
Effect.as(
SessionRunnerModel.resolved(
session.model?.id === "replacement" ? replacementModel : currentModel,
session.model?.variant,
[],
modelCapabilities,
),
),
),
)
let catalogCapabilities = ModelV2.Capabilities.defaults({ tools: true })
const catalog = Layer.mock(Catalog.Service, {
provider: {
get: () => Effect.die("unused"),
all: () => Effect.die("unused"),
available: () => Effect.die("unused"),
},
model: {
get: (providerID, modelID) =>
Effect.succeed(
ModelV2.Info.make({ ...ModelV2.Info.empty(providerID, modelID), capabilities: catalogCapabilities }),
),
all: () => Effect.die("unused"),
available: () => Effect.die("unused"),
default: () => Effect.die("unused"),
small: () => Effect.die("unused"),
},
})
const systemContextKey = Instructions.Key.make("test/context")
let systemBaseline = "Initial context"
let systemRemoved = false
@ -330,7 +314,6 @@ const runnerLayer = AppNodeBuilder.build(SessionRunnerLLM.node, [
[Snapshot.node, Snapshot.noopLayer],
[LayerNodePlatform.llmClient, client],
[SessionRunnerModel.node, models],
[Catalog.node, catalog],
[InstructionBuiltIns.node, systemContext],
[InstructionDiscovery.node, instructionContext],
[Location.node, Location.boundNode({ directory: AbsolutePath.make("/project") })],
@ -385,7 +368,6 @@ const it = testEffect(
[LayerNodePlatform.llmClient, client],
[PermissionV2.node, permission],
[SessionRunnerModel.node, models],
[Catalog.node, catalog],
[InstructionBuiltIns.node, systemContext],
[InstructionDiscovery.node, instructionContext],
[Location.node, Location.boundNode({ directory: AbsolutePath.make("/project") })],
@ -433,7 +415,7 @@ const setup = Effect.gen(function* () {
systemLoadHook = Effect.void
modelResolveHook = Effect.void
currentModel = model
catalogCapabilities = ModelV2.Capabilities.defaults({ tools: true })
modelCapabilities = ModelV2.Capabilities.defaults()
skillBaselines.clear()
responses = undefined
streamFailure = undefined
@ -812,7 +794,7 @@ describe("SessionRunnerLLM", () => {
it.effect("does not advertise tools to a model without tool capability", () =>
Effect.gen(function* () {
yield* setup
catalogCapabilities = ModelV2.Capabilities.defaults()
modelCapabilities = ModelV2.Capabilities.defaults({ tools: false })
const session = yield* SessionV2.Service
yield* session.prompt({ sessionID, prompt: PromptInput.Prompt.make({ text: "No tools" }), resume: false })