test(core): reproduce explorer tool leak
This commit is contained in:
@@ -3,7 +3,7 @@ import path from "path"
|
||||
import { describe, expect } from "bun:test"
|
||||
import { Config } from "@opencode-ai/schema/config"
|
||||
import { Plugin } from "@opencode-ai/schema/plugin"
|
||||
import { Context, DateTime, Effect, Equal, Hash, RcMap, Schema, Stream } from "effect"
|
||||
import { Context, DateTime, Deferred, Effect, Equal, Hash, RcMap, Schema, Stream } from "effect"
|
||||
import { Plugin as EffectPlugin } from "@opencode-ai/plugin/v2/effect"
|
||||
import { AgentV2 } from "@opencode-ai/core/agent"
|
||||
import { Catalog } from "@opencode-ai/core/catalog"
|
||||
@@ -66,6 +66,42 @@ describe("LocationServiceMap", () => {
|
||||
),
|
||||
)
|
||||
|
||||
itWithSdk.live("does not advertise shell before explorer activation completes", () =>
|
||||
Effect.acquireRelease(
|
||||
Effect.promise(() => tmpdir()),
|
||||
(dir) => Effect.promise(() => dir[Symbol.asyncDispose]()),
|
||||
).pipe(
|
||||
Effect.flatMap((dir) =>
|
||||
Effect.gen(function* () {
|
||||
const started = yield* Deferred.make<void>()
|
||||
const release = yield* Deferred.make<void>()
|
||||
const sdk = yield* SdkPlugins.Service
|
||||
yield* sdk.register(
|
||||
EffectPlugin.define({
|
||||
id: "blocked-initial-activation",
|
||||
effect: () => Deferred.succeed(started, undefined).pipe(Effect.andThen(Deferred.await(release))),
|
||||
}),
|
||||
)
|
||||
|
||||
const locations = yield* LocationServiceMap.Service
|
||||
const context = yield* locations.contextEffect(
|
||||
Location.Ref.make({ directory: AbsolutePath.make(dir.path) }),
|
||||
)
|
||||
yield* Deferred.await(started)
|
||||
|
||||
const tools = yield* Effect.gen(function* () {
|
||||
const agents = yield* AgentV2.Service
|
||||
const registry = yield* ToolRegistry.Service
|
||||
const explorer = yield* agents.select("explore")
|
||||
return yield* toolDefinitions(registry, explorer.info?.permissions)
|
||||
}).pipe(Effect.provide(context), Effect.ensuring(Deferred.succeed(release, undefined)))
|
||||
|
||||
expect(tools.map((tool) => tool.name)).not.toContain("shell")
|
||||
}),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
it.live("applies ordered plugin config operations during boot", () =>
|
||||
Effect.acquireRelease(
|
||||
Effect.promise(() => tmpdir()),
|
||||
|
||||
@@ -1045,6 +1045,37 @@ describe("SessionRunnerLLM", () => {
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("does not advertise unrestricted tools while the selected agent is unavailable", () =>
|
||||
Effect.gen(function* () {
|
||||
yield* setup
|
||||
const { db } = yield* Database.Service
|
||||
const registry = yield* ToolRegistry.Service
|
||||
yield* registry.register({
|
||||
shell: Tool.make({
|
||||
description: "Execute a shell command",
|
||||
input: Schema.Struct({ command: Schema.String }),
|
||||
output: Schema.Struct({}),
|
||||
execute: () => Effect.succeed({}),
|
||||
}),
|
||||
})
|
||||
yield* db
|
||||
.update(SessionTable)
|
||||
.set({ agent: "explore" })
|
||||
.where(eq(SessionTable.id, sessionID))
|
||||
.run()
|
||||
.pipe(Effect.orDie)
|
||||
const session = yield* SessionV2.Service
|
||||
yield* session.prompt({ sessionID, prompt: PromptInput.Prompt.make({ text: "Inspect files" }), resume: false })
|
||||
|
||||
requests.length = 0
|
||||
response = []
|
||||
yield* session.resume(sessionID)
|
||||
|
||||
expect(requests).toHaveLength(1)
|
||||
expect(requests[0]?.tools.map((tool) => tool.name)).not.toContain("shell")
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("updates selected-agent skill guidance after an agent switch", () =>
|
||||
Effect.gen(function* () {
|
||||
const session = yield* setup
|
||||
|
||||
Reference in New Issue
Block a user