@fluidframework/tree-agent-langchain 2.90.0 → 2.92.0
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/CHANGELOG.md +8 -0
- package/alpha.d.ts +1 -1
- package/dist/alpha.d.ts +3 -2
- package/dist/chatModel.d.ts +13 -1
- package/dist/chatModel.d.ts.map +1 -1
- package/dist/chatModel.js +124 -6
- package/dist/chatModel.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/public.d.ts +1 -1
- package/internal.d.ts +1 -1
- package/lib/alpha.d.ts +3 -2
- package/lib/chatModel.d.ts +13 -1
- package/lib/chatModel.d.ts.map +1 -1
- package/lib/chatModel.js +122 -5
- package/lib/chatModel.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/public.d.ts +1 -1
- package/package.json +12 -24
- package/src/chatModel.ts +153 -10
- package/src/index.ts +1 -1
package/CHANGELOG.md
CHANGED
package/alpha.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
/*
|
|
7
7
|
* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
|
8
|
-
* Generated by "flub generate entrypoints" in @fluid-tools/build-cli.
|
|
8
|
+
* Generated by "flub generate entrypoints --outFileLegacyBeta legacy --outDir ./lib --node10TypeCompat" in @fluid-tools/build-cli.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
export * from "./lib/alpha.js";
|
package/dist/alpha.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
/*
|
|
7
7
|
* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
|
8
|
-
* Generated by "flub generate entrypoints" in @fluid-tools/build-cli.
|
|
8
|
+
* Generated by "flub generate entrypoints --resolutionConditions require --outFileLegacyBeta legacy --outDir ./dist" in @fluid-tools/build-cli.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
/**
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
export {
|
|
18
18
|
// #region @alpha APIs
|
|
19
|
-
createLangchainChatModel
|
|
19
|
+
createLangchainChatModel,
|
|
20
|
+
createLegacyLangchainChatModel
|
|
20
21
|
// #endregion
|
|
21
22
|
} from "./index.js";
|
package/dist/chatModel.d.ts
CHANGED
|
@@ -5,9 +5,21 @@
|
|
|
5
5
|
import type { SharedTreeChatModel } from "@fluidframework/tree-agent/alpha";
|
|
6
6
|
import type { BaseChatModel } from "@langchain/core/language_models/chat_models";
|
|
7
7
|
/**
|
|
8
|
-
* Creates a
|
|
8
|
+
* Creates a stateless {@link @fluidframework/tree-agent#SharedTreeChatModel} backed by LangChain.
|
|
9
|
+
* @remarks Use with {@link @fluidframework/tree-agent#createTreeAgent | createTreeAgent}.
|
|
9
10
|
* @param langchainModel - The LangChain chat model to use.
|
|
10
11
|
* @alpha
|
|
11
12
|
*/
|
|
12
13
|
export declare function createLangchainChatModel(langchainModel: BaseChatModel): SharedTreeChatModel;
|
|
14
|
+
/**
|
|
15
|
+
* Creates a legacy stateful {@link @fluidframework/tree-agent#SharedTreeChatModel} backed by LangChain.
|
|
16
|
+
* @remarks This implementation maintains internal message history and manages the edit loop via the
|
|
17
|
+
* {@link @fluidframework/tree-agent#SharedTreeChatQuery.edit | edit} callback pattern.
|
|
18
|
+
* Use with {@link @fluidframework/tree-agent#SharedTreeSemanticAgent}.
|
|
19
|
+
* @param langchainModel - The LangChain chat model to use.
|
|
20
|
+
* @deprecated Use {@link createLangchainChatModel} with
|
|
21
|
+
* {@link @fluidframework/tree-agent#createTreeAgent | createTreeAgent} instead.
|
|
22
|
+
* @alpha
|
|
23
|
+
*/
|
|
24
|
+
export declare function createLegacyLangchainChatModel(langchainModel: BaseChatModel): SharedTreeChatModel;
|
|
13
25
|
//# sourceMappingURL=chatModel.d.ts.map
|
package/dist/chatModel.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chatModel.d.ts","sourceRoot":"","sources":["../src/chatModel.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"chatModel.d.ts","sourceRoot":"","sources":["../src/chatModel.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAEX,mBAAmB,EAInB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6CAA6C,CAAC;AAOjF;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,cAAc,EAAE,aAAa,GAAG,mBAAmB,CAE3F;AAuHD;;;;;;;;;GASG;AACH,wBAAgB,8BAA8B,CAC7C,cAAc,EAAE,aAAa,GAC3B,mBAAmB,CAErB"}
|
package/dist/chatModel.js
CHANGED
|
@@ -4,13 +4,14 @@
|
|
|
4
4
|
* Licensed under the MIT License.
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.createLangchainChatModel = void 0;
|
|
8
|
-
/* eslint-disable import-x/no-internal-modules */
|
|
7
|
+
exports.createLegacyLangchainChatModel = exports.createLangchainChatModel = void 0;
|
|
9
8
|
const internal_1 = require("@fluidframework/telemetry-utils/internal");
|
|
10
|
-
const messages_1 = require("@langchain/core/messages");
|
|
11
|
-
const tools_1 = require("@langchain/core/tools");
|
|
9
|
+
const messages_1 = require("@langchain/core/messages"); // eslint-disable-line import-x/no-internal-modules
|
|
10
|
+
const tools_1 = require("@langchain/core/tools"); // eslint-disable-line import-x/no-internal-modules
|
|
11
|
+
// #region New stateless implementation
|
|
12
12
|
/**
|
|
13
|
-
* Creates a
|
|
13
|
+
* Creates a stateless {@link @fluidframework/tree-agent#SharedTreeChatModel} backed by LangChain.
|
|
14
|
+
* @remarks Use with {@link @fluidframework/tree-agent#createTreeAgent | createTreeAgent}.
|
|
14
15
|
* @param langchainModel - The LangChain chat model to use.
|
|
15
16
|
* @alpha
|
|
16
17
|
*/
|
|
@@ -18,7 +19,120 @@ function createLangchainChatModel(langchainModel) {
|
|
|
18
19
|
return new LangchainChatModel(langchainModel);
|
|
19
20
|
}
|
|
20
21
|
exports.createLangchainChatModel = createLangchainChatModel;
|
|
22
|
+
/**
|
|
23
|
+
* Stateless LangChain adapter for {@link @fluidframework/tree-agent#SharedTreeChatModel}.
|
|
24
|
+
* @remarks This class does not maintain internal message history. All context is provided
|
|
25
|
+
* via the `history` parameter to {@link LangchainChatModel.invoke}.
|
|
26
|
+
*/
|
|
21
27
|
class LangchainChatModel {
|
|
28
|
+
constructor(model) {
|
|
29
|
+
this.model = model;
|
|
30
|
+
this.editToolName = "GenerateTreeEditingCode";
|
|
31
|
+
}
|
|
32
|
+
get name() {
|
|
33
|
+
const name = this.model.metadata?.modelName;
|
|
34
|
+
return typeof name === "string" ? name : undefined;
|
|
35
|
+
}
|
|
36
|
+
async invoke(history) {
|
|
37
|
+
// Convert TreeAgentChatMessage[] to LangChain BaseMessage[]
|
|
38
|
+
const messages = convertToLangchainMessages(history);
|
|
39
|
+
// Create a placeholder tool definition so the LLM knows the tool exists.
|
|
40
|
+
// The actual execution is handled by the agent's edit loop — this tool
|
|
41
|
+
// is never directly invoked, it only tells the LLM the tool signature.
|
|
42
|
+
const editingTool = (0, tools_1.tool)(async (js) => js, {
|
|
43
|
+
name: this.editToolName,
|
|
44
|
+
description: "Invokes a JavaScript code snippet to edit a tree of application data.",
|
|
45
|
+
});
|
|
46
|
+
const runnable = this.model.bindTools?.([editingTool], {
|
|
47
|
+
tool_choice: "auto",
|
|
48
|
+
});
|
|
49
|
+
if (runnable === undefined) {
|
|
50
|
+
throw new internal_1.UsageError("LLM client must support function calling or tool use.");
|
|
51
|
+
}
|
|
52
|
+
const responseMessage = await runnable.invoke(messages);
|
|
53
|
+
// Parse the response into TreeAgentChatResponse.
|
|
54
|
+
// Return the first tool call as a tool_call message, preserving the raw args.
|
|
55
|
+
// Arg parsing (extracting code) is the agent's responsibility.
|
|
56
|
+
const firstToolCall = responseMessage.tool_calls !== undefined && responseMessage.tool_calls.length > 0
|
|
57
|
+
? responseMessage.tool_calls[0]
|
|
58
|
+
: undefined;
|
|
59
|
+
if (firstToolCall !== undefined) {
|
|
60
|
+
return {
|
|
61
|
+
role: "tool_call",
|
|
62
|
+
toolCallId: firstToolCall.id,
|
|
63
|
+
toolName: firstToolCall.name,
|
|
64
|
+
toolArgs: firstToolCall.args,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
const content = typeof responseMessage.text === "string"
|
|
68
|
+
? responseMessage.text
|
|
69
|
+
: typeof responseMessage.content === "string"
|
|
70
|
+
? responseMessage.content
|
|
71
|
+
: JSON.stringify(responseMessage.content);
|
|
72
|
+
return { role: "assistant", content };
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Converts an array of {@link TreeAgentChatMessage} to LangChain {@link BaseMessage} format.
|
|
77
|
+
*/
|
|
78
|
+
function convertToLangchainMessages(history) {
|
|
79
|
+
const messages = [];
|
|
80
|
+
for (const msg of history) {
|
|
81
|
+
switch (msg.role) {
|
|
82
|
+
case "system": {
|
|
83
|
+
messages.push(new messages_1.SystemMessage(msg.content));
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
case "user": {
|
|
87
|
+
messages.push(new messages_1.HumanMessage(msg.content));
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
case "assistant": {
|
|
91
|
+
messages.push(new messages_1.AIMessage(msg.content));
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
case "tool_call": {
|
|
95
|
+
messages.push(new messages_1.AIMessage({
|
|
96
|
+
content: "",
|
|
97
|
+
tool_calls: [
|
|
98
|
+
{
|
|
99
|
+
id: msg.toolCallId,
|
|
100
|
+
name: msg.toolName,
|
|
101
|
+
args: msg.toolArgs,
|
|
102
|
+
},
|
|
103
|
+
],
|
|
104
|
+
}));
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
case "tool_result": {
|
|
108
|
+
messages.push(new messages_1.ToolMessage({
|
|
109
|
+
content: msg.content,
|
|
110
|
+
tool_call_id: msg.toolCallId ?? "",
|
|
111
|
+
}));
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
// No default
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return messages;
|
|
118
|
+
}
|
|
119
|
+
// #endregion
|
|
120
|
+
// #region Legacy stateful implementation
|
|
121
|
+
/**
|
|
122
|
+
* Creates a legacy stateful {@link @fluidframework/tree-agent#SharedTreeChatModel} backed by LangChain.
|
|
123
|
+
* @remarks This implementation maintains internal message history and manages the edit loop via the
|
|
124
|
+
* {@link @fluidframework/tree-agent#SharedTreeChatQuery.edit | edit} callback pattern.
|
|
125
|
+
* Use with {@link @fluidframework/tree-agent#SharedTreeSemanticAgent}.
|
|
126
|
+
* @param langchainModel - The LangChain chat model to use.
|
|
127
|
+
* @deprecated Use {@link createLangchainChatModel} with
|
|
128
|
+
* {@link @fluidframework/tree-agent#createTreeAgent | createTreeAgent} instead.
|
|
129
|
+
* @alpha
|
|
130
|
+
*/
|
|
131
|
+
function createLegacyLangchainChatModel(langchainModel) {
|
|
132
|
+
return new LegacyLangchainChatModel(langchainModel);
|
|
133
|
+
}
|
|
134
|
+
exports.createLegacyLangchainChatModel = createLegacyLangchainChatModel;
|
|
135
|
+
class LegacyLangchainChatModel {
|
|
22
136
|
constructor(model) {
|
|
23
137
|
this.model = model;
|
|
24
138
|
this.messages = [];
|
|
@@ -31,6 +145,7 @@ class LangchainChatModel {
|
|
|
31
145
|
appendContext(text) {
|
|
32
146
|
this.messages.push(new messages_1.SystemMessage(text));
|
|
33
147
|
}
|
|
148
|
+
// eslint-disable-next-line import-x/no-deprecated
|
|
34
149
|
async query(query) {
|
|
35
150
|
this.messages.push(new messages_1.HumanMessage(query.text));
|
|
36
151
|
return this.queryEdit(async (js) => query.edit(js));
|
|
@@ -40,7 +155,9 @@ class LangchainChatModel {
|
|
|
40
155
|
name: this.editToolName,
|
|
41
156
|
description: "Invokes a JavaScript code snippet to edit a tree of application data.",
|
|
42
157
|
});
|
|
43
|
-
const runnable = this.model.bindTools?.([editingTool], {
|
|
158
|
+
const runnable = this.model.bindTools?.([editingTool], {
|
|
159
|
+
tool_choice: "auto",
|
|
160
|
+
});
|
|
44
161
|
if (runnable === undefined) {
|
|
45
162
|
throw new internal_1.UsageError("LLM client must support function calling or tool use.");
|
|
46
163
|
}
|
|
@@ -77,4 +194,5 @@ function isEditResult(value) {
|
|
|
77
194
|
return (typeof value.type === "string" &&
|
|
78
195
|
typeof value.message === "string");
|
|
79
196
|
}
|
|
197
|
+
// #endregion
|
|
80
198
|
//# sourceMappingURL=chatModel.js.map
|
package/dist/chatModel.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chatModel.js","sourceRoot":"","sources":["../src/chatModel.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\n/* eslint-disable import-x/no-internal-modules */\n\nimport { UsageError } from \"@fluidframework/telemetry-utils/internal\";\nimport type {\n\tEditResult,\n\tSharedTreeChatModel,\n\tSharedTreeChatQuery,\n} from \"@fluidframework/tree-agent/alpha\";\nimport type { BaseChatModel } from \"@langchain/core/language_models/chat_models\";\nimport type { BaseMessage } from \"@langchain/core/messages\";\nimport { HumanMessage, SystemMessage } from \"@langchain/core/messages\";\nimport { tool } from \"@langchain/core/tools\";\n\n/**\n * Creates a `SharedTreeChatModel` that uses the LangChain library to connect to the underlying LLM.\n * @param langchainModel - The LangChain chat model to use.\n * @alpha\n */\nexport function createLangchainChatModel(langchainModel: BaseChatModel): SharedTreeChatModel {\n\treturn new LangchainChatModel(langchainModel);\n}\n\nclass LangchainChatModel implements SharedTreeChatModel {\n\tprivate readonly messages: BaseMessage[] = [];\n\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: string) => query.edit(js));\n\t}\n\n\tprivate async queryEdit(edit: SharedTreeChatQuery[\"edit\"]): Promise<string> {\n\t\tconst editingTool = tool(edit, {\n\t\t\tname: this.editToolName,\n\t\t\tdescription: \"Invokes a JavaScript code snippet to edit a tree of application data.\",\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\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/**\n * Type guard for {@link EditResult}.\n */\nfunction 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"]}
|
|
1
|
+
{"version":3,"file":"chatModel.js","sourceRoot":"","sources":["../src/chatModel.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 {\n\tEditResult,\n\tSharedTreeChatModel,\n\tTreeAgentChatMessage,\n\tTreeAgentChatResponse,\n\tSharedTreeChatQuery, // eslint-disable-line import-x/no-deprecated\n} from \"@fluidframework/tree-agent/alpha\";\nimport type { BaseChatModel } from \"@langchain/core/language_models/chat_models\"; // eslint-disable-line import-x/no-internal-modules\nimport type { BaseMessage } from \"@langchain/core/messages\"; // eslint-disable-line import-x/no-internal-modules\nimport { AIMessage, HumanMessage, SystemMessage, ToolMessage } from \"@langchain/core/messages\"; // eslint-disable-line import-x/no-internal-modules\nimport { tool } from \"@langchain/core/tools\"; // eslint-disable-line import-x/no-internal-modules\n\n// #region New stateless implementation\n\n/**\n * Creates a stateless {@link @fluidframework/tree-agent#SharedTreeChatModel} backed by LangChain.\n * @remarks Use with {@link @fluidframework/tree-agent#createTreeAgent | createTreeAgent}.\n * @param langchainModel - The LangChain chat model to use.\n * @alpha\n */\nexport function createLangchainChatModel(langchainModel: BaseChatModel): SharedTreeChatModel {\n\treturn new LangchainChatModel(langchainModel);\n}\n\n/**\n * Stateless LangChain adapter for {@link @fluidframework/tree-agent#SharedTreeChatModel}.\n * @remarks This class does not maintain internal message history. All context is provided\n * via the `history` parameter to {@link LangchainChatModel.invoke}.\n */\nclass LangchainChatModel implements SharedTreeChatModel {\n\tpublic readonly editToolName = \"GenerateTreeEditingCode\";\n\n\tpublic constructor(private readonly model: BaseChatModel) {}\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 async invoke(\n\t\thistory: readonly TreeAgentChatMessage[],\n\t): Promise<TreeAgentChatResponse> {\n\t\t// Convert TreeAgentChatMessage[] to LangChain BaseMessage[]\n\t\tconst messages: BaseMessage[] = convertToLangchainMessages(history);\n\n\t\t// Create a placeholder tool definition so the LLM knows the tool exists.\n\t\t// The actual execution is handled by the agent's edit loop — this tool\n\t\t// is never directly invoked, it only tells the LLM the tool signature.\n\t\tconst editingTool = tool(async (js: string) => js, {\n\t\t\tname: this.editToolName,\n\t\t\tdescription: \"Invokes a JavaScript code snippet to edit a tree of application data.\",\n\t\t});\n\n\t\tconst runnable = this.model.bindTools?.([editingTool], {\n\t\t\ttool_choice: \"auto\",\n\t\t});\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(messages);\n\n\t\t// Parse the response into TreeAgentChatResponse.\n\t\t// Return the first tool call as a tool_call message, preserving the raw args.\n\t\t// Arg parsing (extracting code) is the agent's responsibility.\n\t\tconst firstToolCall =\n\t\t\tresponseMessage.tool_calls !== undefined && responseMessage.tool_calls.length > 0\n\t\t\t\t? responseMessage.tool_calls[0]\n\t\t\t\t: undefined;\n\t\tif (firstToolCall !== undefined) {\n\t\t\treturn {\n\t\t\t\trole: \"tool_call\",\n\t\t\t\ttoolCallId: firstToolCall.id,\n\t\t\t\ttoolName: firstToolCall.name,\n\t\t\t\ttoolArgs: firstToolCall.args,\n\t\t\t};\n\t\t}\n\n\t\tconst content =\n\t\t\ttypeof responseMessage.text === \"string\"\n\t\t\t\t? responseMessage.text\n\t\t\t\t: typeof responseMessage.content === \"string\"\n\t\t\t\t\t? responseMessage.content\n\t\t\t\t\t: JSON.stringify(responseMessage.content);\n\t\treturn { role: \"assistant\", content };\n\t}\n}\n\n/**\n * Converts an array of {@link TreeAgentChatMessage} to LangChain {@link BaseMessage} format.\n */\nfunction convertToLangchainMessages(history: readonly TreeAgentChatMessage[]): BaseMessage[] {\n\tconst messages: BaseMessage[] = [];\n\tfor (const msg of history) {\n\t\tswitch (msg.role) {\n\t\t\tcase \"system\": {\n\t\t\t\tmessages.push(new SystemMessage(msg.content));\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"user\": {\n\t\t\t\tmessages.push(new HumanMessage(msg.content));\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"assistant\": {\n\t\t\t\tmessages.push(new AIMessage(msg.content));\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"tool_call\": {\n\t\t\t\tmessages.push(\n\t\t\t\t\tnew AIMessage({\n\t\t\t\t\t\tcontent: \"\",\n\t\t\t\t\t\ttool_calls: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tid: msg.toolCallId,\n\t\t\t\t\t\t\t\tname: msg.toolName,\n\t\t\t\t\t\t\t\targs: msg.toolArgs,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"tool_result\": {\n\t\t\t\tmessages.push(\n\t\t\t\t\tnew ToolMessage({\n\t\t\t\t\t\tcontent: msg.content,\n\t\t\t\t\t\ttool_call_id: msg.toolCallId ?? \"\",\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t// No default\n\t\t}\n\t}\n\treturn messages;\n}\n\n// #endregion\n\n// #region Legacy stateful implementation\n\n/**\n * Creates a legacy stateful {@link @fluidframework/tree-agent#SharedTreeChatModel} backed by LangChain.\n * @remarks This implementation maintains internal message history and manages the edit loop via the\n * {@link @fluidframework/tree-agent#SharedTreeChatQuery.edit | edit} callback pattern.\n * Use with {@link @fluidframework/tree-agent#SharedTreeSemanticAgent}.\n * @param langchainModel - The LangChain chat model to use.\n * @deprecated Use {@link createLangchainChatModel} with\n * {@link @fluidframework/tree-agent#createTreeAgent | createTreeAgent} instead.\n * @alpha\n */\nexport function createLegacyLangchainChatModel(\n\tlangchainModel: BaseChatModel,\n): SharedTreeChatModel {\n\treturn new LegacyLangchainChatModel(langchainModel);\n}\n\nclass LegacyLangchainChatModel implements SharedTreeChatModel {\n\tprivate readonly messages: BaseMessage[] = [];\n\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\t// eslint-disable-next-line import-x/no-deprecated\n\tpublic async query(query: SharedTreeChatQuery): Promise<string> {\n\t\tthis.messages.push(new HumanMessage(query.text));\n\t\treturn this.queryEdit(async (js: string) => query.edit(js));\n\t}\n\n\tprivate async queryEdit(\n\t\tedit: SharedTreeChatQuery[\"edit\"], // eslint-disable-line import-x/no-deprecated\n\t): Promise<string> {\n\t\tconst editingTool = tool(edit, {\n\t\t\tname: this.editToolName,\n\t\t\tdescription: \"Invokes a JavaScript code snippet to edit a tree of application data.\",\n\t\t});\n\t\tconst runnable = this.model.bindTools?.([editingTool], {\n\t\t\ttool_choice: \"auto\",\n\t\t});\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\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/**\n * Type guard for {@link EditResult}.\n */\nfunction 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// #endregion\n"]}
|
package/dist/index.d.ts
CHANGED
package/dist/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,wBAAwB,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,wBAAwB,EAAE,8BAA8B,EAAE,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Licensed under the MIT License.
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.createLangchainChatModel = void 0;
|
|
7
|
+
exports.createLegacyLangchainChatModel = exports.createLangchainChatModel = void 0;
|
|
8
8
|
/**
|
|
9
9
|
* LangChain integration helpers for the {@link @fluidframework/tree-agent#SharedTreeSemanticAgent | SharedTreeSemanticAgent}.
|
|
10
10
|
*
|
|
@@ -12,4 +12,5 @@ exports.createLangchainChatModel = void 0;
|
|
|
12
12
|
*/
|
|
13
13
|
var chatModel_js_1 = require("./chatModel.js");
|
|
14
14
|
Object.defineProperty(exports, "createLangchainChatModel", { enumerable: true, get: function () { return chatModel_js_1.createLangchainChatModel; } });
|
|
15
|
+
Object.defineProperty(exports, "createLegacyLangchainChatModel", { enumerable: true, get: function () { return chatModel_js_1.createLegacyLangchainChatModel; } });
|
|
15
16
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH;;;;GAIG;AAEH,+
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH;;;;GAIG;AAEH,+CAA0F;AAAjF,wHAAA,wBAAwB,OAAA;AAAE,8HAAA,8BAA8B,OAAA","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n/**\n * LangChain integration helpers for the {@link @fluidframework/tree-agent#SharedTreeSemanticAgent | SharedTreeSemanticAgent}.\n *\n * @packageDocumentation\n */\n\nexport { createLangchainChatModel, createLegacyLangchainChatModel } from \"./chatModel.js\";\n"]}
|
package/dist/public.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
/*
|
|
7
7
|
* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
|
8
|
-
* Generated by "flub generate entrypoints" in @fluid-tools/build-cli.
|
|
8
|
+
* Generated by "flub generate entrypoints --resolutionConditions require --outFileLegacyBeta legacy --outDir ./dist" in @fluid-tools/build-cli.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
/**
|
package/internal.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
/*
|
|
7
7
|
* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
|
8
|
-
* Generated by "flub generate entrypoints" in @fluid-tools/build-cli.
|
|
8
|
+
* Generated by "flub generate entrypoints --outFileLegacyBeta legacy --outDir ./lib --node10TypeCompat" in @fluid-tools/build-cli.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
export * from "./lib/index.js";
|
package/lib/alpha.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
/*
|
|
7
7
|
* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
|
8
|
-
* Generated by "flub generate entrypoints" in @fluid-tools/build-cli.
|
|
8
|
+
* Generated by "flub generate entrypoints --outFileLegacyBeta legacy --outDir ./lib --node10TypeCompat" in @fluid-tools/build-cli.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
/**
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
export {
|
|
18
18
|
// #region @alpha APIs
|
|
19
|
-
createLangchainChatModel
|
|
19
|
+
createLangchainChatModel,
|
|
20
|
+
createLegacyLangchainChatModel
|
|
20
21
|
// #endregion
|
|
21
22
|
} from "./index.js";
|
package/lib/chatModel.d.ts
CHANGED
|
@@ -5,9 +5,21 @@
|
|
|
5
5
|
import type { SharedTreeChatModel } from "@fluidframework/tree-agent/alpha";
|
|
6
6
|
import type { BaseChatModel } from "@langchain/core/language_models/chat_models";
|
|
7
7
|
/**
|
|
8
|
-
* Creates a
|
|
8
|
+
* Creates a stateless {@link @fluidframework/tree-agent#SharedTreeChatModel} backed by LangChain.
|
|
9
|
+
* @remarks Use with {@link @fluidframework/tree-agent#createTreeAgent | createTreeAgent}.
|
|
9
10
|
* @param langchainModel - The LangChain chat model to use.
|
|
10
11
|
* @alpha
|
|
11
12
|
*/
|
|
12
13
|
export declare function createLangchainChatModel(langchainModel: BaseChatModel): SharedTreeChatModel;
|
|
14
|
+
/**
|
|
15
|
+
* Creates a legacy stateful {@link @fluidframework/tree-agent#SharedTreeChatModel} backed by LangChain.
|
|
16
|
+
* @remarks This implementation maintains internal message history and manages the edit loop via the
|
|
17
|
+
* {@link @fluidframework/tree-agent#SharedTreeChatQuery.edit | edit} callback pattern.
|
|
18
|
+
* Use with {@link @fluidframework/tree-agent#SharedTreeSemanticAgent}.
|
|
19
|
+
* @param langchainModel - The LangChain chat model to use.
|
|
20
|
+
* @deprecated Use {@link createLangchainChatModel} with
|
|
21
|
+
* {@link @fluidframework/tree-agent#createTreeAgent | createTreeAgent} instead.
|
|
22
|
+
* @alpha
|
|
23
|
+
*/
|
|
24
|
+
export declare function createLegacyLangchainChatModel(langchainModel: BaseChatModel): SharedTreeChatModel;
|
|
13
25
|
//# sourceMappingURL=chatModel.d.ts.map
|
package/lib/chatModel.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chatModel.d.ts","sourceRoot":"","sources":["../src/chatModel.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"chatModel.d.ts","sourceRoot":"","sources":["../src/chatModel.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAEX,mBAAmB,EAInB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6CAA6C,CAAC;AAOjF;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,cAAc,EAAE,aAAa,GAAG,mBAAmB,CAE3F;AAuHD;;;;;;;;;GASG;AACH,wBAAgB,8BAA8B,CAC7C,cAAc,EAAE,aAAa,GAC3B,mBAAmB,CAErB"}
|
package/lib/chatModel.js
CHANGED
|
@@ -2,19 +2,132 @@
|
|
|
2
2
|
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
|
-
/* eslint-disable import-x/no-internal-modules */
|
|
6
5
|
import { UsageError } from "@fluidframework/telemetry-utils/internal";
|
|
7
|
-
import { HumanMessage, SystemMessage } from "@langchain/core/messages";
|
|
8
|
-
import { tool } from "@langchain/core/tools";
|
|
6
|
+
import { AIMessage, HumanMessage, SystemMessage, ToolMessage } from "@langchain/core/messages"; // eslint-disable-line import-x/no-internal-modules
|
|
7
|
+
import { tool } from "@langchain/core/tools"; // eslint-disable-line import-x/no-internal-modules
|
|
8
|
+
// #region New stateless implementation
|
|
9
9
|
/**
|
|
10
|
-
* Creates a
|
|
10
|
+
* Creates a stateless {@link @fluidframework/tree-agent#SharedTreeChatModel} backed by LangChain.
|
|
11
|
+
* @remarks Use with {@link @fluidframework/tree-agent#createTreeAgent | createTreeAgent}.
|
|
11
12
|
* @param langchainModel - The LangChain chat model to use.
|
|
12
13
|
* @alpha
|
|
13
14
|
*/
|
|
14
15
|
export function createLangchainChatModel(langchainModel) {
|
|
15
16
|
return new LangchainChatModel(langchainModel);
|
|
16
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* Stateless LangChain adapter for {@link @fluidframework/tree-agent#SharedTreeChatModel}.
|
|
20
|
+
* @remarks This class does not maintain internal message history. All context is provided
|
|
21
|
+
* via the `history` parameter to {@link LangchainChatModel.invoke}.
|
|
22
|
+
*/
|
|
17
23
|
class LangchainChatModel {
|
|
24
|
+
constructor(model) {
|
|
25
|
+
this.model = model;
|
|
26
|
+
this.editToolName = "GenerateTreeEditingCode";
|
|
27
|
+
}
|
|
28
|
+
get name() {
|
|
29
|
+
const name = this.model.metadata?.modelName;
|
|
30
|
+
return typeof name === "string" ? name : undefined;
|
|
31
|
+
}
|
|
32
|
+
async invoke(history) {
|
|
33
|
+
// Convert TreeAgentChatMessage[] to LangChain BaseMessage[]
|
|
34
|
+
const messages = convertToLangchainMessages(history);
|
|
35
|
+
// Create a placeholder tool definition so the LLM knows the tool exists.
|
|
36
|
+
// The actual execution is handled by the agent's edit loop — this tool
|
|
37
|
+
// is never directly invoked, it only tells the LLM the tool signature.
|
|
38
|
+
const editingTool = tool(async (js) => js, {
|
|
39
|
+
name: this.editToolName,
|
|
40
|
+
description: "Invokes a JavaScript code snippet to edit a tree of application data.",
|
|
41
|
+
});
|
|
42
|
+
const runnable = this.model.bindTools?.([editingTool], {
|
|
43
|
+
tool_choice: "auto",
|
|
44
|
+
});
|
|
45
|
+
if (runnable === undefined) {
|
|
46
|
+
throw new UsageError("LLM client must support function calling or tool use.");
|
|
47
|
+
}
|
|
48
|
+
const responseMessage = await runnable.invoke(messages);
|
|
49
|
+
// Parse the response into TreeAgentChatResponse.
|
|
50
|
+
// Return the first tool call as a tool_call message, preserving the raw args.
|
|
51
|
+
// Arg parsing (extracting code) is the agent's responsibility.
|
|
52
|
+
const firstToolCall = responseMessage.tool_calls !== undefined && responseMessage.tool_calls.length > 0
|
|
53
|
+
? responseMessage.tool_calls[0]
|
|
54
|
+
: undefined;
|
|
55
|
+
if (firstToolCall !== undefined) {
|
|
56
|
+
return {
|
|
57
|
+
role: "tool_call",
|
|
58
|
+
toolCallId: firstToolCall.id,
|
|
59
|
+
toolName: firstToolCall.name,
|
|
60
|
+
toolArgs: firstToolCall.args,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
const content = typeof responseMessage.text === "string"
|
|
64
|
+
? responseMessage.text
|
|
65
|
+
: typeof responseMessage.content === "string"
|
|
66
|
+
? responseMessage.content
|
|
67
|
+
: JSON.stringify(responseMessage.content);
|
|
68
|
+
return { role: "assistant", content };
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Converts an array of {@link TreeAgentChatMessage} to LangChain {@link BaseMessage} format.
|
|
73
|
+
*/
|
|
74
|
+
function convertToLangchainMessages(history) {
|
|
75
|
+
const messages = [];
|
|
76
|
+
for (const msg of history) {
|
|
77
|
+
switch (msg.role) {
|
|
78
|
+
case "system": {
|
|
79
|
+
messages.push(new SystemMessage(msg.content));
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
case "user": {
|
|
83
|
+
messages.push(new HumanMessage(msg.content));
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
case "assistant": {
|
|
87
|
+
messages.push(new AIMessage(msg.content));
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
case "tool_call": {
|
|
91
|
+
messages.push(new AIMessage({
|
|
92
|
+
content: "",
|
|
93
|
+
tool_calls: [
|
|
94
|
+
{
|
|
95
|
+
id: msg.toolCallId,
|
|
96
|
+
name: msg.toolName,
|
|
97
|
+
args: msg.toolArgs,
|
|
98
|
+
},
|
|
99
|
+
],
|
|
100
|
+
}));
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
case "tool_result": {
|
|
104
|
+
messages.push(new ToolMessage({
|
|
105
|
+
content: msg.content,
|
|
106
|
+
tool_call_id: msg.toolCallId ?? "",
|
|
107
|
+
}));
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
// No default
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return messages;
|
|
114
|
+
}
|
|
115
|
+
// #endregion
|
|
116
|
+
// #region Legacy stateful implementation
|
|
117
|
+
/**
|
|
118
|
+
* Creates a legacy stateful {@link @fluidframework/tree-agent#SharedTreeChatModel} backed by LangChain.
|
|
119
|
+
* @remarks This implementation maintains internal message history and manages the edit loop via the
|
|
120
|
+
* {@link @fluidframework/tree-agent#SharedTreeChatQuery.edit | edit} callback pattern.
|
|
121
|
+
* Use with {@link @fluidframework/tree-agent#SharedTreeSemanticAgent}.
|
|
122
|
+
* @param langchainModel - The LangChain chat model to use.
|
|
123
|
+
* @deprecated Use {@link createLangchainChatModel} with
|
|
124
|
+
* {@link @fluidframework/tree-agent#createTreeAgent | createTreeAgent} instead.
|
|
125
|
+
* @alpha
|
|
126
|
+
*/
|
|
127
|
+
export function createLegacyLangchainChatModel(langchainModel) {
|
|
128
|
+
return new LegacyLangchainChatModel(langchainModel);
|
|
129
|
+
}
|
|
130
|
+
class LegacyLangchainChatModel {
|
|
18
131
|
constructor(model) {
|
|
19
132
|
this.model = model;
|
|
20
133
|
this.messages = [];
|
|
@@ -27,6 +140,7 @@ class LangchainChatModel {
|
|
|
27
140
|
appendContext(text) {
|
|
28
141
|
this.messages.push(new SystemMessage(text));
|
|
29
142
|
}
|
|
143
|
+
// eslint-disable-next-line import-x/no-deprecated
|
|
30
144
|
async query(query) {
|
|
31
145
|
this.messages.push(new HumanMessage(query.text));
|
|
32
146
|
return this.queryEdit(async (js) => query.edit(js));
|
|
@@ -36,7 +150,9 @@ class LangchainChatModel {
|
|
|
36
150
|
name: this.editToolName,
|
|
37
151
|
description: "Invokes a JavaScript code snippet to edit a tree of application data.",
|
|
38
152
|
});
|
|
39
|
-
const runnable = this.model.bindTools?.([editingTool], {
|
|
153
|
+
const runnable = this.model.bindTools?.([editingTool], {
|
|
154
|
+
tool_choice: "auto",
|
|
155
|
+
});
|
|
40
156
|
if (runnable === undefined) {
|
|
41
157
|
throw new UsageError("LLM client must support function calling or tool use.");
|
|
42
158
|
}
|
|
@@ -73,4 +189,5 @@ function isEditResult(value) {
|
|
|
73
189
|
return (typeof value.type === "string" &&
|
|
74
190
|
typeof value.message === "string");
|
|
75
191
|
}
|
|
192
|
+
// #endregion
|
|
76
193
|
//# sourceMappingURL=chatModel.js.map
|
package/lib/chatModel.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chatModel.js","sourceRoot":"","sources":["../src/chatModel.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\n/* eslint-disable import-x/no-internal-modules */\n\nimport { UsageError } from \"@fluidframework/telemetry-utils/internal\";\nimport type {\n\tEditResult,\n\tSharedTreeChatModel,\n\tSharedTreeChatQuery,\n} from \"@fluidframework/tree-agent/alpha\";\nimport type { BaseChatModel } from \"@langchain/core/language_models/chat_models\";\nimport type { BaseMessage } from \"@langchain/core/messages\";\nimport { HumanMessage, SystemMessage } from \"@langchain/core/messages\";\nimport { tool } from \"@langchain/core/tools\";\n\n/**\n * Creates a `SharedTreeChatModel` that uses the LangChain library to connect to the underlying LLM.\n * @param langchainModel - The LangChain chat model to use.\n * @alpha\n */\nexport function createLangchainChatModel(langchainModel: BaseChatModel): SharedTreeChatModel {\n\treturn new LangchainChatModel(langchainModel);\n}\n\nclass LangchainChatModel implements SharedTreeChatModel {\n\tprivate readonly messages: BaseMessage[] = [];\n\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: string) => query.edit(js));\n\t}\n\n\tprivate async queryEdit(edit: SharedTreeChatQuery[\"edit\"]): Promise<string> {\n\t\tconst editingTool = tool(edit, {\n\t\t\tname: this.editToolName,\n\t\t\tdescription: \"Invokes a JavaScript code snippet to edit a tree of application data.\",\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\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/**\n * Type guard for {@link EditResult}.\n */\nfunction 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"]}
|
|
1
|
+
{"version":3,"file":"chatModel.js","sourceRoot":"","sources":["../src/chatModel.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 {\n\tEditResult,\n\tSharedTreeChatModel,\n\tTreeAgentChatMessage,\n\tTreeAgentChatResponse,\n\tSharedTreeChatQuery, // eslint-disable-line import-x/no-deprecated\n} from \"@fluidframework/tree-agent/alpha\";\nimport type { BaseChatModel } from \"@langchain/core/language_models/chat_models\"; // eslint-disable-line import-x/no-internal-modules\nimport type { BaseMessage } from \"@langchain/core/messages\"; // eslint-disable-line import-x/no-internal-modules\nimport { AIMessage, HumanMessage, SystemMessage, ToolMessage } from \"@langchain/core/messages\"; // eslint-disable-line import-x/no-internal-modules\nimport { tool } from \"@langchain/core/tools\"; // eslint-disable-line import-x/no-internal-modules\n\n// #region New stateless implementation\n\n/**\n * Creates a stateless {@link @fluidframework/tree-agent#SharedTreeChatModel} backed by LangChain.\n * @remarks Use with {@link @fluidframework/tree-agent#createTreeAgent | createTreeAgent}.\n * @param langchainModel - The LangChain chat model to use.\n * @alpha\n */\nexport function createLangchainChatModel(langchainModel: BaseChatModel): SharedTreeChatModel {\n\treturn new LangchainChatModel(langchainModel);\n}\n\n/**\n * Stateless LangChain adapter for {@link @fluidframework/tree-agent#SharedTreeChatModel}.\n * @remarks This class does not maintain internal message history. All context is provided\n * via the `history` parameter to {@link LangchainChatModel.invoke}.\n */\nclass LangchainChatModel implements SharedTreeChatModel {\n\tpublic readonly editToolName = \"GenerateTreeEditingCode\";\n\n\tpublic constructor(private readonly model: BaseChatModel) {}\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 async invoke(\n\t\thistory: readonly TreeAgentChatMessage[],\n\t): Promise<TreeAgentChatResponse> {\n\t\t// Convert TreeAgentChatMessage[] to LangChain BaseMessage[]\n\t\tconst messages: BaseMessage[] = convertToLangchainMessages(history);\n\n\t\t// Create a placeholder tool definition so the LLM knows the tool exists.\n\t\t// The actual execution is handled by the agent's edit loop — this tool\n\t\t// is never directly invoked, it only tells the LLM the tool signature.\n\t\tconst editingTool = tool(async (js: string) => js, {\n\t\t\tname: this.editToolName,\n\t\t\tdescription: \"Invokes a JavaScript code snippet to edit a tree of application data.\",\n\t\t});\n\n\t\tconst runnable = this.model.bindTools?.([editingTool], {\n\t\t\ttool_choice: \"auto\",\n\t\t});\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(messages);\n\n\t\t// Parse the response into TreeAgentChatResponse.\n\t\t// Return the first tool call as a tool_call message, preserving the raw args.\n\t\t// Arg parsing (extracting code) is the agent's responsibility.\n\t\tconst firstToolCall =\n\t\t\tresponseMessage.tool_calls !== undefined && responseMessage.tool_calls.length > 0\n\t\t\t\t? responseMessage.tool_calls[0]\n\t\t\t\t: undefined;\n\t\tif (firstToolCall !== undefined) {\n\t\t\treturn {\n\t\t\t\trole: \"tool_call\",\n\t\t\t\ttoolCallId: firstToolCall.id,\n\t\t\t\ttoolName: firstToolCall.name,\n\t\t\t\ttoolArgs: firstToolCall.args,\n\t\t\t};\n\t\t}\n\n\t\tconst content =\n\t\t\ttypeof responseMessage.text === \"string\"\n\t\t\t\t? responseMessage.text\n\t\t\t\t: typeof responseMessage.content === \"string\"\n\t\t\t\t\t? responseMessage.content\n\t\t\t\t\t: JSON.stringify(responseMessage.content);\n\t\treturn { role: \"assistant\", content };\n\t}\n}\n\n/**\n * Converts an array of {@link TreeAgentChatMessage} to LangChain {@link BaseMessage} format.\n */\nfunction convertToLangchainMessages(history: readonly TreeAgentChatMessage[]): BaseMessage[] {\n\tconst messages: BaseMessage[] = [];\n\tfor (const msg of history) {\n\t\tswitch (msg.role) {\n\t\t\tcase \"system\": {\n\t\t\t\tmessages.push(new SystemMessage(msg.content));\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"user\": {\n\t\t\t\tmessages.push(new HumanMessage(msg.content));\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"assistant\": {\n\t\t\t\tmessages.push(new AIMessage(msg.content));\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"tool_call\": {\n\t\t\t\tmessages.push(\n\t\t\t\t\tnew AIMessage({\n\t\t\t\t\t\tcontent: \"\",\n\t\t\t\t\t\ttool_calls: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tid: msg.toolCallId,\n\t\t\t\t\t\t\t\tname: msg.toolName,\n\t\t\t\t\t\t\t\targs: msg.toolArgs,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"tool_result\": {\n\t\t\t\tmessages.push(\n\t\t\t\t\tnew ToolMessage({\n\t\t\t\t\t\tcontent: msg.content,\n\t\t\t\t\t\ttool_call_id: msg.toolCallId ?? \"\",\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t// No default\n\t\t}\n\t}\n\treturn messages;\n}\n\n// #endregion\n\n// #region Legacy stateful implementation\n\n/**\n * Creates a legacy stateful {@link @fluidframework/tree-agent#SharedTreeChatModel} backed by LangChain.\n * @remarks This implementation maintains internal message history and manages the edit loop via the\n * {@link @fluidframework/tree-agent#SharedTreeChatQuery.edit | edit} callback pattern.\n * Use with {@link @fluidframework/tree-agent#SharedTreeSemanticAgent}.\n * @param langchainModel - The LangChain chat model to use.\n * @deprecated Use {@link createLangchainChatModel} with\n * {@link @fluidframework/tree-agent#createTreeAgent | createTreeAgent} instead.\n * @alpha\n */\nexport function createLegacyLangchainChatModel(\n\tlangchainModel: BaseChatModel,\n): SharedTreeChatModel {\n\treturn new LegacyLangchainChatModel(langchainModel);\n}\n\nclass LegacyLangchainChatModel implements SharedTreeChatModel {\n\tprivate readonly messages: BaseMessage[] = [];\n\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\t// eslint-disable-next-line import-x/no-deprecated\n\tpublic async query(query: SharedTreeChatQuery): Promise<string> {\n\t\tthis.messages.push(new HumanMessage(query.text));\n\t\treturn this.queryEdit(async (js: string) => query.edit(js));\n\t}\n\n\tprivate async queryEdit(\n\t\tedit: SharedTreeChatQuery[\"edit\"], // eslint-disable-line import-x/no-deprecated\n\t): Promise<string> {\n\t\tconst editingTool = tool(edit, {\n\t\t\tname: this.editToolName,\n\t\t\tdescription: \"Invokes a JavaScript code snippet to edit a tree of application data.\",\n\t\t});\n\t\tconst runnable = this.model.bindTools?.([editingTool], {\n\t\t\ttool_choice: \"auto\",\n\t\t});\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\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/**\n * Type guard for {@link EditResult}.\n */\nfunction 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// #endregion\n"]}
|
package/lib/index.d.ts
CHANGED
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,wBAAwB,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,wBAAwB,EAAE,8BAA8B,EAAE,MAAM,gBAAgB,CAAC"}
|
package/lib/index.js
CHANGED
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,wBAAwB,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 * LangChain integration helpers for the {@link @fluidframework/tree-agent#SharedTreeSemanticAgent | SharedTreeSemanticAgent}.\n *\n * @packageDocumentation\n */\n\nexport { createLangchainChatModel } from \"./chatModel.js\";\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;GAIG;AAEH,OAAO,EAAE,wBAAwB,EAAE,8BAA8B,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 * LangChain integration helpers for the {@link @fluidframework/tree-agent#SharedTreeSemanticAgent | SharedTreeSemanticAgent}.\n *\n * @packageDocumentation\n */\n\nexport { createLangchainChatModel, createLegacyLangchainChatModel } from \"./chatModel.js\";\n"]}
|
package/lib/public.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
/*
|
|
7
7
|
* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
|
8
|
-
* Generated by "flub generate entrypoints" in @fluid-tools/build-cli.
|
|
8
|
+
* Generated by "flub generate entrypoints --outFileLegacyBeta legacy --outDir ./lib --node10TypeCompat" in @fluid-tools/build-cli.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluidframework/tree-agent-langchain",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.92.0",
|
|
4
4
|
"description": "LangChain integration helpers for @fluidframework/tree-agent",
|
|
5
5
|
"homepage": "https://fluidframework.com",
|
|
6
6
|
"repository": {
|
|
@@ -69,21 +69,21 @@
|
|
|
69
69
|
"temp-directory": "nyc/.nyc_output"
|
|
70
70
|
},
|
|
71
71
|
"dependencies": {
|
|
72
|
-
"@fluidframework/telemetry-utils": "~2.
|
|
73
|
-
"@fluidframework/tree-agent": "~2.
|
|
72
|
+
"@fluidframework/telemetry-utils": "~2.92.0",
|
|
73
|
+
"@fluidframework/tree-agent": "~2.92.0",
|
|
74
74
|
"@langchain/core": "^0.3.80"
|
|
75
75
|
},
|
|
76
76
|
"devDependencies": {
|
|
77
77
|
"@arethetypeswrong/cli": "^0.18.2",
|
|
78
|
-
"@biomejs/biome": "~
|
|
79
|
-
"@fluid-internal/mocha-test-setup": "~2.
|
|
80
|
-
"@fluid-tools/build-cli": "^0.
|
|
78
|
+
"@biomejs/biome": "~2.4.5",
|
|
79
|
+
"@fluid-internal/mocha-test-setup": "~2.92.0",
|
|
80
|
+
"@fluid-tools/build-cli": "^0.64.0",
|
|
81
81
|
"@fluidframework/build-common": "^2.0.3",
|
|
82
|
-
"@fluidframework/build-tools": "^0.
|
|
83
|
-
"@fluidframework/core-utils": "~2.
|
|
84
|
-
"@fluidframework/eslint-config-fluid": "
|
|
85
|
-
"@fluidframework/runtime-utils": "~2.
|
|
86
|
-
"@fluidframework/tree": "~2.
|
|
82
|
+
"@fluidframework/build-tools": "^0.64.0",
|
|
83
|
+
"@fluidframework/core-utils": "~2.92.0",
|
|
84
|
+
"@fluidframework/eslint-config-fluid": "^9.0.0",
|
|
85
|
+
"@fluidframework/runtime-utils": "~2.92.0",
|
|
86
|
+
"@fluidframework/tree": "~2.92.0",
|
|
87
87
|
"@langchain/anthropic": "^0.3.24",
|
|
88
88
|
"@langchain/google-genai": "^0.2.16",
|
|
89
89
|
"@langchain/openai": "^0.6.12",
|
|
@@ -103,24 +103,12 @@
|
|
|
103
103
|
"rimraf": "^6.1.3",
|
|
104
104
|
"typescript": "~5.4.5"
|
|
105
105
|
},
|
|
106
|
-
"fluidBuild": {
|
|
107
|
-
"tasks": {
|
|
108
|
-
"build:esnext": [
|
|
109
|
-
"...",
|
|
110
|
-
"typetests:gen"
|
|
111
|
-
],
|
|
112
|
-
"tsc": [
|
|
113
|
-
"...",
|
|
114
|
-
"typetests:gen"
|
|
115
|
-
]
|
|
116
|
-
}
|
|
117
|
-
},
|
|
118
106
|
"typeValidation": {
|
|
119
107
|
"disabled": true
|
|
120
108
|
},
|
|
121
109
|
"scripts": {
|
|
122
110
|
"api": "fluid-build . --task api",
|
|
123
|
-
"api-extractor:commonjs": "flub generate entrypoints --outFileLegacyBeta legacy --outDir ./dist",
|
|
111
|
+
"api-extractor:commonjs": "flub generate entrypoints --resolutionConditions require --outFileLegacyBeta legacy --outDir ./dist",
|
|
124
112
|
"api-extractor:esnext": "flub generate entrypoints --outFileLegacyBeta legacy --outDir ./lib --node10TypeCompat",
|
|
125
113
|
"build": "fluid-build . --task build",
|
|
126
114
|
"build:commonjs": "fluid-build . --task commonjs",
|
package/src/chatModel.ts
CHANGED
|
@@ -3,21 +3,24 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
/* eslint-disable import-x/no-internal-modules */
|
|
7
|
-
|
|
8
6
|
import { UsageError } from "@fluidframework/telemetry-utils/internal";
|
|
9
7
|
import type {
|
|
10
8
|
EditResult,
|
|
11
9
|
SharedTreeChatModel,
|
|
12
|
-
|
|
10
|
+
TreeAgentChatMessage,
|
|
11
|
+
TreeAgentChatResponse,
|
|
12
|
+
SharedTreeChatQuery, // eslint-disable-line import-x/no-deprecated
|
|
13
13
|
} from "@fluidframework/tree-agent/alpha";
|
|
14
|
-
import type { BaseChatModel } from "@langchain/core/language_models/chat_models";
|
|
15
|
-
import type { BaseMessage } from "@langchain/core/messages";
|
|
16
|
-
import { HumanMessage, SystemMessage } from "@langchain/core/messages";
|
|
17
|
-
import { tool } from "@langchain/core/tools";
|
|
14
|
+
import type { BaseChatModel } from "@langchain/core/language_models/chat_models"; // eslint-disable-line import-x/no-internal-modules
|
|
15
|
+
import type { BaseMessage } from "@langchain/core/messages"; // eslint-disable-line import-x/no-internal-modules
|
|
16
|
+
import { AIMessage, HumanMessage, SystemMessage, ToolMessage } from "@langchain/core/messages"; // eslint-disable-line import-x/no-internal-modules
|
|
17
|
+
import { tool } from "@langchain/core/tools"; // eslint-disable-line import-x/no-internal-modules
|
|
18
|
+
|
|
19
|
+
// #region New stateless implementation
|
|
18
20
|
|
|
19
21
|
/**
|
|
20
|
-
* Creates a
|
|
22
|
+
* Creates a stateless {@link @fluidframework/tree-agent#SharedTreeChatModel} backed by LangChain.
|
|
23
|
+
* @remarks Use with {@link @fluidframework/tree-agent#createTreeAgent | createTreeAgent}.
|
|
21
24
|
* @param langchainModel - The LangChain chat model to use.
|
|
22
25
|
* @alpha
|
|
23
26
|
*/
|
|
@@ -25,7 +28,140 @@ export function createLangchainChatModel(langchainModel: BaseChatModel): SharedT
|
|
|
25
28
|
return new LangchainChatModel(langchainModel);
|
|
26
29
|
}
|
|
27
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Stateless LangChain adapter for {@link @fluidframework/tree-agent#SharedTreeChatModel}.
|
|
33
|
+
* @remarks This class does not maintain internal message history. All context is provided
|
|
34
|
+
* via the `history` parameter to {@link LangchainChatModel.invoke}.
|
|
35
|
+
*/
|
|
28
36
|
class LangchainChatModel implements SharedTreeChatModel {
|
|
37
|
+
public readonly editToolName = "GenerateTreeEditingCode";
|
|
38
|
+
|
|
39
|
+
public constructor(private readonly model: BaseChatModel) {}
|
|
40
|
+
|
|
41
|
+
public get name(): string | undefined {
|
|
42
|
+
const name = this.model.metadata?.modelName;
|
|
43
|
+
return typeof name === "string" ? name : undefined;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
public async invoke(
|
|
47
|
+
history: readonly TreeAgentChatMessage[],
|
|
48
|
+
): Promise<TreeAgentChatResponse> {
|
|
49
|
+
// Convert TreeAgentChatMessage[] to LangChain BaseMessage[]
|
|
50
|
+
const messages: BaseMessage[] = convertToLangchainMessages(history);
|
|
51
|
+
|
|
52
|
+
// Create a placeholder tool definition so the LLM knows the tool exists.
|
|
53
|
+
// The actual execution is handled by the agent's edit loop — this tool
|
|
54
|
+
// is never directly invoked, it only tells the LLM the tool signature.
|
|
55
|
+
const editingTool = tool(async (js: string) => js, {
|
|
56
|
+
name: this.editToolName,
|
|
57
|
+
description: "Invokes a JavaScript code snippet to edit a tree of application data.",
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const runnable = this.model.bindTools?.([editingTool], {
|
|
61
|
+
tool_choice: "auto",
|
|
62
|
+
});
|
|
63
|
+
if (runnable === undefined) {
|
|
64
|
+
throw new UsageError("LLM client must support function calling or tool use.");
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const responseMessage = await runnable.invoke(messages);
|
|
68
|
+
|
|
69
|
+
// Parse the response into TreeAgentChatResponse.
|
|
70
|
+
// Return the first tool call as a tool_call message, preserving the raw args.
|
|
71
|
+
// Arg parsing (extracting code) is the agent's responsibility.
|
|
72
|
+
const firstToolCall =
|
|
73
|
+
responseMessage.tool_calls !== undefined && responseMessage.tool_calls.length > 0
|
|
74
|
+
? responseMessage.tool_calls[0]
|
|
75
|
+
: undefined;
|
|
76
|
+
if (firstToolCall !== undefined) {
|
|
77
|
+
return {
|
|
78
|
+
role: "tool_call",
|
|
79
|
+
toolCallId: firstToolCall.id,
|
|
80
|
+
toolName: firstToolCall.name,
|
|
81
|
+
toolArgs: firstToolCall.args,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const content =
|
|
86
|
+
typeof responseMessage.text === "string"
|
|
87
|
+
? responseMessage.text
|
|
88
|
+
: typeof responseMessage.content === "string"
|
|
89
|
+
? responseMessage.content
|
|
90
|
+
: JSON.stringify(responseMessage.content);
|
|
91
|
+
return { role: "assistant", content };
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Converts an array of {@link TreeAgentChatMessage} to LangChain {@link BaseMessage} format.
|
|
97
|
+
*/
|
|
98
|
+
function convertToLangchainMessages(history: readonly TreeAgentChatMessage[]): BaseMessage[] {
|
|
99
|
+
const messages: BaseMessage[] = [];
|
|
100
|
+
for (const msg of history) {
|
|
101
|
+
switch (msg.role) {
|
|
102
|
+
case "system": {
|
|
103
|
+
messages.push(new SystemMessage(msg.content));
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
case "user": {
|
|
107
|
+
messages.push(new HumanMessage(msg.content));
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
case "assistant": {
|
|
111
|
+
messages.push(new AIMessage(msg.content));
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
case "tool_call": {
|
|
115
|
+
messages.push(
|
|
116
|
+
new AIMessage({
|
|
117
|
+
content: "",
|
|
118
|
+
tool_calls: [
|
|
119
|
+
{
|
|
120
|
+
id: msg.toolCallId,
|
|
121
|
+
name: msg.toolName,
|
|
122
|
+
args: msg.toolArgs,
|
|
123
|
+
},
|
|
124
|
+
],
|
|
125
|
+
}),
|
|
126
|
+
);
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
case "tool_result": {
|
|
130
|
+
messages.push(
|
|
131
|
+
new ToolMessage({
|
|
132
|
+
content: msg.content,
|
|
133
|
+
tool_call_id: msg.toolCallId ?? "",
|
|
134
|
+
}),
|
|
135
|
+
);
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
// No default
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return messages;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// #endregion
|
|
145
|
+
|
|
146
|
+
// #region Legacy stateful implementation
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Creates a legacy stateful {@link @fluidframework/tree-agent#SharedTreeChatModel} backed by LangChain.
|
|
150
|
+
* @remarks This implementation maintains internal message history and manages the edit loop via the
|
|
151
|
+
* {@link @fluidframework/tree-agent#SharedTreeChatQuery.edit | edit} callback pattern.
|
|
152
|
+
* Use with {@link @fluidframework/tree-agent#SharedTreeSemanticAgent}.
|
|
153
|
+
* @param langchainModel - The LangChain chat model to use.
|
|
154
|
+
* @deprecated Use {@link createLangchainChatModel} with
|
|
155
|
+
* {@link @fluidframework/tree-agent#createTreeAgent | createTreeAgent} instead.
|
|
156
|
+
* @alpha
|
|
157
|
+
*/
|
|
158
|
+
export function createLegacyLangchainChatModel(
|
|
159
|
+
langchainModel: BaseChatModel,
|
|
160
|
+
): SharedTreeChatModel {
|
|
161
|
+
return new LegacyLangchainChatModel(langchainModel);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
class LegacyLangchainChatModel implements SharedTreeChatModel {
|
|
29
165
|
private readonly messages: BaseMessage[] = [];
|
|
30
166
|
|
|
31
167
|
public constructor(private readonly model: BaseChatModel) {}
|
|
@@ -41,17 +177,22 @@ class LangchainChatModel implements SharedTreeChatModel {
|
|
|
41
177
|
this.messages.push(new SystemMessage(text));
|
|
42
178
|
}
|
|
43
179
|
|
|
180
|
+
// eslint-disable-next-line import-x/no-deprecated
|
|
44
181
|
public async query(query: SharedTreeChatQuery): Promise<string> {
|
|
45
182
|
this.messages.push(new HumanMessage(query.text));
|
|
46
183
|
return this.queryEdit(async (js: string) => query.edit(js));
|
|
47
184
|
}
|
|
48
185
|
|
|
49
|
-
private async queryEdit(
|
|
186
|
+
private async queryEdit(
|
|
187
|
+
edit: SharedTreeChatQuery["edit"], // eslint-disable-line import-x/no-deprecated
|
|
188
|
+
): Promise<string> {
|
|
50
189
|
const editingTool = tool(edit, {
|
|
51
190
|
name: this.editToolName,
|
|
52
191
|
description: "Invokes a JavaScript code snippet to edit a tree of application data.",
|
|
53
192
|
});
|
|
54
|
-
const runnable = this.model.bindTools?.([editingTool], {
|
|
193
|
+
const runnable = this.model.bindTools?.([editingTool], {
|
|
194
|
+
tool_choice: "auto",
|
|
195
|
+
});
|
|
55
196
|
if (runnable === undefined) {
|
|
56
197
|
throw new UsageError("LLM client must support function calling or tool use.");
|
|
57
198
|
}
|
|
@@ -94,3 +235,5 @@ function isEditResult(value: unknown): value is EditResult {
|
|
|
94
235
|
typeof (value as EditResult).message === "string"
|
|
95
236
|
);
|
|
96
237
|
}
|
|
238
|
+
|
|
239
|
+
// #endregion
|
package/src/index.ts
CHANGED