clanka 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/README.md +3 -0
  2. package/dist/Agent.d.ts +119 -0
  3. package/dist/Agent.d.ts.map +1 -0
  4. package/dist/Agent.js +240 -0
  5. package/dist/Agent.js.map +1 -0
  6. package/dist/AgentTools.d.ts +246 -0
  7. package/dist/AgentTools.d.ts.map +1 -0
  8. package/dist/AgentTools.js +374 -0
  9. package/dist/AgentTools.js.map +1 -0
  10. package/dist/AgentTools.test.d.ts +2 -0
  11. package/dist/AgentTools.test.d.ts.map +1 -0
  12. package/dist/AgentTools.test.js +147 -0
  13. package/dist/AgentTools.test.js.map +1 -0
  14. package/dist/ApplyPatch.d.ts +27 -0
  15. package/dist/ApplyPatch.d.ts.map +1 -0
  16. package/dist/ApplyPatch.js +343 -0
  17. package/dist/ApplyPatch.js.map +1 -0
  18. package/dist/ApplyPatch.test.d.ts +2 -0
  19. package/dist/ApplyPatch.test.d.ts.map +1 -0
  20. package/dist/ApplyPatch.test.js +99 -0
  21. package/dist/ApplyPatch.test.js.map +1 -0
  22. package/dist/Codex.d.ts +11 -0
  23. package/dist/Codex.d.ts.map +1 -0
  24. package/dist/Codex.js +14 -0
  25. package/dist/Codex.js.map +1 -0
  26. package/dist/CodexAuth.d.ts +68 -0
  27. package/dist/CodexAuth.d.ts.map +1 -0
  28. package/dist/CodexAuth.js +270 -0
  29. package/dist/CodexAuth.js.map +1 -0
  30. package/dist/CodexAuth.test.d.ts +2 -0
  31. package/dist/CodexAuth.test.d.ts.map +1 -0
  32. package/dist/CodexAuth.test.js +425 -0
  33. package/dist/CodexAuth.test.js.map +1 -0
  34. package/dist/Executor.d.ts +20 -0
  35. package/dist/Executor.d.ts.map +1 -0
  36. package/dist/Executor.js +76 -0
  37. package/dist/Executor.js.map +1 -0
  38. package/dist/OutputFormatter.d.ts +11 -0
  39. package/dist/OutputFormatter.d.ts.map +1 -0
  40. package/dist/OutputFormatter.js +5 -0
  41. package/dist/OutputFormatter.js.map +1 -0
  42. package/dist/ToolkitRenderer.d.ts +17 -0
  43. package/dist/ToolkitRenderer.d.ts.map +1 -0
  44. package/dist/ToolkitRenderer.js +25 -0
  45. package/dist/ToolkitRenderer.js.map +1 -0
  46. package/dist/TypeBuilder.d.ts +11 -0
  47. package/dist/TypeBuilder.d.ts.map +1 -0
  48. package/dist/TypeBuilder.js +383 -0
  49. package/dist/TypeBuilder.js.map +1 -0
  50. package/dist/TypeBuilder.test.d.ts +2 -0
  51. package/dist/TypeBuilder.test.d.ts.map +1 -0
  52. package/dist/TypeBuilder.test.js +243 -0
  53. package/dist/TypeBuilder.test.js.map +1 -0
  54. package/dist/index.d.ts +25 -0
  55. package/dist/index.d.ts.map +1 -0
  56. package/dist/index.js +25 -0
  57. package/dist/index.js.map +1 -0
  58. package/package.json +72 -0
  59. package/src/Agent.ts +398 -0
  60. package/src/AgentTools.test.ts +215 -0
  61. package/src/AgentTools.ts +507 -0
  62. package/src/ApplyPatch.test.ts +154 -0
  63. package/src/ApplyPatch.ts +473 -0
  64. package/src/Codex.ts +14 -0
  65. package/src/CodexAuth.test.ts +729 -0
  66. package/src/CodexAuth.ts +571 -0
  67. package/src/Executor.ts +129 -0
  68. package/src/OutputFormatter.ts +17 -0
  69. package/src/ToolkitRenderer.ts +39 -0
  70. package/src/TypeBuilder.test.ts +508 -0
  71. package/src/TypeBuilder.ts +670 -0
  72. package/src/index.ts +29 -0
@@ -0,0 +1,39 @@
1
+ /**
2
+ * @since 1.0.0
3
+ */
4
+ import { Array, Layer, SchemaAST, ServiceMap } from "effect"
5
+ import { Tool, Toolkit } from "effect/unstable/ai"
6
+ import * as TypeBuilder from "./TypeBuilder.ts"
7
+ import { memoize } from "effect/Function"
8
+
9
+ /**
10
+ * @since 1.0.0
11
+ * @category Services
12
+ */
13
+ export class ToolkitRenderer extends ServiceMap.Service<
14
+ ToolkitRenderer,
15
+ {
16
+ render<Tools extends Record<string, Tool.Any>>(
17
+ tools: Toolkit.Toolkit<Tools>,
18
+ ): string
19
+ }
20
+ >()("clanka/ToolkitRenderer") {
21
+ static readonly layer = Layer.succeed(ToolkitRenderer, {
22
+ render: memoize(
23
+ <Tools extends Record<string, Tool.Any>>(
24
+ tools: Toolkit.Toolkit<Tools>,
25
+ ) => {
26
+ const output = Array.empty<string>()
27
+ for (const [name, tool] of Object.entries(tools.tools)) {
28
+ const paramName =
29
+ SchemaAST.resolveIdentifier(tool.parametersSchema.ast) ?? "options"
30
+ output.push(
31
+ `/** ${tool.description} */
32
+ declare function ${name}(${paramName}: ${TypeBuilder.render(tool.parametersSchema)}): Promise<${TypeBuilder.render(tool.successSchema)}>`,
33
+ )
34
+ }
35
+ return output.join("\n\n")
36
+ },
37
+ ),
38
+ })
39
+ }
@@ -0,0 +1,508 @@
1
+ import { Schema } from "effect"
2
+ import { describe, expect, it } from "vitest"
3
+ import * as TypeBuilder from "./TypeBuilder.ts"
4
+
5
+ const lines = (...parts: ReadonlyArray<string>): string => parts.join("\n")
6
+
7
+ const primitiveCases = [
8
+ ["string", Schema.String, "string"],
9
+ ["number", Schema.Number, "number"],
10
+ ["boolean", Schema.Boolean, "boolean"],
11
+ ["bigint", Schema.BigInt, "bigint"],
12
+ ["symbol", Schema.Symbol, "symbol"],
13
+ ["any", Schema.Any, "any"],
14
+ ["unknown", Schema.Unknown, "unknown"],
15
+ ["void", Schema.Void, "void"],
16
+ ["never", Schema.Never, "never"],
17
+ ["undefined", Schema.Undefined, "undefined"],
18
+ ["null", Schema.Null, "null"],
19
+ ["object", Schema.ObjectKeyword, "object"],
20
+ ] as const satisfies ReadonlyArray<
21
+ readonly [name: string, schema: Schema.Top, expected: string]
22
+ >
23
+
24
+ const literalCases = [
25
+ ["string literals", Schema.Literal("hello"), '"hello"'],
26
+ ["number literals", Schema.Literal(42), "42"],
27
+ ["boolean literals", Schema.Literal(true), "true"],
28
+ ["bigint literals", Schema.Literal(42n), "42n"],
29
+ ["negative zero literals", Schema.Literal(-0), "-0"],
30
+ ["negative number literals", Schema.Literal(-42), "-42"],
31
+ ["negative bigint literals", Schema.Literal(-42n), "-42n"],
32
+ ] as const satisfies ReadonlyArray<
33
+ readonly [name: string, schema: Schema.Top, expected: string]
34
+ >
35
+
36
+ describe("TypeBuilder", () => {
37
+ for (const [name, schema, expected] of primitiveCases) {
38
+ it(`renders ${name}`, () => {
39
+ expect(TypeBuilder.render(schema)).toBe(expected)
40
+ })
41
+ }
42
+
43
+ for (const [name, schema, expected] of literalCases) {
44
+ it(`renders ${name}`, () => {
45
+ expect(TypeBuilder.render(schema)).toBe(expected)
46
+ })
47
+ }
48
+
49
+ it("renders described unique symbols", () => {
50
+ expect(TypeBuilder.render(Schema.UniqueSymbol(Symbol("token")))).toBe(
51
+ 'typeof Symbol.for("token")',
52
+ )
53
+ })
54
+
55
+ it("renders anonymous unique symbols", () => {
56
+ expect(TypeBuilder.render(Schema.UniqueSymbol(Symbol()))).toBe(
57
+ "unique symbol",
58
+ )
59
+ })
60
+
61
+ it("renders declarations with identifiers and type parameters", () => {
62
+ expect(
63
+ TypeBuilder.render(
64
+ Schema.Option(Schema.Number).annotate({ identifier: "Option" }),
65
+ ),
66
+ ).toBe("Option<number>")
67
+ })
68
+
69
+ it("falls back to unknown for declarations without identifiers", () => {
70
+ expect(TypeBuilder.render(Schema.URL)).toBe("unknown")
71
+ })
72
+
73
+ it("renders structs", () => {
74
+ expect(
75
+ TypeBuilder.render(
76
+ Schema.Struct({
77
+ name: Schema.String,
78
+ age: Schema.Number,
79
+ }),
80
+ ),
81
+ ).toBe(
82
+ lines(
83
+ "{",
84
+ " readonly name: string;",
85
+ " readonly age: number;",
86
+ "}",
87
+ ),
88
+ )
89
+ })
90
+
91
+ it("renders optional properties", () => {
92
+ expect(
93
+ TypeBuilder.render(
94
+ Schema.Struct({
95
+ nickname: Schema.optionalKey(Schema.String),
96
+ }),
97
+ ),
98
+ ).toBe(lines("{", " readonly nickname?: string;", "}"))
99
+ })
100
+
101
+ it("renders mutable properties", () => {
102
+ expect(
103
+ TypeBuilder.render(
104
+ Schema.Struct({
105
+ count: Schema.mutableKey(Schema.Number),
106
+ }),
107
+ ),
108
+ ).toBe(lines("{", " count: number;", "}"))
109
+ })
110
+
111
+ it("renders symbol property keys", () => {
112
+ const token = Symbol("token")
113
+
114
+ expect(
115
+ TypeBuilder.render(
116
+ Schema.Struct({
117
+ [token]: Schema.String,
118
+ }),
119
+ ),
120
+ ).toBe(lines("{", ' readonly [Symbol.for("token")]: string;', "}"))
121
+ })
122
+
123
+ it("renders records", () => {
124
+ expect(
125
+ TypeBuilder.render(Schema.Record(Schema.String, Schema.Number)),
126
+ ).toBe(lines("{", " [x: string]: number;", "}"))
127
+ })
128
+
129
+ it("renders structs with rest records", () => {
130
+ expect(
131
+ TypeBuilder.render(
132
+ Schema.StructWithRest(Schema.Struct({ name: Schema.String }), [
133
+ Schema.Record(Schema.String, Schema.Boolean),
134
+ ]),
135
+ ),
136
+ ).toBe(
137
+ lines(
138
+ "{",
139
+ " readonly name: string;",
140
+ " [x: string]: boolean;",
141
+ "}",
142
+ ),
143
+ )
144
+ })
145
+
146
+ it("renders nested object types", () => {
147
+ expect(
148
+ TypeBuilder.render(
149
+ Schema.Struct({
150
+ meta: Schema.Struct({
151
+ count: Schema.Number,
152
+ }),
153
+ }),
154
+ ),
155
+ ).toBe(
156
+ lines(
157
+ "{",
158
+ " readonly meta: {",
159
+ " readonly count: number;",
160
+ " };",
161
+ "}",
162
+ ),
163
+ )
164
+ })
165
+
166
+ it("renders readonly arrays", () => {
167
+ expect(TypeBuilder.render(Schema.Array(Schema.String))).toBe(
168
+ "readonly string[]",
169
+ )
170
+ })
171
+
172
+ it("renders mutable arrays", () => {
173
+ expect(
174
+ TypeBuilder.render(Schema.mutable(Schema.Array(Schema.String))),
175
+ ).toBe("string[]")
176
+ })
177
+
178
+ it("parenthesizes union element arrays", () => {
179
+ expect(
180
+ TypeBuilder.render(
181
+ Schema.Array(Schema.Union([Schema.Number, Schema.Boolean])),
182
+ ),
183
+ ).toBe("readonly (number | boolean)[]")
184
+ })
185
+
186
+ it("parenthesizes nested readonly array element types", () => {
187
+ expect(TypeBuilder.render(Schema.Array(Schema.Array(Schema.String)))).toBe(
188
+ "readonly (readonly string[])[]",
189
+ )
190
+ })
191
+
192
+ it("parenthesizes nested readonly tuple element types", () => {
193
+ expect(
194
+ TypeBuilder.render(Schema.Array(Schema.Tuple([Schema.String]))),
195
+ ).toBe(lines("readonly (readonly [", " string", "])[]"))
196
+ })
197
+
198
+ it("parenthesizes unique symbol array element types", () => {
199
+ expect(
200
+ TypeBuilder.render(Schema.Array(Schema.UniqueSymbol(Symbol()))),
201
+ ).toBe("readonly (unique symbol)[]")
202
+ expect(
203
+ TypeBuilder.render(Schema.Array(Schema.UniqueSymbol(Symbol("token")))),
204
+ ).toBe('readonly (typeof Symbol.for("token"))[]')
205
+ })
206
+
207
+ it("renders readonly tuples", () => {
208
+ expect(
209
+ TypeBuilder.render(Schema.Tuple([Schema.String, Schema.Number])),
210
+ ).toBe(lines("readonly [", " string,", " number", "]"))
211
+ })
212
+
213
+ it("renders mutable tuples", () => {
214
+ expect(
215
+ TypeBuilder.render(
216
+ Schema.mutable(Schema.Tuple([Schema.String, Schema.Number])),
217
+ ),
218
+ ).toBe(lines("[", " string,", " number", "]"))
219
+ })
220
+
221
+ it("renders optional tuple elements", () => {
222
+ expect(
223
+ TypeBuilder.render(
224
+ Schema.Tuple([Schema.String, Schema.optional(Schema.Number)]),
225
+ ),
226
+ ).toBe(lines("readonly [", " string,", " number?", "]"))
227
+ })
228
+
229
+ it("renders tuples with rest elements", () => {
230
+ expect(
231
+ TypeBuilder.render(
232
+ Schema.TupleWithRest(Schema.Tuple([Schema.String]), [
233
+ Schema.Number,
234
+ Schema.Boolean,
235
+ ]),
236
+ ),
237
+ ).toBe(
238
+ lines(
239
+ "readonly [",
240
+ " string,",
241
+ " ...number[],",
242
+ " boolean",
243
+ "]",
244
+ ),
245
+ )
246
+ })
247
+
248
+ it("renders unions", () => {
249
+ expect(
250
+ TypeBuilder.render(Schema.Union([Schema.String, Schema.Number])),
251
+ ).toBe("string | number")
252
+ })
253
+
254
+ it("renders empty unions as never", () => {
255
+ expect(TypeBuilder.render(Schema.Union([]))).toBe("never")
256
+ })
257
+
258
+ it("renders single-member unions without separators", () => {
259
+ expect(TypeBuilder.render(Schema.Union([Schema.String]))).toBe("string")
260
+ })
261
+
262
+ it("renders literal unions", () => {
263
+ expect(TypeBuilder.render(Schema.Literals(["a", "b"]))).toBe('"a" | "b"')
264
+ })
265
+
266
+ it("renders enums as unions of member values", () => {
267
+ expect(
268
+ TypeBuilder.render(
269
+ Schema.Enum({
270
+ Apple: "apple",
271
+ Banana: "banana",
272
+ }),
273
+ ),
274
+ ).toBe('"apple" | "banana"')
275
+ })
276
+
277
+ it("renders numeric enums as literal unions", () => {
278
+ expect(
279
+ TypeBuilder.render(
280
+ Schema.Enum({
281
+ Ok: 200,
282
+ NotFound: 404,
283
+ }),
284
+ ),
285
+ ).toBe("200 | 404")
286
+ })
287
+
288
+ it("renders numeric enum reverse mappings as literal unions", () => {
289
+ expect(
290
+ TypeBuilder.render(
291
+ Schema.Enum({
292
+ 200: "Ok",
293
+ 404: "NotFound",
294
+ Ok: 200,
295
+ NotFound: 404,
296
+ }),
297
+ ),
298
+ ).toBe("200 | 404")
299
+ })
300
+
301
+ it("renders template literals with interpolations", () => {
302
+ expect(
303
+ TypeBuilder.render(Schema.TemplateLiteral(["user_", Schema.String])),
304
+ ).toBe("`user_${string}`")
305
+ })
306
+
307
+ it("renders template literals that start with interpolations", () => {
308
+ expect(
309
+ TypeBuilder.render(Schema.TemplateLiteral([Schema.String, "_suffix"])),
310
+ ).toBe("`${string}_suffix`")
311
+ })
312
+
313
+ it("renders all-literal template literals as string literals", () => {
314
+ expect(
315
+ TypeBuilder.render(Schema.TemplateLiteral(["user_", 42n, "_", 7])),
316
+ ).toBe('"user_42_7"')
317
+ })
318
+
319
+ it("flattens nested template literals", () => {
320
+ expect(
321
+ TypeBuilder.render(
322
+ Schema.TemplateLiteral([
323
+ "a",
324
+ Schema.TemplateLiteral(["b", Schema.Number]),
325
+ "c",
326
+ ]),
327
+ ),
328
+ ).toBe("`ab${number}c`")
329
+ })
330
+
331
+ it("renders unions inside template literal interpolations", () => {
332
+ expect(
333
+ TypeBuilder.render(
334
+ Schema.TemplateLiteral([
335
+ Schema.String,
336
+ Schema.Union([Schema.Literal("-"), Schema.Literal("_")]),
337
+ Schema.Number,
338
+ ]),
339
+ ),
340
+ ).toBe('`${string}${"-" | "_"}${number}`')
341
+ })
342
+
343
+ it("renders optional tuple elements with union members", () => {
344
+ expect(
345
+ TypeBuilder.render(
346
+ Schema.Tuple([
347
+ Schema.String,
348
+ Schema.optional(Schema.Union([Schema.Number, Schema.Boolean])),
349
+ ]),
350
+ ),
351
+ ).toBe(lines("readonly [", " string,", " (number | boolean)?", "]"))
352
+ })
353
+
354
+ it("renders tuples with composite rest element types", () => {
355
+ expect(
356
+ TypeBuilder.render(
357
+ Schema.TupleWithRest(Schema.Tuple([Schema.String]), [
358
+ Schema.Union([Schema.Number, Schema.Boolean]),
359
+ Schema.Boolean,
360
+ ]),
361
+ ),
362
+ ).toBe(
363
+ lines(
364
+ "readonly [",
365
+ " string,",
366
+ " ...(number | boolean)[],",
367
+ " boolean",
368
+ "]",
369
+ ),
370
+ )
371
+ })
372
+
373
+ it("renders recursive suspends using identifier annotations", () => {
374
+ type Category = {
375
+ readonly child?: Category
376
+ }
377
+
378
+ const Category: Schema.Schema<Category> = Schema.suspend(
379
+ (): Schema.Schema<Category> =>
380
+ Schema.Struct({
381
+ child: Schema.optionalKey(Category),
382
+ }).annotate({ identifier: "Category" }),
383
+ )
384
+
385
+ expect(TypeBuilder.render(Category)).toBe(
386
+ lines("{", " readonly child?: Category;", "}"),
387
+ )
388
+ })
389
+
390
+ it("renders recursive arrays using identifier annotations", () => {
391
+ type Category = {
392
+ readonly children: ReadonlyArray<Category>
393
+ }
394
+
395
+ const Category: Schema.Schema<Category> = Schema.suspend(
396
+ (): Schema.Schema<Category> =>
397
+ Schema.Struct({
398
+ children: Schema.Array(Category),
399
+ }).annotate({ identifier: "Category" }),
400
+ )
401
+
402
+ expect(TypeBuilder.render(Category)).toBe(
403
+ lines("{", " readonly children: readonly Category[];", "}"),
404
+ )
405
+ })
406
+
407
+ it("renders transformed schemas from the decoded side", () => {
408
+ expect(TypeBuilder.render(Schema.NumberFromString)).toBe("number")
409
+ })
410
+
411
+ it("ignores brand annotations", () => {
412
+ expect(TypeBuilder.render(Schema.String.pipe(Schema.brand("UserId")))).toBe(
413
+ "string",
414
+ )
415
+ })
416
+
417
+ it("renders documented fields", () => {
418
+ expect(
419
+ TypeBuilder.render(
420
+ Schema.Struct({
421
+ token: Schema.String.annotate({ documentation: "Primary token" }),
422
+ }),
423
+ ),
424
+ ).toBe(
425
+ lines(
426
+ "{",
427
+ " /** Primary token */",
428
+ " readonly token: string;",
429
+ "}",
430
+ ),
431
+ )
432
+ })
433
+
434
+ it("renders documented primitive schemas at the top level", () => {
435
+ expect(
436
+ TypeBuilder.render(
437
+ Schema.String.annotate({ documentation: "Primary token" }),
438
+ ),
439
+ ).toBe(lines("/** Primary token */", "string"))
440
+ })
441
+
442
+ it("renders documented object schemas at the top level", () => {
443
+ expect(
444
+ TypeBuilder.render(
445
+ Schema.Struct({
446
+ token: Schema.String,
447
+ }).annotate({ documentation: "Token payload" }),
448
+ ),
449
+ ).toBe(
450
+ lines("/** Token payload */", "{", " readonly token: string;", "}"),
451
+ )
452
+ })
453
+
454
+ it("renders documented array schemas at the top level", () => {
455
+ expect(
456
+ TypeBuilder.render(
457
+ Schema.Array(Schema.String).annotate({ documentation: "Token list" }),
458
+ ),
459
+ ).toBe(lines("/** Token list */", "readonly string[]"))
460
+ })
461
+
462
+ it("renders documented recursive schemas at the top level", () => {
463
+ type Category = {
464
+ readonly child?: Category
465
+ }
466
+
467
+ const Category: Schema.Schema<Category> = Schema.suspend(
468
+ (): Schema.Schema<Category> =>
469
+ Schema.Struct({
470
+ child: Schema.optionalKey(Category),
471
+ }).annotate({
472
+ documentation: "Recursive category",
473
+ identifier: "Category",
474
+ }),
475
+ )
476
+
477
+ expect(TypeBuilder.render(Category)).toBe(
478
+ lines(
479
+ "/** Recursive category */",
480
+ "{",
481
+ " readonly child?: Category;",
482
+ "}",
483
+ ),
484
+ )
485
+ })
486
+
487
+ it("supports custom new lines", () => {
488
+ expect(
489
+ TypeBuilder.render(
490
+ Schema.Struct({
491
+ token: Schema.String,
492
+ }),
493
+ { newLine: "\r\n" },
494
+ ),
495
+ ).toBe("{\r\n readonly token: string;\r\n}")
496
+ })
497
+
498
+ it("supports omitting trailing semicolons", () => {
499
+ expect(
500
+ TypeBuilder.render(
501
+ Schema.Struct({
502
+ token: Schema.String,
503
+ }),
504
+ { omitTrailingSemicolon: true },
505
+ ),
506
+ ).toBe(lines("{", " readonly token: string", "}"))
507
+ })
508
+ })