@sweetoburrito/backstage-plugin-ai-assistant-backend 0.13.0 → 0.14.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/dist/plugin.cjs.js +25 -41
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/services/agent/helpers/message-parser.cjs.js +31 -0
- package/dist/services/agent/helpers/message-parser.cjs.js.map +1 -0
- package/dist/services/agent/helpers/tool-filter.cjs.js +13 -0
- package/dist/services/agent/helpers/tool-filter.cjs.js.map +1 -0
- package/dist/services/agent/index.cjs.js +140 -0
- package/dist/services/agent/index.cjs.js.map +1 -0
- package/dist/services/callbacks.cjs.js +23 -9
- package/dist/services/callbacks.cjs.js.map +1 -1
- package/dist/services/chat.cjs.js +90 -253
- package/dist/services/chat.cjs.js.map +1 -1
- package/dist/services/conversation.cjs.js +133 -0
- package/dist/services/conversation.cjs.js.map +1 -0
- package/dist/services/mcp/index.cjs.js +37 -24
- package/dist/services/mcp/index.cjs.js.map +1 -1
- package/dist/services/model.cjs.js +45 -0
- package/dist/services/model.cjs.js.map +1 -0
- package/dist/services/router/agent.cjs.js +68 -0
- package/dist/services/router/agent.cjs.js.map +1 -0
- package/dist/services/router/chat.cjs.js +8 -13
- 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/models.cjs.js +2 -2
- package/dist/services/router/models.cjs.js.map +1 -1
- package/dist/services/router/settings/index.cjs.js +0 -3
- package/dist/services/router/settings/index.cjs.js.map +1 -1
- package/dist/services/router/summary.cjs.js +5 -3
- package/dist/services/router/summary.cjs.js.map +1 -1
- package/dist/services/router/tools.cjs.js +21 -0
- package/dist/services/router/tools.cjs.js.map +1 -0
- package/dist/services/summarizer.cjs.js +47 -28
- package/dist/services/summarizer.cjs.js.map +1 -1
- package/dist/services/tools.cjs.js +65 -0
- package/dist/services/tools.cjs.js.map +1 -0
- package/dist/services/user-settings.cjs.js +15 -0
- package/dist/services/user-settings.cjs.js.map +1 -1
- package/package.json +5 -3
|
@@ -1,295 +1,132 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
3
|
+
var pluginCatalogNode = require('@backstage/plugin-catalog-node');
|
|
4
|
+
var pluginSignalsNode = require('@backstage/plugin-signals-node');
|
|
5
5
|
var backstagePluginAiAssistantNode = require('@sweetoburrito/backstage-plugin-ai-assistant-node');
|
|
6
|
-
var tools = require('@langchain/core/tools');
|
|
7
|
-
var prebuilt = require('@langchain/langgraph/prebuilt');
|
|
8
|
-
var prompts$1 = require('@langchain/core/prompts');
|
|
9
6
|
var uuid = require('uuid');
|
|
7
|
+
var backendPluginApi = require('@backstage/backend-plugin-api');
|
|
8
|
+
var conversation = require('./conversation.cjs.js');
|
|
9
|
+
var index = require('./agent/index.cjs.js');
|
|
10
|
+
var prompts = require('@langchain/core/prompts');
|
|
10
11
|
|
|
11
12
|
const createChatService = async ({
|
|
12
|
-
models,
|
|
13
|
-
tools: tools$1,
|
|
14
|
-
logger,
|
|
15
|
-
database,
|
|
16
13
|
signals,
|
|
17
|
-
config,
|
|
18
14
|
catalog,
|
|
19
15
|
cache,
|
|
20
16
|
auth,
|
|
21
|
-
mcp,
|
|
22
17
|
userInfo,
|
|
23
|
-
|
|
24
|
-
|
|
18
|
+
conversation,
|
|
19
|
+
agent
|
|
25
20
|
}) => {
|
|
26
|
-
|
|
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}`;
|
|
36
|
-
const toolGuideline = config.getOptionalString("aiAssistant.prompt.toolGuideline") || prompts.DEFAULT_TOOL_GUIDELINE;
|
|
37
|
-
const chatStore$1 = await chatStore.ChatStore.fromConfig({ database });
|
|
38
|
-
const systemPromptTemplate = prompts$1.SystemMessagePromptTemplate.fromTemplate(`
|
|
39
|
-
PURPOSE:
|
|
40
|
-
{basePrompt}
|
|
41
|
-
|
|
42
|
-
TOOL USAGE GUIDELINES:
|
|
43
|
-
{toolGuideline}
|
|
44
|
-
|
|
45
|
-
Available tools:
|
|
46
|
-
{toolList}
|
|
47
|
-
|
|
21
|
+
const contextPromptTemplate = prompts.SystemMessagePromptTemplate.fromTemplate(`
|
|
48
22
|
Calling User:
|
|
49
|
-
{user}
|
|
50
|
-
|
|
51
|
-
Context:
|
|
52
|
-
{context}`);
|
|
53
|
-
const addMessages = async (messages, userRef, conversationId, recentConversationMessages) => {
|
|
54
|
-
const recentMessages = recentConversationMessages || await chatStore$1.getChatMessages(conversationId, userRef, 5, ["tool"]);
|
|
55
|
-
const conversationSize = (recentMessages?.length ?? 0) + messages.length;
|
|
56
|
-
if (recentMessages.length === 0) {
|
|
57
|
-
const conversation2 = {
|
|
58
|
-
id: conversationId,
|
|
59
|
-
title: "New Conversation",
|
|
60
|
-
userRef
|
|
61
|
-
};
|
|
62
|
-
chatStore$1.createConversation(conversation2);
|
|
63
|
-
chatStore$1.addChatMessage(messages, userRef, conversationId);
|
|
64
|
-
signals.publish({
|
|
65
|
-
channel: `ai-assistant.chat.conversation-details-update`,
|
|
66
|
-
message: { conversation: conversation2 },
|
|
67
|
-
recipients: {
|
|
68
|
-
type: "user",
|
|
69
|
-
entityRef: userRef
|
|
70
|
-
}
|
|
71
|
-
});
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
if (conversationSize < 5) {
|
|
75
|
-
chatStore$1.addChatMessage(messages, userRef, conversationId);
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
const conversation = await chatStore$1.getConversation(
|
|
79
|
-
conversationId,
|
|
80
|
-
userRef
|
|
81
|
-
);
|
|
82
|
-
if (conversation.title !== "New Conversation") {
|
|
83
|
-
chatStore$1.addChatMessage(messages, userRef, conversationId);
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
const summary = await summarizer.summarizeConversation({
|
|
87
|
-
messages: recentMessages,
|
|
88
|
-
length: "25 characters"
|
|
89
|
-
});
|
|
90
|
-
conversation.title = summary;
|
|
91
|
-
chatStore$1.updateConversation(conversation);
|
|
92
|
-
chatStore$1.addChatMessage(messages, userRef, conversationId);
|
|
93
|
-
signals.publish({
|
|
94
|
-
channel: `ai-assistant.chat.conversation-details-update`,
|
|
95
|
-
message: { conversation },
|
|
96
|
-
recipients: {
|
|
97
|
-
type: "user",
|
|
98
|
-
entityRef: userRef
|
|
99
|
-
}
|
|
100
|
-
});
|
|
101
|
-
};
|
|
23
|
+
{user}`);
|
|
102
24
|
const prompt = async ({
|
|
103
25
|
conversationId,
|
|
104
26
|
messages,
|
|
105
|
-
modelId,
|
|
106
27
|
stream = true,
|
|
107
|
-
|
|
108
|
-
tools: enabledTools
|
|
28
|
+
credentials,
|
|
29
|
+
tools: enabledTools,
|
|
30
|
+
modelId
|
|
109
31
|
}) => {
|
|
110
|
-
const model = models.find((m) => m.id === modelId)?.chatModel;
|
|
111
|
-
if (!model) {
|
|
112
|
-
throw new Error(`Model with id ${modelId} not found`);
|
|
113
|
-
}
|
|
114
|
-
const { userEntityRef } = await userInfo.getUserInfo(userCredentials);
|
|
115
32
|
const streamFn = async () => {
|
|
116
|
-
const
|
|
33
|
+
const { userEntityRef } = await userInfo.getUserInfo(credentials);
|
|
34
|
+
const recentConversationMessages = await conversation.getRecentConversationMessages({
|
|
117
35
|
conversationId,
|
|
118
36
|
userEntityRef,
|
|
119
|
-
10,
|
|
120
|
-
["tool"]
|
|
121
|
-
);
|
|
122
|
-
const
|
|
123
|
-
const user = await backstagePluginAiAssistantNode.getUser(cache, userEntityRef, credentials, catalog);
|
|
124
|
-
const mcpTools = await mcp.getTools(userCredentials);
|
|
125
|
-
const agentTools = [...tools$1, ...mcpTools].filter((tool) => {
|
|
126
|
-
if (enabledTools === void 0) return true;
|
|
127
|
-
if (enabledTools.length === 0) return false;
|
|
128
|
-
const enabled = enabledTools.find(
|
|
129
|
-
(enabledTool) => enabledTool.name === tool.name && enabledTool.provider === tool.provider
|
|
130
|
-
);
|
|
131
|
-
return !!enabled;
|
|
132
|
-
}).map((tool) => new tools.DynamicStructuredTool(tool));
|
|
37
|
+
limit: 10,
|
|
38
|
+
excludeRoles: ["tool"]
|
|
39
|
+
});
|
|
40
|
+
const user = await backstagePluginAiAssistantNode.getUser(cache, userEntityRef, catalog, auth);
|
|
133
41
|
const messagesWithoutSystem = messages.filter((m) => m.role !== "system");
|
|
134
|
-
addMessages(
|
|
42
|
+
conversation.addMessages(
|
|
135
43
|
messagesWithoutSystem,
|
|
136
44
|
userEntityRef,
|
|
137
45
|
conversationId,
|
|
138
46
|
recentConversationMessages
|
|
139
47
|
);
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
toolGuideline,
|
|
143
|
-
toolList: agentTools.map((tool) => `- ${tool.name}: ${tool.description}`).join("\n"),
|
|
144
|
-
context: `none`,
|
|
48
|
+
const traceId = uuid.v4();
|
|
49
|
+
const context = await contextPromptTemplate.formatMessages({
|
|
145
50
|
user
|
|
146
51
|
});
|
|
147
|
-
const agent = prebuilt.createReactAgent({
|
|
148
|
-
llm: model,
|
|
149
|
-
tools: agentTools,
|
|
150
|
-
prompt: systemPrompt[0].text
|
|
151
|
-
});
|
|
152
|
-
const { callbacks } = await callback.getChainCallbacks({
|
|
153
|
-
conversationId,
|
|
154
|
-
userId: userEntityRef,
|
|
155
|
-
modelId
|
|
156
|
-
});
|
|
157
|
-
const { metadata: promptMetadata } = await callback.getChainMetadata({
|
|
158
|
-
conversationId,
|
|
159
|
-
userId: userEntityRef,
|
|
160
|
-
modelId
|
|
161
|
-
});
|
|
162
|
-
const traceId = uuid.v4();
|
|
163
|
-
const promptStream = await agent.stream(
|
|
164
|
-
{
|
|
165
|
-
messages: [...recentConversationMessages, ...messages]
|
|
166
|
-
},
|
|
167
|
-
{
|
|
168
|
-
streamMode: ["values"],
|
|
169
|
-
runName: "ai-assistant-chat",
|
|
170
|
-
runId: traceId,
|
|
171
|
-
metadata: promptMetadata,
|
|
172
|
-
callbacks
|
|
173
|
-
}
|
|
174
|
-
);
|
|
175
52
|
const responseMessages = [];
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
message: { messages: [m] },
|
|
222
|
-
recipients: {
|
|
223
|
-
type: "user",
|
|
224
|
-
entityRef: userEntityRef
|
|
53
|
+
const conversationMessages = [...recentConversationMessages, ...messages];
|
|
54
|
+
agent.stream({
|
|
55
|
+
credentials,
|
|
56
|
+
messages: conversationMessages,
|
|
57
|
+
tools: enabledTools,
|
|
58
|
+
modelId,
|
|
59
|
+
metadata: {
|
|
60
|
+
conversationId,
|
|
61
|
+
userId: userEntityRef,
|
|
62
|
+
runName: "ai-assistant-chat",
|
|
63
|
+
runId: traceId
|
|
64
|
+
},
|
|
65
|
+
context: context[0].text,
|
|
66
|
+
onStreamChunk: async (chunkMessages) => {
|
|
67
|
+
const newMessages = chunkMessages.filter(
|
|
68
|
+
(m) => conversationMessages.findIndex((cm) => cm.id === m.id) === -1
|
|
69
|
+
);
|
|
70
|
+
console.log("newMessages: ", newMessages);
|
|
71
|
+
if (newMessages.length !== 0) {
|
|
72
|
+
console.log("newMessages in if: ", newMessages);
|
|
73
|
+
conversation.addMessages(
|
|
74
|
+
newMessages,
|
|
75
|
+
userEntityRef,
|
|
76
|
+
conversationId,
|
|
77
|
+
conversationMessages
|
|
78
|
+
);
|
|
79
|
+
conversationMessages.push(...newMessages);
|
|
80
|
+
responseMessages.push(...newMessages);
|
|
81
|
+
for await (const m of newMessages) {
|
|
82
|
+
const words = m.content.split(" ");
|
|
83
|
+
const chunkSize = 5;
|
|
84
|
+
let messageBuilder = "";
|
|
85
|
+
for (let i = 0; i < words.length; i += chunkSize) {
|
|
86
|
+
const wordChunk = words.slice(i, i + chunkSize).join(" ");
|
|
87
|
+
messageBuilder = messageBuilder.concat(wordChunk).concat(" ");
|
|
88
|
+
m.content = messageBuilder;
|
|
89
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
90
|
+
signals.publish({
|
|
91
|
+
channel: `ai-assistant.chat.conversation-stream:${conversationId}`,
|
|
92
|
+
message: { messages: [m] },
|
|
93
|
+
recipients: {
|
|
94
|
+
type: "user",
|
|
95
|
+
entityRef: userEntityRef
|
|
96
|
+
}
|
|
97
|
+
});
|
|
225
98
|
}
|
|
226
|
-
}
|
|
99
|
+
}
|
|
227
100
|
}
|
|
228
101
|
}
|
|
229
|
-
|
|
230
|
-
}
|
|
231
|
-
addMessages(responseMessages, userEntityRef, conversationId, [
|
|
232
|
-
...recentConversationMessages,
|
|
233
|
-
...messages
|
|
234
|
-
]);
|
|
102
|
+
});
|
|
235
103
|
return responseMessages;
|
|
236
104
|
};
|
|
237
|
-
|
|
238
|
-
return stream ? [] : result;
|
|
239
|
-
};
|
|
240
|
-
const getAvailableModels = async () => {
|
|
241
|
-
return models.map((x) => x.id);
|
|
242
|
-
};
|
|
243
|
-
const getConversation = async (options) => {
|
|
244
|
-
const { conversationId, userEntityRef } = options;
|
|
245
|
-
const conversation = await chatStore$1.getChatMessages(
|
|
246
|
-
conversationId,
|
|
247
|
-
userEntityRef
|
|
248
|
-
);
|
|
249
|
-
return conversation;
|
|
250
|
-
};
|
|
251
|
-
const getConversations = async ({
|
|
252
|
-
userEntityRef
|
|
253
|
-
}) => {
|
|
254
|
-
const conversations = await chatStore$1.getConversations(userEntityRef);
|
|
255
|
-
return conversations;
|
|
256
|
-
};
|
|
257
|
-
const scoreMessage = async (messageId, score) => {
|
|
258
|
-
const message = await chatStore$1.getMessageById(messageId);
|
|
259
|
-
if (!message) {
|
|
260
|
-
throw new Error(`Message with id ${messageId} not found`);
|
|
261
|
-
}
|
|
262
|
-
const updatedMessage = {
|
|
263
|
-
...message,
|
|
264
|
-
score
|
|
265
|
-
};
|
|
266
|
-
chatStore$1.updateMessage(updatedMessage);
|
|
267
|
-
callback.handleScoreCallbacks({
|
|
268
|
-
name: "helpfulness",
|
|
269
|
-
message: updatedMessage
|
|
270
|
-
});
|
|
271
|
-
};
|
|
272
|
-
const getAvailableTools = async ({
|
|
273
|
-
credentials
|
|
274
|
-
}) => {
|
|
275
|
-
const mcpTools = await mcp.getTools(credentials);
|
|
276
|
-
const availableTools = tools$1.concat(mcpTools).map((tool) => ({
|
|
277
|
-
name: tool.name,
|
|
278
|
-
provider: tool.provider,
|
|
279
|
-
description: tool.description
|
|
280
|
-
}));
|
|
281
|
-
return availableTools;
|
|
105
|
+
return stream ? await streamFn() : [];
|
|
282
106
|
};
|
|
283
107
|
return {
|
|
284
|
-
prompt
|
|
285
|
-
getAvailableModels,
|
|
286
|
-
getConversation,
|
|
287
|
-
getConversations,
|
|
288
|
-
addMessages,
|
|
289
|
-
scoreMessage,
|
|
290
|
-
getAvailableTools
|
|
108
|
+
prompt
|
|
291
109
|
};
|
|
292
110
|
};
|
|
111
|
+
const chatServiceRef = backendPluginApi.createServiceRef({
|
|
112
|
+
id: "ai-assistant.chat-service",
|
|
113
|
+
defaultFactory: async (service) => backendPluginApi.createServiceFactory({
|
|
114
|
+
service,
|
|
115
|
+
deps: {
|
|
116
|
+
cache: backendPluginApi.coreServices.cache,
|
|
117
|
+
auth: backendPluginApi.coreServices.auth,
|
|
118
|
+
userInfo: backendPluginApi.coreServices.userInfo,
|
|
119
|
+
signals: pluginSignalsNode.signalsServiceRef,
|
|
120
|
+
catalog: pluginCatalogNode.catalogServiceRef,
|
|
121
|
+
conversation: conversation.conversationServiceRef,
|
|
122
|
+
agent: index.agentServiceRef
|
|
123
|
+
},
|
|
124
|
+
factory: async (options) => {
|
|
125
|
+
return createChatService(options);
|
|
126
|
+
}
|
|
127
|
+
})
|
|
128
|
+
});
|
|
293
129
|
|
|
130
|
+
exports.chatServiceRef = chatServiceRef;
|
|
294
131
|
exports.createChatService = createChatService;
|
|
295
132
|
//# sourceMappingURL=chat.cjs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat.cjs.js","sources":["../../src/services/chat.ts"],"sourcesContent":["import { CatalogService } from '@backstage/plugin-catalog-node';\nimport {\n LoggerService,\n RootConfigService,\n DatabaseService,\n AuthService,\n} from '@backstage/backend-plugin-api';\nimport { ChatStore } from '../database/chat-store';\nimport {\n Conversation,\n Message,\n JsonObject,\n Tool,\n UserTool,\n EnabledTool,\n} from '@sweetoburrito/backstage-plugin-ai-assistant-common';\nimport { SignalsService } from '@backstage/plugin-signals-node';\nimport {\n DEFAULT_FORMATTING_PROMPT,\n DEFAULT_IDENTITY_PROMPT,\n DEFAULT_SYSTEM_PROMPT,\n DEFAULT_TOOL_GUIDELINE,\n} from '../constants/prompts';\nimport {\n Model,\n getUser,\n} from '@sweetoburrito/backstage-plugin-ai-assistant-node';\nimport { DynamicStructuredTool } from '@langchain/core/tools';\nimport { createReactAgent } from '@langchain/langgraph/prebuilt';\nimport { SystemMessagePromptTemplate } from '@langchain/core/prompts';\nimport { SummarizerService } from './summarizer';\nimport { v4 as uuid } from 'uuid';\nimport type {\n BackstageCredentials,\n CacheService,\n UserInfoService,\n} from '@backstage/backend-plugin-api';\nimport { AIMessage, ToolMessage } from '@langchain/core/messages';\nimport { McpService } from './mcp';\nimport { CallbackService } from './callbacks';\n\nexport type ChatServiceOptions = {\n models: Model[];\n tools: Tool[];\n logger: LoggerService;\n config: RootConfigService;\n database: DatabaseService;\n signals: SignalsService;\n catalog: CatalogService;\n cache: CacheService;\n auth: AuthService;\n mcp: McpService;\n userInfo: UserInfoService;\n callback: CallbackService;\n summarizer: SummarizerService;\n};\n\ntype PromptOptions = {\n modelId: string;\n messages: Message[];\n conversationId: string;\n stream?: boolean;\n userCredentials: BackstageCredentials;\n tools?: EnabledTool[];\n};\n\ntype GetConversationOptions = {\n conversationId: string;\n userEntityRef: string;\n};\n\ntype GetConversationsOptions = {\n userEntityRef: string;\n};\n\n// Helper type for messages with required fields except traceId which remains optional\ntype MessageWithRequiredFields = Required<Omit<Message, 'traceId'>> &\n Pick<Message, 'traceId'>;\n\nexport type ChatService = {\n prompt: (options: PromptOptions) => Promise<MessageWithRequiredFields[]>;\n getAvailableModels: () => Promise<string[]>;\n getConversation: (\n options: GetConversationOptions,\n ) => Promise<MessageWithRequiredFields[]>;\n getConversations: (\n options: GetConversationsOptions,\n ) => Promise<Conversation[]>;\n addMessages: (\n messages: Message[],\n userRef: string,\n conversationId: string,\n recentConversationMessages?: Message[],\n ) => Promise<void>;\n scoreMessage: (messageId: string, score: number) => Promise<void>;\n getAvailableTools: (options: {\n credentials: BackstageCredentials;\n }) => Promise<UserTool[]>;\n};\n\nexport const createChatService = async ({\n models,\n tools,\n logger,\n database,\n signals,\n config,\n catalog,\n cache,\n auth,\n mcp,\n userInfo,\n callback,\n summarizer,\n}: ChatServiceOptions): Promise<ChatService> => {\n logger.info(`Available models: ${models.map(m => m.id).join(', ')}`);\n logger.info(`Available tools: ${tools.map(t => t.name).join(', ')}`);\n\n const identityPrompt =\n config.getOptionalString('aiAssistant.prompt.identity') ||\n DEFAULT_IDENTITY_PROMPT;\n\n const formattingPrompt =\n config.getOptionalString('aiAssistant.prompt.formatting') ||\n DEFAULT_FORMATTING_PROMPT;\n\n const contentPrompt =\n config.getOptionalString('aiAssistant.prompt.content') ||\n DEFAULT_SYSTEM_PROMPT;\n\n const combinedBasePrompt = `${identityPrompt}\\n\\n${formattingPrompt}\\n\\n${contentPrompt}`;\n\n const toolGuideline =\n config.getOptionalString('aiAssistant.prompt.toolGuideline') ||\n DEFAULT_TOOL_GUIDELINE;\n\n const chatStore = await ChatStore.fromConfig({ database });\n\n const systemPromptTemplate = SystemMessagePromptTemplate.fromTemplate(`\n PURPOSE:\n {basePrompt}\n\n TOOL USAGE GUIDELINES:\n {toolGuideline}\n\n Available tools:\n {toolList}\n\n Calling User:\n {user}\n\n Context:\n {context}`);\n\n const addMessages: ChatService['addMessages'] = async (\n messages,\n userRef,\n conversationId,\n recentConversationMessages,\n ) => {\n // If we have recentConversationMessages, use them; otherwise, fetch the last 5 messages\n const recentMessages =\n recentConversationMessages ||\n (await chatStore.getChatMessages(conversationId, userRef, 5, ['tool']));\n\n const conversationSize = (recentMessages?.length ?? 0) + messages.length;\n\n if (recentMessages.length === 0) {\n const conversation: Conversation = {\n id: conversationId,\n title: 'New Conversation',\n userRef,\n };\n chatStore.createConversation(conversation);\n chatStore.addChatMessage(messages, userRef, conversationId);\n\n signals.publish({\n channel: `ai-assistant.chat.conversation-details-update`,\n message: { conversation },\n recipients: {\n type: 'user',\n entityRef: userRef,\n },\n });\n return;\n }\n\n if (conversationSize < 5) {\n chatStore.addChatMessage(messages, userRef, conversationId);\n return;\n }\n\n const conversation = await chatStore.getConversation(\n conversationId,\n userRef,\n );\n\n if (conversation.title !== 'New Conversation') {\n chatStore.addChatMessage(messages, userRef, conversationId);\n return;\n }\n\n const summary = await summarizer.summarizeConversation({\n messages: recentMessages,\n length: '25 characters',\n });\n\n conversation.title = summary;\n\n chatStore.updateConversation(conversation);\n chatStore.addChatMessage(messages, userRef, conversationId);\n\n signals.publish({\n channel: `ai-assistant.chat.conversation-details-update`,\n message: { conversation },\n recipients: {\n type: 'user',\n entityRef: userRef,\n },\n });\n };\n\n const prompt: ChatService['prompt'] = async ({\n conversationId,\n messages,\n modelId,\n stream = true,\n userCredentials,\n tools: enabledTools,\n }: PromptOptions) => {\n const model = models.find(m => m.id === modelId)?.chatModel;\n\n if (!model) {\n throw new Error(`Model with id ${modelId} not found`);\n }\n\n const { userEntityRef } = await userInfo.getUserInfo(userCredentials);\n\n const streamFn = async () => {\n const recentConversationMessages = await chatStore.getChatMessages(\n conversationId,\n userEntityRef,\n 10,\n ['tool'],\n );\n\n const credentials = await auth.getOwnServiceCredentials();\n const user = await getUser(cache, userEntityRef, credentials, catalog);\n\n const mcpTools = await mcp.getTools(userCredentials);\n\n const agentTools = [...tools, ...mcpTools]\n .filter(tool => {\n // If tools parameter is undefined, allow all tools\n if (enabledTools === undefined) return true;\n\n // If empty array, no tools should be enabled\n if (enabledTools.length === 0) return false;\n // Otherwise, only allow tools that are in the enabled list\n const enabled = enabledTools.find(\n enabledTool =>\n enabledTool.name === tool.name &&\n enabledTool.provider === tool.provider,\n );\n return !!enabled;\n })\n .map(tool => new DynamicStructuredTool(tool));\n\n const messagesWithoutSystem = messages.filter(m => m.role !== 'system');\n\n addMessages(\n messagesWithoutSystem,\n userEntityRef,\n conversationId,\n recentConversationMessages,\n );\n\n const systemPrompt = await systemPromptTemplate.formatMessages({\n basePrompt: combinedBasePrompt,\n toolGuideline,\n toolList: agentTools\n .map(tool => `- ${tool.name}: ${tool.description}`)\n .join('\\n'),\n context: `none`,\n user,\n });\n\n const agent = createReactAgent({\n llm: model,\n tools: agentTools,\n prompt: systemPrompt[0].text,\n });\n\n const { callbacks } = await callback.getChainCallbacks({\n conversationId,\n userId: userEntityRef,\n modelId,\n });\n\n const { metadata: promptMetadata } = await callback.getChainMetadata({\n conversationId,\n userId: userEntityRef,\n modelId,\n });\n\n const traceId = uuid();\n\n const promptStream = await agent.stream(\n {\n messages: [...recentConversationMessages, ...messages],\n },\n {\n streamMode: ['values'],\n runName: 'ai-assistant-chat',\n runId: traceId,\n metadata: promptMetadata,\n callbacks,\n },\n );\n\n const responseMessages: MessageWithRequiredFields[] = [];\n\n for await (const [, chunk] of promptStream) {\n const { messages: promptMessages } = chunk;\n\n const newMessages: MessageWithRequiredFields[] = promptMessages\n .filter(\n m =>\n responseMessages.findIndex(\n rm => m.id === rm.metadata.langGraphId,\n ) === -1,\n )\n .filter(\n m =>\n recentConversationMessages.findIndex(rm => rm.id === m.id) === -1,\n )\n .filter(m => m.getType() !== 'human')\n .map(m => {\n const id = uuid();\n const role = m.getType();\n const content =\n typeof m.content === 'string'\n ? m.content\n : JSON.stringify(m.content);\n\n const metadata: JsonObject = {\n langGraphId: m.id ?? '',\n };\n\n if (role === 'ai') {\n const aiMessage = m as AIMessage;\n metadata.toolCalls = aiMessage.tool_calls || [];\n metadata.finishReason =\n aiMessage.response_metadata.finish_reason || undefined;\n metadata.modelName =\n aiMessage.response_metadata.model_name || undefined;\n }\n\n if (role === 'tool') {\n const toolMessage = m as ToolMessage;\n metadata.name = toolMessage.name || '';\n }\n\n return {\n id,\n role,\n content,\n metadata,\n score: 0,\n traceId: traceId,\n };\n });\n\n // Simulate streaming until langchain messages error is better understood\n for await (const m of newMessages) {\n const words = m.content.split(' ');\n const chunkSize = 5; // Send 5 words at a time\n let messageBuilder = '';\n\n for (let i = 0; i < words.length; i += chunkSize) {\n const wordChunk = words.slice(i, i + chunkSize).join(' ');\n messageBuilder = messageBuilder.concat(wordChunk).concat(' ');\n m.content = messageBuilder;\n\n await new Promise(resolve => setTimeout(resolve, 50));\n\n signals.publish({\n channel: `ai-assistant.chat.conversation-stream:${conversationId}`,\n message: { messages: [m] },\n recipients: {\n type: 'user',\n entityRef: userEntityRef,\n },\n });\n }\n }\n\n responseMessages.push(...newMessages);\n }\n\n addMessages(responseMessages, userEntityRef, conversationId, [\n ...recentConversationMessages,\n ...messages,\n ]);\n\n return responseMessages;\n };\n\n const result = streamFn();\n\n return stream ? [] : result;\n };\n\n const getAvailableModels: ChatService['getAvailableModels'] = async () => {\n return models.map(x => x.id);\n };\n\n const getConversation: ChatService['getConversation'] = async (\n options: GetConversationOptions,\n ) => {\n const { conversationId, userEntityRef } = options;\n\n const conversation = await chatStore.getChatMessages(\n conversationId,\n userEntityRef,\n );\n\n return conversation;\n };\n\n const getConversations: ChatService['getConversations'] = async ({\n userEntityRef,\n }: GetConversationsOptions) => {\n const conversations = await chatStore.getConversations(userEntityRef);\n\n return conversations;\n };\n\n const scoreMessage: ChatService['scoreMessage'] = async (\n messageId: string,\n score: number,\n ) => {\n const message = await chatStore.getMessageById(messageId);\n\n if (!message) {\n throw new Error(`Message with id ${messageId} not found`);\n }\n\n const updatedMessage: Required<Message> = {\n ...message,\n score,\n };\n\n chatStore.updateMessage(updatedMessage);\n\n callback.handleScoreCallbacks({\n name: 'helpfulness',\n message: updatedMessage,\n });\n };\n\n const getAvailableTools: ChatService['getAvailableTools'] = async ({\n credentials,\n }) => {\n const mcpTools = await mcp.getTools(credentials);\n\n const availableTools: UserTool[] = tools.concat(mcpTools).map(tool => ({\n name: tool.name,\n provider: tool.provider,\n description: tool.description,\n }));\n\n return availableTools;\n };\n\n return {\n prompt,\n getAvailableModels,\n getConversation,\n getConversations,\n addMessages,\n scoreMessage,\n getAvailableTools,\n };\n};\n"],"names":["tools","DEFAULT_IDENTITY_PROMPT","DEFAULT_FORMATTING_PROMPT","DEFAULT_SYSTEM_PROMPT","DEFAULT_TOOL_GUIDELINE","chatStore","ChatStore","SystemMessagePromptTemplate","conversation","getUser","DynamicStructuredTool","createReactAgent","uuid"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"chat.cjs.js","sources":["../../src/services/chat.ts"],"sourcesContent":["import {\n CatalogService,\n catalogServiceRef,\n} from '@backstage/plugin-catalog-node';\nimport {\n SignalsService,\n signalsServiceRef,\n} from '@backstage/plugin-signals-node';\n\nimport {\n Message,\n EnabledTool,\n} from '@sweetoburrito/backstage-plugin-ai-assistant-common';\n\nimport { getUser } from '@sweetoburrito/backstage-plugin-ai-assistant-node';\nimport { v4 as uuid } from 'uuid';\nimport type {\n BackstageCredentials,\n CacheService,\n UserInfoService,\n AuthService,\n ServiceRef,\n} from '@backstage/backend-plugin-api';\nimport {\n coreServices,\n createServiceFactory,\n createServiceRef,\n} from '@backstage/backend-plugin-api';\nimport { ConversationService, conversationServiceRef } from './conversation';\nimport { agentServiceRef, AgentService } from './agent';\nimport { SystemMessagePromptTemplate } from '@langchain/core/prompts';\n\nexport type ChatServiceOptions = {\n signals: SignalsService;\n catalog: CatalogService;\n cache: CacheService;\n auth: AuthService;\n userInfo: UserInfoService;\n conversation: ConversationService;\n agent: AgentService;\n};\n\ntype PromptOptions = {\n credentials: BackstageCredentials;\n messages: Message[];\n conversationId: string;\n stream?: boolean;\n tools?: EnabledTool[];\n modelId?: string;\n};\n\nexport type ChatService = {\n prompt: (options: PromptOptions) => Promise<Message[]>;\n};\n\nexport const createChatService = async ({\n signals,\n catalog,\n cache,\n auth,\n userInfo,\n conversation,\n agent,\n}: ChatServiceOptions): Promise<ChatService> => {\n const contextPromptTemplate = SystemMessagePromptTemplate.fromTemplate(`\n Calling User:\n {user}`);\n\n const prompt: ChatService['prompt'] = async ({\n conversationId,\n messages,\n stream = true,\n credentials,\n tools: enabledTools,\n modelId,\n }: PromptOptions) => {\n const streamFn = async () => {\n const { userEntityRef } = await userInfo.getUserInfo(credentials);\n const recentConversationMessages =\n await conversation.getRecentConversationMessages({\n conversationId,\n userEntityRef,\n limit: 10,\n excludeRoles: ['tool'],\n });\n\n const user = await getUser(cache, userEntityRef, catalog, auth);\n\n const messagesWithoutSystem = messages.filter(m => m.role !== 'system');\n\n conversation.addMessages(\n messagesWithoutSystem,\n userEntityRef,\n conversationId,\n recentConversationMessages,\n );\n\n const traceId = uuid();\n\n const context = await contextPromptTemplate.formatMessages({\n user,\n });\n\n const responseMessages: Message[] = [];\n\n const conversationMessages = [...recentConversationMessages, ...messages];\n\n agent.stream({\n credentials,\n messages: conversationMessages,\n tools: enabledTools,\n modelId,\n metadata: {\n conversationId,\n userId: userEntityRef,\n runName: 'ai-assistant-chat',\n runId: traceId,\n },\n context: context[0].text,\n onStreamChunk: async chunkMessages => {\n const newMessages: Message[] = chunkMessages.filter(\n m => conversationMessages.findIndex(cm => cm.id === m.id) === -1,\n );\n\n console.log('newMessages: ', newMessages);\n\n if (newMessages.length !== 0) {\n console.log('newMessages in if: ', newMessages);\n\n conversation.addMessages(\n newMessages,\n userEntityRef,\n conversationId,\n conversationMessages,\n );\n\n conversationMessages.push(...newMessages);\n responseMessages.push(...newMessages);\n\n // Simulate streaming until langchain messages error is better understood\n for await (const m of newMessages) {\n const words = m.content.split(' ');\n const chunkSize = 5; // Send 5 words at a time\n let messageBuilder = '';\n\n for (let i = 0; i < words.length; i += chunkSize) {\n const wordChunk = words.slice(i, i + chunkSize).join(' ');\n messageBuilder = messageBuilder.concat(wordChunk).concat(' ');\n m.content = messageBuilder;\n\n await new Promise(resolve => setTimeout(resolve, 50));\n\n signals.publish({\n channel: `ai-assistant.chat.conversation-stream:${conversationId}`,\n message: { messages: [m] },\n recipients: {\n type: 'user',\n entityRef: userEntityRef,\n },\n });\n }\n }\n }\n },\n });\n\n return responseMessages;\n };\n\n return stream ? await streamFn() : [];\n };\n\n return {\n prompt,\n };\n};\n\nexport const chatServiceRef: ServiceRef<ChatService, 'plugin', 'singleton'> =\n createServiceRef<ChatService>({\n id: 'ai-assistant.chat-service',\n defaultFactory: async service =>\n createServiceFactory({\n service,\n deps: {\n cache: coreServices.cache,\n auth: coreServices.auth,\n userInfo: coreServices.userInfo,\n signals: signalsServiceRef,\n catalog: catalogServiceRef,\n conversation: conversationServiceRef,\n agent: agentServiceRef,\n },\n factory: async options => {\n return createChatService(options);\n },\n }),\n });\n"],"names":["SystemMessagePromptTemplate","getUser","uuid","createServiceRef","createServiceFactory","coreServices","signalsServiceRef","catalogServiceRef","conversationServiceRef","agentServiceRef"],"mappings":"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"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var backendPluginApi = require('@backstage/backend-plugin-api');
|
|
4
|
+
var chatStore = require('../database/chat-store.cjs.js');
|
|
5
|
+
var callbacks = require('./callbacks.cjs.js');
|
|
6
|
+
var pluginSignalsNode = require('@backstage/plugin-signals-node');
|
|
7
|
+
var summarizer = require('./summarizer.cjs.js');
|
|
8
|
+
|
|
9
|
+
const createConversationService = async ({
|
|
10
|
+
database,
|
|
11
|
+
callback,
|
|
12
|
+
signals,
|
|
13
|
+
summarizer
|
|
14
|
+
}) => {
|
|
15
|
+
const chatStore$1 = await chatStore.ChatStore.fromConfig({ database });
|
|
16
|
+
const getConversation = async (options) => {
|
|
17
|
+
const { conversationId, userEntityRef } = options;
|
|
18
|
+
const conversation = await chatStore$1.getChatMessages(
|
|
19
|
+
conversationId,
|
|
20
|
+
userEntityRef
|
|
21
|
+
);
|
|
22
|
+
return conversation;
|
|
23
|
+
};
|
|
24
|
+
const getConversations = async ({
|
|
25
|
+
userEntityRef
|
|
26
|
+
}) => {
|
|
27
|
+
const conversations = await chatStore$1.getConversations(userEntityRef);
|
|
28
|
+
return conversations;
|
|
29
|
+
};
|
|
30
|
+
const scoreMessage = async (messageId, score) => {
|
|
31
|
+
const message = await chatStore$1.getMessageById(messageId);
|
|
32
|
+
if (!message) {
|
|
33
|
+
throw new Error(`Message with id ${messageId} not found`);
|
|
34
|
+
}
|
|
35
|
+
const updatedMessage = {
|
|
36
|
+
...message,
|
|
37
|
+
score
|
|
38
|
+
};
|
|
39
|
+
chatStore$1.updateMessage(updatedMessage);
|
|
40
|
+
callback.handleScoreCallbacks({
|
|
41
|
+
name: "helpfulness",
|
|
42
|
+
message: updatedMessage
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
const getRecentConversationMessages = async ({ conversationId, userEntityRef, excludeRoles, limit }) => {
|
|
46
|
+
const recentConversationMessages = await chatStore$1.getChatMessages(
|
|
47
|
+
conversationId,
|
|
48
|
+
userEntityRef,
|
|
49
|
+
limit,
|
|
50
|
+
excludeRoles
|
|
51
|
+
);
|
|
52
|
+
return recentConversationMessages;
|
|
53
|
+
};
|
|
54
|
+
const addMessages = async (messages, userRef, conversationId, recentConversationMessages) => {
|
|
55
|
+
const recentMessages = recentConversationMessages || await getRecentConversationMessages({
|
|
56
|
+
conversationId,
|
|
57
|
+
userEntityRef: userRef,
|
|
58
|
+
limit: 5,
|
|
59
|
+
excludeRoles: ["tool"]
|
|
60
|
+
});
|
|
61
|
+
const conversationSize = (recentMessages?.length ?? 0) + messages.length;
|
|
62
|
+
if (recentMessages.length === 0) {
|
|
63
|
+
const conversation2 = {
|
|
64
|
+
id: conversationId,
|
|
65
|
+
title: "New Conversation",
|
|
66
|
+
userRef
|
|
67
|
+
};
|
|
68
|
+
chatStore$1.createConversation(conversation2);
|
|
69
|
+
chatStore$1.addChatMessage(messages, userRef, conversationId);
|
|
70
|
+
signals.publish({
|
|
71
|
+
channel: `ai-assistant.chat.conversation-details-update`,
|
|
72
|
+
message: { conversation: conversation2 },
|
|
73
|
+
recipients: {
|
|
74
|
+
type: "user",
|
|
75
|
+
entityRef: userRef
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
if (conversationSize < 5) {
|
|
81
|
+
chatStore$1.addChatMessage(messages, userRef, conversationId);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const conversation = await chatStore$1.getConversation(
|
|
85
|
+
conversationId,
|
|
86
|
+
userRef
|
|
87
|
+
);
|
|
88
|
+
if (conversation.title !== "New Conversation") {
|
|
89
|
+
chatStore$1.addChatMessage(messages, userRef, conversationId);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
const summary = await summarizer.summarizeConversation({
|
|
93
|
+
messages: recentMessages,
|
|
94
|
+
length: "25 characters"
|
|
95
|
+
});
|
|
96
|
+
conversation.title = summary;
|
|
97
|
+
chatStore$1.updateConversation(conversation);
|
|
98
|
+
chatStore$1.addChatMessage(messages, userRef, conversationId);
|
|
99
|
+
signals.publish({
|
|
100
|
+
channel: `ai-assistant.chat.conversation-details-update`,
|
|
101
|
+
message: { conversation },
|
|
102
|
+
recipients: {
|
|
103
|
+
type: "user",
|
|
104
|
+
entityRef: userRef
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
};
|
|
108
|
+
return {
|
|
109
|
+
getConversation,
|
|
110
|
+
getConversations,
|
|
111
|
+
addMessages,
|
|
112
|
+
scoreMessage,
|
|
113
|
+
getRecentConversationMessages
|
|
114
|
+
};
|
|
115
|
+
};
|
|
116
|
+
const conversationServiceRef = backendPluginApi.createServiceRef({
|
|
117
|
+
id: "ai-assistant.conversation-service",
|
|
118
|
+
defaultFactory: async (service) => backendPluginApi.createServiceFactory({
|
|
119
|
+
service,
|
|
120
|
+
deps: {
|
|
121
|
+
database: backendPluginApi.coreServices.database,
|
|
122
|
+
callback: callbacks.callbackServiceRef,
|
|
123
|
+
signals: pluginSignalsNode.signalsServiceRef,
|
|
124
|
+
summarizer: summarizer.summarizerServiceRef
|
|
125
|
+
},
|
|
126
|
+
factory: async (options) => {
|
|
127
|
+
return createConversationService(options);
|
|
128
|
+
}
|
|
129
|
+
})
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
exports.conversationServiceRef = conversationServiceRef;
|
|
133
|
+
//# sourceMappingURL=conversation.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conversation.cjs.js","sources":["../../src/services/conversation.ts"],"sourcesContent":["import {\n coreServices,\n createServiceFactory,\n createServiceRef,\n DatabaseService,\n ServiceRef,\n} from '@backstage/backend-plugin-api';\n\nimport { ChatStore } from '../database/chat-store';\nimport {\n Conversation,\n Message,\n} from '@sweetoburrito/backstage-plugin-ai-assistant-common';\nimport { CallbackService, callbackServiceRef } from './callbacks';\n\nimport {\n SignalsService,\n signalsServiceRef,\n} from '@backstage/plugin-signals-node';\nimport { SummarizerService, summarizerServiceRef } from './summarizer';\n\nexport type ConversationService = {\n getConversation: (options: {\n conversationId: string;\n userEntityRef: string;\n }) => Promise<Message[]>;\n getConversations: (options: {\n userEntityRef: string;\n }) => Promise<Conversation[]>;\n addMessages: (\n messages: Message[],\n userRef: string,\n conversationId: string,\n recentConversationMessages?: Message[],\n ) => Promise<void>;\n scoreMessage: (messageId: string, score: number) => Promise<void>;\n getRecentConversationMessages: (options: {\n conversationId: string;\n userEntityRef: string;\n limit?: number;\n excludeRoles?: Message['role'][];\n }) => Promise<Message[]>;\n};\n\nexport type CreateConversationServiceOptions = {\n database: DatabaseService;\n callback: CallbackService;\n signals: SignalsService;\n summarizer: SummarizerService;\n};\n\nconst createConversationService = async ({\n database,\n callback,\n signals,\n summarizer,\n}: CreateConversationServiceOptions): Promise<ConversationService> => {\n const chatStore = await ChatStore.fromConfig({ database });\n\n const getConversation: ConversationService['getConversation'] =\n async options => {\n const { conversationId, userEntityRef } = options;\n\n const conversation = await chatStore.getChatMessages(\n conversationId,\n userEntityRef,\n );\n\n return conversation;\n };\n\n const getConversations: ConversationService['getConversations'] = async ({\n userEntityRef,\n }) => {\n const conversations = await chatStore.getConversations(userEntityRef);\n\n return conversations;\n };\n\n const scoreMessage: ConversationService['scoreMessage'] = async (\n messageId: string,\n score: number,\n ) => {\n const message = await chatStore.getMessageById(messageId);\n\n if (!message) {\n throw new Error(`Message with id ${messageId} not found`);\n }\n\n const updatedMessage: Required<Message> = {\n ...message,\n score,\n };\n\n chatStore.updateMessage(updatedMessage);\n\n callback.handleScoreCallbacks({\n name: 'helpfulness',\n message: updatedMessage,\n });\n };\n\n const getRecentConversationMessages: ConversationService['getRecentConversationMessages'] =\n async ({ conversationId, userEntityRef, excludeRoles, limit }) => {\n const recentConversationMessages = await chatStore.getChatMessages(\n conversationId,\n userEntityRef,\n limit,\n excludeRoles,\n );\n\n return recentConversationMessages;\n };\n\n const addMessages: ConversationService['addMessages'] = async (\n messages,\n userRef,\n conversationId,\n recentConversationMessages,\n ) => {\n // If we have recentConversationMessages, use them; otherwise, fetch the last 5 messages\n const recentMessages =\n recentConversationMessages ||\n (await getRecentConversationMessages({\n conversationId,\n userEntityRef: userRef,\n limit: 5,\n excludeRoles: ['tool'],\n }));\n\n const conversationSize = (recentMessages?.length ?? 0) + messages.length;\n\n if (recentMessages.length === 0) {\n const conversation: Conversation = {\n id: conversationId,\n title: 'New Conversation',\n userRef,\n };\n chatStore.createConversation(conversation);\n chatStore.addChatMessage(messages, userRef, conversationId);\n\n signals.publish({\n channel: `ai-assistant.chat.conversation-details-update`,\n message: { conversation },\n recipients: {\n type: 'user',\n entityRef: userRef,\n },\n });\n return;\n }\n\n if (conversationSize < 5) {\n chatStore.addChatMessage(messages, userRef, conversationId);\n return;\n }\n\n const conversation = await chatStore.getConversation(\n conversationId,\n userRef,\n );\n\n if (conversation.title !== 'New Conversation') {\n chatStore.addChatMessage(messages, userRef, conversationId);\n return;\n }\n\n const summary = await summarizer.summarizeConversation({\n messages: recentMessages,\n length: '25 characters',\n });\n\n conversation.title = summary;\n\n chatStore.updateConversation(conversation);\n chatStore.addChatMessage(messages, userRef, conversationId);\n\n signals.publish({\n channel: `ai-assistant.chat.conversation-details-update`,\n message: { conversation },\n recipients: {\n type: 'user',\n entityRef: userRef,\n },\n });\n };\n\n return {\n getConversation,\n getConversations,\n addMessages,\n scoreMessage,\n getRecentConversationMessages,\n };\n};\n\nexport const conversationServiceRef: ServiceRef<\n ConversationService,\n 'plugin',\n 'singleton'\n> = createServiceRef<ConversationService>({\n id: 'ai-assistant.conversation-service',\n defaultFactory: async service =>\n createServiceFactory({\n service,\n deps: {\n database: coreServices.database,\n callback: callbackServiceRef,\n signals: signalsServiceRef,\n summarizer: summarizerServiceRef,\n },\n factory: async options => {\n return createConversationService(options);\n },\n }),\n});\n"],"names":["chatStore","ChatStore","conversation","createServiceRef","createServiceFactory","coreServices","callbackServiceRef","signalsServiceRef","summarizerServiceRef"],"mappings":"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"}
|