chore(core): checkpoint model capability defaults

This commit is contained in:
Aiden Cline 2026-07-07 21:19:14 -05:00
commit 0030028ebc
14 changed files with 380 additions and 28 deletions

View file

@ -38,6 +38,7 @@ import { SessionRunnerModel } from "@opencode-ai/core/session/runner/model"
import { ToolRegistry } from "@opencode-ai/core/tool/registry"
import { ApplicationTools } from "@opencode-ai/core/tool/application-tools"
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"
@ -155,8 +156,33 @@ const echoNode = makeLocationNode({ name: "test/session-runner-tools", layer: ec
let modelResolveHook = Effect.void
let currentModel = model
const models = SessionRunnerModel.layerWith((session) =>
modelResolveHook.pipe(Effect.as(session.model?.id === "replacement" ? replacementModel : currentModel)),
modelResolveHook.pipe(
Effect.as(
SessionRunnerModel.resolved(
session.model?.id === "replacement" ? replacementModel : currentModel,
session.model?.variant,
),
),
),
)
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 = SystemContext.Key.make("test/context")
let systemBaseline = "Initial context"
let systemRemoved = false
@ -229,6 +255,7 @@ const runnerLayer = AppNodeBuilder.build(SessionRunnerLLM.node, [
[Snapshot.node, Snapshot.noopLayer],
[LayerNodePlatform.llmClient, client],
[SessionRunnerModel.node, models],
[Catalog.node, catalog],
[SystemContextRegistry.node, systemContext],
[Location.node, Location.boundNode({ directory: AbsolutePath.make("/project") })],
[SkillGuidance.node, skillGuidance],
@ -278,6 +305,7 @@ const it = testEffect(
[LayerNodePlatform.llmClient, client],
[PermissionV2.node, permission],
[SessionRunnerModel.node, models],
[Catalog.node, catalog],
[SystemContextRegistry.node, systemContext],
[Location.node, Location.boundNode({ directory: AbsolutePath.make("/project") })],
[SkillGuidance.node, skillGuidance],
@ -318,6 +346,7 @@ const setup = Effect.gen(function* () {
systemLoadHook = Effect.void
modelResolveHook = Effect.void
currentModel = model
catalogCapabilities = ModelV2.Capabilities.defaults({ tools: true })
skillBaselines.clear()
responses = undefined
streamFailure = undefined
@ -655,6 +684,22 @@ describe("SessionRunnerLLM", () => {
}),
)
it.effect("does not advertise tools to a model without tool capability", () =>
Effect.gen(function* () {
yield* setup
catalogCapabilities = ModelV2.Capabilities.defaults()
const session = yield* SessionV2.Service
yield* session.prompt({ sessionID, prompt: Prompt.make({ text: "No tools" }), resume: false })
requests.length = 0
response = []
yield* session.resume(sessionID)
expect(requests).toHaveLength(1)
expect(requests[0]?.tools).toEqual([])
}),
)
it.effect("retries the first provider turn after system context becomes available", () =>
Effect.gen(function* () {
yield* setup