mirror of
https://github.com/n8n-io/n8n.git
synced 2025-01-12 05:17:28 -08:00
spike/poc work
This commit is contained in:
parent
706702dff8
commit
28f87d7ecb
|
@ -270,6 +270,7 @@ export async function toolsAgentExecute(this: IExecuteFunctions): Promise<INodeE
|
|||
messages.push(['placeholder', '{agent_scratchpad}']);
|
||||
const prompt = ChatPromptTemplate.fromMessages(messages);
|
||||
|
||||
// here agent is created first step with tools
|
||||
const agent = createToolCallingAgent({
|
||||
llm: model,
|
||||
tools,
|
||||
|
|
|
@ -2,7 +2,10 @@
|
|||
/* eslint-disable n8n-nodes-base/node-dirname-against-convention */
|
||||
import type { Document } from '@langchain/core/documents';
|
||||
import type { Embeddings } from '@langchain/core/embeddings';
|
||||
import type { BaseLanguageModel } from '@langchain/core/language_models/base';
|
||||
import type { VectorStore } from '@langchain/core/vectorstores';
|
||||
import { VectorDBQAChain } from 'langchain/chains';
|
||||
import { VectorStoreQATool } from 'langchain/tools';
|
||||
import { NodeConnectionType, NodeOperationError } from 'n8n-workflow';
|
||||
import type {
|
||||
IExecuteFunctions,
|
||||
|
@ -129,6 +132,7 @@ export const createVectorStoreNode = (args: VectorStoreNodeConstructorArgs) =>
|
|||
defaults: {
|
||||
name: args.meta.displayName,
|
||||
},
|
||||
usableAsTool: true,
|
||||
codex: {
|
||||
categories: ['AI'],
|
||||
subcategories: {
|
||||
|
@ -143,11 +147,13 @@ export const createVectorStoreNode = (args: VectorStoreNodeConstructorArgs) =>
|
|||
},
|
||||
},
|
||||
credentials: args.meta.credentials,
|
||||
// todo add model input only if used as tool
|
||||
// todo use model from parent by default only show model input if custom mode is used
|
||||
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
||||
inputs: `={{
|
||||
((parameters) => {
|
||||
const mode = parameters?.mode;
|
||||
const inputs = [{ displayName: "Embedding", type: "${NodeConnectionType.AiEmbedding}", required: true, maxConnections: 1}]
|
||||
const inputs = [{ displayName: "Embedding", type: "${NodeConnectionType.AiEmbedding}", required: true, maxConnections: 1}, {displayName: 'Model', maxConnections: 1, type: "${NodeConnectionType.AiLanguageModel}", required: true}]
|
||||
|
||||
if (['insert', 'load', 'update'].includes(mode)) {
|
||||
inputs.push({ displayName: "", type: "${NodeConnectionType.Main}"})
|
||||
|
@ -381,24 +387,54 @@ export const createVectorStoreNode = (args: VectorStoreNodeConstructorArgs) =>
|
|||
);
|
||||
}
|
||||
|
||||
// here vector stores supply data to parent nodes
|
||||
async supplyData(this: ISupplyDataFunctions, itemIndex: number): Promise<SupplyData> {
|
||||
const mode = this.getNodeParameter('mode', 0) as 'load' | 'insert' | 'retrieve';
|
||||
const filter = getMetadataFiltersValues(this, itemIndex);
|
||||
// todo allow name and description to be configurable
|
||||
const name = 'vector_store_tool'; //this.getNodeParameter('name', itemIndex) as string;
|
||||
const toolDescription = 'get data'; //this.getNodeParameter('description', itemIndex) as string;
|
||||
const topK = this.getNodeParameter('topK', itemIndex, 4) as number;
|
||||
|
||||
const embeddings = (await this.getInputConnectionData(
|
||||
NodeConnectionType.AiEmbedding,
|
||||
0,
|
||||
)) as Embeddings;
|
||||
|
||||
if (mode === 'retrieve') {
|
||||
const filter = getMetadataFiltersValues(this, itemIndex);
|
||||
const vectorStore = await args.getVectorStoreClient(this, filter, embeddings, itemIndex);
|
||||
return {
|
||||
response: logWrapper(vectorStore, this),
|
||||
};
|
||||
}
|
||||
|
||||
throw new NodeOperationError(
|
||||
this.getNode(),
|
||||
'Only the "retrieve" operation mode is supported to supply data',
|
||||
);
|
||||
const llm = (await this.getInputConnectionData(
|
||||
NodeConnectionType.AiLanguageModel,
|
||||
0,
|
||||
)) as BaseLanguageModel;
|
||||
|
||||
const description = VectorStoreQATool.getDescription(name, toolDescription);
|
||||
const vectorStoreTool = new VectorStoreQATool(name, description, {
|
||||
llm,
|
||||
vectorStore,
|
||||
});
|
||||
|
||||
vectorStoreTool.chain = VectorDBQAChain.fromLLM(llm, vectorStore, {
|
||||
k: topK,
|
||||
});
|
||||
|
||||
return {
|
||||
response: logWrapper(vectorStoreTool, this),
|
||||
};
|
||||
|
||||
// todo make this backward compatible, allowing to be used directly as a vector store
|
||||
// const mode = this.getNodeParameter('mode', 0) as 'load' | 'insert' | 'retrieve';
|
||||
// const filter = getMetadataFiltersValues(this, itemIndex);
|
||||
|
||||
// if (mode === 'retrieve') {
|
||||
// const vectorStore = await args.getVectorStoreClient(this, filter, embeddings, itemIndex);
|
||||
// return {
|
||||
// response: logWrapper(vectorStore, this),
|
||||
// };
|
||||
// }
|
||||
|
||||
// throw new NodeOperationError(
|
||||
// this.getNode(),
|
||||
// 'Only the "retrieve" operation mode is supported to supply data',
|
||||
// );
|
||||
}
|
||||
};
|
||||
|
|
|
@ -74,6 +74,7 @@ export class NodeTypes implements INodeTypes {
|
|||
const clonedNode = Object.create(versionedNodeType, {
|
||||
description: { value: clonedDescription },
|
||||
}) as INodeType;
|
||||
// convert nodes to tools as loading them
|
||||
const tool = NodeHelpers.convertNodeToAiTool(clonedNode);
|
||||
loadedNodes[nodeType + 'Tool'] = { sourcePath: '', type: tool };
|
||||
return tool;
|
||||
|
|
|
@ -2238,12 +2238,15 @@ export async function getInputConnectionData(
|
|||
}
|
||||
|
||||
try {
|
||||
// here sub-node supplyData function gets called
|
||||
// passing data to parent nodes
|
||||
const response = await nodeType.supplyData.call(context, itemIndex);
|
||||
if (response.closeFunction) {
|
||||
closeFunctions.push(response.closeFunction);
|
||||
}
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.log('e', error);
|
||||
// Propagate errors from sub-nodes
|
||||
if (error.functionality === 'configuration-node') throw error;
|
||||
if (!(error instanceof ExecutionBaseError)) {
|
||||
|
|
|
@ -356,6 +356,7 @@ const declarativeNodeOptionParameters: INodeProperties = {
|
|||
* as an AI Agent Tool.
|
||||
* Returns the modified item (not copied)
|
||||
*/
|
||||
// convert any node into ai tool
|
||||
export function convertNodeToAiTool<
|
||||
T extends object & { description: INodeTypeDescription | INodeTypeBaseDescription },
|
||||
>(item: T): T {
|
||||
|
@ -366,7 +367,8 @@ export function convertNodeToAiTool<
|
|||
|
||||
if (isFullDescription(item.description)) {
|
||||
item.description.name += 'Tool';
|
||||
item.description.inputs = [];
|
||||
// todo if vector store keep inputs
|
||||
// item.description.inputs = [];
|
||||
item.description.outputs = [NodeConnectionType.AiTool];
|
||||
item.description.displayName += ' Tool';
|
||||
delete item.description.usableAsTool;
|
||||
|
|
Loading…
Reference in a new issue