1import type * as Context from "effect/Context";
2import * as Effect from "effect/Effect";
3import type { RuntimeContext } from "../RuntimeContext.ts";
4import { effectClass } from "../Util/effect.ts";
5import type { ToolImpl } from "./Tool.ts";
6
7export type Services<Refs extends any[]> = Refs[number] extends infer A
8 ? A extends
9 | ToolImpl<infer _T, infer _Err, infer Req>
10 | Context.Service<infer Req, infer _Shape>
11 ? Req
12 : never
13 : never;
14
15export interface Agent<
16 Name extends string = string,
17 Refs extends any[] = any[],
18 Service = AgentService,
19 Req = never,
20> {
21 [Symbol.iterator](): Effect.EffectIterator<
22 Effect.Effect<Service, never, Req>
23 >;
24 "~alchemy/Kind": "Agent";
25 name: Name;
26 refs: Refs;
27 req: Services<Refs>;
28 new (): AgentService;
29}
30
31export interface AgentService {
32 send(request: {
33 input: any;
34 session?: string;
35 }): Effect.Effect<void, never, RuntimeContext>;
36}
37
38export const Agent: {
39 <Self>(): {
40 <Name extends string>(
41 id: Name,
42 ): {
43 <const Refs extends any[]>(
44 template: TemplateStringsArray,
45 ...refs: Refs
46 ): Agent<Name, Refs, Self, Services<Refs>>;
47 };
48 };
49 <Name extends string>(
50 id: Name,
51 ): {
52 <Refs extends any[]>(
53 template: TemplateStringsArray,
54 ...refs: Refs
55 ): Agent<Name, Refs, AgentService, Services<Refs>>;
56 };
57} = ((name?: string) =>
58 name
59 ? (template: TemplateStringsArray, ...refs: any[]) =>
60 makeAgent(name, template, refs)
61 : (name: string) =>
62 (template: TemplateStringsArray, ...refs: any[]) =>
63 makeAgent(name, template, refs)) as any;
64
65const makeAgent = (name: string, template: TemplateStringsArray, refs: any[]) =>
66 Object.assign(
67 effectClass(
68 Effect.gen(function* () {
69 // TODO(sam): implement the agent
70 }),
71 ),
72 {
73 "~alchemy/Kind": "Agent",
74 "~alchemy/Name": name,
75 refs,
76 template,
77 },
78 ) as any;