forked from anomalyco/opencode
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathagent.ts
More file actions
111 lines (98 loc) · 3.52 KB
/
Copy pathagent.ts
File metadata and controls
111 lines (98 loc) · 3.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
export * as AgentV2 from "./agent"
import { makeLocationNode } from "./effect/app-node"
import { Array, Context, Effect, Layer, Types } from "effect"
import { Agent } from "@opencode-ai/schema/agent"
import { State } from "./state"
export const ID = Agent.ID
export type ID = typeof ID.Type
export const defaultID = ID.make("build")
export const Color = Agent.Color
export const Info = Agent.Info
export type Info = Agent.Info
export interface Selection {
readonly id: ID
readonly info: Info | undefined
}
type Data = {
agents: Map<ID, Types.DeepMutable<Info>>
default?: ID
}
export type Draft = {
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<Draft> {
readonly get: (id: ID) => Effect.Effect<Info | undefined>
readonly default: () => Effect.Effect<Info | undefined>
readonly resolve: (id?: ID | string) => Effect.Effect<Info | undefined>
readonly select: (id?: ID | string) => Effect.Effect<Selection>
readonly all: () => Effect.Effect<Info[]>
}
export class Service extends Context.Service<Service, Interface>()("@opencode/v2/Agent") {}
const layer = Layer.effect(
Service,
Effect.gen(function* () {
const state = State.create<Data, Draft>({
initial: () => ({ agents: new Map() }),
draft: (draft) => ({
list: () => Array.fromIterable(draft.agents.values()) as Info[],
get: (id) => draft.agents.get(id),
default: (id) => {
draft.default = id
},
update: (id, fn) => {
const current = draft.agents.get(id) ?? (Info.empty(id) as Types.DeepMutable<Info>)
if (!draft.agents.has(id)) draft.agents.set(id, current)
fn(current)
current.id = id
},
remove: (id) => {
draft.agents.delete(id)
},
}),
})
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("AgentV2.get")(function* (id) {
return state.get().agents.get(id)
}),
default: Effect.fn("AgentV2.default")(function* () {
return selectedDefault()
}),
resolve: Effect.fn("AgentV2.resolve")(function* (id) {
if (id !== undefined) return state.get().agents.get(ID.make(id))
return selectedDefault()
}),
select: Effect.fn("AgentV2.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 }
}),
all: Effect.fn("AgentV2.all")(function* () {
return Array.fromIterable(state.get().agents.values())
}),
})
}),
)
export const locationLayer = layer
export const node = makeLocationNode({ service: Service, layer, deps: [] })