fix(effect): add effect bridge for callback contexts (#22504)

This commit is contained in:
Kit Langton
2026-04-15 11:22:34 -04:00
committed by GitHub
parent f06d82b6e8
commit f1751401aa
14 changed files with 499 additions and 399 deletions

View File

@@ -25,7 +25,7 @@ import { Bus } from "@/bus"
import { TuiEvent } from "@/cli/cmd/tui/event"
import open from "open"
import { Effect, Exit, Layer, Option, Context, Stream } from "effect"
import { EffectLogger } from "@/effect/logger"
import { EffectBridge } from "@/effect/bridge"
import { InstanceState } from "@/effect/instance-state"
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"
import * as CrossSpawnSpawner from "@/effect/cross-spawn-spawner"
@@ -471,25 +471,24 @@ export namespace MCP {
Effect.catch(() => Effect.succeed([] as number[])),
)
function watch(s: State, name: string, client: MCPClient, timeout?: number) {
function watch(s: State, name: string, client: MCPClient, bridge: EffectBridge.Shape, timeout?: number) {
client.setNotificationHandler(ToolListChangedNotificationSchema, async () => {
log.info("tools list changed notification received", { server: name })
if (s.clients[name] !== client || s.status[name]?.status !== "connected") return
const listed = await Effect.runPromise(defs(name, client, timeout).pipe(Effect.provide(EffectLogger.layer)))
const listed = await bridge.promise(defs(name, client, timeout))
if (!listed) return
if (s.clients[name] !== client || s.status[name]?.status !== "connected") return
s.defs[name] = listed
await Effect.runPromise(
bus.publish(ToolsChanged, { server: name }).pipe(Effect.ignore, Effect.provide(EffectLogger.layer)),
)
await bridge.promise(bus.publish(ToolsChanged, { server: name }).pipe(Effect.ignore))
})
}
const state = yield* InstanceState.make<State>(
Effect.fn("MCP.state")(function* () {
const cfg = yield* cfgSvc.get()
const bridge = yield* EffectBridge.make()
const config = cfg.mcp ?? {}
const s: State = {
status: {},
@@ -518,7 +517,7 @@ export namespace MCP {
if (result.mcpClient) {
s.clients[key] = result.mcpClient
s.defs[key] = result.defs!
watch(s, key, result.mcpClient, mcp.timeout)
watch(s, key, result.mcpClient, bridge, mcp.timeout)
}
}),
{ concurrency: "unbounded" },
@@ -565,11 +564,12 @@ export namespace MCP {
listed: MCPToolDef[],
timeout?: number,
) {
const bridge = yield* EffectBridge.make()
yield* closeClient(s, name)
s.status[name] = { status: "connected" }
s.clients[name] = client
s.defs[name] = listed
watch(s, name, client, timeout)
watch(s, name, client, bridge, timeout)
return s.status[name]
})