1import * as Effect from "effect/Effect";
2import * as Layer from "effect/Layer";
3import * as S from "effect/Schema";
4
5import * as Cloudflare from "alchemy/Cloudflare";
6
7import * as AI from "alchemy/AI";
8import { DevBox } from "../DevBox.ts";
9
10export const path = AI.Parameter("path", S.String)`
11The path to the file to search.`;
12
13export const contents = AI.Parameter("contents", S.String)`
14The contents of the file to write.`;
15
16export class WriteFile extends (AI.Tool<WriteFile>()("writeFile")`
17Create or overwrite a file at the given ${path} with the provided ${contents}.`) {}
18
19export const Storage = Cloudflare.R2.Bucket("Storage", { forceDestroy: true });
20
21export const WriteFileR2 = Layer.effect(
22 WriteFile,
23 Effect.gen(function* () {
24 const bucket = yield* Cloudflare.R2.ReadWriteBucket(Storage);
25
26 return ({ path, contents }) =>
27 bucket.put(path, contents).pipe(Effect.orDie);
28 }),
29);
30
31export const WriteFileDevBox = Layer.effect(
32 WriteFile,
33 Effect.gen(function* () {
34 const devBox = yield* DevBox;
35
36 return ({ path, contents }) => devBox.writeFile(path, contents);
37 }),
38);
39
40export class ReadFile extends (AI.Tool("readFile")`
41Read the contents of a file at the given ${path}.`) {}
42
43export class EditFile extends (AI.Tool("editFile")`
44Apply a targeted edit to an existing file by replacing an exact string with a new one.`) {}