Something went wrong. Try again.
opencode v2 mirror
Something went wrong. Try again.
TypeScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135export * as Agent from "./agent.js"
import path from "path"import { makeLocationNode } from "@opencode/util/effect/app-node"import { Array, Context, Effect, Layer, Types } from "effect"import { Agent } from "@opencode/schema/agent"import { Global } from "@opencode/util/global"import { Bus } from "./bus.js"import { State } from "./state.js"
const SHELL_OUTPUT_GLOB = (data: string) => path.join(data, "shell", "*", "*")const TOOL_OUTPUT_GLOB = (data: string) => path.join(data, "tool-output", "*")
export const ID = Agent.IDexport type ID = typeof ID.Typeexport const Name = Agent.Nameexport type Name = Agent.Nameexport const defaultID = ID.make("build")
export const Color = Agent.Color
export const Info = Agent.Infoexport type Info = Agent.Info
export { Event } from "@opencode/schema/agent"
export interface Selection { readonly id: ID readonly info: Info | undefined}
type Data = { agents: Map<ID, Types.DeepMutable<Info>> default?: ID}
export type Editor = { list: () => readonly Info[] get: (id: ID) => Info | undefined default: (id: ID | undefined) => void update: (id: ID, fn: (agent: Types.DeepMutable<Info>) => void) => void remove: (id: ID) => void}
export interface Interface extends State.Transformable<Editor> { readonly get: (id: ID) => Effect.Effect<Info | undefined> readonly resolve: (id?: ID | string) => Effect.Effect<Info | undefined> readonly select: (id?: ID | string) => Effect.Effect<Selection> readonly list: () => Effect.Effect<Info[]>}
export class Service extends Context.Service<Service, Interface>()("@opencode/Agent") {}
const layer = Layer.effect( Service, Effect.gen(function* () { const bus = yield* Bus.Service const global = yield* Global.Service const permissions: Info["permissions"] = [ { action: "external_directory", resource: SHELL_OUTPUT_GLOB(global.data), effect: "allow" }, { action: "external_directory", resource: TOOL_OUTPUT_GLOB(global.data), effect: "allow" }, { action: "external_directory", resource: path.join(global.tmp, "*"), effect: "allow" }, { action: "external_directory", resource: path.join(global.config, "*"), effect: "allow" }, ] const state = State.create<Data, Editor>({ name: "agent", initial: () => ({ agents: new Map() }), editor: (editor) => ({ list: () => Array.fromIterable(editor.agents.values()) as Info[], get: (id) => editor.agents.get(id), default: (id) => { editor.default = id }, update: (id, fn) => { const defaults = Info.default(id) const current = editor.agents.get(id) ?? ({ ...defaults, permissions: [...defaults.permissions, ...permissions], } as Types.DeepMutable<Info>) if (!editor.agents.has(id)) editor.agents.set(id, current) fn(current) current.id = id }, remove: (id) => { editor.agents.delete(id) }, }), notify: () => bus.publish(Agent.Event.Updated, {}).pipe(Effect.asVoid), }) const selectable = (agent: Info | undefined) => agent && agent.mode !== "subagent" && !agent.hidden ? agent : undefined const selectedDefault = () => { const data = state.get() const configured = data.default ? selectable(data.agents.get(data.default)) : undefined if (configured) return configured const build = selectable(data.agents.get(ID.make("build"))) if (build) return build for (const agent of data.agents.values()) { const fallback = selectable(agent) if (fallback) return fallback } }
return Service.of({ transform: state.transform, reload: state.reload, get: Effect.fn("Agent.get")(function* (id) { return state.get().agents.get(id) }), resolve: Effect.fnUntraced(function* (id) { if (id !== undefined) return state.get().agents.get(ID.make(id)) return selectedDefault() }), select: Effect.fn("Agent.select")(function* (id) { if (id !== undefined) { const selected = ID.make(id) return { id: selected, info: state.get().agents.get(selected) } } const info = selectedDefault() return { id: info?.id ?? defaultID, info } }), list: Effect.fn("Agent.list")(function* () { const agents = Array.fromIterable(state.get().agents.values()) const selected = selectedDefault() if (!selected) return agents return [selected, ...agents.filter((agent) => agent.id !== selected.id)] }), }) }),)
export const node = makeLocationNode({ service: Service, layer, deps: [Bus.node, Global.node] })