@fluidframework/tree-agent 2.63.0-359286 → 2.63.0-359734
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.
- package/api-report/tree-agent.alpha.api.md +16 -18
- package/dist/agent.d.ts +1 -2
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +24 -51
- package/dist/agent.js.map +1 -1
- package/dist/alpha.d.ts +1 -0
- package/dist/api.d.ts +38 -20
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -1
- package/dist/index.js.map +1 -1
- package/dist/langchain.d.ts +3 -4
- package/dist/langchain.d.ts.map +1 -1
- package/dist/langchain.js +2 -4
- package/dist/langchain.js.map +1 -1
- package/dist/prompt.d.ts +1 -2
- package/dist/prompt.d.ts.map +1 -1
- package/dist/prompt.js +18 -21
- package/dist/prompt.js.map +1 -1
- package/dist/ses.d.ts +21 -0
- package/dist/ses.d.ts.map +1 -0
- package/dist/ses.js +64 -0
- package/dist/ses.js.map +1 -0
- package/dist/utils.d.ts +4 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +16 -1
- package/dist/utils.js.map +1 -1
- package/lib/agent.d.ts +1 -2
- package/lib/agent.d.ts.map +1 -1
- package/lib/agent.js +25 -52
- package/lib/agent.js.map +1 -1
- package/lib/alpha.d.ts +1 -0
- package/lib/api.d.ts +38 -20
- package/lib/api.d.ts.map +1 -1
- package/lib/api.js.map +1 -1
- package/lib/index.d.ts +2 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +7 -0
- package/lib/index.js.map +1 -1
- package/lib/langchain.d.ts +3 -4
- package/lib/langchain.d.ts.map +1 -1
- package/lib/langchain.js +2 -4
- package/lib/langchain.js.map +1 -1
- package/lib/prompt.d.ts +1 -2
- package/lib/prompt.d.ts.map +1 -1
- package/lib/prompt.js +18 -21
- package/lib/prompt.js.map +1 -1
- package/lib/ses.d.ts +21 -0
- package/lib/ses.d.ts.map +1 -0
- package/lib/ses.js +60 -0
- package/lib/ses.js.map +1 -0
- package/lib/utils.d.ts +4 -0
- package/lib/utils.d.ts.map +1 -1
- package/lib/utils.js +14 -0
- package/lib/utils.js.map +1 -1
- package/package.json +10 -9
- package/src/agent.ts +34 -74
- package/src/api.ts +39 -23
- package/src/index.ts +2 -1
- package/src/langchain.ts +6 -8
- package/src/prompt.ts +19 -23
- package/src/ses.ts +73 -0
- package/src/utils.ts +14 -0
package/src/prompt.ts
CHANGED
|
@@ -25,11 +25,10 @@ import {
|
|
|
25
25
|
*/
|
|
26
26
|
export function getPrompt<TRoot extends ImplicitFieldSchema>(args: {
|
|
27
27
|
subtree: Subtree<TRoot>;
|
|
28
|
-
editToolName
|
|
29
|
-
editFunctionName?: string;
|
|
28
|
+
editToolName: string | undefined;
|
|
30
29
|
domainHints?: string;
|
|
31
30
|
}): string {
|
|
32
|
-
const { subtree, editToolName,
|
|
31
|
+
const { subtree, editToolName, domainHints } = args;
|
|
33
32
|
const { field, schema } = subtree;
|
|
34
33
|
const arrayInterfaceName = "TreeArray";
|
|
35
34
|
const mapInterfaceName = "TreeMap";
|
|
@@ -70,7 +69,7 @@ export function getPrompt<TRoot extends ImplicitFieldSchema>(args: {
|
|
|
70
69
|
const details: SchemaDetails = { hasHelperMethods: false };
|
|
71
70
|
const typescriptSchemaTypes = getZodSchemaAsTypeScript(domainTypes, details);
|
|
72
71
|
const helperMethodExplanation = details.hasHelperMethods
|
|
73
|
-
? `Manipulating the data using the APIs described below is allowed, but when possible ALWAYS prefer to use
|
|
72
|
+
? `Manipulating the data using the APIs described below is allowed, but when possible ALWAYS prefer to use any application helper methods exposed on the schema TypeScript types if the goal can be accomplished that way.
|
|
74
73
|
It will often not be possible to fully accomplish the goal using those helpers. When this is the case, mutate the objects as normal, taking into account the following guidance.`
|
|
75
74
|
: "";
|
|
76
75
|
|
|
@@ -78,16 +77,14 @@ It will often not be possible to fully accomplish the goal using those helpers.
|
|
|
78
77
|
exampleObjectName === undefined
|
|
79
78
|
? ""
|
|
80
79
|
: `When constructing new objects, you should wrap them in the appropriate builder function rather than simply making a javascript object.
|
|
81
|
-
The builders are available on the
|
|
80
|
+
The builders are available on the \`create\` property on the context object and are named according to the type that they create.
|
|
82
81
|
For example:
|
|
83
82
|
|
|
84
83
|
\`\`\`javascript
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
// const ${communize(exampleObjectName)} = { /* ...properties... */ };
|
|
90
|
-
}
|
|
84
|
+
// This creates a new ${exampleObjectName} object:
|
|
85
|
+
const ${communize(exampleObjectName)} = context.create.${exampleObjectName}({ /* ...properties... */ });
|
|
86
|
+
// Don't do this:
|
|
87
|
+
// const ${communize(exampleObjectName)} = { /* ...properties... */ };
|
|
91
88
|
\`\`\`\n\n`;
|
|
92
89
|
|
|
93
90
|
const arrayEditing = `#### Editing Arrays
|
|
@@ -121,26 +118,25 @@ ${getTreeMapNodeDocumentation(mapInterfaceName)}
|
|
|
121
118
|
`;
|
|
122
119
|
|
|
123
120
|
const rootTypes = normalizeFieldSchema(schema).allowedTypeSet;
|
|
124
|
-
const editing = `If the user asks you to edit the tree, you should author a JavaScript
|
|
125
|
-
|
|
121
|
+
const editing = `If the user asks you to edit the tree, you should author a snippet of JavaScript code to accomplish the user-specified goal, following the instructions for editing detailed below.
|
|
122
|
+
You must use the "${editToolName}" tool to run the generated code.
|
|
126
123
|
After editing the tree, review the latest state of the tree to see if it satisfies the user's request.
|
|
127
124
|
If it does not, or if you receive an error, you may try again with a different approach.
|
|
128
125
|
Once the tree is in the desired state, you should inform the user that the request has been completed.
|
|
129
126
|
|
|
130
127
|
### Editing
|
|
131
128
|
|
|
132
|
-
If the user asks you to edit the document, you will write a JavaScript
|
|
133
|
-
The
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
You may
|
|
138
|
-
You may also set the \`root\` property to be an entirely new value as long as it is one of the types allowed at the root of the tree (\`${Array.from(rootTypes.values(), (t) => getFriendlyName(t)).join(" | ")}\`).
|
|
129
|
+
If the user asks you to edit the document, you will write a snippet of JavaScript code that mutates the data in-place to achieve the user's goal.
|
|
130
|
+
The snippet may be synchronous or asynchronous (i.e. it may \`await\` functions if necessary).
|
|
131
|
+
The snippet has a \`context\` variable in its scope.
|
|
132
|
+
This \`context\` variable holds the current state of the tree in the \`root\` property.
|
|
133
|
+
You may mutate any part of the root tree as necessary, taking into account the caveats around${hasArrays ? ` arrays${hasMaps ? " and" : ""}` : ""}${hasMaps ? " maps" : ""} detailed below.
|
|
134
|
+
You may also set the \`root\` property of the context to be an entirely new value as long as it is one of the types allowed at the root of the tree (\`${Array.from(rootTypes.values(), (t) => getFriendlyName(t)).join(" | ")}\`).
|
|
139
135
|
${helperMethodExplanation}
|
|
140
136
|
|
|
141
137
|
${hasArrays ? arrayEditing : ""}${hasMaps ? mapEditing : ""}#### Additional Notes
|
|
142
138
|
|
|
143
|
-
Before outputting the
|
|
139
|
+
Before outputting the edit function, you should check that it is valid according to both the application tree's schema and any restrictions of the editing APIs described above.
|
|
144
140
|
|
|
145
141
|
Once data has been removed from the tree (e.g. replaced via assignment, or removed from an array), that data cannot be re-inserted into the tree - instead, it must be deep cloned and recreated.
|
|
146
142
|
|
|
@@ -158,14 +154,14 @@ ${typescriptSchemaTypes}
|
|
|
158
154
|
If the user asks you a question about the tree, you should inspect the state of the tree and answer the question.
|
|
159
155
|
When answering such a question, DO NOT answer with information that is not part of the document unless requested to do so.
|
|
160
156
|
|
|
161
|
-
${
|
|
157
|
+
${editToolName === undefined ? "" : editing}### Application data
|
|
162
158
|
|
|
163
159
|
${
|
|
164
160
|
domainHints === undefined
|
|
165
161
|
? ""
|
|
166
162
|
: `\nThe application supplied the following additional instructions: ${domainHints}`
|
|
167
163
|
}
|
|
168
|
-
The current state of
|
|
164
|
+
The current state of \`context.root\` (a \`${field === undefined ? "undefined" : getFriendlyName(Tree.schema(field))}\`) is:
|
|
169
165
|
|
|
170
166
|
\`\`\`JSON
|
|
171
167
|
${stringified}
|
package/src/ses.ts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { CompartmentOptions, LockdownOptions } from "ses";
|
|
7
|
+
|
|
8
|
+
import type { SemanticAgentOptions } from "./api.js";
|
|
9
|
+
import { toErrorString } from "./utils.js";
|
|
10
|
+
|
|
11
|
+
const lockdownSymbol = Symbol.for("tree-agent.ses.locked");
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Create an implementation of {@link SemanticAgentOptions.executeEdit} that uses the SES library to run the provided code in a secure environment.
|
|
15
|
+
* @param createCompartment - This function can be used to optionally configure the SES Compartment used to execute the code.
|
|
16
|
+
* The provided globals must be included in the compartment's globals and must not conflict with any additional globals passed in.
|
|
17
|
+
* @param lockdownOptions - Optional configuration passed to the SES `lockdown` function.
|
|
18
|
+
* @returns A function that can be used as the {@link SemanticAgentOptions.executeEdit | executeEdit} callback.
|
|
19
|
+
* @remarks This function will both import the SES library and call its `lockdown` function the first time it is called.
|
|
20
|
+
* Therefore, this function should be called only once, early in an application's lifetime.
|
|
21
|
+
* @alpha
|
|
22
|
+
*/
|
|
23
|
+
export async function createSesEditEvaluator(options?: {
|
|
24
|
+
compartmentOptions?: CompartmentOptions;
|
|
25
|
+
lockdownOptions?: LockdownOptions;
|
|
26
|
+
}): Promise<SemanticAgentOptions["executeEdit"]> {
|
|
27
|
+
const optionsGlobals: Map<string, unknown> =
|
|
28
|
+
options?.compartmentOptions?.globals ?? new Map<string, unknown>();
|
|
29
|
+
if (optionsGlobals.has("context") === true) {
|
|
30
|
+
throw new Error(
|
|
31
|
+
"The 'context' global is reserved and cannot be overridden in the compartment options.",
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Importing 'ses' has side effects, so we do it lazily to avoid impacting environments that don't use this evaluator.
|
|
36
|
+
await import("ses");
|
|
37
|
+
|
|
38
|
+
if (!(lockdownSymbol in globalThis)) {
|
|
39
|
+
try {
|
|
40
|
+
lockdown(options?.lockdownOptions);
|
|
41
|
+
Object.defineProperty(globalThis, lockdownSymbol, {
|
|
42
|
+
value: true,
|
|
43
|
+
writable: false,
|
|
44
|
+
configurable: false,
|
|
45
|
+
enumerable: false,
|
|
46
|
+
});
|
|
47
|
+
} catch (error: unknown) {
|
|
48
|
+
if (toErrorString(error).includes("SES_ALREADY_LOCKED_DOWN")) {
|
|
49
|
+
Object.defineProperty(globalThis, lockdownSymbol, {
|
|
50
|
+
value: true,
|
|
51
|
+
writable: false,
|
|
52
|
+
configurable: false,
|
|
53
|
+
enumerable: false,
|
|
54
|
+
});
|
|
55
|
+
} else {
|
|
56
|
+
throw error;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return async (context: Record<string, unknown>, code: string) => {
|
|
62
|
+
const compartmentOptions = {
|
|
63
|
+
...options?.compartmentOptions,
|
|
64
|
+
globals: {
|
|
65
|
+
...Object.fromEntries(optionsGlobals),
|
|
66
|
+
context,
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const compartment = new Compartment({ ...compartmentOptions, __options__: true });
|
|
71
|
+
await compartment.evaluate(code);
|
|
72
|
+
};
|
|
73
|
+
}
|
package/src/utils.ts
CHANGED
|
@@ -619,3 +619,17 @@ export function findNamedSchemas(
|
|
|
619
619
|
export function communize(str: string): string {
|
|
620
620
|
return str.charAt(0).toLowerCase() + str.slice(1);
|
|
621
621
|
}
|
|
622
|
+
|
|
623
|
+
/**
|
|
624
|
+
* Stringify an unknown error value
|
|
625
|
+
*/
|
|
626
|
+
export function toErrorString(error: unknown): string {
|
|
627
|
+
if (error instanceof Error) {
|
|
628
|
+
return error.message;
|
|
629
|
+
}
|
|
630
|
+
try {
|
|
631
|
+
return JSON.stringify(error);
|
|
632
|
+
} catch {
|
|
633
|
+
return String(error);
|
|
634
|
+
}
|
|
635
|
+
}
|