@fluidframework/tree-agent 2.81.0-374083 → 2.81.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 (46) hide show
  1. package/CHANGELOG.md +95 -0
  2. package/api-report/tree-agent.alpha.api.md +33 -1
  3. package/dist/alpha.d.ts +5 -0
  4. package/dist/index.d.ts +1 -1
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js.map +1 -1
  7. package/dist/prompt.d.ts +4 -0
  8. package/dist/prompt.d.ts.map +1 -1
  9. package/dist/prompt.js +20 -2
  10. package/dist/prompt.js.map +1 -1
  11. package/dist/renderSchemaTypeScript.d.ts.map +1 -1
  12. package/dist/renderSchemaTypeScript.js +18 -8
  13. package/dist/renderSchemaTypeScript.js.map +1 -1
  14. package/dist/renderTypeFactoryTypeScript.d.ts +1 -1
  15. package/dist/renderTypeFactoryTypeScript.d.ts.map +1 -1
  16. package/dist/renderTypeFactoryTypeScript.js +71 -3
  17. package/dist/renderTypeFactoryTypeScript.js.map +1 -1
  18. package/dist/treeAgentTypes.d.ts +86 -1
  19. package/dist/treeAgentTypes.d.ts.map +1 -1
  20. package/dist/treeAgentTypes.js +37 -0
  21. package/dist/treeAgentTypes.js.map +1 -1
  22. package/lib/alpha.d.ts +5 -0
  23. package/lib/index.d.ts +1 -1
  24. package/lib/index.d.ts.map +1 -1
  25. package/lib/index.js.map +1 -1
  26. package/lib/prompt.d.ts +4 -0
  27. package/lib/prompt.d.ts.map +1 -1
  28. package/lib/prompt.js +20 -2
  29. package/lib/prompt.js.map +1 -1
  30. package/lib/renderSchemaTypeScript.d.ts.map +1 -1
  31. package/lib/renderSchemaTypeScript.js +18 -8
  32. package/lib/renderSchemaTypeScript.js.map +1 -1
  33. package/lib/renderTypeFactoryTypeScript.d.ts +1 -1
  34. package/lib/renderTypeFactoryTypeScript.d.ts.map +1 -1
  35. package/lib/renderTypeFactoryTypeScript.js +71 -3
  36. package/lib/renderTypeFactoryTypeScript.js.map +1 -1
  37. package/lib/treeAgentTypes.d.ts +86 -1
  38. package/lib/treeAgentTypes.d.ts.map +1 -1
  39. package/lib/treeAgentTypes.js +37 -0
  40. package/lib/treeAgentTypes.js.map +1 -1
  41. package/package.json +10 -10
  42. package/src/index.ts +5 -0
  43. package/src/prompt.ts +21 -2
  44. package/src/renderSchemaTypeScript.ts +18 -8
  45. package/src/renderTypeFactoryTypeScript.ts +82 -2
  46. package/src/treeAgentTypes.ts +121 -0
package/src/prompt.ts CHANGED
@@ -8,12 +8,17 @@ import { NodeKind, Tree, TreeNode } from "@fluidframework/tree";
8
8
  import type { ImplicitFieldSchema, TreeMapNode } from "@fluidframework/tree";
9
9
  import type { ReadableField } from "@fluidframework/tree/alpha";
10
10
  import { getSimpleSchema } from "@fluidframework/tree/alpha";
11
- import { normalizeFieldSchema } from "@fluidframework/tree/internal";
11
+ import { normalizeFieldSchema, ValueSchema } from "@fluidframework/tree/internal";
12
12
 
13
13
  import type { Subtree } from "./subtree.js";
14
14
  import { generateEditTypesForPrompt } from "./typeGeneration.js";
15
15
  import { getFriendlyName, communize, findSchemas } from "./utils.js";
16
16
 
17
+ /**
18
+ * The type name used for handles in generated TypeScript.
19
+ */
20
+ export const fluidHandleTypeName = "_OpaqueHandle";
21
+
17
22
  /**
18
23
  * Produces a "system" prompt for the tree agent, based on the provided subtree.
19
24
  */
@@ -32,6 +37,7 @@ export function getPrompt(args: {
32
37
  let nodeTypeUnion: string | undefined;
33
38
  let hasArrays = false;
34
39
  let hasMaps = false;
40
+ let hasFluidHandles = false;
35
41
  let exampleObjectName: string | undefined;
36
42
  for (const s of findSchemas(schema)) {
37
43
  if (s.kind !== NodeKind.Leaf) {
@@ -54,6 +60,10 @@ export function getPrompt(args: {
54
60
  exampleObjectName ??= getFriendlyName(s);
55
61
  break;
56
62
  }
63
+ case NodeKind.Leaf: {
64
+ hasFluidHandles ||= s.info === ValueSchema.FluidHandle;
65
+ break;
66
+ }
57
67
  // No default
58
68
  }
59
69
  }
@@ -63,6 +73,15 @@ export function getPrompt(args: {
63
73
  schema,
64
74
  getSimpleSchema(schema),
65
75
  );
76
+ const fluidHandleType = hasFluidHandles
77
+ ? `/**
78
+ * Opaque handle type representing a reference to a Fluid object.
79
+ * This type should not be constructed by generated code.
80
+ */
81
+ type ${fluidHandleTypeName} = unknown;
82
+
83
+ `
84
+ : "";
66
85
  const exampleTypeName =
67
86
  nodeTypeUnion === undefined
68
87
  ? undefined
@@ -274,7 +293,7 @@ Finally, double check that the edits would accomplish the user's request (if it
274
293
  The JSON tree adheres to the following Typescript schema:
275
294
 
276
295
  \`\`\`typescript
277
- ${typescriptSchemaTypes}
296
+ ${fluidHandleType}${typescriptSchemaTypes}
278
297
  \`\`\`
279
298
 
280
299
  If the user asks you a question about the tree, you should inspect the state of the tree and answer the question.
@@ -17,6 +17,7 @@ import { z } from "zod";
17
17
 
18
18
  import type { BindableSchema, FunctionWrapper } from "./methodBinding.js";
19
19
  import { getExposedMethods } from "./methodBinding.js";
20
+ import { fluidHandleTypeName } from "./prompt.js";
20
21
  import { getExposedProperties, type PropertyDef } from "./propertyBinding.js";
21
22
  import {
22
23
  instanceOfsTypeFactory,
@@ -290,7 +291,9 @@ export function renderSchemaTypeScript(
290
291
  lines.push(`// ${note}`);
291
292
  }
292
293
  }
293
- lines.push(formatMethod(name, method));
294
+ const methodString = formatMethod(name, method);
295
+ const methodLines = methodString.split("\n");
296
+ lines.push(...methodLines);
294
297
  }
295
298
  if (lines.length > 0) {
296
299
  hasHelperMethods = true;
@@ -440,7 +443,11 @@ function renderPropertyLines(properties: Record<string, PropertyDef>): string[]
440
443
  }
441
444
  }
442
445
  const modifier = property.readOnly ? "readonly " : "";
443
- lines.push(`${modifier}${name}: ${renderType(property.schema)};`);
446
+ const typeString = renderType(property.schema, 0);
447
+ const propertyLine = `${modifier}${name}: ${typeString};`;
448
+ // Split multi-line type strings and add to lines array
449
+ const propertyLines = propertyLine.split("\n");
450
+ lines.push(...propertyLines);
444
451
  }
445
452
  return lines;
446
453
  }
@@ -449,13 +456,13 @@ function formatMethod(name: string, method: FunctionWrapper): string {
449
456
  const args: string[] = [];
450
457
  for (const [argName, argType] of method.args) {
451
458
  const { innerType, optional } = unwrapOptional(argType);
452
- const renderedType = renderType(innerType);
459
+ const renderedType = renderType(innerType, 0);
453
460
  args.push(`${argName}${optional ? "?" : ""}: ${renderedType}`);
454
461
  }
455
462
  if (method.rest !== null) {
456
- args.push(`...rest: ${renderType(method.rest)}[]`);
463
+ args.push(`...rest: ${renderType(method.rest, 0)}[]`);
457
464
  }
458
- return `${name}(${args.join(", ")}): ${renderType(method.returns)};`;
465
+ return `${name}(${args.join(", ")}): ${renderType(method.returns, 0)};`;
459
466
  }
460
467
 
461
468
  function renderLeaf(leafKind: ValueSchema): string {
@@ -472,8 +479,11 @@ function renderLeaf(leafKind: ValueSchema): string {
472
479
  case ValueSchema.Null: {
473
480
  return "null";
474
481
  }
482
+ case ValueSchema.FluidHandle: {
483
+ return fluidHandleTypeName;
484
+ }
475
485
  default: {
476
- throw new Error(`Unsupported leaf kind ${NodeKind[leafKind]}.`);
486
+ throw new Error(`Unsupported leaf kind.`);
477
487
  }
478
488
  }
479
489
  }
@@ -532,8 +542,8 @@ function ensureNoMemberConflicts(
532
542
  /**
533
543
  * Dispatches to the correct renderer based on whether the type is Zod or type factory.
534
544
  */
535
- function renderType(type: z.ZodTypeAny | TypeFactoryType): string {
545
+ function renderType(type: z.ZodTypeAny | TypeFactoryType, indentLevel: number = 0): string {
536
546
  return isTypeFactoryType(type)
537
- ? renderTypeFactoryTypeScript(type, getFriendlyName, instanceOfsTypeFactory)
547
+ ? renderTypeFactoryTypeScript(type, getFriendlyName, instanceOfsTypeFactory, indentLevel)
538
548
  : renderZodTypeScript(type, getFriendlyName, instanceOfs);
539
549
  }
@@ -9,6 +9,7 @@ import type { ObjectNodeSchema, TreeNodeSchema } from "@fluidframework/tree/alph
9
9
  import type {
10
10
  TypeFactoryType,
11
11
  TypeFactoryArray,
12
+ TypeFactoryPromise,
12
13
  TypeFactoryObject,
13
14
  TypeFactoryTuple,
14
15
  TypeFactoryRecord,
@@ -17,6 +18,8 @@ import type {
17
18
  TypeFactoryOptional,
18
19
  TypeFactoryReadonly,
19
20
  TypeFactoryUnion,
21
+ TypeFactoryIntersection,
22
+ TypeFactoryFunction,
20
23
  } from "./treeAgentTypes.js";
21
24
 
22
25
  export { instanceOfsTypeFactory } from "./treeAgentTypes.js";
@@ -29,10 +32,11 @@ export function renderTypeFactoryTypeScript(
29
32
  typeFactoryType: TypeFactoryType,
30
33
  getFriendlyName: (schema: TreeNodeSchema) => string,
31
34
  instanceOfLookup: WeakMap<TypeFactoryType, ObjectNodeSchema>,
35
+ initialIndent: number = 0,
32
36
  ): string {
33
37
  let result = "";
34
- let startOfLine = true;
35
- let indent = 0;
38
+ let startOfLine = false;
39
+ let indent = initialIndent;
36
40
 
37
41
  appendType(typeFactoryType, TypePrecedence.Union);
38
42
  return result;
@@ -75,6 +79,10 @@ export function renderTypeFactoryTypeScript(
75
79
  append("boolean");
76
80
  return;
77
81
  }
82
+ case "date": {
83
+ append("Date");
84
+ return;
85
+ }
78
86
  case "void": {
79
87
  append("void");
80
88
  return;
@@ -95,6 +103,10 @@ export function renderTypeFactoryTypeScript(
95
103
  appendArrayType(type as TypeFactoryArray);
96
104
  return;
97
105
  }
106
+ case "promise": {
107
+ appendPromiseType(type as TypeFactoryPromise);
108
+ return;
109
+ }
98
110
  case "object": {
99
111
  appendObjectType(type as TypeFactoryObject);
100
112
  return;
@@ -103,6 +115,13 @@ export function renderTypeFactoryTypeScript(
103
115
  appendUnionTypes((type as TypeFactoryUnion).options, TypePrecedence.Union);
104
116
  return;
105
117
  }
118
+ case "intersection": {
119
+ appendIntersectionTypes(
120
+ (type as TypeFactoryIntersection).types,
121
+ TypePrecedence.Intersection,
122
+ );
123
+ return;
124
+ }
106
125
  case "tuple": {
107
126
  appendTupleType(type as TypeFactoryTuple);
108
127
  return;
@@ -130,6 +149,10 @@ export function renderTypeFactoryTypeScript(
130
149
  appendReadonlyType(type as TypeFactoryReadonly);
131
150
  return;
132
151
  }
152
+ case "function": {
153
+ appendFunctionType(type as TypeFactoryFunction);
154
+ return;
155
+ }
133
156
  case "instanceof": {
134
157
  const schema = instanceOfLookup.get(type);
135
158
  if (schema === undefined) {
@@ -153,6 +176,12 @@ export function renderTypeFactoryTypeScript(
153
176
  append("[]");
154
177
  }
155
178
 
179
+ function appendPromiseType(promiseType: TypeFactoryPromise): void {
180
+ append("Promise<");
181
+ appendType(promiseType.innerType, TypePrecedence.Union);
182
+ append(">");
183
+ }
184
+
156
185
  function appendObjectType(objectType: TypeFactoryObject): void {
157
186
  append("{");
158
187
  appendNewLine();
@@ -188,6 +217,20 @@ export function renderTypeFactoryTypeScript(
188
217
  }
189
218
  }
190
219
 
220
+ function appendIntersectionTypes(
221
+ types: readonly TypeFactoryType[],
222
+ minPrecedence: TypePrecedence,
223
+ ): void {
224
+ let first = true;
225
+ for (const innerType of types) {
226
+ if (!first) {
227
+ append(" & ");
228
+ }
229
+ appendType(innerType, minPrecedence);
230
+ first = false;
231
+ }
232
+ }
233
+
191
234
  function appendTupleType(tupleType: TypeFactoryTuple): void {
192
235
  append("[");
193
236
  let first = true;
@@ -239,6 +282,40 @@ export function renderTypeFactoryTypeScript(
239
282
  appendType(readonlyType.innerType);
240
283
  append(">");
241
284
  }
285
+
286
+ function appendFunctionType(functionType: TypeFactoryFunction): void {
287
+ append("(");
288
+ let first = true;
289
+ for (const param of functionType.parameters) {
290
+ if (!first) {
291
+ append(", ");
292
+ }
293
+ const [name, type] = param;
294
+ append(name);
295
+ if (type._kind === "optional") {
296
+ append("?");
297
+ append(": ");
298
+ appendType((type as TypeFactoryOptional).innerType, TypePrecedence.Union);
299
+ } else {
300
+ append(": ");
301
+ appendType(type, TypePrecedence.Union);
302
+ }
303
+ first = false;
304
+ }
305
+ if (functionType.restParameter !== undefined) {
306
+ if (!first) {
307
+ append(", ");
308
+ }
309
+ const [name, type] = functionType.restParameter;
310
+ append("...");
311
+ append(name);
312
+ append(": ");
313
+ appendType(type, TypePrecedence.Object);
314
+ append("[]");
315
+ }
316
+ append(") => ");
317
+ appendType(functionType.returnType, TypePrecedence.Union);
318
+ }
242
319
  }
243
320
 
244
321
  const enum TypePrecedence {
@@ -252,6 +329,9 @@ function getTypePrecedence(type: TypeFactoryType): TypePrecedence {
252
329
  case "union": {
253
330
  return TypePrecedence.Union;
254
331
  }
332
+ case "intersection": {
333
+ return TypePrecedence.Intersection;
334
+ }
255
335
  default: {
256
336
  return TypePrecedence.Object;
257
337
  }
@@ -19,15 +19,19 @@ export type TypeFactoryTypeKind =
19
19
  | "undefined"
20
20
  | "null"
21
21
  | "unknown"
22
+ | "date"
23
+ | "promise"
22
24
  | "array"
23
25
  | "object"
24
26
  | "record"
25
27
  | "map"
26
28
  | "tuple"
27
29
  | "union"
30
+ | "intersection"
28
31
  | "literal"
29
32
  | "optional"
30
33
  | "readonly"
34
+ | "function"
31
35
  | "instanceof";
32
36
 
33
37
  /**
@@ -53,15 +57,19 @@ const validTypeKinds: ReadonlySet<TypeFactoryTypeKind> = new Set<TypeFactoryType
53
57
  "undefined",
54
58
  "null",
55
59
  "unknown",
60
+ "date",
61
+ "promise",
56
62
  "array",
57
63
  "object",
58
64
  "record",
59
65
  "map",
60
66
  "tuple",
61
67
  "union",
68
+ "intersection",
62
69
  "literal",
63
70
  "optional",
64
71
  "readonly",
72
+ "function",
65
73
  "instanceof",
66
74
  ]);
67
75
 
@@ -112,6 +120,17 @@ export interface TypeFactoryBoolean extends TypeFactoryType {
112
120
  readonly _kind: "boolean";
113
121
  }
114
122
 
123
+ /**
124
+ * Represents a Date type in the type factory system.
125
+ * @alpha
126
+ */
127
+ export interface TypeFactoryDate extends TypeFactoryType {
128
+ /**
129
+ * {@inheritDoc TypeFactoryType._kind}
130
+ */
131
+ readonly _kind: "date";
132
+ }
133
+
115
134
  /**
116
135
  * Represents a void type in the type factory system.
117
136
  * @alpha
@@ -173,6 +192,21 @@ export interface TypeFactoryArray extends TypeFactoryType {
173
192
  readonly element: TypeFactoryType;
174
193
  }
175
194
 
195
+ /**
196
+ * Represents a Promise type in the type factory system.
197
+ * @alpha
198
+ */
199
+ export interface TypeFactoryPromise extends TypeFactoryType {
200
+ /**
201
+ * {@inheritDoc TypeFactoryType._kind}
202
+ */
203
+ readonly _kind: "promise";
204
+ /**
205
+ * The type that the Promise resolves to.
206
+ */
207
+ readonly innerType: TypeFactoryType;
208
+ }
209
+
176
210
  /**
177
211
  * Represents an object type with a fixed shape in the type factory system.
178
212
  * @alpha
@@ -260,6 +294,21 @@ export interface TypeFactoryUnion extends TypeFactoryType {
260
294
  readonly options: readonly TypeFactoryType[];
261
295
  }
262
296
 
297
+ /**
298
+ * Represents an intersection type in the type factory system.
299
+ * @alpha
300
+ */
301
+ export interface TypeFactoryIntersection extends TypeFactoryType {
302
+ /**
303
+ * {@inheritDoc TypeFactoryType._kind}
304
+ */
305
+ readonly _kind: "intersection";
306
+ /**
307
+ * The types to intersect.
308
+ */
309
+ readonly types: readonly TypeFactoryType[];
310
+ }
311
+
263
312
  /**
264
313
  * Represents a literal type (specific string, number, or boolean value) in the type factory system.
265
314
  * @alpha
@@ -305,6 +354,35 @@ export interface TypeFactoryReadonly extends TypeFactoryType {
305
354
  readonly innerType: TypeFactoryType;
306
355
  }
307
356
 
357
+ /**
358
+ * Represents a function parameter as a tuple of [name, type].
359
+ * @alpha
360
+ */
361
+ export type TypeFactoryFunctionParameter = readonly [name: string, type: TypeFactoryType];
362
+
363
+ /**
364
+ * Represents a function type in the type factory system.
365
+ * @alpha
366
+ */
367
+ export interface TypeFactoryFunction extends TypeFactoryType {
368
+ /**
369
+ * {@inheritDoc TypeFactoryType._kind}
370
+ */
371
+ readonly _kind: "function";
372
+ /**
373
+ * The function parameters.
374
+ */
375
+ readonly parameters: readonly TypeFactoryFunctionParameter[];
376
+ /**
377
+ * The function return type.
378
+ */
379
+ readonly returnType: TypeFactoryType;
380
+ /**
381
+ * Optional rest parameter for variable-length argument lists.
382
+ */
383
+ readonly restParameter?: TypeFactoryFunctionParameter;
384
+ }
385
+
308
386
  /**
309
387
  * Represents an instanceof type that references a SharedTree schema class in the type factory system.
310
388
  * @alpha
@@ -349,6 +427,14 @@ export const typeFactory = {
349
427
  return { _kind: "boolean" };
350
428
  },
351
429
 
430
+ /**
431
+ * Create a Date type.
432
+ * @alpha
433
+ */
434
+ date(): TypeFactoryDate {
435
+ return { _kind: "date" };
436
+ },
437
+
352
438
  /**
353
439
  * Create a void type.
354
440
  * @alpha
@@ -389,6 +475,14 @@ export const typeFactory = {
389
475
  return { _kind: "array", element };
390
476
  },
391
477
 
478
+ /**
479
+ * Create a Promise type.
480
+ * @alpha
481
+ */
482
+ promise(innerType: TypeFactoryType): TypeFactoryPromise {
483
+ return { _kind: "promise", innerType };
484
+ },
485
+
392
486
  /**
393
487
  * Create an object type.
394
488
  * @alpha
@@ -439,6 +533,19 @@ export const typeFactory = {
439
533
  return { _kind: "union", options };
440
534
  },
441
535
 
536
+ /**
537
+ * Create an intersection type.
538
+ * @alpha
539
+ */
540
+ intersection(types: readonly TypeFactoryType[]): TypeFactoryIntersection {
541
+ if (types.length === 0) {
542
+ throw new UsageError(
543
+ "typeFactory.intersection requires at least one type. Empty intersections are not valid TypeScript types.",
544
+ );
545
+ }
546
+ return { _kind: "intersection", types };
547
+ },
548
+
442
549
  /**
443
550
  * Create a literal type.
444
551
  * @alpha
@@ -463,6 +570,20 @@ export const typeFactory = {
463
570
  return { _kind: "readonly", innerType };
464
571
  },
465
572
 
573
+ /**
574
+ * Create a function type.
575
+ * @alpha
576
+ */
577
+ function(
578
+ parameters: readonly TypeFactoryFunctionParameter[],
579
+ returnType: TypeFactoryType,
580
+ restParameter?: TypeFactoryFunctionParameter,
581
+ ): TypeFactoryFunction {
582
+ return restParameter === undefined
583
+ ? { _kind: "function", parameters, returnType }
584
+ : { _kind: "function", parameters, returnType, restParameter };
585
+ },
586
+
466
587
  /**
467
588
  * Create an instanceOf type for a SharedTree schema class.
468
589
  * @alpha