@fluidframework/tree-agent 2.63.0-359461 → 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 +9 -2
- package/dist/agent.d.ts +0 -3
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +21 -49
- package/dist/agent.js.map +1 -1
- package/dist/alpha.d.ts +1 -0
- package/dist/api.d.ts +18 -7
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/langchain.d.ts.map +1 -1
- package/dist/langchain.js +2 -3
- package/dist/langchain.js.map +1 -1
- package/dist/prompt.d.ts.map +1 -1
- package/dist/prompt.js +15 -17
- 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 +0 -3
- package/lib/agent.d.ts.map +1 -1
- package/lib/agent.js +22 -50
- package/lib/agent.js.map +1 -1
- package/lib/alpha.d.ts +1 -0
- package/lib/api.d.ts +18 -7
- package/lib/api.d.ts.map +1 -1
- package/lib/api.js.map +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/lib/langchain.d.ts.map +1 -1
- package/lib/langchain.js +2 -3
- package/lib/langchain.js.map +1 -1
- package/lib/prompt.d.ts.map +1 -1
- package/lib/prompt.js +15 -17
- 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 -10
- package/src/agent.ts +29 -61
- package/src/api.ts +19 -12
- package/src/index.ts +1 -0
- package/src/langchain.ts +2 -3
- package/src/prompt.ts +15 -17
- package/src/ses.ts +73 -0
- package/src/utils.ts +14 -0
- package/dist/functionParsing.d.ts +0 -13
- package/dist/functionParsing.d.ts.map +0 -1
- package/dist/functionParsing.js +0 -215
- package/dist/functionParsing.js.map +0 -1
- package/lib/functionParsing.d.ts +0 -13
- package/lib/functionParsing.d.ts.map +0 -1
- package/lib/functionParsing.js +0 -210
- package/lib/functionParsing.js.map +0 -1
- package/src/functionParsing.ts +0 -268
package/lib/agent.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.js","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type {\n\tImplicitFieldSchema,\n\tTreeFieldFromImplicitField,\n\tTreeNodeSchema,\n} from \"@fluidframework/tree\";\nimport { TreeNode } from \"@fluidframework/tree\";\nimport type {\n\tReadableField,\n\tFactoryContentObject,\n\tInsertableContent,\n\tReadSchema,\n} from \"@fluidframework/tree/alpha\";\nimport { ObjectNodeSchema, Tree } from \"@fluidframework/tree/alpha\";\n\nimport type {\n\tSharedTreeChatModel,\n\tEditFunction,\n\tEditResult,\n\tSemanticAgentOptions,\n\tLogger,\n} from \"./api.js\";\nimport { findInvocableFunctionName, stripExportSyntax } from \"./functionParsing.js\";\nimport { getPrompt, stringifyTree } from \"./prompt.js\";\nimport { Subtree } from \"./subtree.js\";\nimport {\n\tconstructNode,\n\tgetFriendlyName,\n\tllmDefault,\n\ttype TreeView,\n\tfindNamedSchemas,\n} from \"./utils.js\";\n\n/**\n * The default maximum number of sequential edits the LLM can make before we assume it's stuck in a loop.\n * @remarks This can be overridden by passing {@link SemanticAgentOptions.maximumSequentialEdits | maximumSequentialEdits} to {@link createSemanticAgent}.\n */\nconst defaultMaxSequentialEdits = 20;\n\n/**\n * The name of the parameter passed to the edit function.\n */\nconst paramsName = \"params\";\n\n/**\n * An agent that uses a {@link SharedTreeChatModel} to interact with a SharedTree.\n * @remarks This class forwards user queries to the chat model, and handles the application of any edits to the tree that the model requests.\n * @alpha @sealed\n */\nexport class SharedTreeSemanticAgent<TSchema extends ImplicitFieldSchema> {\n\t// Converted from ECMAScript private fields (#name) to TypeScript private members for easier debugger inspection.\n\tprivate readonly outerTree: Subtree<TSchema>;\n\t/**\n\t * Whether or not the outer tree has changed since the last query finished.\n\t */\n\tprivate outerTreeIsDirty = false;\n\n\tpublic constructor(\n\t\tprivate readonly client: SharedTreeChatModel,\n\t\ttree: TreeView<TSchema> | (ReadableField<TSchema> & TreeNode),\n\t\tprivate readonly options?: Readonly<SemanticAgentOptions>,\n\t) {\n\t\tif (tree instanceof TreeNode) {\n\t\t\tTree.on(tree, \"treeChanged\", () => (this.outerTreeIsDirty = true));\n\t\t} else {\n\t\t\ttree.events.on(\"changed\", () => (this.outerTreeIsDirty = true));\n\t\t}\n\n\t\tthis.outerTree = new Subtree(tree);\n\t\tconst prompt = getPrompt({\n\t\t\tsubtree: this.outerTree,\n\t\t\teditToolName: this.client.editToolName,\n\t\t\tdomainHints: this.options?.domainHints,\n\t\t});\n\t\tthis.options?.logger?.log(`# Fluid Framework SharedTree AI Agent Log\\n\\n`);\n\t\tconst now = new Date();\n\t\tconst formattedDate = now.toLocaleString(undefined, {\n\t\t\tweekday: \"long\",\n\t\t\tyear: \"numeric\",\n\t\t\tmonth: \"long\",\n\t\t\tday: \"numeric\",\n\t\t\thour: \"numeric\",\n\t\t\tminute: \"2-digit\",\n\t\t\tsecond: \"2-digit\",\n\t\t});\n\t\tthis.options?.logger?.log(`Agent created: **${formattedDate}**\\n\\n`);\n\t\tif (this.client.name !== undefined) {\n\t\t\tthis.options?.logger?.log(`Model: **${this.client.name}**\\n\\n`);\n\t\t}\n\t\tthis.client.appendContext?.(prompt);\n\t\tthis.options?.logger?.log(`## System Prompt\\n\\n${prompt}\\n\\n`);\n\t}\n\n\t/**\n\t * Given a user prompt, return a response.\n\t *\n\t * @param userPrompt - The prompt to send to the agent.\n\t * @returns The agent's response.\n\t */\n\tpublic async query(userPrompt: string): Promise<string> {\n\t\tthis.options?.logger?.log(`## User Query\\n\\n${userPrompt}\\n\\n`);\n\n\t\t// Notify the llm if the tree has changed since the last query, and if so, provide the new state of the tree.\n\t\tif (this.outerTreeIsDirty) {\n\t\t\tconst stringified = stringifyTree(this.outerTree.field);\n\t\t\tthis.client.appendContext?.(\n\t\t\t\t`The tree has changed since the last query. The new state of the tree is: \\n\\n\\`\\`\\`JSON\\n${stringified}\\n\\`\\`\\``,\n\t\t\t);\n\t\t\tthis.options?.logger?.log(\n\t\t\t\t`### Latest Tree State\\n\\nThe Tree was edited by a local or remote user since the previous query. The latest state is:\\n\\n\\`\\`\\`JSON\\n${stringified}\\n\\`\\`\\`\\n\\n`,\n\t\t\t);\n\t\t}\n\n\t\t// Fork a branch that will live for the lifetime of this query (which can be multiple LLM calls if the there are errors or the LLM decides to take multiple steps to accomplish a task).\n\t\t// The branch will be merged back into the outer branch if and only if the query succeeds.\n\t\tconst queryTree = this.outerTree.fork();\n\t\tconst maxEditCount = this.options?.maximumSequentialEdits ?? defaultMaxSequentialEdits;\n\t\tlet active = true;\n\t\tlet editCount = 0;\n\t\tlet editFailed = false;\n\t\tconst { editToolName } = this.client;\n\t\tconst edit = async (js: string): Promise<EditResult> => {\n\t\t\tif (editToolName === undefined) {\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"disabledError\",\n\t\t\t\t\tmessage: \"Editing is not enabled for this model.\",\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (!active) {\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"expiredError\",\n\t\t\t\t\tmessage: `The query has already completed. Further edits are not allowed.`,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tif (++editCount > maxEditCount) {\n\t\t\t\teditFailed = true;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"tooManyEditsError\",\n\t\t\t\t\tmessage: `The maximum number of edits (${maxEditCount}) for this query has been exceeded.`,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst editResult = await applyTreeFunction(\n\t\t\t\tqueryTree,\n\t\t\t\tjs,\n\t\t\t\tthis.options?.validator,\n\t\t\t\tthis.options?.logger,\n\t\t\t);\n\n\t\t\teditFailed ||= editResult.type !== \"success\";\n\t\t\treturn editResult;\n\t\t};\n\n\t\tconst responseMessage = await this.client.query({\n\t\t\ttext: userPrompt,\n\t\t\tedit,\n\t\t});\n\t\tactive = false;\n\n\t\tif (!editFailed) {\n\t\t\tthis.outerTree.branch.merge(queryTree.branch);\n\t\t\tthis.outerTreeIsDirty = false;\n\t\t}\n\t\tthis.options?.logger?.log(`## Response\\n\\n`);\n\t\tthis.options?.logger?.log(`${responseMessage}\\n\\n`);\n\t\treturn responseMessage;\n\t}\n}\n\n/**\n * Creates an unhydrated node of the given schema with the given value.\n * @remarks If the schema is an object with {@link llmDefault | default values}, this function populates the node with those defaults.\n */\nfunction constructTreeNode(schema: TreeNodeSchema, value: FactoryContentObject): TreeNode {\n\tif (schema instanceof ObjectNodeSchema) {\n\t\tconst inputWithDefaults: Record<string, InsertableContent | undefined> = {};\n\t\tfor (const [key, field] of schema.fields) {\n\t\t\tif (value[key] === undefined) {\n\t\t\t\tif (\n\t\t\t\t\ttypeof field.metadata.custom === \"object\" &&\n\t\t\t\t\tfield.metadata.custom !== null &&\n\t\t\t\t\tllmDefault in field.metadata.custom\n\t\t\t\t) {\n\t\t\t\t\tconst defaulter = field.metadata.custom[llmDefault];\n\t\t\t\t\tif (typeof defaulter === \"function\") {\n\t\t\t\t\t\tconst defaultValue: unknown = defaulter();\n\t\t\t\t\t\tif (defaultValue !== undefined) {\n\t\t\t\t\t\t\tinputWithDefaults[key] = defaultValue;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tinputWithDefaults[key] = value[key];\n\t\t\t}\n\t\t}\n\t\treturn constructNode(schema, inputWithDefaults);\n\t}\n\treturn constructNode(schema, value);\n}\n\n/**\n * Applies the given function (as a string of JavaScript code or an actual function) to the given tree.\n */\nasync function applyTreeFunction<TSchema extends ImplicitFieldSchema>(\n\ttree: Subtree<TSchema>,\n\tfn: string | EditFunction<TSchema>,\n\tvalidator: ((js: string) => boolean) | undefined,\n\tlogger: Logger | undefined,\n): Promise<EditResult> {\n\tlogger?.log(`### Editing Tool Invoked\\n\\n`);\n\tlogger?.log(`#### Generated Code\\n\\n\\`\\`\\`javascript\\n${fn}\\n\\`\\`\\`\\n\\n`);\n\n\tif (validator?.(fn.toString()) === false) {\n\t\tlogger?.log(`#### Code Validation Failed\\n\\n`);\n\t\treturn {\n\t\t\ttype: \"validationError\",\n\t\t\tmessage: \"The generated code did not pass validation. Please try again.\",\n\t\t};\n\t}\n\n\t// Stick the tree schema constructors on an object passed to the function so that the LLM can create new nodes.\n\tconst create: Record<string, (input: FactoryContentObject) => TreeNode> = {};\n\tfor (const schema of findNamedSchemas(tree.schema)) {\n\t\tconst name = getFriendlyName(schema);\n\t\tcreate[name] = (input: FactoryContentObject) => constructTreeNode(schema, input);\n\t}\n\n\t// Fork a branch to edit. If the edit fails or produces an error, we discard this branch, otherwise we merge it.\n\tconst editTree = tree.fork();\n\tconst params = {\n\t\tget root(): ReadableField<TSchema> {\n\t\t\treturn editTree.field;\n\t\t},\n\t\tset root(value: TreeFieldFromImplicitField<ReadSchema<TSchema>>) {\n\t\t\teditTree.field = value;\n\t\t},\n\t\tcreate,\n\t};\n\n\tlet editFunction: EditFunction<TSchema>;\n\tif (typeof fn === \"string\") {\n\t\ttry {\n\t\t\teditFunction = processLlmCode(fn);\n\t\t} catch (error) {\n\t\t\tlogger?.log(`#### Error\\n\\n`);\n\t\t\tconst errorMessage = error instanceof Error ? error.message : JSON.stringify(error);\n\t\t\tlogger?.log(`\\`\\`\\`JSON\\n${errorMessage}\\n\\`\\`\\`\\n\\n`);\n\t\t\teditTree.branch.dispose();\n\t\t\treturn {\n\t\t\t\ttype: \"compileError\",\n\t\t\t\tmessage: `The supplied JavaScript function is not valid: ${errorMessage}`,\n\t\t\t};\n\t\t}\n\t} else {\n\t\teditFunction = fn;\n\t}\n\n\ttry {\n\t\tawait editFunction(params);\n\t} catch (error: unknown) {\n\t\tlogger?.log(`#### Error\\n\\n`);\n\t\tconst errorMessage = error instanceof Error ? error.message : JSON.stringify(error);\n\t\tlogger?.log(`\\`\\`\\`JSON\\n${errorMessage}\\n\\`\\`\\`\\n\\n`);\n\t\teditTree.branch.dispose();\n\t\treturn {\n\t\t\ttype: \"runtimeError\",\n\t\t\tmessage: `Running the function produced an error. The state of the tree will be reset to its previous state as it was before the function ran. Please try again. Here is the error: ${errorMessage}`,\n\t\t};\n\t}\n\n\ttree.branch.merge(editTree.branch);\n\tlogger?.log(`#### New Tree State\\n\\n`);\n\tlogger?.log(`${`\\`\\`\\`JSON\\n${stringifyTree(tree.field)}\\n\\`\\`\\``}\\n\\n`);\n\treturn {\n\t\ttype: \"success\",\n\t\tmessage: `After running the function, the new state of the tree is:\\n\\n\\`\\`\\`JSON\\n${stringifyTree(tree.field)}\\n\\`\\`\\``,\n\t};\n}\n\nfunction processLlmCode<TSchema extends ImplicitFieldSchema>(\n\tcode: string,\n): EditFunction<TSchema> {\n\tconst functionName = findInvocableFunctionName(code);\n\tif (functionName === undefined) {\n\t\tthrow new Error(\"Generated code does not contain an invokable function\");\n\t}\n\n\tconst executionCode = `${stripExportSyntax(code)}\\n\\nreturn ${functionName}(${paramsName});`;\n\t// eslint-disable-next-line no-new-func, @typescript-eslint/no-implied-eval\n\tconst fn = new Function(paramsName, executionCode);\n\treturn fn as EditFunction<TSchema>;\n}\n\n/**\n * Finds the name of the first invocable function in the given code.\n */\n"]}
|
|
1
|
+
{"version":3,"file":"agent.js","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type {\n\tImplicitFieldSchema,\n\tTreeFieldFromImplicitField,\n\tTreeNodeSchema,\n} from \"@fluidframework/tree\";\nimport { TreeNode } from \"@fluidframework/tree\";\nimport type {\n\tReadableField,\n\tFactoryContentObject,\n\tInsertableContent,\n\tReadSchema,\n} from \"@fluidframework/tree/alpha\";\nimport { ObjectNodeSchema, Tree } from \"@fluidframework/tree/alpha\";\n\nimport type { SharedTreeChatModel, EditResult, SemanticAgentOptions, Logger } from \"./api.js\";\nimport { getPrompt, stringifyTree } from \"./prompt.js\";\nimport { Subtree } from \"./subtree.js\";\nimport {\n\tconstructNode,\n\tgetFriendlyName,\n\tllmDefault,\n\ttype TreeView,\n\tfindNamedSchemas,\n\ttoErrorString,\n} from \"./utils.js\";\n\n/**\n * The default maximum number of sequential edits the LLM can make before we assume it's stuck in a loop.\n * @remarks This can be overridden by passing {@link SemanticAgentOptions.maximumSequentialEdits | maximumSequentialEdits} to {@link createSemanticAgent}.\n */\nconst defaultMaxSequentialEdits = 20;\n\n/**\n * An agent that uses a {@link SharedTreeChatModel} to interact with a SharedTree.\n * @remarks This class forwards user queries to the chat model, and handles the application of any edits to the tree that the model requests.\n * @alpha @sealed\n */\nexport class SharedTreeSemanticAgent<TSchema extends ImplicitFieldSchema> {\n\t// Converted from ECMAScript private fields (#name) to TypeScript private members for easier debugger inspection.\n\tprivate readonly outerTree: Subtree<TSchema>;\n\t/**\n\t * Whether or not the outer tree has changed since the last query finished.\n\t */\n\tprivate outerTreeIsDirty = false;\n\n\tpublic constructor(\n\t\tprivate readonly client: SharedTreeChatModel,\n\t\ttree: TreeView<TSchema> | (ReadableField<TSchema> & TreeNode),\n\t\tprivate readonly options?: Readonly<SemanticAgentOptions>,\n\t) {\n\t\tif (tree instanceof TreeNode) {\n\t\t\tTree.on(tree, \"treeChanged\", () => (this.outerTreeIsDirty = true));\n\t\t} else {\n\t\t\ttree.events.on(\"changed\", () => (this.outerTreeIsDirty = true));\n\t\t}\n\n\t\tthis.outerTree = new Subtree(tree);\n\t\tconst prompt = getPrompt({\n\t\t\tsubtree: this.outerTree,\n\t\t\teditToolName: this.client.editToolName,\n\t\t\tdomainHints: this.options?.domainHints,\n\t\t});\n\t\tthis.options?.logger?.log(`# Fluid Framework SharedTree AI Agent Log\\n\\n`);\n\t\tconst now = new Date();\n\t\tconst formattedDate = now.toLocaleString(undefined, {\n\t\t\tweekday: \"long\",\n\t\t\tyear: \"numeric\",\n\t\t\tmonth: \"long\",\n\t\t\tday: \"numeric\",\n\t\t\thour: \"numeric\",\n\t\t\tminute: \"2-digit\",\n\t\t\tsecond: \"2-digit\",\n\t\t});\n\t\tthis.options?.logger?.log(`Agent created: **${formattedDate}**\\n\\n`);\n\t\tif (this.client.name !== undefined) {\n\t\t\tthis.options?.logger?.log(`Model: **${this.client.name}**\\n\\n`);\n\t\t}\n\t\tthis.client.appendContext?.(prompt);\n\t\tthis.options?.logger?.log(`## System Prompt\\n\\n${prompt}\\n\\n`);\n\t}\n\n\t/**\n\t * Given a user prompt, return a response.\n\t *\n\t * @param userPrompt - The prompt to send to the agent.\n\t * @returns The agent's response.\n\t */\n\tpublic async query(userPrompt: string): Promise<string> {\n\t\tthis.options?.logger?.log(`## User Query\\n\\n${userPrompt}\\n\\n`);\n\n\t\t// Notify the llm if the tree has changed since the last query, and if so, provide the new state of the tree.\n\t\tif (this.outerTreeIsDirty) {\n\t\t\tconst stringified = stringifyTree(this.outerTree.field);\n\t\t\tthis.client.appendContext?.(\n\t\t\t\t`The tree has changed since the last query. The new state of the tree is: \\n\\n\\`\\`\\`JSON\\n${stringified}\\n\\`\\`\\``,\n\t\t\t);\n\t\t\tthis.options?.logger?.log(\n\t\t\t\t`### Latest Tree State\\n\\nThe Tree was edited by a local or remote user since the previous query. The latest state is:\\n\\n\\`\\`\\`JSON\\n${stringified}\\n\\`\\`\\`\\n\\n`,\n\t\t\t);\n\t\t}\n\n\t\t// Fork a branch that will live for the lifetime of this query (which can be multiple LLM calls if the there are errors or the LLM decides to take multiple steps to accomplish a task).\n\t\t// The branch will be merged back into the outer branch if and only if the query succeeds.\n\t\tconst queryTree = this.outerTree.fork();\n\t\tconst maxEditCount = this.options?.maximumSequentialEdits ?? defaultMaxSequentialEdits;\n\t\tlet active = true;\n\t\tlet editCount = 0;\n\t\tlet editFailed = false;\n\t\tconst { editToolName } = this.client;\n\t\tconst edit = async (editCode: string): Promise<EditResult> => {\n\t\t\tif (editToolName === undefined) {\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"disabledError\",\n\t\t\t\t\tmessage: \"Editing is not enabled for this model.\",\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (!active) {\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"expiredError\",\n\t\t\t\t\tmessage: `The query has already completed. Further edits are not allowed.`,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tif (++editCount > maxEditCount) {\n\t\t\t\teditFailed = true;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"tooManyEditsError\",\n\t\t\t\t\tmessage: `The maximum number of edits (${maxEditCount}) for this query has been exceeded.`,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst editResult = await applyTreeFunction(\n\t\t\t\tqueryTree,\n\t\t\t\teditCode,\n\t\t\t\tthis.options?.validateEdit ?? defaultValidateEdit,\n\t\t\t\tthis.options?.executeEdit ?? defaultExecuteEdit,\n\t\t\t\tthis.options?.logger,\n\t\t\t);\n\n\t\t\teditFailed ||= editResult.type !== \"success\";\n\t\t\treturn editResult;\n\t\t};\n\n\t\tconst responseMessage = await this.client.query({\n\t\t\ttext: userPrompt,\n\t\t\tedit,\n\t\t});\n\t\tactive = false;\n\n\t\tif (!editFailed) {\n\t\t\tthis.outerTree.branch.merge(queryTree.branch);\n\t\t\tthis.outerTreeIsDirty = false;\n\t\t}\n\t\tthis.options?.logger?.log(`## Response\\n\\n`);\n\t\tthis.options?.logger?.log(`${responseMessage}\\n\\n`);\n\t\treturn responseMessage;\n\t}\n}\n\n/**\n * Creates an unhydrated node of the given schema with the given value.\n * @remarks If the schema is an object with {@link llmDefault | default values}, this function populates the node with those defaults.\n */\nfunction constructTreeNode(schema: TreeNodeSchema, value: FactoryContentObject): TreeNode {\n\tif (schema instanceof ObjectNodeSchema) {\n\t\tconst inputWithDefaults: Record<string, InsertableContent | undefined> = {};\n\t\tfor (const [key, field] of schema.fields) {\n\t\t\tif (value[key] === undefined) {\n\t\t\t\tif (\n\t\t\t\t\ttypeof field.metadata.custom === \"object\" &&\n\t\t\t\t\tfield.metadata.custom !== null &&\n\t\t\t\t\tllmDefault in field.metadata.custom\n\t\t\t\t) {\n\t\t\t\t\tconst defaulter = field.metadata.custom[llmDefault];\n\t\t\t\t\tif (typeof defaulter === \"function\") {\n\t\t\t\t\t\tconst defaultValue: unknown = defaulter();\n\t\t\t\t\t\tif (defaultValue !== undefined) {\n\t\t\t\t\t\t\tinputWithDefaults[key] = defaultValue;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tinputWithDefaults[key] = value[key];\n\t\t\t}\n\t\t}\n\t\treturn constructNode(schema, inputWithDefaults);\n\t}\n\treturn constructNode(schema, value);\n}\n\n/**\n * Applies the given function (as a string of JavaScript code or an actual function) to the given tree.\n */\nasync function applyTreeFunction<TSchema extends ImplicitFieldSchema>(\n\ttree: Subtree<TSchema>,\n\teditCode: string,\n\tvalidateEdit: Required<SemanticAgentOptions>[\"validateEdit\"],\n\texecuteEdit: Required<SemanticAgentOptions>[\"executeEdit\"],\n\tlogger: Logger | undefined,\n): Promise<EditResult> {\n\tlogger?.log(`### Editing Tool Invoked\\n\\n`);\n\tlogger?.log(`#### Generated Code\\n\\n\\`\\`\\`javascript\\n${editCode}\\n\\`\\`\\`\\n\\n`);\n\n\ttry {\n\t\tawait validateEdit(editCode);\n\t} catch (error: unknown) {\n\t\tlogger?.log(`#### Code Validation Failed\\n\\n`);\n\t\tlogger?.log(`\\`\\`\\`JSON\\n${toErrorString(error)}\\n\\`\\`\\`\\n\\n`);\n\t\treturn {\n\t\t\ttype: \"validationError\",\n\t\t\tmessage: `The generated code did not pass validation: ${toErrorString(error)}`,\n\t\t};\n\t}\n\n\t// Stick the tree schema constructors on an object passed to the function so that the LLM can create new nodes.\n\tconst create: Record<string, (input: FactoryContentObject) => TreeNode> = {};\n\tfor (const schema of findNamedSchemas(tree.schema)) {\n\t\tconst name = getFriendlyName(schema);\n\t\tcreate[name] = (input: FactoryContentObject) => constructTreeNode(schema, input);\n\t}\n\n\t// Fork a branch to edit. If the edit fails or produces an error, we discard this branch, otherwise we merge it.\n\tconst editTree = tree.fork();\n\tconst context = {\n\t\tget root(): ReadableField<TSchema> {\n\t\t\treturn editTree.field;\n\t\t},\n\t\tset root(value: TreeFieldFromImplicitField<ReadSchema<TSchema>>) {\n\t\t\teditTree.field = value;\n\t\t},\n\t\tcreate,\n\t};\n\n\ttry {\n\t\tawait executeEdit(context, editCode);\n\t} catch (error: unknown) {\n\t\tlogger?.log(`#### Error\\n\\n`);\n\t\tlogger?.log(`\\`\\`\\`JSON\\n${toErrorString(error)}\\n\\`\\`\\`\\n\\n`);\n\t\teditTree.branch.dispose();\n\t\treturn {\n\t\t\ttype: \"executionError\",\n\t\t\tmessage: `Running the generated code produced an error. The state of the tree will be reset to its previous state as it was before the code ran. Please try again. Here is the error: ${toErrorString(error)}`,\n\t\t};\n\t}\n\n\ttree.branch.merge(editTree.branch);\n\tlogger?.log(`#### New Tree State\\n\\n`);\n\tlogger?.log(`${`\\`\\`\\`JSON\\n${stringifyTree(tree.field)}\\n\\`\\`\\``}\\n\\n`);\n\treturn {\n\t\ttype: \"success\",\n\t\tmessage: `After running the code, the new state of the tree is:\\n\\n\\`\\`\\`JSON\\n${stringifyTree(tree.field)}\\n\\`\\`\\``,\n\t};\n}\n\nconst defaultValidateEdit: Required<SemanticAgentOptions>[\"validateEdit\"] = () => {};\n\nconst defaultExecuteEdit: Required<SemanticAgentOptions>[\"executeEdit\"] = async (\n\tcontext,\n\tcode,\n) => {\n\t// eslint-disable-next-line no-new-func, @typescript-eslint/no-implied-eval\n\tconst fn = new Function(\"context\", code);\n\tawait fn(context);\n};\n"]}
|
package/lib/alpha.d.ts
CHANGED
package/lib/api.d.ts
CHANGED
|
@@ -24,10 +24,22 @@ export interface SemanticAgentOptions {
|
|
|
24
24
|
*/
|
|
25
25
|
domainHints?: string;
|
|
26
26
|
/**
|
|
27
|
-
* Validates any generated JavaScript created by the {@link SharedTreeChatModel.editToolName | model's editing tool}
|
|
28
|
-
* @remarks
|
|
27
|
+
* Validates any generated JavaScript created by the {@link SharedTreeChatModel.editToolName | model's editing tool}.
|
|
28
|
+
* @remarks This happens before the code is executed - execution can be intercepted by using the {@link SemanticAgentOptions.executeEdit | executeEdit} callback.
|
|
29
|
+
* @param code - The generated JavaScript code as a string.
|
|
30
|
+
* @throws If the code is invalid, this function should throw an error with a human-readable message describing why it is invalid.
|
|
29
31
|
*/
|
|
30
|
-
|
|
32
|
+
validateEdit?: (code: string) => void | Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* Evaluates (executes) any generated JavaScript created by the {@link SharedTreeChatModel.editToolName | model's editing tool}.
|
|
35
|
+
* @remarks This happens only after the code has been successfully validated by the optional {@link SemanticAgentOptions.validateEdit | validateEdit} function.
|
|
36
|
+
* @param context - An object that must be provided to the generated code as a variable named "context" in its top-level scope.
|
|
37
|
+
* @param code - The generated JavaScript code as a string.
|
|
38
|
+
* @throws If an error is thrown while evaluating the code, it will be caught and the message will be forwarded to the model for debugging.
|
|
39
|
+
* @remarks If this function is not provided, the generated code will be executed using a simple `eval` call, which may not provide sufficient security guarantees for some environments.
|
|
40
|
+
* Use a library such as SES to provide a more secure implementation - see {@link createSesEditEvaluator} for a drop-in option.
|
|
41
|
+
*/
|
|
42
|
+
executeEdit?: (context: Record<string, unknown>, code: string) => void | Promise<void>;
|
|
31
43
|
/**
|
|
32
44
|
* The maximum number of sequential edits the LLM can make before we assume it's stuck in a loop.
|
|
33
45
|
*/
|
|
@@ -42,15 +54,14 @@ export interface SemanticAgentOptions {
|
|
|
42
54
|
* @remarks
|
|
43
55
|
* - `success`: The edit was successfully applied.
|
|
44
56
|
* - `disabledError`: The model is not allowed to edit the tree (i.e. {@link SharedTreeChatModel.editToolName} was not provided).
|
|
45
|
-
* - `validationError`: The provided JavaScript did not pass the optional {@link SemanticAgentOptions.
|
|
46
|
-
* - `
|
|
47
|
-
* - `runtimeError`: An error was thrown while executing the provided JavaScript.
|
|
57
|
+
* - `validationError`: The provided JavaScript did not pass the optional {@link SemanticAgentOptions.validateEdit} function.
|
|
58
|
+
* - `executionError`: An error was thrown while parsing or executing the provided JavaScript.
|
|
48
59
|
* - `tooManyEditsError`: The {@link SharedTreeChatQuery.edit} function has been called more than the number of times specified by {@link SemanticAgentOptions.maximumSequentialEdits} for the same message.
|
|
49
60
|
* - `expiredError`: The {@link SharedTreeChatQuery.edit} function was called after the issuing query has already completed.
|
|
50
61
|
* @alpha
|
|
51
62
|
*/
|
|
52
63
|
export interface EditResult {
|
|
53
|
-
type: "success" | "disabledError" | "validationError" | "
|
|
64
|
+
type: "success" | "disabledError" | "validationError" | "executionError" | "tooManyEditsError" | "expiredError";
|
|
54
65
|
/**
|
|
55
66
|
* A human-readable message describing the result of the edit attempt.
|
|
56
67
|
* @remarks In the case of an error, this message is appropriate to include in a model's chat history.
|
package/lib/api.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAE1E,OAAO,KAAK,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAEtF;;;GAGG;AACH,MAAM,WAAW,MAAM;IACtB;;OAEG;IACH,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACpC;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtD;;;;;;;;OAQG;IACH,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvF;;OAEG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,UAAU;IAC1B,IAAI,EACD,SAAS,GACT,eAAe,GACf,iBAAiB,GACjB,gBAAgB,GAChB,mBAAmB,GACnB,cAAc,CAAC;IAElB;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,UAAU,CAQhE;AAED;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IACnC;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CACtC;AAED;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IACnC;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,aAAa,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC;;;OAGG;IACH,KAAK,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACrD;AAED;;GAEG;AACH,MAAM,MAAM,YAAY,CAAC,OAAO,SAAS,mBAAmB,IAAI,CAAC,EAChE,IAAI,EACJ,MAAM,GACN,EAAE;IACF,IAAI,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;IAC7B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,QAAQ,CAAC,CAAC;CAClE,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC"}
|
package/lib/api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAgFH;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,KAAc;IAC1C,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACjD,OAAO,KAAK,CAAC;IACd,CAAC;IACD,OAAO,CACN,OAAQ,KAAoB,CAAC,IAAI,KAAK,QAAQ;QAC9C,OAAQ,KAAoB,CAAC,OAAO,KAAK,QAAQ,CACjD,CAAC;AACH,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { ImplicitFieldSchema, TreeNode } from \"@fluidframework/tree\";\n// This is used for doc links\nimport type { FactoryContentObject, ReadableField } from \"@fluidframework/tree/alpha\";\n\n/**\n * Logger interface for logging events from a {@link SharedTreeSemanticAgent}.\n * @alpha\n */\nexport interface Logger {\n\t/**\n\t * Log a message.\n\t */\n\tlog(message: string): void;\n}\n\n/**\n * Options used to parameterize the creation of a {@link SharedTreeSemanticAgent}.\n * @alpha\n */\nexport interface SemanticAgentOptions {\n\t/**\n\t * Additional information about the application domain that will be included in the context provided to the {@link SharedTreeChatModel | model}.\n\t */\n\tdomainHints?: string;\n\t/**\n\t * Validates any generated JavaScript created by the {@link SharedTreeChatModel.editToolName | model's editing tool}.\n\t * @remarks This happens before the code is executed - execution can be intercepted by using the {@link SemanticAgentOptions.executeEdit | executeEdit} callback.\n\t * @param code - The generated JavaScript code as a string.\n\t * @throws If the code is invalid, this function should throw an error with a human-readable message describing why it is invalid.\n\t */\n\tvalidateEdit?: (code: string) => void | Promise<void>;\n\t/**\n\t * Evaluates (executes) any generated JavaScript created by the {@link SharedTreeChatModel.editToolName | model's editing tool}.\n\t * @remarks This happens only after the code has been successfully validated by the optional {@link SemanticAgentOptions.validateEdit | validateEdit} function.\n\t * @param context - An object that must be provided to the generated code as a variable named \"context\" in its top-level scope.\n\t * @param code - The generated JavaScript code as a string.\n\t * @throws If an error is thrown while evaluating the code, it will be caught and the message will be forwarded to the model for debugging.\n\t * @remarks If this function is not provided, the generated code will be executed using a simple `eval` call, which may not provide sufficient security guarantees for some environments.\n\t * Use a library such as SES to provide a more secure implementation - see {@link createSesEditEvaluator} for a drop-in option.\n\t */\n\texecuteEdit?: (context: Record<string, unknown>, code: string) => void | Promise<void>;\n\t/**\n\t * The maximum number of sequential edits the LLM can make before we assume it's stuck in a loop.\n\t */\n\tmaximumSequentialEdits?: number;\n\t/**\n\t * If supplied, generates human-readable markdown text describing the actions taken by the {@link SharedTreeSemanticAgent | agent} as it performs queries.\n\t */\n\tlogger?: Logger;\n}\n\n/**\n * A result from an edit attempt via the {@link SharedTreeChatQuery.edit} function.\n * @remarks\n * - `success`: The edit was successfully applied.\n * - `disabledError`: The model is not allowed to edit the tree (i.e. {@link SharedTreeChatModel.editToolName} was not provided).\n * - `validationError`: The provided JavaScript did not pass the optional {@link SemanticAgentOptions.validateEdit} function.\n * - `executionError`: An error was thrown while parsing or executing the provided JavaScript.\n * - `tooManyEditsError`: The {@link SharedTreeChatQuery.edit} function has been called more than the number of times specified by {@link SemanticAgentOptions.maximumSequentialEdits} for the same message.\n * - `expiredError`: The {@link SharedTreeChatQuery.edit} function was called after the issuing query has already completed.\n * @alpha\n */\nexport interface EditResult {\n\ttype:\n\t\t| \"success\"\n\t\t| \"disabledError\"\n\t\t| \"validationError\"\n\t\t| \"executionError\"\n\t\t| \"tooManyEditsError\"\n\t\t| \"expiredError\";\n\n\t/**\n\t * A human-readable message describing the result of the edit attempt.\n\t * @remarks In the case of an error, this message is appropriate to include in a model's chat history.\n\t */\n\tmessage: string;\n}\n\n/**\n * Type guard for {@link EditResult}.\n */\nexport function isEditResult(value: unknown): value is EditResult {\n\tif (value === null || typeof value !== \"object\") {\n\t\treturn false;\n\t}\n\treturn (\n\t\ttypeof (value as EditResult).type === \"string\" &&\n\t\ttypeof (value as EditResult).message === \"string\"\n\t);\n}\n\n/**\n * A query from a user to a {@link SharedTreeSemanticAgent}.\n * @remarks Processing a query may involve editing the SharedTree via the provided {@link SharedTreeChatQuery.edit} function.\n * @alpha\n */\nexport interface SharedTreeChatQuery {\n\t/**\n\t * The user's query.\n\t */\n\ttext: string;\n\t/**\n\t * Edit the tree with the provided JavaScript function code.\n\t * @remarks Attempting an edit may fail for a variety of reasons which are captured in the {@link EditResult | returned object}.\n\t */\n\tedit(js: string): Promise<EditResult>;\n}\n\n/**\n * A plugin interface that handles queries from a {@link SharedTreeSemanticAgent}.\n * @remarks This wraps an underlying communication with an LLM and receives all necessary {@link SharedTreeChatModel.appendContext | context} from the {@link SharedTreeSemanticAgent | agent} for the LLM to properly analyze and edit the tree.\n * @alpha\n */\nexport interface SharedTreeChatModel {\n\t/**\n\t * A optional name of this chat model.\n\t * @remarks If supplied, this may be used in logging or debugging information.\n\t * @example \"gpt-5\"\n\t */\n\tname?: string;\n\t/**\n\t * The name of the tool that the model should use to edit the tree.\n\t * @remarks If supplied, this will be mentioned in the context provided to the model so that the underlying LLM will be encouraged to use it when a user query requires an edit.\n\t * The model should \"implement\" the tool by registering it with the underlying LLM API.\n\t * The tool should take an LLM-generated JavaScript function as input and supply it to the {@link SharedTreeChatQuery.edit | edit} function.\n\t * Instructions for generating the proper function signature and implementation will be provided by the {@link SharedTreeSemanticAgent | agent} via {@link SharedTreeChatModel.appendContext | context}.\n\t * If not supplied, the model will not be able to edit the tree (running the {@link SharedTreeChatQuery.edit | edit} function will fail).\n\t */\n\teditToolName?: string;\n\t/**\n\t * Add contextual information to the model that may be relevant to future queries.\n\t * @remarks In practice, this may be implemented by e.g. appending a \"system\" message to an LLM's chat/message history.\n\t * This context must be present in the context window of every {@link SharedTreeChatModel.query | query} for e.g. {@link SharedTreeChatModel.editToolName | editing} to work.\n\t * @param text - The message or context to append.\n\t */\n\tappendContext?(text: string): void;\n\t/**\n\t * Queries the chat model with a request from the user.\n\t * @remarks This model may simply return a text response to the query, or it may first call the {@link SharedTreeChatQuery.edit} function (potentially multiple times) to modify the tree in response to the query.\n\t */\n\tquery(message: SharedTreeChatQuery): Promise<string>;\n}\n\n/**\n * A function that edits a SharedTree.\n */\nexport type EditFunction<TSchema extends ImplicitFieldSchema> = ({\n\troot,\n\tcreate,\n}: {\n\troot: ReadableField<TSchema>;\n\tcreate: Record<string, (input: FactoryContentObject) => TreeNode>;\n}) => void | Promise<void>;\n"]}
|
package/lib/index.d.ts
CHANGED
|
@@ -12,4 +12,5 @@ export type { EditResult, SharedTreeChatModel, SharedTreeChatQuery, Logger, Sema
|
|
|
12
12
|
export { type TreeView, llmDefault } from "./utils.js";
|
|
13
13
|
export { buildFunc, exposeMethodsSymbol, type ArgsTuple, type ExposedMethods, type Arg, type FunctionDef, type MethodKeys, type BindableSchema, type Ctor, type Infer, type IExposedMethods, } from "./methodBinding.js";
|
|
14
14
|
export { LangchainChatModel, createSemanticAgent } from "./langchain.js";
|
|
15
|
+
export { createSesEditEvaluator } from "./ses.js";
|
|
15
16
|
//# sourceMappingURL=index.d.ts.map
|
package/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;GAIG;AAEH,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AACrD,YAAY,EACX,UAAU,EACV,mBAAmB,EACnB,mBAAmB,EACnB,MAAM,EACN,oBAAoB,GACpB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,KAAK,QAAQ,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,EACN,SAAS,EACT,mBAAmB,EACnB,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,KAAK,GAAG,EACR,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,IAAI,EACT,KAAK,KAAK,EACV,KAAK,eAAe,GACpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;GAIG;AAEH,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AACrD,YAAY,EACX,UAAU,EACV,mBAAmB,EACnB,mBAAmB,EACnB,MAAM,EACN,oBAAoB,GACpB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,KAAK,QAAQ,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,EACN,SAAS,EACT,mBAAmB,EACnB,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,KAAK,GAAG,EACR,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,IAAI,EACT,KAAK,KAAK,EACV,KAAK,eAAe,GACpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACzE,OAAO,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC"}
|
package/lib/index.js
CHANGED
|
@@ -11,4 +11,5 @@ export { SharedTreeSemanticAgent } from "./agent.js";
|
|
|
11
11
|
export { llmDefault } from "./utils.js";
|
|
12
12
|
export { buildFunc, exposeMethodsSymbol, } from "./methodBinding.js";
|
|
13
13
|
export { LangchainChatModel, createSemanticAgent } from "./langchain.js";
|
|
14
|
+
export { createSesEditEvaluator } from "./ses.js";
|
|
14
15
|
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;GAIG;AAEH,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAQrD,OAAO,EAAiB,UAAU,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,EACN,SAAS,EACT,mBAAmB,GAUnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n/**\n * A library for creating AI agents to interact with a {@link SharedTree | https://fluidframework.com/docs/data-structures/tree/}.\n *\n * @packageDocumentation\n */\n\nexport { SharedTreeSemanticAgent } from \"./agent.js\";\nexport type {\n\tEditResult,\n\tSharedTreeChatModel,\n\tSharedTreeChatQuery,\n\tLogger,\n\tSemanticAgentOptions,\n} from \"./api.js\";\nexport { type TreeView, llmDefault } from \"./utils.js\";\nexport {\n\tbuildFunc,\n\texposeMethodsSymbol,\n\ttype ArgsTuple,\n\ttype ExposedMethods,\n\ttype Arg,\n\ttype FunctionDef,\n\ttype MethodKeys,\n\ttype BindableSchema,\n\ttype Ctor,\n\ttype Infer,\n\ttype IExposedMethods,\n} from \"./methodBinding.js\";\nexport { LangchainChatModel, createSemanticAgent } from \"./langchain.js\";\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;GAIG;AAEH,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAQrD,OAAO,EAAiB,UAAU,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,EACN,SAAS,EACT,mBAAmB,GAUnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACzE,OAAO,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n/**\n * A library for creating AI agents to interact with a {@link SharedTree | https://fluidframework.com/docs/data-structures/tree/}.\n *\n * @packageDocumentation\n */\n\nexport { SharedTreeSemanticAgent } from \"./agent.js\";\nexport type {\n\tEditResult,\n\tSharedTreeChatModel,\n\tSharedTreeChatQuery,\n\tLogger,\n\tSemanticAgentOptions,\n} from \"./api.js\";\nexport { type TreeView, llmDefault } from \"./utils.js\";\nexport {\n\tbuildFunc,\n\texposeMethodsSymbol,\n\ttype ArgsTuple,\n\ttype ExposedMethods,\n\ttype Arg,\n\ttype FunctionDef,\n\ttype MethodKeys,\n\ttype BindableSchema,\n\ttype Ctor,\n\ttype Infer,\n\ttype IExposedMethods,\n} from \"./methodBinding.js\";\nexport { LangchainChatModel, createSemanticAgent } from \"./langchain.js\";\nexport { createSesEditEvaluator } from \"./ses.js\";\n"]}
|
package/lib/langchain.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"langchain.d.ts","sourceRoot":"","sources":["../src/langchain.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,mBAAmB,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAE/F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6CAA6C,CAAC;AAYjF,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAEN,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C;;;;GAIG;AACH,qBAAa,kBAAmB,YAAW,mBAAmB;IAE1C,OAAO,CAAC,QAAQ,CAAC,KAAK;IADzC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkD;gBACvC,KAAK,EAAE,aAAa;IAExD,SAAgB,YAAY,6BAA6B;IAEzD,IAAW,IAAI,IAAI,MAAM,GAAG,SAAS,CAGpC;IAEM,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAI3B,KAAK,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC;YAKjD,SAAS;
|
|
1
|
+
{"version":3,"file":"langchain.d.ts","sourceRoot":"","sources":["../src/langchain.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,mBAAmB,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAE/F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6CAA6C,CAAC;AAYjF,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAEN,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C;;;;GAIG;AACH,qBAAa,kBAAmB,YAAW,mBAAmB;IAE1C,OAAO,CAAC,QAAQ,CAAC,KAAK;IADzC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkD;gBACvC,KAAK,EAAE,aAAa;IAExD,SAAgB,YAAY,6BAA6B;IAEzD,IAAW,IAAI,IAAI,MAAM,GAAG,SAAS,CAGpC;IAEM,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAI3B,KAAK,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC;YAKjD,SAAS;CA2CvB;AAID;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,SAAS,mBAAmB,EACtE,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC,EAC3B,OAAO,CAAC,EAAE,QAAQ,CAAC,oBAAoB,CAAC,GACtC,uBAAuB,CAAC,OAAO,CAAC,CAAC;AACpC;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,SAAS,mBAAmB,EACtE,MAAM,EAAE,aAAa,EACrB,IAAI,EAAE,aAAa,CAAC,OAAO,CAAC,GAAG,QAAQ,EACvC,OAAO,CAAC,EAAE,QAAQ,CAAC,oBAAoB,CAAC,GACtC,uBAAuB,CAAC,OAAO,CAAC,CAAC;AACpC;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,SAAS,mBAAmB,EACtE,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,OAAO,CAAC,GAAG,QAAQ,CAAC,EACjE,OAAO,CAAC,EAAE,QAAQ,CAAC,oBAAoB,CAAC,GACtC,uBAAuB,CAAC,OAAO,CAAC,CAAC"}
|
package/lib/langchain.js
CHANGED
|
@@ -38,10 +38,9 @@ export class LangchainChatModel {
|
|
|
38
38
|
return edit(functionCode);
|
|
39
39
|
}, {
|
|
40
40
|
name: this.editToolName,
|
|
41
|
-
description: `Invokes a JavaScript
|
|
41
|
+
description: `Invokes a JavaScript code snippet to edit a tree of application data.`,
|
|
42
42
|
schema: z.object({
|
|
43
|
-
functionCode: z.string().describe(`The
|
|
44
|
-
For example: "function editTree({ root, create }) { /* your code here */ }"`),
|
|
43
|
+
functionCode: z.string().describe(`The JavaScript snippet code.`),
|
|
45
44
|
}),
|
|
46
45
|
});
|
|
47
46
|
const runnable = this.model.bindTools?.([editingTool], { tool_choice: "auto" });
|
package/lib/langchain.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"langchain.js","sourceRoot":"","sources":["../src/langchain.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,0CAA0C,CAAC;AAMtE,OAAO,EACN,YAAY,EACZ,aAAa;AACb,sDAAsD;EACtD,MAAM,0BAA0B,CAAC;AAClC,sDAAsD;AACtD,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAC7C,OAAO,CAAC,MAAM,KAAK,CAAC;AAEpB,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EACN,YAAY,GAIZ,MAAM,UAAU,CAAC;AAGlB;;;;GAIG;AACH,MAAM,OAAO,kBAAkB;IAE9B,YAAoC,KAAoB;QAApB,UAAK,GAAL,KAAK,CAAe;QADvC,aAAQ,GAA+C,EAAE,CAAC;QAG3D,iBAAY,GAAG,yBAAyB,CAAC;IAFE,CAAC;IAI5D,IAAW,IAAI;QACd,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,SAAS,CAAC;QAC5C,OAAO,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;IACpD,CAAC;IAEM,aAAa,CAAC,IAAY;QAChC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;IAC7C,CAAC;IAEM,KAAK,CAAC,KAAK,CAAC,KAA0B;QAC5C,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;QACjD,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IACrD,CAAC;IAEO,KAAK,CAAC,SAAS,CAAC,IAAiC;QACxD,MAAM,WAAW,GAAG,IAAI,CACvB,KAAK,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE;YAC1B,OAAO,IAAI,CAAC,YAAY,CAAC,CAAC;QAC3B,CAAC,EACD;YACC,IAAI,EAAE,IAAI,CAAC,YAAY;YACvB,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"langchain.js","sourceRoot":"","sources":["../src/langchain.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { UsageError } from \"@fluidframework/telemetry-utils/internal\";\nimport type { ImplicitFieldSchema, ReadableField, TreeNode } from \"@fluidframework/tree/alpha\";\n// eslint-disable-next-line import/no-internal-modules\nimport type { BaseChatModel } from \"@langchain/core/language_models/chat_models\";\n// eslint-disable-next-line import/no-internal-modules\nimport type { AIMessage, ToolMessage } from \"@langchain/core/messages\";\nimport {\n\tHumanMessage,\n\tSystemMessage,\n\t// eslint-disable-next-line import/no-internal-modules\n} from \"@langchain/core/messages\";\n// eslint-disable-next-line import/no-internal-modules\nimport { tool } from \"@langchain/core/tools\";\nimport z from \"zod\";\n\nimport { SharedTreeSemanticAgent } from \"./agent.js\";\nimport {\n\tisEditResult,\n\ttype SemanticAgentOptions,\n\ttype SharedTreeChatModel,\n\ttype SharedTreeChatQuery,\n} from \"./api.js\";\nimport type { TreeView } from \"./utils.js\";\n\n/**\n * An implementation of {@link SharedTreeChatModel} that wraps a Langchain chat model.\n * @remarks This class is responsible for managing the conversation history and interacting with the Langchain model (e.g. via Tool use for editing).\n * @alpha\n */\nexport class LangchainChatModel implements SharedTreeChatModel {\n\tprivate readonly messages: (HumanMessage | AIMessage | ToolMessage)[] = [];\n\tpublic constructor(private readonly model: BaseChatModel) {}\n\n\tpublic readonly editToolName = \"GenerateTreeEditingCode\";\n\n\tpublic get name(): string | undefined {\n\t\tconst name = this.model.metadata?.modelName;\n\t\treturn typeof name === \"string\" ? name : undefined;\n\t}\n\n\tpublic appendContext(text: string): void {\n\t\tthis.messages.push(new SystemMessage(text));\n\t}\n\n\tpublic async query(query: SharedTreeChatQuery): Promise<string> {\n\t\tthis.messages.push(new HumanMessage(query.text));\n\t\treturn this.queryEdit(async (js) => query.edit(js));\n\t}\n\n\tprivate async queryEdit(edit: SharedTreeChatQuery[\"edit\"]): Promise<string> {\n\t\tconst editingTool = tool(\n\t\t\tasync ({ functionCode }) => {\n\t\t\t\treturn edit(functionCode);\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: this.editToolName,\n\t\t\t\tdescription: `Invokes a JavaScript code snippet to edit a tree of application data.`,\n\t\t\t\tschema: z.object({\n\t\t\t\t\tfunctionCode: z.string().describe(`The JavaScript snippet code.`),\n\t\t\t\t}),\n\t\t\t},\n\t\t);\n\t\tconst runnable = this.model.bindTools?.([editingTool], { tool_choice: \"auto\" });\n\t\tif (runnable === undefined) {\n\t\t\tthrow new UsageError(\"LLM client must support function calling or tool use.\");\n\t\t}\n\n\t\tconst responseMessage = await runnable.invoke(this.messages);\n\t\tthis.messages.push(responseMessage);\n\n\t\tif (responseMessage.tool_calls !== undefined && responseMessage.tool_calls.length > 0) {\n\t\t\tfor (const toolCall of responseMessage.tool_calls) {\n\t\t\t\tswitch (toolCall.name) {\n\t\t\t\t\tcase editingTool.name: {\n\t\t\t\t\t\tconst toolResult = await editingTool.invoke(toolCall);\n\t\t\t\t\t\tthis.messages.push(toolResult);\n\t\t\t\t\t\tconst editResult: unknown = JSON.parse(toolResult.text);\n\t\t\t\t\t\tif (isEditResult(editResult) && editResult.type === \"tooManyEditsError\") {\n\t\t\t\t\t\t\treturn editResult.message;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// This call will either terminate the edit chain (if the LLM decides not to edit further) or continue it if more edits are required.\n\t\t\t\t\t\treturn this.queryEdit(edit);\n\t\t\t\t\t}\n\t\t\t\t\tdefault: {\n\t\t\t\t\t\tthis.messages.push(new HumanMessage(`Unrecognized tool call: ${toolCall.name}`));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn responseMessage.text;\n\t}\n}\n\n// #region Legacy APIs\n\n/**\n * Create a {@link SharedTreeSemanticAgent} using a Langchain chat model.\n * @alpha\n * @deprecated Use {@link SharedTreeSemanticAgent} with a {@link LangchainChatModel} instead.\n */\nexport function createSemanticAgent<TSchema extends ImplicitFieldSchema>(\n\tclient: BaseChatModel,\n\ttreeView: TreeView<TSchema>,\n\toptions?: Readonly<SemanticAgentOptions>,\n): SharedTreeSemanticAgent<TSchema>;\n/**\n * Create a {@link SharedTreeSemanticAgent} using a Langchain chat model.\n * @alpha\n * @deprecated Use {@link SharedTreeSemanticAgent} with a {@link LangchainChatModel} instead.\n */\nexport function createSemanticAgent<TSchema extends ImplicitFieldSchema>(\n\tclient: BaseChatModel,\n\tnode: ReadableField<TSchema> & TreeNode,\n\toptions?: Readonly<SemanticAgentOptions>,\n): SharedTreeSemanticAgent<TSchema>;\n/**\n * Create a {@link SharedTreeSemanticAgent} using a Langchain chat model.\n * @alpha\n * @deprecated Use {@link SharedTreeSemanticAgent} with a {@link LangchainChatModel} instead.\n */\nexport function createSemanticAgent<TSchema extends ImplicitFieldSchema>(\n\tclient: BaseChatModel,\n\ttreeView: TreeView<TSchema> | (ReadableField<TSchema> & TreeNode),\n\toptions?: Readonly<SemanticAgentOptions>,\n): SharedTreeSemanticAgent<TSchema>;\n/**\n * Create a {@link SharedTreeSemanticAgent} using a Langchain chat model.\n * @alpha\n * @deprecated Use {@link SharedTreeSemanticAgent} with a {@link LangchainChatModel} instead.\n */\nexport function createSemanticAgent<TSchema extends ImplicitFieldSchema>(\n\tclient: BaseChatModel,\n\ttreeView: TreeView<TSchema> | (ReadableField<TSchema> & TreeNode),\n\toptions?: Readonly<SemanticAgentOptions>,\n): SharedTreeSemanticAgent<TSchema> {\n\treturn new SharedTreeSemanticAgent(new LangchainChatModel(client), treeView, options);\n}\n\n// #endregion Legacy APIs\n"]}
|
package/lib/prompt.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,mBAAmB,EAAe,MAAM,sBAAsB,CAAC;AAC7E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAIhE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAW5C;;GAEG;AACH,wBAAgB,SAAS,CAAC,KAAK,SAAS,mBAAmB,EAAE,IAAI,EAAE;IAClE,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IACxB,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,mBAAmB,EAAe,MAAM,sBAAsB,CAAC;AAC7E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAIhE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAW5C;;GAEG;AACH,wBAAgB,SAAS,CAAC,KAAK,SAAS,mBAAmB,EAAE,IAAI,EAAE;IAClE,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IACxB,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB,GAAG,MAAM,CA4IT;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,aAAa,CAAC,mBAAmB,CAAC,GAAG,MAAM,CA8C9E"}
|
package/lib/prompt.js
CHANGED
|
@@ -50,22 +50,20 @@ export function getPrompt(args) {
|
|
|
50
50
|
const details = { hasHelperMethods: false };
|
|
51
51
|
const typescriptSchemaTypes = getZodSchemaAsTypeScript(domainTypes, details);
|
|
52
52
|
const helperMethodExplanation = details.hasHelperMethods
|
|
53
|
-
? `Manipulating the data using the APIs described below is allowed, but when possible ALWAYS prefer to use
|
|
53
|
+
? `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.
|
|
54
54
|
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.`
|
|
55
55
|
: "";
|
|
56
56
|
const builderExplanation = exampleObjectName === undefined
|
|
57
57
|
? ""
|
|
58
58
|
: `When constructing new objects, you should wrap them in the appropriate builder function rather than simply making a javascript object.
|
|
59
|
-
The builders are available on the
|
|
59
|
+
The builders are available on the \`create\` property on the context object and are named according to the type that they create.
|
|
60
60
|
For example:
|
|
61
61
|
|
|
62
62
|
\`\`\`javascript
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
// const ${communize(exampleObjectName)} = { /* ...properties... */ };
|
|
68
|
-
}
|
|
63
|
+
// This creates a new ${exampleObjectName} object:
|
|
64
|
+
const ${communize(exampleObjectName)} = context.create.${exampleObjectName}({ /* ...properties... */ });
|
|
65
|
+
// Don't do this:
|
|
66
|
+
// const ${communize(exampleObjectName)} = { /* ...properties... */ };
|
|
69
67
|
\`\`\`\n\n`;
|
|
70
68
|
const arrayEditing = `#### Editing Arrays
|
|
71
69
|
|
|
@@ -96,20 +94,20 @@ ${getTreeMapNodeDocumentation(mapInterfaceName)}
|
|
|
96
94
|
|
|
97
95
|
`;
|
|
98
96
|
const rootTypes = normalizeFieldSchema(schema).allowedTypeSet;
|
|
99
|
-
const editing = `If the user asks you to edit the tree, you should author a JavaScript
|
|
100
|
-
You must use the "${editToolName}" tool to
|
|
97
|
+
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.
|
|
98
|
+
You must use the "${editToolName}" tool to run the generated code.
|
|
101
99
|
After editing the tree, review the latest state of the tree to see if it satisfies the user's request.
|
|
102
100
|
If it does not, or if you receive an error, you may try again with a different approach.
|
|
103
101
|
Once the tree is in the desired state, you should inform the user that the request has been completed.
|
|
104
102
|
|
|
105
103
|
### Editing
|
|
106
104
|
|
|
107
|
-
If the user asks you to edit the document, you will write a JavaScript
|
|
108
|
-
The
|
|
109
|
-
The
|
|
110
|
-
This \`
|
|
111
|
-
You may mutate any part of the tree as necessary, taking into account the caveats around arrays and maps detailed below.
|
|
112
|
-
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(" | ")}\`).
|
|
105
|
+
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.
|
|
106
|
+
The snippet may be synchronous or asynchronous (i.e. it may \`await\` functions if necessary).
|
|
107
|
+
The snippet has a \`context\` variable in its scope.
|
|
108
|
+
This \`context\` variable holds the current state of the tree in the \`root\` property.
|
|
109
|
+
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.
|
|
110
|
+
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(" | ")}\`).
|
|
113
111
|
${helperMethodExplanation}
|
|
114
112
|
|
|
115
113
|
${hasArrays ? arrayEditing : ""}${hasMaps ? mapEditing : ""}#### Additional Notes
|
|
@@ -136,7 +134,7 @@ ${editToolName === undefined ? "" : editing}### Application data
|
|
|
136
134
|
${domainHints === undefined
|
|
137
135
|
? ""
|
|
138
136
|
: `\nThe application supplied the following additional instructions: ${domainHints}`}
|
|
139
|
-
The current state of
|
|
137
|
+
The current state of \`context.root\` (a \`${field === undefined ? "undefined" : getFriendlyName(Tree.schema(field))}\`) is:
|
|
140
138
|
|
|
141
139
|
\`\`\`JSON
|
|
142
140
|
${stringified}
|
package/lib/prompt.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { NodeKind, Tree, TreeNode } from \"@fluidframework/tree\";\nimport type { ImplicitFieldSchema, TreeMapNode } from \"@fluidframework/tree\";\nimport type { ReadableField } from \"@fluidframework/tree/alpha\";\nimport { getSimpleSchema } from \"@fluidframework/tree/alpha\";\nimport { normalizeFieldSchema } from \"@fluidframework/tree/internal\";\n\nimport type { Subtree } from \"./subtree.js\";\nimport { generateEditTypesForPrompt } from \"./typeGeneration.js\";\nimport {\n\tgetFriendlyName,\n\tgetZodSchemaAsTypeScript,\n\tisNamedSchema,\n\tcommunize,\n\tunqualifySchema,\n\ttype SchemaDetails,\n} from \"./utils.js\";\n\n/**\n * Produces a \"system\" prompt for the tree agent, based on the provided subtree.\n */\nexport function getPrompt<TRoot extends ImplicitFieldSchema>(args: {\n\tsubtree: Subtree<TRoot>;\n\teditToolName: string | undefined;\n\tdomainHints?: string;\n}): string {\n\tconst { subtree, editToolName, domainHints } = args;\n\tconst { field, schema } = subtree;\n\tconst arrayInterfaceName = \"TreeArray\";\n\tconst mapInterfaceName = \"TreeMap\";\n\tconst simpleSchema = getSimpleSchema(schema);\n\t// Inspect the schema to determine what kinds of nodes are possible - this will affect how much information we need to include in the prompt.\n\tlet hasArrays = false;\n\tlet hasMaps = false;\n\tlet exampleObjectName: string | undefined;\n\tfor (const [definition, nodeSchema] of simpleSchema.definitions) {\n\t\tswitch (nodeSchema.kind) {\n\t\t\tcase NodeKind.Array: {\n\t\t\t\thasArrays = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase NodeKind.Map: {\n\t\t\t\thasMaps = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase NodeKind.Object: {\n\t\t\t\texampleObjectName ??= unqualifySchema(definition);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t// No default\n\t\t}\n\t}\n\n\tconst { domainTypes } = generateEditTypesForPrompt(schema, simpleSchema);\n\tfor (const [key, value] of Object.entries(domainTypes)) {\n\t\t// eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n\t\tdelete domainTypes[key];\n\t\tif (isNamedSchema(key)) {\n\t\t\tconst friendlyKey = unqualifySchema(key);\n\t\t\tdomainTypes[friendlyKey] = value;\n\t\t}\n\t}\n\n\tconst stringified = stringifyTree(field);\n\tconst details: SchemaDetails = { hasHelperMethods: false };\n\tconst typescriptSchemaTypes = getZodSchemaAsTypeScript(domainTypes, details);\n\tconst helperMethodExplanation = details.hasHelperMethods\n\t\t? `Manipulating the data using the APIs described below is allowed, but when possible ALWAYS prefer to use the application helper methods exposed on the schema TypeScript types if the goal can be accomplished that way.\nIt 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.`\n\t\t: \"\";\n\n\tconst builderExplanation =\n\t\texampleObjectName === undefined\n\t\t\t? \"\"\n\t\t\t: `When constructing new objects, you should wrap them in the appropriate builder function rather than simply making a javascript object.\nThe builders are available on the \"create\" property on the first argument of the edit function and are named according to the type that they create.\nFor example:\n\n\\`\\`\\`javascript\nfunction editTree({ root, create }) {\n\t// This creates a new ${exampleObjectName} object:\n\tconst ${communize(exampleObjectName)} = create.${exampleObjectName}({ /* ...properties... */ });\n\t// Don't do this:\n\t// const ${communize(exampleObjectName)} = { /* ...properties... */ };\n}\n\\`\\`\\`\\n\\n`;\n\n\tconst arrayEditing = `#### Editing Arrays\n\nThe arrays in the tree are somewhat different than normal JavaScript \\`Array\\`s.\nRead-only operations are generally the same - you can create them, read via index, and call non-mutating methods like \\`concat\\`, \\`map\\`, \\`filter\\`, \\`find\\`, \\`forEach\\`, \\`indexOf\\`, \\`slice\\`, \\`join\\`, etc.\nHowever, write operations (e.g. index assignment, \\`push\\`, \\`pop\\`, \\`splice\\`, etc.) are not supported.\nInstead, you must use the methods on the following interface to mutate the array:\n\n\\`\\`\\`typescript\n${getTreeArrayNodeDocumentation(arrayInterfaceName)}\n\\`\\`\\`\n\nWhen possible, ensure that the edits preserve the identity of objects already in the tree.\nFor example, prefer \\`array.moveToIndex\\` over \\`array.removeAt\\` + \\`array.insertAt\\` and prefer \\`array.moveRangeToIndex\\` over \\`array.removeRange\\` + \\`array.insertAt\\`.\n\n`;\n\n\tconst mapEditing = `#### Editing Maps\n\nThe maps in the tree are somewhat different than normal JavaScript \\`Map\\`s.\nMap keys are always strings.\nRead-only operations are generally the same - you can create them, read via \\`get\\`, and call non-mutating methods like \\`has\\`, \\`forEach\\`, \\`entries\\`, \\`keys\\`, \\`values\\`, etc. (note the subtle differences around return values and iteration order).\nHowever, write operations (e.g. \\`set\\`, \\`delete\\`, etc.) are not supported.\nInstead, you must use the methods on the following interface to mutate the map:\n\n\\`\\`\\`typescript\n${getTreeMapNodeDocumentation(mapInterfaceName)}\n\\`\\`\\`\n\n`;\n\n\tconst rootTypes = normalizeFieldSchema(schema).allowedTypeSet;\n\tconst editing = `If the user asks you to edit the tree, you should author a JavaScript function to accomplish the user-specified goal, following the instructions for editing detailed below.\nYou must use the \"${editToolName}\" tool to perform the edit.\nAfter editing the tree, review the latest state of the tree to see if it satisfies the user's request.\nIf it does not, or if you receive an error, you may try again with a different approach.\nOnce the tree is in the desired state, you should inform the user that the request has been completed.\n\n### Editing\n\nIf the user asks you to edit the document, you will write a JavaScript function that mutates the data in-place to achieve the user's goal.\nThe edit function may be synchronous or asynchronous.\nThe edit function must have a first parameter which has a \\`root\\` property.\nThis \\`root\\` property holds the current state of the tree as shown above.\nYou may mutate any part of the tree as necessary, taking into account the caveats around arrays and maps detailed below.\nYou 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(\" | \")}\\`).\n${helperMethodExplanation}\n\n${hasArrays ? arrayEditing : \"\"}${hasMaps ? mapEditing : \"\"}#### Additional Notes\n\nBefore 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.\n\nOnce 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.\n\n${builderExplanation}Finally, double check that the edits would accomplish the user's request (if it is possible).\n\n`;\n\n\tconst prompt = `You are a helpful assistant collaborating with the user on a document. The document state is a JSON tree, and you are able to analyze and edit it.\nThe JSON tree adheres to the following Typescript schema:\n\n\\`\\`\\`typescript\n${typescriptSchemaTypes}\n\\`\\`\\`\n\nIf the user asks you a question about the tree, you should inspect the state of the tree and answer the question.\nWhen answering such a question, DO NOT answer with information that is not part of the document unless requested to do so.\n\n${editToolName === undefined ? \"\" : editing}### Application data\n\n${\n\tdomainHints === undefined\n\t\t? \"\"\n\t\t: `\\nThe application supplied the following additional instructions: ${domainHints}`\n}\nThe current state of the application tree (a \\`${field === undefined ? \"undefined\" : getFriendlyName(Tree.schema(field))}\\`) is:\n\n\\`\\`\\`JSON\n${stringified}\n\\`\\`\\``;\n\treturn prompt;\n}\n\n/**\n * Serializes tree data e.g. to include in a prompt or message.\n * @remarks This includes some extra metadata to make it easier to understand the structure of the tree.\n */\nexport function stringifyTree(tree: ReadableField<ImplicitFieldSchema>): string {\n\tconst typeReplacementKey = \"_e944da5a5fd04ea2b8b2eb6109e089ed\";\n\tconst indexReplacementKey = \"_27bb216b474d45e6aaee14d1ec267b96\";\n\tconst mapReplacementKey = \"_a0d98d22a1c644539f07828d3f064d71\";\n\tconst stringified = JSON.stringify(\n\t\ttree,\n\t\t(_, node: unknown) => {\n\t\t\tif (node instanceof TreeNode) {\n\t\t\t\tconst key = Tree.key(node);\n\t\t\t\tconst index = typeof key === \"number\" ? key : undefined;\n\t\t\t\tconst schema = Tree.schema(node);\n\t\t\t\tswitch (schema.kind) {\n\t\t\t\t\tcase NodeKind.Object: {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t[typeReplacementKey]: getFriendlyName(schema),\n\t\t\t\t\t\t\t[indexReplacementKey]: index,\n\t\t\t\t\t\t\t...node,\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t\tcase NodeKind.Map: {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t[indexReplacementKey]: index,\n\t\t\t\t\t\t\t[mapReplacementKey]: \"\",\n\t\t\t\t\t\t\t...Object.fromEntries(node as TreeMapNode),\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t\tdefault: {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t[indexReplacementKey]: index,\n\t\t\t\t\t\t\t...node,\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn node;\n\t\t},\n\t\t2,\n\t);\n\n\treturn stringified\n\t\t.replace(new RegExp(`\"${typeReplacementKey}\":`, \"g\"), `// Type:`)\n\t\t.replace(new RegExp(`\"${indexReplacementKey}\":`, \"g\"), `// Index:`)\n\t\t.replace(\n\t\t\tnew RegExp(`\"${mapReplacementKey}\": \"\"`, \"g\"),\n\t\t\t`// Note: This is a map that has been serialized to JSON. It is not a key-value object/record but is being printed as such.`,\n\t\t);\n}\n\n/**\n * Retrieves the documentation for the `TreeArrayNode` interface to feed to the LLM.\n * @remarks The documentation has been simplified in various ways to make it easier for the LLM to understand.\n * @privateRemarks TODO: How do we keep this in sync with the actual `TreeArrayNode` docs if/when those docs change?\n */\nfunction getTreeArrayNodeDocumentation(typeName: string): string {\n\treturn `/** A special type of array which implements 'readonly T[]' (i.e. it supports all read-only JS array methods) and provides custom array mutation APIs. */\nexport interface ${typeName}<T> extends ReadonlyArray<T> {\n\t/**\n\t * Inserts new item(s) at a specified location.\n\t * @param index - The index at which to insert \\`value\\`.\n\t * @param value - The content to insert.\n\t * @throws Throws if \\`index\\` is not in the range [0, \\`array.length\\`).\n\t */\n\tinsertAt(index: number, ...value: readonly T[]): void;\n\n\t/**\n\t * Removes the item at the specified location.\n\t * @param index - The index at which to remove the item.\n\t * @throws Throws if \\`index\\` is not in the range [0, \\`array.length\\`).\n\t */\n\tremoveAt(index: number): void;\n\n\t/**\n\t * Removes all items between the specified indices.\n\t * @param start - The starting index of the range to remove (inclusive). Defaults to the start of the array.\n\t * @param end - The ending index of the range to remove (exclusive). Defaults to \\`array.length\\`.\n\t * @throws Throws if \\`start\\` is not in the range [0, \\`array.length\\`].\n\t * @throws Throws if \\`end\\` is less than \\`start\\`.\n\t * If \\`end\\` is not supplied or is greater than the length of the array, all items after \\`start\\` are removed.\n\t *\n\t * @remarks\n\t * The default values for start and end are computed when this is called,\n\t * and thus the behavior is the same as providing them explicitly, even with respect to merge resolution with concurrent edits.\n\t * For example, two concurrent transactions both emptying the array with \\`node.removeRange()\\` then inserting an item,\n\t * will merge to result in the array having both inserted items.\n\t */\n\tremoveRange(start?: number, end?: number): void;\n\n\t/**\n\t * Moves the specified item to the desired location in the array.\n\t *\n\t * WARNING - This API is easily misused.\n\t * Please read the documentation for the \\`destinationGap\\` parameter carefully.\n\t *\n\t * @param destinationGap - The location *between* existing items that the moved item should be moved to.\n\t *\n\t * WARNING - \\`destinationGap\\` describes a location between existing items *prior to applying the move operation*.\n\t *\n\t * For example, if the array contains items \\`[A, B, C]\\` before the move, the \\`destinationGap\\` must be one of the following:\n\t *\n\t * - \\`0\\` (between the start of the array and \\`A\\`'s original position)\n\t * - \\`1\\` (between \\`A\\`'s original position and \\`B\\`'s original position)\n\t * - \\`2\\` (between \\`B\\`'s original position and \\`C\\`'s original position)\n\t * - \\`3\\` (between \\`C\\`'s original position and the end of the array)\n\t *\n\t * So moving \\`A\\` between \\`B\\` and \\`C\\` would require \\`destinationGap\\` to be \\`2\\`.\n\t *\n\t * This interpretation of \\`destinationGap\\` makes it easy to specify the desired destination relative to a sibling item that is not being moved,\n\t * or relative to the start or end of the array:\n\t *\n\t * - Move to the start of the array: \\`array.moveToIndex(0, ...)\\` (see also \\`moveToStart\\`)\n\t * - Move to before some item X: \\`array.moveToIndex(indexOfX, ...)\\`\n\t * - Move to after some item X: \\`array.moveToIndex(indexOfX + 1\\`, ...)\n\t * - Move to the end of the array: \\`array.moveToIndex(array.length, ...)\\` (see also \\`moveToEnd\\`)\n\t *\n\t * This interpretation of \\`destinationGap\\` does however make it less obvious how to move an item relative to its current position:\n\t *\n\t * - Move item B before its predecessor: \\`array.moveToIndex(indexOfB - 1, ...)\\`\n\t * - Move item B after its successor: \\`array.moveToIndex(indexOfB + 2, ...)\\`\n\t *\n\t * Notice the asymmetry between \\`-1\\` and \\`+2\\` in the above examples.\n\t * In such scenarios, it can often be easier to approach such edits by swapping adjacent items:\n\t * If items A and B are adjacent, such that A precedes B,\n\t * then they can be swapped with \\`array.moveToIndex(indexOfA, indexOfB)\\`.\n\t *\n\t * @param sourceIndex - The index of the item to move.\n\t * @param source - The optional source array to move the item out of (defaults to this array).\n\t * @throws Throws if any of the source index is not in the range [0, \\`array.length\\`),\n\t * or if the index is not in the range [0, \\`array.length\\`].\n\t */\n\tmoveToIndex(destinationGap: number, sourceIndex: number, source?: ${typeName}<T>): void;\n\n\t/**\n\t * Moves the specified items to the desired location within the array.\n\t *\n\t * WARNING - This API is easily misused.\n\t * Please read the documentation for the \\`destinationGap\\` parameter carefully.\n\t *\n\t * @param destinationGap - The location *between* existing items that the moved item should be moved to.\n\t *\n\t * WARNING - \\`destinationGap\\` describes a location between existing items *prior to applying the move operation*.\n\t *\n\t * For example, if the array contains items \\`[A, B, C]\\` before the move, the \\`destinationGap\\` must be one of the following:\n\t *\n\t * - \\`0\\` (between the start of the array and \\`A\\`'s original position)\n\t * - \\`1\\` (between \\`A\\`'s original position and \\`B\\`'s original position)\n\t * - \\`2\\` (between \\`B\\`'s original position and \\`C\\`'s original position)\n\t * - \\`3\\` (between \\`C\\`'s original position and the end of the array)\n\t *\n\t * So moving \\`A\\` between \\`B\\` and \\`C\\` would require \\`destinationGap\\` to be \\`2\\`.\n\t *\n\t * This interpretation of \\`destinationGap\\` makes it easy to specify the desired destination relative to a sibling item that is not being moved,\n\t * or relative to the start or end of the array:\n\t *\n\t * - Move to the start of the array: \\`array.moveToIndex(0, ...)\\` (see also \\`moveToStart\\`)\n\t * - Move to before some item X: \\`array.moveToIndex(indexOfX, ...)\\`\n\t * - Move to after some item X: \\`array.moveToIndex(indexOfX + 1\\`, ...)\n\t * - Move to the end of the array: \\`array.moveToIndex(array.length, ...)\\` (see also \\`moveToEnd\\`)\n\t *\n\t * This interpretation of \\`destinationGap\\` does however make it less obvious how to move an item relative to its current position:\n\t *\n\t * - Move item B before its predecessor: \\`array.moveToIndex(indexOfB - 1, ...)\\`\n\t * - Move item B after its successor: \\`array.moveToIndex(indexOfB + 2, ...)\\`\n\t *\n\t * Notice the asymmetry between \\`-1\\` and \\`+2\\` in the above examples.\n\t * In such scenarios, it can often be easier to approach such edits by swapping adjacent items:\n\t * If items A and B are adjacent, such that A precedes B,\n\t * then they can be swapped with \\`array.moveToIndex(indexOfA, indexOfB)\\`.\n\t *\n\t * @param sourceStart - The starting index of the range to move (inclusive).\n\t * @param sourceEnd - The ending index of the range to move (exclusive)\n\t * @param source - The optional source array to move items out of (defaults to this array).\n\t * @throws Throws if the types of any of the items being moved are not allowed in the destination array,\n\t * if any of the input indices are not in the range [0, \\`array.length\\`], or if \\`sourceStart\\` is greater than \\`sourceEnd\\`.\n\t */\n\tmoveRangeToIndex(\n\t\tdestinationGap: number,\n\t\tsourceStart: number,\n\t\tsourceEnd: number,\n\t\tsource?: ${typeName}<T>,\n\t): void;\n}`;\n}\n\n/**\n * Retrieves the documentation for the `TreeMapNode` interface to feed to the LLM.\n * @remarks The documentation has been simplified in various ways to make it easier for the LLM to understand.\n * @privateRemarks TODO: How do we keep this in sync with the actual `TreeMapNode` docs if/when those docs change?\n */\nfunction getTreeMapNodeDocumentation(typeName: string): string {\n\treturn `/**\n * A map of string keys to tree objects.\n */\nexport interface ${typeName}<T> extends ReadonlyMap<string, T> {\n\t/**\n\t * Adds or updates an entry in the map with a specified \\`key\\` and a \\`value\\`.\n\t *\n\t * @param key - The key of the element to add to the map.\n\t * @param value - The value of the element to add to the map.\n\t *\n\t * @remarks\n\t * Setting the value at a key to \\`undefined\\` is equivalent to calling {@link ${typeName}.delete} with that key.\n\t */\n\tset(key: string, value: T | undefined): void;\n\n\t/**\n\t * Removes the specified element from this map by its \\`key\\`.\n\t *\n\t * @remarks\n\t * Note: unlike JavaScript's Map API, this method does not return a flag indicating whether or not the value was\n\t * deleted.\n\t *\n\t * @param key - The key of the element to remove from the map.\n\t */\n\tdelete(key: string): void;\n\n\t/**\n\t * Returns an iterable of keys in the map.\n\t *\n\t * @remarks\n\t * Note: no guarantees are made regarding the order of the keys returned.\n\t * If your usage scenario depends on consistent ordering, you will need to sort these yourself.\n\t */\n\tkeys(): IterableIterator<string>;\n\n\t/**\n\t * Returns an iterable of values in the map.\n\t *\n\t * @remarks\n\t * Note: no guarantees are made regarding the order of the values returned.\n\t * If your usage scenario depends on consistent ordering, you will need to sort these yourself.\n\t */\n\tvalues(): IterableIterator<T>;\n\n\t/**\n\t * Returns an iterable of key/value pairs for every entry in the map.\n\t *\n\t * @remarks\n\t * Note: no guarantees are made regarding the order of the entries returned.\n\t * If your usage scenario depends on consistent ordering, you will need to sort these yourself.\n\t */\n\tentries(): IterableIterator<[string, T]>;\n\n\t/**\n\t * Executes the provided function once per each key/value pair in this map.\n\t *\n\t * @remarks\n\t * Note: no guarantees are made regarding the order in which the function is called with respect to the map's entries.\n\t * If your usage scenario depends on consistent ordering, you will need to sort these yourself.\n\t */\n\tforEach(\n\t\tcallbackfn: (\n\t\t\tvalue: T,\n\t\t\tkey: string,\n\t\t\tmap: ReadonlyMap<string, T>,\n\t\t) => void,\n\t\tthisArg?: any,\n\t): void;\n}`;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { NodeKind, Tree, TreeNode } from \"@fluidframework/tree\";\nimport type { ImplicitFieldSchema, TreeMapNode } from \"@fluidframework/tree\";\nimport type { ReadableField } from \"@fluidframework/tree/alpha\";\nimport { getSimpleSchema } from \"@fluidframework/tree/alpha\";\nimport { normalizeFieldSchema } from \"@fluidframework/tree/internal\";\n\nimport type { Subtree } from \"./subtree.js\";\nimport { generateEditTypesForPrompt } from \"./typeGeneration.js\";\nimport {\n\tgetFriendlyName,\n\tgetZodSchemaAsTypeScript,\n\tisNamedSchema,\n\tcommunize,\n\tunqualifySchema,\n\ttype SchemaDetails,\n} from \"./utils.js\";\n\n/**\n * Produces a \"system\" prompt for the tree agent, based on the provided subtree.\n */\nexport function getPrompt<TRoot extends ImplicitFieldSchema>(args: {\n\tsubtree: Subtree<TRoot>;\n\teditToolName: string | undefined;\n\tdomainHints?: string;\n}): string {\n\tconst { subtree, editToolName, domainHints } = args;\n\tconst { field, schema } = subtree;\n\tconst arrayInterfaceName = \"TreeArray\";\n\tconst mapInterfaceName = \"TreeMap\";\n\tconst simpleSchema = getSimpleSchema(schema);\n\t// Inspect the schema to determine what kinds of nodes are possible - this will affect how much information we need to include in the prompt.\n\tlet hasArrays = false;\n\tlet hasMaps = false;\n\tlet exampleObjectName: string | undefined;\n\tfor (const [definition, nodeSchema] of simpleSchema.definitions) {\n\t\tswitch (nodeSchema.kind) {\n\t\t\tcase NodeKind.Array: {\n\t\t\t\thasArrays = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase NodeKind.Map: {\n\t\t\t\thasMaps = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase NodeKind.Object: {\n\t\t\t\texampleObjectName ??= unqualifySchema(definition);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t// No default\n\t\t}\n\t}\n\n\tconst { domainTypes } = generateEditTypesForPrompt(schema, simpleSchema);\n\tfor (const [key, value] of Object.entries(domainTypes)) {\n\t\t// eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n\t\tdelete domainTypes[key];\n\t\tif (isNamedSchema(key)) {\n\t\t\tconst friendlyKey = unqualifySchema(key);\n\t\t\tdomainTypes[friendlyKey] = value;\n\t\t}\n\t}\n\n\tconst stringified = stringifyTree(field);\n\tconst details: SchemaDetails = { hasHelperMethods: false };\n\tconst typescriptSchemaTypes = getZodSchemaAsTypeScript(domainTypes, details);\n\tconst helperMethodExplanation = details.hasHelperMethods\n\t\t? `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.\nIt 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.`\n\t\t: \"\";\n\n\tconst builderExplanation =\n\t\texampleObjectName === undefined\n\t\t\t? \"\"\n\t\t\t: `When constructing new objects, you should wrap them in the appropriate builder function rather than simply making a javascript object.\nThe builders are available on the \\`create\\` property on the context object and are named according to the type that they create.\nFor example:\n\n\\`\\`\\`javascript\n// This creates a new ${exampleObjectName} object:\nconst ${communize(exampleObjectName)} = context.create.${exampleObjectName}({ /* ...properties... */ });\n// Don't do this:\n// const ${communize(exampleObjectName)} = { /* ...properties... */ };\n\\`\\`\\`\\n\\n`;\n\n\tconst arrayEditing = `#### Editing Arrays\n\nThe arrays in the tree are somewhat different than normal JavaScript \\`Array\\`s.\nRead-only operations are generally the same - you can create them, read via index, and call non-mutating methods like \\`concat\\`, \\`map\\`, \\`filter\\`, \\`find\\`, \\`forEach\\`, \\`indexOf\\`, \\`slice\\`, \\`join\\`, etc.\nHowever, write operations (e.g. index assignment, \\`push\\`, \\`pop\\`, \\`splice\\`, etc.) are not supported.\nInstead, you must use the methods on the following interface to mutate the array:\n\n\\`\\`\\`typescript\n${getTreeArrayNodeDocumentation(arrayInterfaceName)}\n\\`\\`\\`\n\nWhen possible, ensure that the edits preserve the identity of objects already in the tree.\nFor example, prefer \\`array.moveToIndex\\` over \\`array.removeAt\\` + \\`array.insertAt\\` and prefer \\`array.moveRangeToIndex\\` over \\`array.removeRange\\` + \\`array.insertAt\\`.\n\n`;\n\n\tconst mapEditing = `#### Editing Maps\n\nThe maps in the tree are somewhat different than normal JavaScript \\`Map\\`s.\nMap keys are always strings.\nRead-only operations are generally the same - you can create them, read via \\`get\\`, and call non-mutating methods like \\`has\\`, \\`forEach\\`, \\`entries\\`, \\`keys\\`, \\`values\\`, etc. (note the subtle differences around return values and iteration order).\nHowever, write operations (e.g. \\`set\\`, \\`delete\\`, etc.) are not supported.\nInstead, you must use the methods on the following interface to mutate the map:\n\n\\`\\`\\`typescript\n${getTreeMapNodeDocumentation(mapInterfaceName)}\n\\`\\`\\`\n\n`;\n\n\tconst rootTypes = normalizeFieldSchema(schema).allowedTypeSet;\n\tconst 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.\nYou must use the \"${editToolName}\" tool to run the generated code.\nAfter editing the tree, review the latest state of the tree to see if it satisfies the user's request.\nIf it does not, or if you receive an error, you may try again with a different approach.\nOnce the tree is in the desired state, you should inform the user that the request has been completed.\n\n### Editing\n\nIf 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.\nThe snippet may be synchronous or asynchronous (i.e. it may \\`await\\` functions if necessary).\nThe snippet has a \\`context\\` variable in its scope.\nThis \\`context\\` variable holds the current state of the tree in the \\`root\\` property.\nYou may mutate any part of the root tree as necessary, taking into account the caveats around${hasArrays ? ` arrays${hasMaps ? \" and\" : \"\"}` : \"\"}${hasMaps ? \" maps\" : \"\"} detailed below.\nYou 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(\" | \")}\\`).\n${helperMethodExplanation}\n\n${hasArrays ? arrayEditing : \"\"}${hasMaps ? mapEditing : \"\"}#### Additional Notes\n\nBefore 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.\n\nOnce 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.\n\n${builderExplanation}Finally, double check that the edits would accomplish the user's request (if it is possible).\n\n`;\n\n\tconst prompt = `You are a helpful assistant collaborating with the user on a document. The document state is a JSON tree, and you are able to analyze and edit it.\nThe JSON tree adheres to the following Typescript schema:\n\n\\`\\`\\`typescript\n${typescriptSchemaTypes}\n\\`\\`\\`\n\nIf the user asks you a question about the tree, you should inspect the state of the tree and answer the question.\nWhen answering such a question, DO NOT answer with information that is not part of the document unless requested to do so.\n\n${editToolName === undefined ? \"\" : editing}### Application data\n\n${\n\tdomainHints === undefined\n\t\t? \"\"\n\t\t: `\\nThe application supplied the following additional instructions: ${domainHints}`\n}\nThe current state of \\`context.root\\` (a \\`${field === undefined ? \"undefined\" : getFriendlyName(Tree.schema(field))}\\`) is:\n\n\\`\\`\\`JSON\n${stringified}\n\\`\\`\\``;\n\treturn prompt;\n}\n\n/**\n * Serializes tree data e.g. to include in a prompt or message.\n * @remarks This includes some extra metadata to make it easier to understand the structure of the tree.\n */\nexport function stringifyTree(tree: ReadableField<ImplicitFieldSchema>): string {\n\tconst typeReplacementKey = \"_e944da5a5fd04ea2b8b2eb6109e089ed\";\n\tconst indexReplacementKey = \"_27bb216b474d45e6aaee14d1ec267b96\";\n\tconst mapReplacementKey = \"_a0d98d22a1c644539f07828d3f064d71\";\n\tconst stringified = JSON.stringify(\n\t\ttree,\n\t\t(_, node: unknown) => {\n\t\t\tif (node instanceof TreeNode) {\n\t\t\t\tconst key = Tree.key(node);\n\t\t\t\tconst index = typeof key === \"number\" ? key : undefined;\n\t\t\t\tconst schema = Tree.schema(node);\n\t\t\t\tswitch (schema.kind) {\n\t\t\t\t\tcase NodeKind.Object: {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t[typeReplacementKey]: getFriendlyName(schema),\n\t\t\t\t\t\t\t[indexReplacementKey]: index,\n\t\t\t\t\t\t\t...node,\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t\tcase NodeKind.Map: {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t[indexReplacementKey]: index,\n\t\t\t\t\t\t\t[mapReplacementKey]: \"\",\n\t\t\t\t\t\t\t...Object.fromEntries(node as TreeMapNode),\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t\tdefault: {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t[indexReplacementKey]: index,\n\t\t\t\t\t\t\t...node,\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn node;\n\t\t},\n\t\t2,\n\t);\n\n\treturn stringified\n\t\t.replace(new RegExp(`\"${typeReplacementKey}\":`, \"g\"), `// Type:`)\n\t\t.replace(new RegExp(`\"${indexReplacementKey}\":`, \"g\"), `// Index:`)\n\t\t.replace(\n\t\t\tnew RegExp(`\"${mapReplacementKey}\": \"\"`, \"g\"),\n\t\t\t`// Note: This is a map that has been serialized to JSON. It is not a key-value object/record but is being printed as such.`,\n\t\t);\n}\n\n/**\n * Retrieves the documentation for the `TreeArrayNode` interface to feed to the LLM.\n * @remarks The documentation has been simplified in various ways to make it easier for the LLM to understand.\n * @privateRemarks TODO: How do we keep this in sync with the actual `TreeArrayNode` docs if/when those docs change?\n */\nfunction getTreeArrayNodeDocumentation(typeName: string): string {\n\treturn `/** A special type of array which implements 'readonly T[]' (i.e. it supports all read-only JS array methods) and provides custom array mutation APIs. */\nexport interface ${typeName}<T> extends ReadonlyArray<T> {\n\t/**\n\t * Inserts new item(s) at a specified location.\n\t * @param index - The index at which to insert \\`value\\`.\n\t * @param value - The content to insert.\n\t * @throws Throws if \\`index\\` is not in the range [0, \\`array.length\\`).\n\t */\n\tinsertAt(index: number, ...value: readonly T[]): void;\n\n\t/**\n\t * Removes the item at the specified location.\n\t * @param index - The index at which to remove the item.\n\t * @throws Throws if \\`index\\` is not in the range [0, \\`array.length\\`).\n\t */\n\tremoveAt(index: number): void;\n\n\t/**\n\t * Removes all items between the specified indices.\n\t * @param start - The starting index of the range to remove (inclusive). Defaults to the start of the array.\n\t * @param end - The ending index of the range to remove (exclusive). Defaults to \\`array.length\\`.\n\t * @throws Throws if \\`start\\` is not in the range [0, \\`array.length\\`].\n\t * @throws Throws if \\`end\\` is less than \\`start\\`.\n\t * If \\`end\\` is not supplied or is greater than the length of the array, all items after \\`start\\` are removed.\n\t *\n\t * @remarks\n\t * The default values for start and end are computed when this is called,\n\t * and thus the behavior is the same as providing them explicitly, even with respect to merge resolution with concurrent edits.\n\t * For example, two concurrent transactions both emptying the array with \\`node.removeRange()\\` then inserting an item,\n\t * will merge to result in the array having both inserted items.\n\t */\n\tremoveRange(start?: number, end?: number): void;\n\n\t/**\n\t * Moves the specified item to the desired location in the array.\n\t *\n\t * WARNING - This API is easily misused.\n\t * Please read the documentation for the \\`destinationGap\\` parameter carefully.\n\t *\n\t * @param destinationGap - The location *between* existing items that the moved item should be moved to.\n\t *\n\t * WARNING - \\`destinationGap\\` describes a location between existing items *prior to applying the move operation*.\n\t *\n\t * For example, if the array contains items \\`[A, B, C]\\` before the move, the \\`destinationGap\\` must be one of the following:\n\t *\n\t * - \\`0\\` (between the start of the array and \\`A\\`'s original position)\n\t * - \\`1\\` (between \\`A\\`'s original position and \\`B\\`'s original position)\n\t * - \\`2\\` (between \\`B\\`'s original position and \\`C\\`'s original position)\n\t * - \\`3\\` (between \\`C\\`'s original position and the end of the array)\n\t *\n\t * So moving \\`A\\` between \\`B\\` and \\`C\\` would require \\`destinationGap\\` to be \\`2\\`.\n\t *\n\t * This interpretation of \\`destinationGap\\` makes it easy to specify the desired destination relative to a sibling item that is not being moved,\n\t * or relative to the start or end of the array:\n\t *\n\t * - Move to the start of the array: \\`array.moveToIndex(0, ...)\\` (see also \\`moveToStart\\`)\n\t * - Move to before some item X: \\`array.moveToIndex(indexOfX, ...)\\`\n\t * - Move to after some item X: \\`array.moveToIndex(indexOfX + 1\\`, ...)\n\t * - Move to the end of the array: \\`array.moveToIndex(array.length, ...)\\` (see also \\`moveToEnd\\`)\n\t *\n\t * This interpretation of \\`destinationGap\\` does however make it less obvious how to move an item relative to its current position:\n\t *\n\t * - Move item B before its predecessor: \\`array.moveToIndex(indexOfB - 1, ...)\\`\n\t * - Move item B after its successor: \\`array.moveToIndex(indexOfB + 2, ...)\\`\n\t *\n\t * Notice the asymmetry between \\`-1\\` and \\`+2\\` in the above examples.\n\t * In such scenarios, it can often be easier to approach such edits by swapping adjacent items:\n\t * If items A and B are adjacent, such that A precedes B,\n\t * then they can be swapped with \\`array.moveToIndex(indexOfA, indexOfB)\\`.\n\t *\n\t * @param sourceIndex - The index of the item to move.\n\t * @param source - The optional source array to move the item out of (defaults to this array).\n\t * @throws Throws if any of the source index is not in the range [0, \\`array.length\\`),\n\t * or if the index is not in the range [0, \\`array.length\\`].\n\t */\n\tmoveToIndex(destinationGap: number, sourceIndex: number, source?: ${typeName}<T>): void;\n\n\t/**\n\t * Moves the specified items to the desired location within the array.\n\t *\n\t * WARNING - This API is easily misused.\n\t * Please read the documentation for the \\`destinationGap\\` parameter carefully.\n\t *\n\t * @param destinationGap - The location *between* existing items that the moved item should be moved to.\n\t *\n\t * WARNING - \\`destinationGap\\` describes a location between existing items *prior to applying the move operation*.\n\t *\n\t * For example, if the array contains items \\`[A, B, C]\\` before the move, the \\`destinationGap\\` must be one of the following:\n\t *\n\t * - \\`0\\` (between the start of the array and \\`A\\`'s original position)\n\t * - \\`1\\` (between \\`A\\`'s original position and \\`B\\`'s original position)\n\t * - \\`2\\` (between \\`B\\`'s original position and \\`C\\`'s original position)\n\t * - \\`3\\` (between \\`C\\`'s original position and the end of the array)\n\t *\n\t * So moving \\`A\\` between \\`B\\` and \\`C\\` would require \\`destinationGap\\` to be \\`2\\`.\n\t *\n\t * This interpretation of \\`destinationGap\\` makes it easy to specify the desired destination relative to a sibling item that is not being moved,\n\t * or relative to the start or end of the array:\n\t *\n\t * - Move to the start of the array: \\`array.moveToIndex(0, ...)\\` (see also \\`moveToStart\\`)\n\t * - Move to before some item X: \\`array.moveToIndex(indexOfX, ...)\\`\n\t * - Move to after some item X: \\`array.moveToIndex(indexOfX + 1\\`, ...)\n\t * - Move to the end of the array: \\`array.moveToIndex(array.length, ...)\\` (see also \\`moveToEnd\\`)\n\t *\n\t * This interpretation of \\`destinationGap\\` does however make it less obvious how to move an item relative to its current position:\n\t *\n\t * - Move item B before its predecessor: \\`array.moveToIndex(indexOfB - 1, ...)\\`\n\t * - Move item B after its successor: \\`array.moveToIndex(indexOfB + 2, ...)\\`\n\t *\n\t * Notice the asymmetry between \\`-1\\` and \\`+2\\` in the above examples.\n\t * In such scenarios, it can often be easier to approach such edits by swapping adjacent items:\n\t * If items A and B are adjacent, such that A precedes B,\n\t * then they can be swapped with \\`array.moveToIndex(indexOfA, indexOfB)\\`.\n\t *\n\t * @param sourceStart - The starting index of the range to move (inclusive).\n\t * @param sourceEnd - The ending index of the range to move (exclusive)\n\t * @param source - The optional source array to move items out of (defaults to this array).\n\t * @throws Throws if the types of any of the items being moved are not allowed in the destination array,\n\t * if any of the input indices are not in the range [0, \\`array.length\\`], or if \\`sourceStart\\` is greater than \\`sourceEnd\\`.\n\t */\n\tmoveRangeToIndex(\n\t\tdestinationGap: number,\n\t\tsourceStart: number,\n\t\tsourceEnd: number,\n\t\tsource?: ${typeName}<T>,\n\t): void;\n}`;\n}\n\n/**\n * Retrieves the documentation for the `TreeMapNode` interface to feed to the LLM.\n * @remarks The documentation has been simplified in various ways to make it easier for the LLM to understand.\n * @privateRemarks TODO: How do we keep this in sync with the actual `TreeMapNode` docs if/when those docs change?\n */\nfunction getTreeMapNodeDocumentation(typeName: string): string {\n\treturn `/**\n * A map of string keys to tree objects.\n */\nexport interface ${typeName}<T> extends ReadonlyMap<string, T> {\n\t/**\n\t * Adds or updates an entry in the map with a specified \\`key\\` and a \\`value\\`.\n\t *\n\t * @param key - The key of the element to add to the map.\n\t * @param value - The value of the element to add to the map.\n\t *\n\t * @remarks\n\t * Setting the value at a key to \\`undefined\\` is equivalent to calling {@link ${typeName}.delete} with that key.\n\t */\n\tset(key: string, value: T | undefined): void;\n\n\t/**\n\t * Removes the specified element from this map by its \\`key\\`.\n\t *\n\t * @remarks\n\t * Note: unlike JavaScript's Map API, this method does not return a flag indicating whether or not the value was\n\t * deleted.\n\t *\n\t * @param key - The key of the element to remove from the map.\n\t */\n\tdelete(key: string): void;\n\n\t/**\n\t * Returns an iterable of keys in the map.\n\t *\n\t * @remarks\n\t * Note: no guarantees are made regarding the order of the keys returned.\n\t * If your usage scenario depends on consistent ordering, you will need to sort these yourself.\n\t */\n\tkeys(): IterableIterator<string>;\n\n\t/**\n\t * Returns an iterable of values in the map.\n\t *\n\t * @remarks\n\t * Note: no guarantees are made regarding the order of the values returned.\n\t * If your usage scenario depends on consistent ordering, you will need to sort these yourself.\n\t */\n\tvalues(): IterableIterator<T>;\n\n\t/**\n\t * Returns an iterable of key/value pairs for every entry in the map.\n\t *\n\t * @remarks\n\t * Note: no guarantees are made regarding the order of the entries returned.\n\t * If your usage scenario depends on consistent ordering, you will need to sort these yourself.\n\t */\n\tentries(): IterableIterator<[string, T]>;\n\n\t/**\n\t * Executes the provided function once per each key/value pair in this map.\n\t *\n\t * @remarks\n\t * Note: no guarantees are made regarding the order in which the function is called with respect to the map's entries.\n\t * If your usage scenario depends on consistent ordering, you will need to sort these yourself.\n\t */\n\tforEach(\n\t\tcallbackfn: (\n\t\t\tvalue: T,\n\t\t\tkey: string,\n\t\t\tmap: ReadonlyMap<string, T>,\n\t\t) => void,\n\t\tthisArg?: any,\n\t): void;\n}`;\n}\n"]}
|
package/lib/ses.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
import type { CompartmentOptions, LockdownOptions } from "ses";
|
|
6
|
+
import type { SemanticAgentOptions } from "./api.js";
|
|
7
|
+
/**
|
|
8
|
+
* Create an implementation of {@link SemanticAgentOptions.executeEdit} that uses the SES library to run the provided code in a secure environment.
|
|
9
|
+
* @param createCompartment - This function can be used to optionally configure the SES Compartment used to execute the code.
|
|
10
|
+
* The provided globals must be included in the compartment's globals and must not conflict with any additional globals passed in.
|
|
11
|
+
* @param lockdownOptions - Optional configuration passed to the SES `lockdown` function.
|
|
12
|
+
* @returns A function that can be used as the {@link SemanticAgentOptions.executeEdit | executeEdit} callback.
|
|
13
|
+
* @remarks This function will both import the SES library and call its `lockdown` function the first time it is called.
|
|
14
|
+
* Therefore, this function should be called only once, early in an application's lifetime.
|
|
15
|
+
* @alpha
|
|
16
|
+
*/
|
|
17
|
+
export declare function createSesEditEvaluator(options?: {
|
|
18
|
+
compartmentOptions?: CompartmentOptions;
|
|
19
|
+
lockdownOptions?: LockdownOptions;
|
|
20
|
+
}): Promise<SemanticAgentOptions["executeEdit"]>;
|
|
21
|
+
//# sourceMappingURL=ses.d.ts.map
|
package/lib/ses.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ses.d.ts","sourceRoot":"","sources":["../src/ses.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,KAAK,CAAC;AAE/D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAKrD;;;;;;;;;GASG;AACH,wBAAsB,sBAAsB,CAAC,OAAO,CAAC,EAAE;IACtD,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACxC,eAAe,CAAC,EAAE,eAAe,CAAC;CAClC,GAAG,OAAO,CAAC,oBAAoB,CAAC,aAAa,CAAC,CAAC,CA+C/C"}
|
package/lib/ses.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
import { toErrorString } from "./utils.js";
|
|
6
|
+
const lockdownSymbol = Symbol.for("tree-agent.ses.locked");
|
|
7
|
+
/**
|
|
8
|
+
* Create an implementation of {@link SemanticAgentOptions.executeEdit} that uses the SES library to run the provided code in a secure environment.
|
|
9
|
+
* @param createCompartment - This function can be used to optionally configure the SES Compartment used to execute the code.
|
|
10
|
+
* The provided globals must be included in the compartment's globals and must not conflict with any additional globals passed in.
|
|
11
|
+
* @param lockdownOptions - Optional configuration passed to the SES `lockdown` function.
|
|
12
|
+
* @returns A function that can be used as the {@link SemanticAgentOptions.executeEdit | executeEdit} callback.
|
|
13
|
+
* @remarks This function will both import the SES library and call its `lockdown` function the first time it is called.
|
|
14
|
+
* Therefore, this function should be called only once, early in an application's lifetime.
|
|
15
|
+
* @alpha
|
|
16
|
+
*/
|
|
17
|
+
export async function createSesEditEvaluator(options) {
|
|
18
|
+
const optionsGlobals = options?.compartmentOptions?.globals ?? new Map();
|
|
19
|
+
if (optionsGlobals.has("context") === true) {
|
|
20
|
+
throw new Error("The 'context' global is reserved and cannot be overridden in the compartment options.");
|
|
21
|
+
}
|
|
22
|
+
// Importing 'ses' has side effects, so we do it lazily to avoid impacting environments that don't use this evaluator.
|
|
23
|
+
await import("ses");
|
|
24
|
+
if (!(lockdownSymbol in globalThis)) {
|
|
25
|
+
try {
|
|
26
|
+
lockdown(options?.lockdownOptions);
|
|
27
|
+
Object.defineProperty(globalThis, lockdownSymbol, {
|
|
28
|
+
value: true,
|
|
29
|
+
writable: false,
|
|
30
|
+
configurable: false,
|
|
31
|
+
enumerable: false,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
if (toErrorString(error).includes("SES_ALREADY_LOCKED_DOWN")) {
|
|
36
|
+
Object.defineProperty(globalThis, lockdownSymbol, {
|
|
37
|
+
value: true,
|
|
38
|
+
writable: false,
|
|
39
|
+
configurable: false,
|
|
40
|
+
enumerable: false,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
throw error;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return async (context, code) => {
|
|
49
|
+
const compartmentOptions = {
|
|
50
|
+
...options?.compartmentOptions,
|
|
51
|
+
globals: {
|
|
52
|
+
...Object.fromEntries(optionsGlobals),
|
|
53
|
+
context,
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
const compartment = new Compartment({ ...compartmentOptions, __options__: true });
|
|
57
|
+
await compartment.evaluate(code);
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=ses.js.map
|
package/lib/ses.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ses.js","sourceRoot":"","sources":["../src/ses.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,cAAc,GAAG,MAAM,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;AAE3D;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,OAG5C;IACA,MAAM,cAAc,GACnB,OAAO,EAAE,kBAAkB,EAAE,OAAO,IAAI,IAAI,GAAG,EAAmB,CAAC;IACpE,IAAI,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,IAAI,EAAE,CAAC;QAC5C,MAAM,IAAI,KAAK,CACd,uFAAuF,CACvF,CAAC;IACH,CAAC;IAED,sHAAsH;IACtH,MAAM,MAAM,CAAC,KAAK,CAAC,CAAC;IAEpB,IAAI,CAAC,CAAC,cAAc,IAAI,UAAU,CAAC,EAAE,CAAC;QACrC,IAAI,CAAC;YACJ,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;YACnC,MAAM,CAAC,cAAc,CAAC,UAAU,EAAE,cAAc,EAAE;gBACjD,KAAK,EAAE,IAAI;gBACX,QAAQ,EAAE,KAAK;gBACf,YAAY,EAAE,KAAK;gBACnB,UAAU,EAAE,KAAK;aACjB,CAAC,CAAC;QACJ,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACzB,IAAI,aAAa,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,yBAAyB,CAAC,EAAE,CAAC;gBAC9D,MAAM,CAAC,cAAc,CAAC,UAAU,EAAE,cAAc,EAAE;oBACjD,KAAK,EAAE,IAAI;oBACX,QAAQ,EAAE,KAAK;oBACf,YAAY,EAAE,KAAK;oBACnB,UAAU,EAAE,KAAK;iBACjB,CAAC,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACP,MAAM,KAAK,CAAC;YACb,CAAC;QACF,CAAC;IACF,CAAC;IAED,OAAO,KAAK,EAAE,OAAgC,EAAE,IAAY,EAAE,EAAE;QAC/D,MAAM,kBAAkB,GAAG;YAC1B,GAAG,OAAO,EAAE,kBAAkB;YAC9B,OAAO,EAAE;gBACR,GAAG,MAAM,CAAC,WAAW,CAAC,cAAc,CAAC;gBACrC,OAAO;aACP;SACD,CAAC;QAEF,MAAM,WAAW,GAAG,IAAI,WAAW,CAAC,EAAE,GAAG,kBAAkB,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC;QAClF,MAAM,WAAW,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAClC,CAAC,CAAC;AACH,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { CompartmentOptions, LockdownOptions } from \"ses\";\n\nimport type { SemanticAgentOptions } from \"./api.js\";\nimport { toErrorString } from \"./utils.js\";\n\nconst lockdownSymbol = Symbol.for(\"tree-agent.ses.locked\");\n\n/**\n * Create an implementation of {@link SemanticAgentOptions.executeEdit} that uses the SES library to run the provided code in a secure environment.\n * @param createCompartment - This function can be used to optionally configure the SES Compartment used to execute the code.\n * The provided globals must be included in the compartment's globals and must not conflict with any additional globals passed in.\n * @param lockdownOptions - Optional configuration passed to the SES `lockdown` function.\n * @returns A function that can be used as the {@link SemanticAgentOptions.executeEdit | executeEdit} callback.\n * @remarks This function will both import the SES library and call its `lockdown` function the first time it is called.\n * Therefore, this function should be called only once, early in an application's lifetime.\n * @alpha\n */\nexport async function createSesEditEvaluator(options?: {\n\tcompartmentOptions?: CompartmentOptions;\n\tlockdownOptions?: LockdownOptions;\n}): Promise<SemanticAgentOptions[\"executeEdit\"]> {\n\tconst optionsGlobals: Map<string, unknown> =\n\t\toptions?.compartmentOptions?.globals ?? new Map<string, unknown>();\n\tif (optionsGlobals.has(\"context\") === true) {\n\t\tthrow new Error(\n\t\t\t\"The 'context' global is reserved and cannot be overridden in the compartment options.\",\n\t\t);\n\t}\n\n\t// Importing 'ses' has side effects, so we do it lazily to avoid impacting environments that don't use this evaluator.\n\tawait import(\"ses\");\n\n\tif (!(lockdownSymbol in globalThis)) {\n\t\ttry {\n\t\t\tlockdown(options?.lockdownOptions);\n\t\t\tObject.defineProperty(globalThis, lockdownSymbol, {\n\t\t\t\tvalue: true,\n\t\t\t\twritable: false,\n\t\t\t\tconfigurable: false,\n\t\t\t\tenumerable: false,\n\t\t\t});\n\t\t} catch (error: unknown) {\n\t\t\tif (toErrorString(error).includes(\"SES_ALREADY_LOCKED_DOWN\")) {\n\t\t\t\tObject.defineProperty(globalThis, lockdownSymbol, {\n\t\t\t\t\tvalue: true,\n\t\t\t\t\twritable: false,\n\t\t\t\t\tconfigurable: false,\n\t\t\t\t\tenumerable: false,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn async (context: Record<string, unknown>, code: string) => {\n\t\tconst compartmentOptions = {\n\t\t\t...options?.compartmentOptions,\n\t\t\tglobals: {\n\t\t\t\t...Object.fromEntries(optionsGlobals),\n\t\t\t\tcontext,\n\t\t\t},\n\t\t};\n\n\t\tconst compartment = new Compartment({ ...compartmentOptions, __options__: true });\n\t\tawait compartment.evaluate(code);\n\t};\n}\n"]}
|