|
|
@@ -1,13 +1,14 @@
|
|
|
import { describe, expect } from "bun:test"
|
|
|
-import { DateTime, Effect, Fiber, Layer, Schema, Stream } from "effect"
|
|
|
+import { Effect, Fiber, Layer, Schema, Stream } from "effect"
|
|
|
import path from "path"
|
|
|
import { Money } from "@opencode-ai/schema/money"
|
|
|
import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
|
|
|
import { LayerNode } from "@opencode-ai/util/effect/layer-node"
|
|
|
import { Global } from "@opencode-ai/util/global"
|
|
|
-import { makeGlobalNode } from "@opencode-ai/util/effect/app-node"
|
|
|
+import { makeGlobalNode, makeLocationNode } from "@opencode-ai/util/effect/app-node"
|
|
|
import { Database } from "@opencode-ai/core/database/database"
|
|
|
import { Bus } from "@opencode-ai/core/bus"
|
|
|
+import { Config } from "@opencode-ai/core/config"
|
|
|
import { Location } from "@opencode-ai/core/location"
|
|
|
import { Model } from "@opencode-ai/core/model"
|
|
|
import { Provider } from "@opencode-ai/core/provider"
|
|
|
@@ -24,12 +25,13 @@ import { SessionRunnerModel } from "@opencode-ai/core/session/runner/model"
|
|
|
import { SessionStore } from "@opencode-ai/core/session/store"
|
|
|
import { PluginRuntime } from "@opencode-ai/core/plugin/runtime"
|
|
|
import { PluginSupervisor } from "@opencode-ai/core/plugin/supervisor"
|
|
|
+import { Permission } from "@opencode-ai/core/permission"
|
|
|
import { SubagentTool } from "@opencode-ai/core/tool/plugin/subagent"
|
|
|
import { Tool } from "@opencode-ai/core/tool"
|
|
|
import { tmpdir } from "./fixture/tmpdir"
|
|
|
import { tempGlobalLayer } from "./fixture/global"
|
|
|
import { testEffect } from "./lib/effect"
|
|
|
-import { executeTool, toolIdentity, waitForTool } from "./lib/tool"
|
|
|
+import { executeTool, registerToolPlugin, toolIdentity } from "./lib/tool"
|
|
|
|
|
|
const childText = "child final response"
|
|
|
const childModel = Model.Ref.make({ id: Model.ID.make("child"), providerID: Provider.ID.make("test") })
|
|
|
@@ -92,23 +94,30 @@ const executionNode = makeGlobalNode({
|
|
|
deps: [Bus.node, SessionStore.node],
|
|
|
})
|
|
|
|
|
|
-const layer = AppNodeBuilder.build(
|
|
|
- LayerNode.group([
|
|
|
- Database.node,
|
|
|
- Bus.node,
|
|
|
- Job.node,
|
|
|
- Session.node,
|
|
|
- SessionExecution.node,
|
|
|
- PluginRuntime.providerNode,
|
|
|
- LocationServiceMap.node,
|
|
|
- ]),
|
|
|
- [
|
|
|
- [SessionExecution.node, executionNode],
|
|
|
- [Global.node, tempGlobalLayer],
|
|
|
- ],
|
|
|
-)
|
|
|
+const subagentPluginSupervisor = makeLocationNode({
|
|
|
+ service: PluginSupervisor.Service,
|
|
|
+ layer: Layer.effect(
|
|
|
+ PluginSupervisor.Service,
|
|
|
+ registerToolPlugin(SubagentTool.Plugin).pipe(Effect.as(PluginSupervisor.Service.of({ flush: Effect.void }))),
|
|
|
+ ),
|
|
|
+ deps: [Agent.node, Config.node, Permission.node, PluginRuntime.node, Tool.node],
|
|
|
+})
|
|
|
|
|
|
-const it = testEffect(layer)
|
|
|
+const nodes = LayerNode.group([
|
|
|
+ Database.node,
|
|
|
+ Bus.node,
|
|
|
+ Job.node,
|
|
|
+ Session.node,
|
|
|
+ SessionExecution.node,
|
|
|
+ PluginRuntime.providerNode,
|
|
|
+ LocationServiceMap.node,
|
|
|
+])
|
|
|
+const replacements = [
|
|
|
+ [SessionExecution.node, executionNode],
|
|
|
+ [Global.node, tempGlobalLayer],
|
|
|
+] satisfies LayerNode.Replacements
|
|
|
+const productionIt = testEffect(AppNodeBuilder.build(nodes, replacements))
|
|
|
+const it = testEffect(AppNodeBuilder.build(nodes, [...replacements, [PluginSupervisor.node, subagentPluginSupervisor]]))
|
|
|
|
|
|
const withSubagent = (location: Location.Ref) =>
|
|
|
Effect.gen(function* () {
|
|
|
@@ -136,7 +145,7 @@ const withSubagent = (location: Location.Ref) =>
|
|
|
})
|
|
|
|
|
|
describe("SubagentTool", () => {
|
|
|
- it.live("registers globally while resolving agents from the caller location", () =>
|
|
|
+ productionIt.live("registers globally while resolving agents from the caller location", () =>
|
|
|
Effect.acquireRelease(
|
|
|
Effect.promise(() => tmpdir()),
|
|
|
(dir) => Effect.promise(() => dir[Symbol.asyncDispose]()),
|
|
|
@@ -150,7 +159,6 @@ describe("SubagentTool", () => {
|
|
|
|
|
|
const locations = yield* LocationServiceMap.Service
|
|
|
const registry = yield* Tool.Service.pipe(Effect.provide(locations.get(parent.location)))
|
|
|
- yield* waitForTool(registry, SubagentTool.name)
|
|
|
expect((yield* registry.snapshot()).definitions.map((tool) => tool.name)).toContain(SubagentTool.name)
|
|
|
expect(
|
|
|
yield* executeTool(registry, {
|
|
|
@@ -186,7 +194,6 @@ describe("SubagentTool", () => {
|
|
|
yield* withSubagent(parent.location)
|
|
|
const locations = yield* LocationServiceMap.Service
|
|
|
const registry = yield* Tool.Service.pipe(Effect.provide(locations.get(parent.location)))
|
|
|
- yield* waitForTool(registry, SubagentTool.name)
|
|
|
|
|
|
expect(
|
|
|
yield* executeTool(registry, {
|
|
|
@@ -229,7 +236,6 @@ describe("SubagentTool", () => {
|
|
|
yield* withSubagent(parent.location)
|
|
|
const locations = yield* LocationServiceMap.Service
|
|
|
const registry = yield* Tool.Service.pipe(Effect.provide(locations.get(parent.location)))
|
|
|
- yield* waitForTool(registry, SubagentTool.name)
|
|
|
|
|
|
const settled = yield* executeTool(registry, {
|
|
|
sessionID: parent.id,
|
|
|
@@ -270,7 +276,6 @@ describe("SubagentTool", () => {
|
|
|
yield* withSubagent(parent.location)
|
|
|
const locations = yield* LocationServiceMap.Service
|
|
|
const registry = yield* Tool.Service.pipe(Effect.provide(locations.get(parent.location)))
|
|
|
- yield* waitForTool(registry, SubagentTool.name)
|
|
|
const progress: Tool.Metadata[] = []
|
|
|
|
|
|
const settled = yield* executeTool(registry, {
|
|
|
@@ -333,7 +338,6 @@ describe("SubagentTool", () => {
|
|
|
yield* withSubagent(parent.location)
|
|
|
const locations = yield* LocationServiceMap.Service
|
|
|
const registry = yield* Tool.Service.pipe(Effect.provide(locations.get(parent.location)))
|
|
|
- yield* waitForTool(registry, SubagentTool.name)
|
|
|
|
|
|
expect(
|
|
|
yield* executeTool(registry, {
|
|
|
@@ -371,7 +375,6 @@ describe("SubagentTool", () => {
|
|
|
yield* withSubagent(parent.location)
|
|
|
const locations = yield* LocationServiceMap.Service
|
|
|
const registry = yield* Tool.Service.pipe(Effect.provide(locations.get(parent.location)))
|
|
|
- yield* waitForTool(registry, SubagentTool.name)
|
|
|
const bus = yield* Bus.Service
|
|
|
const admitted = yield* bus.subscribe(SessionEvent.InputAdmitted).pipe(
|
|
|
Stream.filter((event) => event.data.sessionID === parent.id && event.data.input.type === "synthetic"),
|