@sweetoburrito/backstage-plugin-ai-assistant-backend 0.8.0 → 0.10.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/config.d.ts +8 -0
- package/dist/constants/prompts.cjs.js +25 -13
- package/dist/constants/prompts.cjs.js.map +1 -1
- package/dist/database/chat-store.cjs.js +22 -2
- package/dist/database/chat-store.cjs.js.map +1 -1
- package/dist/database/mcp-store.cjs.js +46 -0
- package/dist/database/mcp-store.cjs.js.map +1 -0
- package/dist/plugin.cjs.js +26 -3
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/services/callbacks.cjs.js +49 -0
- package/dist/services/callbacks.cjs.js.map +1 -0
- package/dist/services/chat.cjs.js +79 -33
- package/dist/services/chat.cjs.js.map +1 -1
- package/dist/services/mcp.cjs.js +119 -0
- package/dist/services/mcp.cjs.js.map +1 -0
- package/dist/services/router/chat.cjs.js +23 -3
- package/dist/services/router/chat.cjs.js.map +1 -1
- package/dist/services/router/index.cjs.js +4 -0
- package/dist/services/router/index.cjs.js.map +1 -1
- package/dist/services/router/mcp.cjs.js +81 -0
- package/dist/services/router/mcp.cjs.js.map +1 -0
- package/dist/services/router/summary.cjs.js +56 -0
- package/dist/services/router/summary.cjs.js.map +1 -0
- package/dist/services/summarizer.cjs.js +38 -14
- package/dist/services/summarizer.cjs.js.map +1 -1
- package/dist/services/tools/searchKnowledge.cjs.js +1 -1
- package/dist/services/tools/searchKnowledge.cjs.js.map +1 -1
- package/migrations/20251029_mcp.js +42 -0
- package/migrations/20251029_score.js +52 -0
- package/package.json +7 -3
package/config.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { HumanDuration } from '@backstage/types';
|
|
2
2
|
import { SchedulerServiceTaskScheduleDefinitionConfig } from '@backstage/backend-plugin-api';
|
|
3
|
+
import { McpServerConfig } from '@sweetoburrito/backstage-plugin-ai-assistant-common';
|
|
3
4
|
|
|
4
5
|
export interface Config {
|
|
5
6
|
aiAssistant: {
|
|
@@ -28,5 +29,12 @@ export interface Config {
|
|
|
28
29
|
ingestion?: {
|
|
29
30
|
schedule?: SchedulerServiceTaskScheduleDefinitionConfig;
|
|
30
31
|
};
|
|
32
|
+
mcp: {
|
|
33
|
+
/**
|
|
34
|
+
* @visibility secret
|
|
35
|
+
*/
|
|
36
|
+
encryptionKey: string;
|
|
37
|
+
servers?: Array<McpServerConfig>;
|
|
38
|
+
};
|
|
31
39
|
};
|
|
32
40
|
}
|
|
@@ -1,21 +1,30 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const
|
|
3
|
+
const DEFAULT_CONVERSATION_SUMMARY_PROMPT = "Summarize this conversation in a concise manner. The summary should capture the main points. Return the summary only, without any additional text. Do not include any introductions or other part of the conversation that doesn't contribute to the summary or form part of the overall conversation as part of the summary.";
|
|
4
|
+
const DEFAULT_SUMMARY_PROMPT = "Summarize the following content in a concise manner. The summary should capture the main points. Return the summary only, without any additional text. Do not include any introductions or other part of the content that doesn't contribute to the summary.";
|
|
5
|
+
const DEFAULT_IDENTITY_PROMPT = `
|
|
5
6
|
You are a helpful assistant that answers questions based on provided context from various documents. The context may come from sources such as internal wikis, code repositories, technical documentation, or other structured or unstructured data.
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
`;
|
|
8
|
+
const DEFAULT_FORMATTING_PROMPT = `
|
|
9
|
+
CRITICAL FORMATTING RULES - MUST ALWAYS FOLLOW:
|
|
10
|
+
1. **ALWAYS use proper markdown formatting in ALL responses**
|
|
11
|
+
2. **NEVER output plain URLs** - ALWAYS convert them to clickable markdown links using [description](url) syntax
|
|
12
|
+
3. **For images, ALWAYS use markdown image syntax**: 
|
|
13
|
+
4. **For all URLs, ALWAYS format as**: [descriptive text](url) - never just paste the raw URL
|
|
14
|
+
5. Use headings (##, ###), bullet points, numbered lists, and **bold**/*italic* text appropriately
|
|
15
|
+
6. Format code with backticks: \`inline code\` or \`\`\`language for code blocks
|
|
16
|
+
7. Structure responses clearly with proper spacing and organization
|
|
17
|
+
`;
|
|
18
|
+
const DEFAULT_SYSTEM_PROMPT = `
|
|
19
|
+
Content Rules:
|
|
8
20
|
1. Always base your answers on the provided context. Do not make up information.
|
|
9
21
|
2. When relevant, cite or reference the source information provided in the context.
|
|
10
|
-
3.
|
|
11
|
-
4.
|
|
12
|
-
5.
|
|
13
|
-
6.
|
|
14
|
-
7.
|
|
15
|
-
8.
|
|
16
|
-
9. Adapt your approach based on the specific tools and capabilities available in the current session
|
|
17
|
-
10. When you have a link to an image, include it in your response using markdown format .
|
|
18
|
-
11. When you have a link to a document, include it in your response using markdown format [description](document_url).
|
|
22
|
+
3. Maintain a professional, friendly, and helpful tone.
|
|
23
|
+
4. Return only the relevant information without any filler or unnecessary details.
|
|
24
|
+
5. If you don't know the answer, admit it and suggest ways to find the information.
|
|
25
|
+
6. **Actively use available tools** to enhance your responses
|
|
26
|
+
7. Adapt your approach based on the specific tools and capabilities available in the current session
|
|
27
|
+
8. When you do not have the information needed to answer, use the tools provided to gather more context before responding.
|
|
19
28
|
`;
|
|
20
29
|
const DEFAULT_TOOL_GUIDELINE = `
|
|
21
30
|
TOOL USAGE GUIDELINES:
|
|
@@ -27,6 +36,9 @@ TOOL USAGE GUIDELINES:
|
|
|
27
36
|
- If a tool fails, try an alternative approach before using another tool
|
|
28
37
|
`;
|
|
29
38
|
|
|
39
|
+
exports.DEFAULT_CONVERSATION_SUMMARY_PROMPT = DEFAULT_CONVERSATION_SUMMARY_PROMPT;
|
|
40
|
+
exports.DEFAULT_FORMATTING_PROMPT = DEFAULT_FORMATTING_PROMPT;
|
|
41
|
+
exports.DEFAULT_IDENTITY_PROMPT = DEFAULT_IDENTITY_PROMPT;
|
|
30
42
|
exports.DEFAULT_SUMMARY_PROMPT = DEFAULT_SUMMARY_PROMPT;
|
|
31
43
|
exports.DEFAULT_SYSTEM_PROMPT = DEFAULT_SYSTEM_PROMPT;
|
|
32
44
|
exports.DEFAULT_TOOL_GUIDELINE = DEFAULT_TOOL_GUIDELINE;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompts.cjs.js","sources":["../../src/constants/prompts.ts"],"sourcesContent":["export const
|
|
1
|
+
{"version":3,"file":"prompts.cjs.js","sources":["../../src/constants/prompts.ts"],"sourcesContent":["export const DEFAULT_CONVERSATION_SUMMARY_PROMPT =\n \"Summarize this conversation in a concise manner. The summary should capture the main points. Return the summary only, without any additional text. Do not include any introductions or other part of the conversation that doesn't contribute to the summary or form part of the overall conversation as part of the summary.\";\n\nexport const DEFAULT_SUMMARY_PROMPT =\n \"Summarize the following content in a concise manner. The summary should capture the main points. Return the summary only, without any additional text. Do not include any introductions or other part of the content that doesn't contribute to the summary.\";\n\nexport const DEFAULT_IDENTITY_PROMPT = `\nYou are a helpful assistant that answers questions based on provided context from various documents. The context may come from sources such as internal wikis, code repositories, technical documentation, or other structured or unstructured data.\n`;\n\nexport const DEFAULT_FORMATTING_PROMPT = `\nCRITICAL FORMATTING RULES - MUST ALWAYS FOLLOW:\n1. **ALWAYS use proper markdown formatting in ALL responses**\n2. **NEVER output plain URLs** - ALWAYS convert them to clickable markdown links using [description](url) syntax\n3. **For images, ALWAYS use markdown image syntax**: \n4. **For all URLs, ALWAYS format as**: [descriptive text](url) - never just paste the raw URL\n5. Use headings (##, ###), bullet points, numbered lists, and **bold**/*italic* text appropriately\n6. Format code with backticks: \\`inline code\\` or \\`\\`\\`language for code blocks\n7. Structure responses clearly with proper spacing and organization\n`;\n\nexport const DEFAULT_SYSTEM_PROMPT = `\nContent Rules:\n1. Always base your answers on the provided context. Do not make up information.\n2. When relevant, cite or reference the source information provided in the context.\n3. Maintain a professional, friendly, and helpful tone.\n4. Return only the relevant information without any filler or unnecessary details.\n5. If you don't know the answer, admit it and suggest ways to find the information.\n6. **Actively use available tools** to enhance your responses\n7. Adapt your approach based on the specific tools and capabilities available in the current session\n8. When you do not have the information needed to answer, use the tools provided to gather more context before responding.\n`;\n\nexport const DEFAULT_TOOL_GUIDELINE = `\nTOOL USAGE GUIDELINES:\n- Only use tools when explicitly needed to answer the user's question\n- Read tool descriptions carefully before using them\n- If you can answer without tools, do so\n- IMPORTANT: When using tools, always explain why you're using each tool\n- Use tools in logical sequence, not randomly\n- If a tool fails, try an alternative approach before using another tool\n`;\n"],"names":[],"mappings":";;AAAO,MAAM,mCAAA,GACX;AAEK,MAAM,sBAAA,GACX;AAEK,MAAM,uBAAA,GAA0B;AAAA;AAAA;AAIhC,MAAM,yBAAA,GAA4B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWlC,MAAM,qBAAA,GAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAY9B,MAAM,sBAAA,GAAyB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;;;;;;;"}
|
|
@@ -33,7 +33,9 @@ class ChatStore {
|
|
|
33
33
|
role: row.role,
|
|
34
34
|
content: row.content,
|
|
35
35
|
id: row.id,
|
|
36
|
-
metadata: row.metadata
|
|
36
|
+
metadata: row.metadata,
|
|
37
|
+
score: row.score,
|
|
38
|
+
traceId: row.trace_id
|
|
37
39
|
}));
|
|
38
40
|
return chatMessages;
|
|
39
41
|
}
|
|
@@ -44,6 +46,7 @@ class ChatStore {
|
|
|
44
46
|
role: msg.role,
|
|
45
47
|
content: msg.content,
|
|
46
48
|
metadata: msg.metadata,
|
|
49
|
+
trace_id: msg.traceId,
|
|
47
50
|
userRef,
|
|
48
51
|
created_at: this.client.fn.now()
|
|
49
52
|
}));
|
|
@@ -53,7 +56,9 @@ class ChatStore {
|
|
|
53
56
|
await this.messageTable().where({ id: message.id }).update({
|
|
54
57
|
role: message.role,
|
|
55
58
|
content: message.content,
|
|
56
|
-
metadata: message.metadata
|
|
59
|
+
metadata: message.metadata,
|
|
60
|
+
score: message.score,
|
|
61
|
+
trace_id: message.traceId
|
|
57
62
|
});
|
|
58
63
|
}
|
|
59
64
|
async getConversation(conversationId, userRef) {
|
|
@@ -90,6 +95,21 @@ class ChatStore {
|
|
|
90
95
|
}));
|
|
91
96
|
return conversations;
|
|
92
97
|
}
|
|
98
|
+
async getMessageById(messageId) {
|
|
99
|
+
const row = await this.messageTable().where({ id: messageId }).first();
|
|
100
|
+
if (!row) {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
const message = {
|
|
104
|
+
id: row.id,
|
|
105
|
+
role: row.role,
|
|
106
|
+
content: row.content,
|
|
107
|
+
metadata: row.metadata,
|
|
108
|
+
score: row.score,
|
|
109
|
+
traceId: row.trace_id
|
|
110
|
+
};
|
|
111
|
+
return message;
|
|
112
|
+
}
|
|
93
113
|
}
|
|
94
114
|
|
|
95
115
|
exports.ChatStore = ChatStore;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat-store.cjs.js","sources":["../../src/database/chat-store.ts"],"sourcesContent":["import { DatabaseService } from '@backstage/backend-plugin-api';\nimport {\n Message,\n Conversation,\n} from '@sweetoburrito/backstage-plugin-ai-assistant-common';\n\nimport { Knex } from 'knex';\n\nconst MESSAGE_TABLE_NAME = 'message';\nconst CONVERSATION_TABLE_NAME = 'conversation';\n\nexport type ChatStoreOptions = {\n database: DatabaseService;\n};\n\nexport class ChatStore {\n /**\n * Creates an instance of ChatStore.\n * @param client - The Knex client to interact with the PostgreSQL database.\n */\n constructor(private readonly client: Knex) {}\n\n static async fromConfig({ database }: ChatStoreOptions) {\n const client = await database.getClient();\n return new ChatStore(client);\n }\n\n messageTable() {\n return this.client(MESSAGE_TABLE_NAME);\n }\n\n conversationTable() {\n return this.client(CONVERSATION_TABLE_NAME);\n }\n\n async getChatMessages(\n conversationId: string,\n userRef: string,\n limit?: number,\n excludeRoles?: Message['role'][],\n ): Promise<Required<Message>[]> {\n let query = this.messageTable()\n .where({ conversation_id: conversationId, userRef })\n .select('*')\n .orderBy('created_at', 'asc');\n\n if (typeof limit === 'number') {\n query = query.limit(limit).orderBy('created_at', 'desc');\n }\n\n if (excludeRoles && excludeRoles.length > 0) {\n query = query.whereNotIn('role', excludeRoles);\n }\n\n const rows = await query;\n\n const chatMessages: Required<Message>[] = rows.map(row => ({\n role: row.role,\n content: row.content,\n id: row.id,\n metadata: row.metadata,\n }));\n\n return chatMessages;\n }\n\n async addChatMessage(\n messages: Message[],\n userRef: string,\n conversationId: string,\n ): Promise<void> {\n const rows = messages.map(msg => ({\n id: msg.id,\n conversation_id: conversationId,\n role: msg.role,\n content: msg.content,\n metadata: msg.metadata,\n userRef,\n created_at: this.client.fn.now(),\n }));\n\n await this.messageTable().insert(rows);\n }\n\n async updateMessage(message: Required<Message>) {\n await this.messageTable().where({ id: message.id }).update({\n role: message.role,\n content: message.content,\n metadata: message.metadata,\n });\n }\n\n async getConversation(\n conversationId: string,\n userRef: string,\n ): Promise<Conversation> {\n const row = await this.conversationTable()\n .where({ id: conversationId, userRef })\n .first();\n\n if (!row) {\n throw new Error('Conversation not found');\n }\n\n const conversation: Conversation = {\n id: row.id,\n title: row.title,\n userRef: row.userRef,\n };\n\n return conversation;\n }\n\n async createConversation(conversation: Conversation) {\n await this.conversationTable().insert({\n id: conversation.id,\n title: conversation.title,\n userRef: conversation.userRef,\n });\n }\n\n async updateConversation(conversation: Conversation) {\n await this.conversationTable().where({ id: conversation.id }).update({\n title: conversation.title,\n userRef: conversation.userRef,\n });\n }\n\n async getConversations(userRef: string): Promise<Conversation[]> {\n const rows = await this.conversationTable()\n .where({ userRef })\n .select('*')\n .orderBy('created_at', 'desc');\n\n const conversations: Conversation[] = rows.map(row => ({\n id: row.id,\n title: row.title,\n userRef: row.userRef,\n }));\n\n return conversations;\n }\n}\n"],"names":[],"mappings":";;AAQA,MAAM,kBAAA,GAAqB,SAAA;AAC3B,MAAM,uBAAA,GAA0B,cAAA;AAMzB,MAAM,SAAA,CAAU;AAAA;AAAA;AAAA;AAAA;AAAA,EAKrB,YAA6B,MAAA,EAAc;AAAd,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AAAA,EAAe;AAAA,EAE5C,aAAa,UAAA,CAAW,EAAE,QAAA,EAAS,EAAqB;AACtD,IAAA,MAAM,MAAA,GAAS,MAAM,QAAA,CAAS,SAAA,EAAU;AACxC,IAAA,OAAO,IAAI,UAAU,MAAM,CAAA;AAAA,EAC7B;AAAA,EAEA,YAAA,GAAe;AACb,IAAA,OAAO,IAAA,CAAK,OAAO,kBAAkB,CAAA;AAAA,EACvC;AAAA,EAEA,iBAAA,GAAoB;AAClB,IAAA,OAAO,IAAA,CAAK,OAAO,uBAAuB,CAAA;AAAA,EAC5C;AAAA,EAEA,MAAM,eAAA,CACJ,cAAA,EACA,OAAA,EACA,OACA,YAAA,EAC8B;AAC9B,IAAA,IAAI,QAAQ,IAAA,CAAK,YAAA,EAAa,CAC3B,KAAA,CAAM,EAAE,eAAA,EAAiB,cAAA,EAAgB,OAAA,EAAS,EAClD,MAAA,CAAO,GAAG,CAAA,CACV,OAAA,CAAQ,cAAc,KAAK,CAAA;AAE9B,IAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,MAAA,KAAA,GAAQ,MAAM,KAAA,CAAM,KAAK,CAAA,CAAE,OAAA,CAAQ,cAAc,MAAM,CAAA;AAAA,IACzD;AAEA,IAAA,IAAI,YAAA,IAAgB,YAAA,CAAa,MAAA,GAAS,CAAA,EAAG;AAC3C,MAAA,KAAA,GAAQ,KAAA,CAAM,UAAA,CAAW,MAAA,EAAQ,YAAY,CAAA;AAAA,IAC/C;AAEA,IAAA,MAAM,OAAO,MAAM,KAAA;AAEnB,IAAA,MAAM,YAAA,GAAoC,IAAA,CAAK,GAAA,CAAI,CAAA,GAAA,MAAQ;AAAA,MACzD,MAAM,GAAA,CAAI,IAAA;AAAA,MACV,SAAS,GAAA,CAAI,OAAA;AAAA,MACb,IAAI,GAAA,CAAI,EAAA;AAAA,MACR,UAAU,GAAA,CAAI;AAAA,
|
|
1
|
+
{"version":3,"file":"chat-store.cjs.js","sources":["../../src/database/chat-store.ts"],"sourcesContent":["import { DatabaseService } from '@backstage/backend-plugin-api';\nimport {\n Message,\n Conversation,\n} from '@sweetoburrito/backstage-plugin-ai-assistant-common';\n\nimport { Knex } from 'knex';\n\nconst MESSAGE_TABLE_NAME = 'message';\nconst CONVERSATION_TABLE_NAME = 'conversation';\n\nexport type ChatStoreOptions = {\n database: DatabaseService;\n};\n\nexport class ChatStore {\n /**\n * Creates an instance of ChatStore.\n * @param client - The Knex client to interact with the PostgreSQL database.\n */\n constructor(private readonly client: Knex) {}\n\n static async fromConfig({ database }: ChatStoreOptions) {\n const client = await database.getClient();\n return new ChatStore(client);\n }\n\n messageTable() {\n return this.client(MESSAGE_TABLE_NAME);\n }\n\n conversationTable() {\n return this.client(CONVERSATION_TABLE_NAME);\n }\n\n async getChatMessages(\n conversationId: string,\n userRef: string,\n limit?: number,\n excludeRoles?: Message['role'][],\n ): Promise<Required<Message>[]> {\n let query = this.messageTable()\n .where({ conversation_id: conversationId, userRef })\n .select('*')\n .orderBy('created_at', 'asc');\n\n if (typeof limit === 'number') {\n query = query.limit(limit).orderBy('created_at', 'desc');\n }\n\n if (excludeRoles && excludeRoles.length > 0) {\n query = query.whereNotIn('role', excludeRoles);\n }\n\n const rows = await query;\n\n const chatMessages: Required<Message>[] = rows.map(row => ({\n role: row.role,\n content: row.content,\n id: row.id,\n metadata: row.metadata,\n score: row.score,\n traceId: row.trace_id,\n }));\n\n return chatMessages;\n }\n\n async addChatMessage(\n messages: Message[],\n userRef: string,\n conversationId: string,\n ): Promise<void> {\n const rows = messages.map(msg => ({\n id: msg.id,\n conversation_id: conversationId,\n role: msg.role,\n content: msg.content,\n metadata: msg.metadata,\n trace_id: msg.traceId,\n userRef,\n created_at: this.client.fn.now(),\n }));\n\n await this.messageTable().insert(rows);\n }\n\n async updateMessage(message: Required<Message>) {\n await this.messageTable().where({ id: message.id }).update({\n role: message.role,\n content: message.content,\n metadata: message.metadata,\n score: message.score,\n trace_id: message.traceId,\n });\n }\n\n async getConversation(\n conversationId: string,\n userRef: string,\n ): Promise<Conversation> {\n const row = await this.conversationTable()\n .where({ id: conversationId, userRef })\n .first();\n\n if (!row) {\n throw new Error('Conversation not found');\n }\n\n const conversation: Conversation = {\n id: row.id,\n title: row.title,\n userRef: row.userRef,\n };\n\n return conversation;\n }\n\n async createConversation(conversation: Conversation) {\n await this.conversationTable().insert({\n id: conversation.id,\n title: conversation.title,\n userRef: conversation.userRef,\n });\n }\n\n async updateConversation(conversation: Conversation) {\n await this.conversationTable().where({ id: conversation.id }).update({\n title: conversation.title,\n userRef: conversation.userRef,\n });\n }\n\n async getConversations(userRef: string): Promise<Conversation[]> {\n const rows = await this.conversationTable()\n .where({ userRef })\n .select('*')\n .orderBy('created_at', 'desc');\n\n const conversations: Conversation[] = rows.map(row => ({\n id: row.id,\n title: row.title,\n userRef: row.userRef,\n }));\n\n return conversations;\n }\n\n async getMessageById(messageId: string): Promise<Required<Message> | null> {\n const row = await this.messageTable().where({ id: messageId }).first();\n\n if (!row) {\n return null;\n }\n\n const message: Required<Message> = {\n id: row.id,\n role: row.role,\n content: row.content,\n metadata: row.metadata,\n score: row.score,\n traceId: row.trace_id,\n };\n\n return message;\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const MCP_TABLE_NAME = "user_mcp_config";
|
|
4
|
+
class McpStore {
|
|
5
|
+
/**
|
|
6
|
+
* Creates an instance of ChatStore.
|
|
7
|
+
* @param client - The Knex client to interact with the PostgreSQL database.
|
|
8
|
+
*/
|
|
9
|
+
constructor(client) {
|
|
10
|
+
this.client = client;
|
|
11
|
+
}
|
|
12
|
+
static async fromConfig({ database }) {
|
|
13
|
+
const client = await database.getClient();
|
|
14
|
+
return new McpStore(client);
|
|
15
|
+
}
|
|
16
|
+
mcpTable() {
|
|
17
|
+
return this.client(MCP_TABLE_NAME);
|
|
18
|
+
}
|
|
19
|
+
async getUserUserMcpConfigNames(userRef) {
|
|
20
|
+
const rows = await this.mcpTable().where({ userRef }).select("name");
|
|
21
|
+
return rows.map((row) => row.name);
|
|
22
|
+
}
|
|
23
|
+
async getUserMcpConfigs(userRef) {
|
|
24
|
+
const rows = await this.mcpTable().where({ userRef }).select();
|
|
25
|
+
return rows.map((row) => ({
|
|
26
|
+
name: row.name,
|
|
27
|
+
encryptedOptions: row.encryptedOptions
|
|
28
|
+
}));
|
|
29
|
+
}
|
|
30
|
+
async createUserMcpConfig(userRef, name, encryptedOptions) {
|
|
31
|
+
await this.mcpTable().insert({
|
|
32
|
+
userRef,
|
|
33
|
+
name,
|
|
34
|
+
encryptedOptions
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
async updateUserMcpConfig(userRef, name, encryptedOptions) {
|
|
38
|
+
await this.mcpTable().where({ userRef, name }).update({ encryptedOptions });
|
|
39
|
+
}
|
|
40
|
+
async deleteUserMcpConfig(userRef, name) {
|
|
41
|
+
await this.mcpTable().where({ userRef, name }).delete();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
exports.McpStore = McpStore;
|
|
46
|
+
//# sourceMappingURL=mcp-store.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-store.cjs.js","sources":["../../src/database/mcp-store.ts"],"sourcesContent":["import { DatabaseService } from '@backstage/backend-plugin-api';\n\nimport { Knex } from 'knex';\n\nconst MCP_TABLE_NAME = 'user_mcp_config';\n\nexport type McpStoreOptions = {\n database: DatabaseService;\n};\n\nexport class McpStore {\n /**\n * Creates an instance of ChatStore.\n * @param client - The Knex client to interact with the PostgreSQL database.\n */\n constructor(private readonly client: Knex) {}\n\n static async fromConfig({ database }: McpStoreOptions) {\n const client = await database.getClient();\n return new McpStore(client);\n }\n\n mcpTable() {\n return this.client(MCP_TABLE_NAME);\n }\n\n async getUserUserMcpConfigNames(userRef: string): Promise<string[]> {\n const rows = await this.mcpTable().where({ userRef }).select('name');\n return rows.map(row => row.name);\n }\n\n async getUserMcpConfigs(\n userRef: string,\n ): Promise<Array<{ name: string; encryptedOptions: string }>> {\n const rows = await this.mcpTable().where({ userRef }).select();\n return rows.map(row => ({\n name: row.name,\n encryptedOptions: row.encryptedOptions,\n }));\n }\n\n async createUserMcpConfig(\n userRef: string,\n name: string,\n encryptedOptions: string,\n ): Promise<void> {\n await this.mcpTable().insert({\n userRef,\n name,\n encryptedOptions,\n });\n }\n\n async updateUserMcpConfig(\n userRef: string,\n name: string,\n encryptedOptions: string,\n ): Promise<void> {\n await this.mcpTable().where({ userRef, name }).update({ encryptedOptions });\n }\n\n async deleteUserMcpConfig(userRef: string, name: string): Promise<void> {\n await this.mcpTable().where({ userRef, name }).delete();\n }\n}\n"],"names":[],"mappings":";;AAIA,MAAM,cAAA,GAAiB,iBAAA;AAMhB,MAAM,QAAA,CAAS;AAAA;AAAA;AAAA;AAAA;AAAA,EAKpB,YAA6B,MAAA,EAAc;AAAd,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AAAA,EAAe;AAAA,EAE5C,aAAa,UAAA,CAAW,EAAE,QAAA,EAAS,EAAoB;AACrD,IAAA,MAAM,MAAA,GAAS,MAAM,QAAA,CAAS,SAAA,EAAU;AACxC,IAAA,OAAO,IAAI,SAAS,MAAM,CAAA;AAAA,EAC5B;AAAA,EAEA,QAAA,GAAW;AACT,IAAA,OAAO,IAAA,CAAK,OAAO,cAAc,CAAA;AAAA,EACnC;AAAA,EAEA,MAAM,0BAA0B,OAAA,EAAoC;AAClE,IAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,QAAA,EAAS,CAAE,KAAA,CAAM,EAAE,OAAA,EAAS,CAAA,CAAE,MAAA,CAAO,MAAM,CAAA;AACnE,IAAA,OAAO,IAAA,CAAK,GAAA,CAAI,CAAA,GAAA,KAAO,GAAA,CAAI,IAAI,CAAA;AAAA,EACjC;AAAA,EAEA,MAAM,kBACJ,OAAA,EAC4D;AAC5D,IAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,QAAA,EAAS,CAAE,MAAM,EAAE,OAAA,EAAS,CAAA,CAAE,MAAA,EAAO;AAC7D,IAAA,OAAO,IAAA,CAAK,IAAI,CAAA,GAAA,MAAQ;AAAA,MACtB,MAAM,GAAA,CAAI,IAAA;AAAA,MACV,kBAAkB,GAAA,CAAI;AAAA,KACxB,CAAE,CAAA;AAAA,EACJ;AAAA,EAEA,MAAM,mBAAA,CACJ,OAAA,EACA,IAAA,EACA,gBAAA,EACe;AACf,IAAA,MAAM,IAAA,CAAK,QAAA,EAAS,CAAE,MAAA,CAAO;AAAA,MAC3B,OAAA;AAAA,MACA,IAAA;AAAA,MACA;AAAA,KACD,CAAA;AAAA,EACH;AAAA,EAEA,MAAM,mBAAA,CACJ,OAAA,EACA,IAAA,EACA,gBAAA,EACe;AACf,IAAA,MAAM,IAAA,CAAK,QAAA,EAAS,CAAE,KAAA,CAAM,EAAE,OAAA,EAAS,IAAA,EAAM,CAAA,CAAE,MAAA,CAAO,EAAE,gBAAA,EAAkB,CAAA;AAAA,EAC5E;AAAA,EAEA,MAAM,mBAAA,CAAoB,OAAA,EAAiB,IAAA,EAA6B;AACtE,IAAA,MAAM,IAAA,CAAK,UAAS,CAAE,KAAA,CAAM,EAAE,OAAA,EAAS,IAAA,EAAM,CAAA,CAAE,MAAA,EAAO;AAAA,EACxD;AACF;;;;"}
|
package/dist/plugin.cjs.js
CHANGED
|
@@ -10,6 +10,9 @@ var pgVectorStore = require('./database/pg-vector-store.cjs.js');
|
|
|
10
10
|
var pluginSignalsNode = require('@backstage/plugin-signals-node');
|
|
11
11
|
var searchKnowledge = require('./services/tools/searchKnowledge.cjs.js');
|
|
12
12
|
var pluginCatalogNode = require('@backstage/plugin-catalog-node');
|
|
13
|
+
var mcp = require('./services/mcp.cjs.js');
|
|
14
|
+
var callbacks = require('./services/callbacks.cjs.js');
|
|
15
|
+
var summarizer = require('./services/summarizer.cjs.js');
|
|
13
16
|
|
|
14
17
|
const aiAssistantPlugin = backendPluginApi.createBackendPlugin({
|
|
15
18
|
pluginId: "ai-assistant",
|
|
@@ -17,6 +20,7 @@ const aiAssistantPlugin = backendPluginApi.createBackendPlugin({
|
|
|
17
20
|
const ingestors = [];
|
|
18
21
|
const models = [];
|
|
19
22
|
const tools = [];
|
|
23
|
+
const callbacks$1 = [];
|
|
20
24
|
let embeddingsProvider;
|
|
21
25
|
env.registerExtensionPoint(backstagePluginAiAssistantNode.dataIngestorExtensionPoint, {
|
|
22
26
|
registerIngestor: (ingestor) => {
|
|
@@ -52,6 +56,11 @@ const aiAssistantPlugin = backendPluginApi.createBackendPlugin({
|
|
|
52
56
|
tools.push(tool);
|
|
53
57
|
}
|
|
54
58
|
});
|
|
59
|
+
env.registerExtensionPoint(backstagePluginAiAssistantNode.callbackProviderExtensionPoint, {
|
|
60
|
+
register: (callbackProvider) => {
|
|
61
|
+
callbacks$1.push(callbackProvider);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
55
64
|
env.registerInit({
|
|
56
65
|
deps: {
|
|
57
66
|
httpRouter: backendPluginApi.coreServices.httpRouter,
|
|
@@ -67,7 +76,7 @@ const aiAssistantPlugin = backendPluginApi.createBackendPlugin({
|
|
|
67
76
|
auth: backendPluginApi.coreServices.auth
|
|
68
77
|
},
|
|
69
78
|
async init(options) {
|
|
70
|
-
const { httpRouter, database } = options;
|
|
79
|
+
const { httpRouter, database, config } = options;
|
|
71
80
|
const client = await database.getClient();
|
|
72
81
|
await migrations.applyDatabaseMigrations(client);
|
|
73
82
|
const vectorStore = await pgVectorStore.PgVectorStore.fromConfig(options);
|
|
@@ -80,14 +89,28 @@ const aiAssistantPlugin = backendPluginApi.createBackendPlugin({
|
|
|
80
89
|
vectorStore,
|
|
81
90
|
ingestors
|
|
82
91
|
});
|
|
92
|
+
const mcp$1 = await mcp.createMcpService(options);
|
|
83
93
|
const searchKnowledgeTool = searchKnowledge.createSearchKnowledgeTool({ vectorStore });
|
|
84
94
|
tools.push(searchKnowledgeTool);
|
|
95
|
+
const callback = await callbacks.createCallbackService({
|
|
96
|
+
callbacks: callbacks$1
|
|
97
|
+
});
|
|
98
|
+
const summarizer$1 = await summarizer.createSummarizerService({
|
|
99
|
+
config,
|
|
100
|
+
models,
|
|
101
|
+
callback
|
|
102
|
+
});
|
|
85
103
|
const chat$1 = await chat.createChatService({
|
|
86
104
|
...options,
|
|
87
105
|
models,
|
|
88
|
-
tools
|
|
106
|
+
tools,
|
|
107
|
+
mcp: mcp$1,
|
|
108
|
+
callback,
|
|
109
|
+
summarizer: summarizer$1
|
|
89
110
|
});
|
|
90
|
-
httpRouter.use(
|
|
111
|
+
httpRouter.use(
|
|
112
|
+
await index.createRouter({ ...options, chat: chat$1, mcp: mcp$1, summarizer: summarizer$1 })
|
|
113
|
+
);
|
|
91
114
|
dataIngestionPipeline.start();
|
|
92
115
|
}
|
|
93
116
|
});
|
package/dist/plugin.cjs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.cjs.js","sources":["../src/plugin.ts"],"sourcesContent":["import {\n coreServices,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport { createRouter } from './services/router';\nimport {\n dataIngestorExtensionPoint,\n EmbeddingsProvider,\n embeddingsProviderExtensionPoint,\n Ingestor,\n Model,\n modelProviderExtensionPoint,\n Tool,\n toolExtensionPoint,\n} from '@sweetoburrito/backstage-plugin-ai-assistant-node';\nimport { createDataIngestionPipeline } from './services/ingestor';\nimport { createChatService } from './services/chat';\nimport { applyDatabaseMigrations } from './database/migrations';\nimport { PgVectorStore } from './database';\nimport { signalsServiceRef } from '@backstage/plugin-signals-node';\nimport { createSearchKnowledgeTool } from './services/tools/searchKnowledge';\nimport { catalogServiceRef } from '@backstage/plugin-catalog-node';\n
|
|
1
|
+
{"version":3,"file":"plugin.cjs.js","sources":["../src/plugin.ts"],"sourcesContent":["import {\n coreServices,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport { createRouter } from './services/router';\nimport {\n dataIngestorExtensionPoint,\n EmbeddingsProvider,\n embeddingsProviderExtensionPoint,\n Ingestor,\n Model,\n modelProviderExtensionPoint,\n Tool,\n toolExtensionPoint,\n callbackProviderExtensionPoint,\n CallbackProvider,\n} from '@sweetoburrito/backstage-plugin-ai-assistant-node';\nimport { createDataIngestionPipeline } from './services/ingestor';\nimport { createChatService } from './services/chat';\nimport { applyDatabaseMigrations } from './database/migrations';\nimport { PgVectorStore } from './database';\nimport { signalsServiceRef } from '@backstage/plugin-signals-node';\nimport { createSearchKnowledgeTool } from './services/tools/searchKnowledge';\nimport { catalogServiceRef } from '@backstage/plugin-catalog-node';\nimport { createMcpService } from './services/mcp';\nimport { createCallbackService } from './services/callbacks';\nimport { createSummarizerService } from './services/summarizer';\n/**\n * aiAssistantPlugin backend plugin\n *\n * @public\n */\n\nexport const aiAssistantPlugin = createBackendPlugin({\n pluginId: 'ai-assistant',\n register(env) {\n const ingestors: Ingestor[] = [];\n const models: Model[] = [];\n const tools: Tool[] = [];\n const callbacks: CallbackProvider[] = [];\n\n let embeddingsProvider: EmbeddingsProvider;\n\n env.registerExtensionPoint(dataIngestorExtensionPoint, {\n registerIngestor: ingestor => {\n const existingIngestor = ingestors.find(i => i.id === ingestor.id);\n if (existingIngestor) {\n throw new Error(\n `Ingestor with id ${ingestor.id} is already registered.`,\n );\n }\n ingestors.push(ingestor);\n },\n });\n\n env.registerExtensionPoint(embeddingsProviderExtensionPoint, {\n register: provider => {\n embeddingsProvider = provider;\n },\n });\n\n env.registerExtensionPoint(modelProviderExtensionPoint, {\n register: model => {\n const existingModel = models.find(m => m.id === model.id);\n if (existingModel) {\n throw new Error(`Model with id ${model.id} is already registered.`);\n }\n models.push(model);\n },\n });\n\n env.registerExtensionPoint(toolExtensionPoint, {\n register: tool => {\n const existingTool = tools.find(t => t.name === tool.name);\n if (existingTool) {\n throw new Error(`Tool with name ${tool.name} is already registered.`);\n }\n tools.push(tool);\n },\n });\n\n env.registerExtensionPoint(callbackProviderExtensionPoint, {\n register: callbackProvider => {\n callbacks.push(callbackProvider);\n },\n });\n\n env.registerInit({\n deps: {\n httpRouter: coreServices.httpRouter,\n database: coreServices.database,\n logger: coreServices.logger,\n config: coreServices.rootConfig,\n scheduler: coreServices.scheduler,\n httpAuth: coreServices.httpAuth,\n userInfo: coreServices.userInfo,\n signals: signalsServiceRef,\n catalog: catalogServiceRef,\n cache: coreServices.cache,\n auth: coreServices.auth,\n },\n\n async init(options) {\n const { httpRouter, database, config } = options;\n\n const client = await database.getClient();\n\n await applyDatabaseMigrations(client);\n\n const vectorStore = await PgVectorStore.fromConfig(options);\n\n if (!embeddingsProvider) {\n throw new Error('No Embeddings Provider was registered.');\n }\n\n vectorStore.connectEmbeddings(await embeddingsProvider.getEmbeddings());\n\n const dataIngestionPipeline = createDataIngestionPipeline({\n ...options,\n vectorStore,\n ingestors,\n });\n\n const mcp = await createMcpService(options);\n\n const searchKnowledgeTool = createSearchKnowledgeTool({ vectorStore });\n tools.push(searchKnowledgeTool);\n\n const callback = await createCallbackService({\n callbacks,\n });\n\n const summarizer = await createSummarizerService({\n config,\n models,\n callback,\n });\n\n const chat = await createChatService({\n ...options,\n models,\n tools,\n mcp,\n callback,\n summarizer,\n });\n\n httpRouter.use(\n await createRouter({ ...options, chat, mcp, summarizer }),\n );\n dataIngestionPipeline.start();\n },\n });\n },\n});\n"],"names":["createBackendPlugin","callbacks","dataIngestorExtensionPoint","embeddingsProviderExtensionPoint","modelProviderExtensionPoint","toolExtensionPoint","callbackProviderExtensionPoint","coreServices","signalsServiceRef","catalogServiceRef","applyDatabaseMigrations","PgVectorStore","createDataIngestionPipeline","mcp","createMcpService","createSearchKnowledgeTool","createCallbackService","summarizer","createSummarizerService","chat","createChatService","createRouter"],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const createCallbackService = async ({
|
|
4
|
+
callbacks
|
|
5
|
+
}) => {
|
|
6
|
+
const getChainCallbacks = async (options) => {
|
|
7
|
+
const callbackHandlers = [];
|
|
8
|
+
for (const { chainCallback } of callbacks) {
|
|
9
|
+
if (!chainCallback) {
|
|
10
|
+
continue;
|
|
11
|
+
}
|
|
12
|
+
const callbackHandler = await chainCallback(options);
|
|
13
|
+
callbackHandlers.push(callbackHandler);
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
callbacks: callbackHandlers
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
const getChainMetadata = async (options) => {
|
|
20
|
+
const metadata = {};
|
|
21
|
+
for (const { chainMetadataCallback } of callbacks) {
|
|
22
|
+
if (!chainMetadataCallback) {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
const callbackData = await chainMetadataCallback(options);
|
|
26
|
+
Object.assign(metadata, callbackData.metadata);
|
|
27
|
+
}
|
|
28
|
+
return { metadata };
|
|
29
|
+
};
|
|
30
|
+
const handleScoreCallbacks = async ({
|
|
31
|
+
name,
|
|
32
|
+
message
|
|
33
|
+
}) => {
|
|
34
|
+
callbacks.forEach(async ({ scoreCallback }) => {
|
|
35
|
+
if (!scoreCallback) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
scoreCallback({ name, message });
|
|
39
|
+
});
|
|
40
|
+
};
|
|
41
|
+
return {
|
|
42
|
+
getChainCallbacks,
|
|
43
|
+
getChainMetadata,
|
|
44
|
+
handleScoreCallbacks
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
exports.createCallbackService = createCallbackService;
|
|
49
|
+
//# sourceMappingURL=callbacks.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"callbacks.cjs.js","sources":["../../src/services/callbacks.ts"],"sourcesContent":["import {\n CallbackProvider,\n ChainMetadata,\n ChainCallbackOptions,\n ChainCallback,\n} from '@sweetoburrito/backstage-plugin-ai-assistant-node';\n\nexport type CallbackService = {\n getChainCallbacks: (options: ChainCallbackOptions) => Promise<{\n callbacks: ReturnType<ChainCallback>[];\n }>;\n\n getChainMetadata: (\n options: ChainCallbackOptions,\n ) => Promise<{ metadata: ChainMetadata }>;\n\n handleScoreCallbacks: NonNullable<CallbackProvider['scoreCallback']>;\n};\n\nexport type CreateCallbackServiceOptions = {\n callbacks: CallbackProvider[];\n};\n\nexport const createCallbackService = async ({\n callbacks,\n}: CreateCallbackServiceOptions): Promise<CallbackService> => {\n const getChainCallbacks: CallbackService['getChainCallbacks'] =\n async options => {\n const callbackHandlers: ReturnType<ChainCallback>[] = [];\n\n for (const { chainCallback } of callbacks) {\n if (!chainCallback) {\n continue;\n }\n\n const callbackHandler = await chainCallback(options);\n\n callbackHandlers.push(callbackHandler);\n }\n\n return {\n callbacks: callbackHandlers,\n };\n };\n\n const getChainMetadata: CallbackService['getChainMetadata'] =\n async options => {\n const metadata: ChainMetadata = {};\n\n for (const { chainMetadataCallback } of callbacks) {\n if (!chainMetadataCallback) {\n continue;\n }\n\n const callbackData = await chainMetadataCallback(options);\n\n Object.assign(metadata, callbackData.metadata);\n }\n\n return { metadata };\n };\n\n const handleScoreCallbacks: CallbackService['handleScoreCallbacks'] = async ({\n name,\n message,\n }) => {\n callbacks.forEach(async ({ scoreCallback }) => {\n if (!scoreCallback) {\n return;\n }\n\n scoreCallback({ name, message });\n });\n };\n\n return {\n getChainCallbacks,\n getChainMetadata,\n handleScoreCallbacks,\n };\n};\n"],"names":[],"mappings":";;AAuBO,MAAM,wBAAwB,OAAO;AAAA,EAC1C;AACF,CAAA,KAA8D;AAC5D,EAAA,MAAM,iBAAA,GACJ,OAAM,OAAA,KAAW;AACf,IAAA,MAAM,mBAAgD,EAAC;AAEvD,IAAA,KAAA,MAAW,EAAE,aAAA,EAAc,IAAK,SAAA,EAAW;AACzC,MAAA,IAAI,CAAC,aAAA,EAAe;AAClB,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,eAAA,GAAkB,MAAM,aAAA,CAAc,OAAO,CAAA;AAEnD,MAAA,gBAAA,CAAiB,KAAK,eAAe,CAAA;AAAA,IACvC;AAEA,IAAA,OAAO;AAAA,MACL,SAAA,EAAW;AAAA,KACb;AAAA,EACF,CAAA;AAEF,EAAA,MAAM,gBAAA,GACJ,OAAM,OAAA,KAAW;AACf,IAAA,MAAM,WAA0B,EAAC;AAEjC,IAAA,KAAA,MAAW,EAAE,qBAAA,EAAsB,IAAK,SAAA,EAAW;AACjD,MAAA,IAAI,CAAC,qBAAA,EAAuB;AAC1B,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,YAAA,GAAe,MAAM,qBAAA,CAAsB,OAAO,CAAA;AAExD,MAAA,MAAA,CAAO,MAAA,CAAO,QAAA,EAAU,YAAA,CAAa,QAAQ,CAAA;AAAA,IAC/C;AAEA,IAAA,OAAO,EAAE,QAAA,EAAS;AAAA,EACpB,CAAA;AAEF,EAAA,MAAM,uBAAgE,OAAO;AAAA,IAC3E,IAAA;AAAA,IACA;AAAA,GACF,KAAM;AACJ,IAAA,SAAA,CAAU,OAAA,CAAQ,OAAO,EAAE,aAAA,EAAc,KAAM;AAC7C,MAAA,IAAI,CAAC,aAAA,EAAe;AAClB,QAAA;AAAA,MACF;AAEA,MAAA,aAAA,CAAc,EAAE,IAAA,EAAM,OAAA,EAAS,CAAA;AAAA,IACjC,CAAC,CAAA;AAAA,EACH,CAAA;AAEA,EAAA,OAAO;AAAA,IACL,iBAAA;AAAA,IACA,gBAAA;AAAA,IACA;AAAA,GACF;AACF;;;;"}
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
var chatStore = require('../database/chat-store.cjs.js');
|
|
4
4
|
var prompts = require('../constants/prompts.cjs.js');
|
|
5
|
+
var backstagePluginAiAssistantNode = require('@sweetoburrito/backstage-plugin-ai-assistant-node');
|
|
5
6
|
var tools = require('@langchain/core/tools');
|
|
6
7
|
var prebuilt = require('@langchain/langgraph/prebuilt');
|
|
7
8
|
var prompts$1 = require('@langchain/core/prompts');
|
|
8
|
-
var summarizer = require('./summarizer.cjs.js');
|
|
9
9
|
var uuid = require('uuid');
|
|
10
10
|
|
|
11
11
|
const createChatService = async ({
|
|
@@ -17,14 +17,24 @@ const createChatService = async ({
|
|
|
17
17
|
config,
|
|
18
18
|
catalog,
|
|
19
19
|
cache,
|
|
20
|
-
auth
|
|
20
|
+
auth,
|
|
21
|
+
mcp,
|
|
22
|
+
userInfo,
|
|
23
|
+
callback,
|
|
24
|
+
summarizer
|
|
21
25
|
}) => {
|
|
22
26
|
logger.info(`Available models: ${models.map((m) => m.id).join(", ")}`);
|
|
23
|
-
|
|
27
|
+
logger.info(`Available tools: ${tools$1.map((t) => t.name).join(", ")}`);
|
|
28
|
+
const identityPrompt = config.getOptionalString("aiAssistant.prompt.identity") || prompts.DEFAULT_IDENTITY_PROMPT;
|
|
29
|
+
const formattingPrompt = config.getOptionalString("aiAssistant.prompt.formatting") || prompts.DEFAULT_FORMATTING_PROMPT;
|
|
30
|
+
const contentPrompt = config.getOptionalString("aiAssistant.prompt.content") || prompts.DEFAULT_SYSTEM_PROMPT;
|
|
31
|
+
const combinedBasePrompt = `${identityPrompt}
|
|
32
|
+
|
|
33
|
+
${formattingPrompt}
|
|
34
|
+
|
|
35
|
+
${contentPrompt}`;
|
|
24
36
|
const toolGuideline = config.getOptionalString("aiAssistant.prompt.toolGuideline") || prompts.DEFAULT_TOOL_GUIDELINE;
|
|
25
37
|
const chatStore$1 = await chatStore.ChatStore.fromConfig({ database });
|
|
26
|
-
const summarizer$1 = await summarizer.createSummarizerService({ config, models });
|
|
27
|
-
const agentTools = tools$1.map((tool) => new tools.DynamicStructuredTool(tool));
|
|
28
38
|
const systemPromptTemplate = prompts$1.SystemMessagePromptTemplate.fromTemplate(`
|
|
29
39
|
PURPOSE:
|
|
30
40
|
{basePrompt}
|
|
@@ -73,7 +83,10 @@ const createChatService = async ({
|
|
|
73
83
|
chatStore$1.addChatMessage(messages, userRef, conversationId);
|
|
74
84
|
return;
|
|
75
85
|
}
|
|
76
|
-
const summary = await summarizer
|
|
86
|
+
const summary = await summarizer.summarizeConversation({
|
|
87
|
+
messages: recentMessages,
|
|
88
|
+
length: "25 characters"
|
|
89
|
+
});
|
|
77
90
|
conversation.title = summary;
|
|
78
91
|
chatStore$1.updateConversation(conversation);
|
|
79
92
|
chatStore$1.addChatMessage(messages, userRef, conversationId);
|
|
@@ -91,12 +104,13 @@ const createChatService = async ({
|
|
|
91
104
|
messages,
|
|
92
105
|
modelId,
|
|
93
106
|
stream = true,
|
|
94
|
-
|
|
107
|
+
userCredentials
|
|
95
108
|
}) => {
|
|
96
109
|
const model = models.find((m) => m.id === modelId)?.chatModel;
|
|
97
110
|
if (!model) {
|
|
98
111
|
throw new Error(`Model with id ${modelId} not found`);
|
|
99
112
|
}
|
|
113
|
+
const { userEntityRef } = await userInfo.getUserInfo(userCredentials);
|
|
100
114
|
const streamFn = async () => {
|
|
101
115
|
const recentConversationMessages = await chatStore$1.getChatMessages(
|
|
102
116
|
conversationId,
|
|
@@ -105,15 +119,18 @@ const createChatService = async ({
|
|
|
105
119
|
["tool"]
|
|
106
120
|
);
|
|
107
121
|
const credentials = await auth.getOwnServiceCredentials();
|
|
108
|
-
const user = await getUser(cache, userEntityRef, credentials, catalog);
|
|
122
|
+
const user = await backstagePluginAiAssistantNode.getUser(cache, userEntityRef, credentials, catalog);
|
|
123
|
+
const mcpTools = await mcp.getTools(userCredentials);
|
|
124
|
+
const agentTools = tools$1.map((tool) => new tools.DynamicStructuredTool(tool)).concat(mcpTools.map((tool) => new tools.DynamicStructuredTool(tool)));
|
|
125
|
+
const messagesWithoutSystem = messages.filter((m) => m.role !== "system");
|
|
109
126
|
addMessages(
|
|
110
|
-
|
|
127
|
+
messagesWithoutSystem,
|
|
111
128
|
userEntityRef,
|
|
112
129
|
conversationId,
|
|
113
130
|
recentConversationMessages
|
|
114
131
|
);
|
|
115
132
|
const systemPrompt = await systemPromptTemplate.formatMessages({
|
|
116
|
-
basePrompt:
|
|
133
|
+
basePrompt: combinedBasePrompt,
|
|
117
134
|
toolGuideline,
|
|
118
135
|
toolList: agentTools.map((tool) => `- ${tool.name}: ${tool.description}`).join("\n"),
|
|
119
136
|
context: `none`,
|
|
@@ -124,22 +141,45 @@ const createChatService = async ({
|
|
|
124
141
|
tools: agentTools,
|
|
125
142
|
prompt: systemPrompt[0].text
|
|
126
143
|
});
|
|
144
|
+
const { callbacks } = await callback.getChainCallbacks({
|
|
145
|
+
conversationId,
|
|
146
|
+
userId: userEntityRef,
|
|
147
|
+
modelId
|
|
148
|
+
});
|
|
149
|
+
const { metadata: promptMetadata } = await callback.getChainMetadata({
|
|
150
|
+
conversationId,
|
|
151
|
+
userId: userEntityRef,
|
|
152
|
+
modelId
|
|
153
|
+
});
|
|
154
|
+
const traceId = uuid.v4();
|
|
127
155
|
const promptStream = await agent.stream(
|
|
128
156
|
{
|
|
129
157
|
messages: [...recentConversationMessages, ...messages]
|
|
130
158
|
},
|
|
131
|
-
{
|
|
159
|
+
{
|
|
160
|
+
streamMode: ["values"],
|
|
161
|
+
runName: "ai-assistant-chat",
|
|
162
|
+
runId: traceId,
|
|
163
|
+
metadata: promptMetadata,
|
|
164
|
+
callbacks
|
|
165
|
+
}
|
|
132
166
|
);
|
|
133
167
|
const responseMessages = [];
|
|
134
168
|
for await (const [, chunk] of promptStream) {
|
|
135
169
|
const { messages: promptMessages } = chunk;
|
|
136
|
-
const newMessages = promptMessages.filter(
|
|
170
|
+
const newMessages = promptMessages.filter(
|
|
171
|
+
(m) => responseMessages.findIndex(
|
|
172
|
+
(rm) => m.id === rm.metadata.langGraphId
|
|
173
|
+
) === -1
|
|
174
|
+
).filter(
|
|
137
175
|
(m) => recentConversationMessages.findIndex((rm) => rm.id === m.id) === -1
|
|
138
176
|
).filter((m) => m.getType() !== "human").map((m) => {
|
|
139
|
-
const id =
|
|
177
|
+
const id = uuid.v4();
|
|
140
178
|
const role = m.getType();
|
|
141
179
|
const content = typeof m.content === "string" ? m.content : JSON.stringify(m.content);
|
|
142
|
-
const metadata = {
|
|
180
|
+
const metadata = {
|
|
181
|
+
langGraphId: m.id ?? ""
|
|
182
|
+
};
|
|
143
183
|
if (role === "ai") {
|
|
144
184
|
const aiMessage = m;
|
|
145
185
|
metadata.toolCalls = aiMessage.tool_calls || [];
|
|
@@ -154,14 +194,18 @@ const createChatService = async ({
|
|
|
154
194
|
id,
|
|
155
195
|
role,
|
|
156
196
|
content,
|
|
157
|
-
metadata
|
|
197
|
+
metadata,
|
|
198
|
+
score: 0,
|
|
199
|
+
traceId
|
|
158
200
|
};
|
|
159
201
|
});
|
|
160
202
|
for await (const m of newMessages) {
|
|
161
|
-
const
|
|
203
|
+
const words = m.content.split(" ");
|
|
204
|
+
const chunkSize = 5;
|
|
162
205
|
let messageBuilder = "";
|
|
163
|
-
for
|
|
164
|
-
|
|
206
|
+
for (let i = 0; i < words.length; i += chunkSize) {
|
|
207
|
+
const wordChunk = words.slice(i, i + chunkSize).join(" ");
|
|
208
|
+
messageBuilder = messageBuilder.concat(wordChunk).concat(" ");
|
|
165
209
|
m.content = messageBuilder;
|
|
166
210
|
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
167
211
|
signals.publish({
|
|
@@ -176,9 +220,6 @@ const createChatService = async ({
|
|
|
176
220
|
}
|
|
177
221
|
responseMessages.push(...newMessages);
|
|
178
222
|
}
|
|
179
|
-
responseMessages.forEach((m) => {
|
|
180
|
-
m.id = uuid.v4();
|
|
181
|
-
});
|
|
182
223
|
addMessages(responseMessages, userEntityRef, conversationId, [
|
|
183
224
|
...recentConversationMessages,
|
|
184
225
|
...messages
|
|
@@ -205,25 +246,30 @@ const createChatService = async ({
|
|
|
205
246
|
const conversations = await chatStore$1.getConversations(userEntityRef);
|
|
206
247
|
return conversations;
|
|
207
248
|
};
|
|
249
|
+
const scoreMessage = async (messageId, score) => {
|
|
250
|
+
const message = await chatStore$1.getMessageById(messageId);
|
|
251
|
+
if (!message) {
|
|
252
|
+
throw new Error(`Message with id ${messageId} not found`);
|
|
253
|
+
}
|
|
254
|
+
const updatedMessage = {
|
|
255
|
+
...message,
|
|
256
|
+
score
|
|
257
|
+
};
|
|
258
|
+
chatStore$1.updateMessage(updatedMessage);
|
|
259
|
+
callback.handleScoreCallbacks({
|
|
260
|
+
name: "helpfulness",
|
|
261
|
+
message: updatedMessage
|
|
262
|
+
});
|
|
263
|
+
};
|
|
208
264
|
return {
|
|
209
265
|
prompt,
|
|
210
266
|
getAvailableModels,
|
|
211
267
|
getConversation,
|
|
212
268
|
getConversations,
|
|
213
|
-
addMessages
|
|
269
|
+
addMessages,
|
|
270
|
+
scoreMessage
|
|
214
271
|
};
|
|
215
272
|
};
|
|
216
|
-
async function getUser(cache, userEntityRef, credentials, catalog) {
|
|
217
|
-
const cached = await cache.get(userEntityRef);
|
|
218
|
-
if (cached) {
|
|
219
|
-
return JSON.parse(String(cached));
|
|
220
|
-
}
|
|
221
|
-
const user = await catalog.getEntityByRef(userEntityRef, {
|
|
222
|
-
credentials
|
|
223
|
-
});
|
|
224
|
-
await cache.set(userEntityRef, JSON.stringify(user));
|
|
225
|
-
return user;
|
|
226
|
-
}
|
|
227
273
|
|
|
228
274
|
exports.createChatService = createChatService;
|
|
229
275
|
//# sourceMappingURL=chat.cjs.js.map
|