@sweetoburrito/backstage-plugin-ai-assistant-backend 0.0.0-snapshot-20251029080430

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.
Files changed (38) hide show
  1. package/README.md +28 -0
  2. package/config.d.ts +32 -0
  3. package/dist/constants/prompts.cjs.js +43 -0
  4. package/dist/constants/prompts.cjs.js.map +1 -0
  5. package/dist/database/chat-store.cjs.js +96 -0
  6. package/dist/database/chat-store.cjs.js.map +1 -0
  7. package/dist/database/migrations.cjs.js +16 -0
  8. package/dist/database/migrations.cjs.js.map +1 -0
  9. package/dist/database/pg-vector-store.cjs.js +193 -0
  10. package/dist/database/pg-vector-store.cjs.js.map +1 -0
  11. package/dist/index.cjs.js +10 -0
  12. package/dist/index.cjs.js.map +1 -0
  13. package/dist/index.d.ts +10 -0
  14. package/dist/plugin.cjs.js +101 -0
  15. package/dist/plugin.cjs.js.map +1 -0
  16. package/dist/services/chat.cjs.js +258 -0
  17. package/dist/services/chat.cjs.js.map +1 -0
  18. package/dist/services/ingestor.cjs.js +89 -0
  19. package/dist/services/ingestor.cjs.js.map +1 -0
  20. package/dist/services/langfuse.cjs.js +39 -0
  21. package/dist/services/langfuse.cjs.js.map +1 -0
  22. package/dist/services/router/chat.cjs.js +73 -0
  23. package/dist/services/router/chat.cjs.js.map +1 -0
  24. package/dist/services/router/index.cjs.js +25 -0
  25. package/dist/services/router/index.cjs.js.map +1 -0
  26. package/dist/services/router/middleware/validation.cjs.js +19 -0
  27. package/dist/services/router/middleware/validation.cjs.js.map +1 -0
  28. package/dist/services/router/models.cjs.js +20 -0
  29. package/dist/services/router/models.cjs.js.map +1 -0
  30. package/dist/services/summarizer.cjs.js +54 -0
  31. package/dist/services/summarizer.cjs.js.map +1 -0
  32. package/dist/services/tools/searchKnowledge.cjs.js +47 -0
  33. package/dist/services/tools/searchKnowledge.cjs.js.map +1 -0
  34. package/migrations/20250822_init.js +47 -0
  35. package/migrations/20250828_chat_history.js +44 -0
  36. package/migrations/20250909_conversations.js +92 -0
  37. package/migrations/20251005_tools.js +32 -0
  38. package/package.json +92 -0
@@ -0,0 +1,258 @@
1
+ 'use strict';
2
+
3
+ var chatStore = require('../database/chat-store.cjs.js');
4
+ var prompts = require('../constants/prompts.cjs.js');
5
+ var tools = require('@langchain/core/tools');
6
+ var prebuilt = require('@langchain/langgraph/prebuilt');
7
+ var prompts$1 = require('@langchain/core/prompts');
8
+ var summarizer = require('./summarizer.cjs.js');
9
+ var langchain = require('@langfuse/langchain');
10
+ var uuid = require('uuid');
11
+
12
+ const createChatService = async ({
13
+ models,
14
+ tools: tools$1,
15
+ logger,
16
+ database,
17
+ signals,
18
+ config,
19
+ catalog,
20
+ cache,
21
+ auth,
22
+ langfuseEnabled
23
+ }) => {
24
+ logger.info(`Available models: ${models.map((m) => m.id).join(", ")}`);
25
+ logger.info(`Available tools: ${tools$1.map((t) => t.name).join(", ")}`);
26
+ const identityPrompt = config.getOptionalString("aiAssistant.prompt.identity") || prompts.DEFAULT_IDENTITY_PROMPT;
27
+ const formattingPrompt = config.getOptionalString("aiAssistant.prompt.formatting") || prompts.DEFAULT_FORMATTING_PROMPT;
28
+ const contentPrompt = config.getOptionalString("aiAssistant.prompt.content") || prompts.DEFAULT_SYSTEM_PROMPT;
29
+ const combinedBasePrompt = `${identityPrompt}
30
+
31
+ ${formattingPrompt}
32
+
33
+ ${contentPrompt}`;
34
+ const toolGuideline = config.getOptionalString("aiAssistant.prompt.toolGuideline") || prompts.DEFAULT_TOOL_GUIDELINE;
35
+ const chatStore$1 = await chatStore.ChatStore.fromConfig({ database });
36
+ const summarizer$1 = await summarizer.createSummarizerService({
37
+ config,
38
+ models,
39
+ langfuseEnabled
40
+ });
41
+ const agentTools = tools$1.map((tool) => new tools.DynamicStructuredTool(tool));
42
+ const systemPromptTemplate = prompts$1.SystemMessagePromptTemplate.fromTemplate(`
43
+ PURPOSE:
44
+ {basePrompt}
45
+
46
+ TOOL USAGE GUIDELINES:
47
+ {toolGuideline}
48
+
49
+ Available tools:
50
+ {toolList}
51
+
52
+ Calling User:
53
+ {user}
54
+
55
+ Context:
56
+ {context}`);
57
+ const addMessages = async (messages, userRef, conversationId, recentConversationMessages) => {
58
+ const recentMessages = recentConversationMessages || await chatStore$1.getChatMessages(conversationId, userRef, 5, ["tool"]);
59
+ const conversationSize = (recentMessages?.length ?? 0) + messages.length;
60
+ if (recentMessages.length === 0) {
61
+ const conversation2 = {
62
+ id: conversationId,
63
+ title: "New Conversation",
64
+ userRef
65
+ };
66
+ chatStore$1.createConversation(conversation2);
67
+ chatStore$1.addChatMessage(messages, userRef, conversationId);
68
+ signals.publish({
69
+ channel: `ai-assistant.chat.conversation-details-update`,
70
+ message: { conversation: conversation2 },
71
+ recipients: {
72
+ type: "user",
73
+ entityRef: userRef
74
+ }
75
+ });
76
+ return;
77
+ }
78
+ if (conversationSize < 5) {
79
+ chatStore$1.addChatMessage(messages, userRef, conversationId);
80
+ return;
81
+ }
82
+ const conversation = await chatStore$1.getConversation(
83
+ conversationId,
84
+ userRef
85
+ );
86
+ if (conversation.title !== "New Conversation") {
87
+ chatStore$1.addChatMessage(messages, userRef, conversationId);
88
+ return;
89
+ }
90
+ const summary = await summarizer$1.summarize(recentMessages, "25 characters");
91
+ conversation.title = summary;
92
+ chatStore$1.updateConversation(conversation);
93
+ chatStore$1.addChatMessage(messages, userRef, conversationId);
94
+ signals.publish({
95
+ channel: `ai-assistant.chat.conversation-details-update`,
96
+ message: { conversation },
97
+ recipients: {
98
+ type: "user",
99
+ entityRef: userRef
100
+ }
101
+ });
102
+ };
103
+ const prompt = async ({
104
+ conversationId,
105
+ messages,
106
+ modelId,
107
+ stream = true,
108
+ userEntityRef
109
+ }) => {
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 streamFn = async () => {
115
+ const recentConversationMessages = await chatStore$1.getChatMessages(
116
+ conversationId,
117
+ userEntityRef,
118
+ 10,
119
+ ["tool"]
120
+ );
121
+ const credentials = await auth.getOwnServiceCredentials();
122
+ const user = await getUser(cache, userEntityRef, credentials, catalog);
123
+ addMessages(
124
+ messages,
125
+ userEntityRef,
126
+ conversationId,
127
+ recentConversationMessages
128
+ );
129
+ const systemPrompt = await systemPromptTemplate.formatMessages({
130
+ basePrompt: combinedBasePrompt,
131
+ toolGuideline,
132
+ toolList: agentTools.map((tool) => `- ${tool.name}: ${tool.description}`).join("\n"),
133
+ context: `none`,
134
+ user
135
+ });
136
+ const agent = prebuilt.createReactAgent({
137
+ llm: model,
138
+ tools: agentTools,
139
+ prompt: systemPrompt[0].text
140
+ });
141
+ const langfuseHandler = langfuseEnabled ? new langchain.CallbackHandler({
142
+ sessionId: conversationId,
143
+ userId: userEntityRef,
144
+ tags: ["backstage-ai-assistant", "chat"]
145
+ }) : void 0;
146
+ const promptStream = await agent.stream(
147
+ {
148
+ messages: [...recentConversationMessages, ...messages]
149
+ },
150
+ {
151
+ streamMode: ["values"],
152
+ runName: "ai-assistant-chat",
153
+ metadata: {
154
+ langfuseUserId: userEntityRef,
155
+ langfuseSessionId: conversationId,
156
+ langfuseTags: ["ai-assistant", "chat", modelId]
157
+ },
158
+ callbacks: langfuseHandler ? [langfuseHandler] : []
159
+ }
160
+ );
161
+ const responseMessages = [];
162
+ for await (const [, chunk] of promptStream) {
163
+ const { messages: promptMessages } = chunk;
164
+ const newMessages = promptMessages.filter((m) => responseMessages.findIndex((rm) => rm.id === m.id) === -1).filter(
165
+ (m) => recentConversationMessages.findIndex((rm) => rm.id === m.id) === -1
166
+ ).filter((m) => m.getType() !== "human").map((m) => {
167
+ const id = m.id ?? "";
168
+ const role = m.getType();
169
+ const content = typeof m.content === "string" ? m.content : JSON.stringify(m.content);
170
+ const metadata = {};
171
+ if (role === "ai") {
172
+ const aiMessage = m;
173
+ metadata.toolCalls = aiMessage.tool_calls || [];
174
+ metadata.finishReason = aiMessage.response_metadata.finish_reason || void 0;
175
+ metadata.modelName = aiMessage.response_metadata.model_name || void 0;
176
+ }
177
+ if (role === "tool") {
178
+ const toolMessage = m;
179
+ metadata.name = toolMessage.name || "";
180
+ }
181
+ return {
182
+ id,
183
+ role,
184
+ content,
185
+ metadata
186
+ };
187
+ });
188
+ for await (const m of newMessages) {
189
+ const words = m.content.split(" ");
190
+ const chunkSize = 5;
191
+ let messageBuilder = "";
192
+ for (let i = 0; i < words.length; i += chunkSize) {
193
+ const wordChunk = words.slice(i, i + chunkSize).join(" ");
194
+ messageBuilder = messageBuilder.concat(wordChunk).concat(" ");
195
+ m.content = messageBuilder;
196
+ await new Promise((resolve) => setTimeout(resolve, 50));
197
+ signals.publish({
198
+ channel: `ai-assistant.chat.conversation-stream:${conversationId}`,
199
+ message: { messages: [m] },
200
+ recipients: {
201
+ type: "user",
202
+ entityRef: userEntityRef
203
+ }
204
+ });
205
+ }
206
+ }
207
+ responseMessages.push(...newMessages);
208
+ }
209
+ addMessages(
210
+ responseMessages.map((m) => ({ ...m, id: uuid.v4() })),
211
+ userEntityRef,
212
+ conversationId,
213
+ [...recentConversationMessages, ...messages]
214
+ );
215
+ return responseMessages;
216
+ };
217
+ const result = streamFn();
218
+ return stream ? [] : result;
219
+ };
220
+ const getAvailableModels = async () => {
221
+ return models.map((x) => x.id);
222
+ };
223
+ const getConversation = async (options) => {
224
+ const { conversationId, userEntityRef } = options;
225
+ const conversation = await chatStore$1.getChatMessages(
226
+ conversationId,
227
+ userEntityRef
228
+ );
229
+ return conversation;
230
+ };
231
+ const getConversations = async ({
232
+ userEntityRef
233
+ }) => {
234
+ const conversations = await chatStore$1.getConversations(userEntityRef);
235
+ return conversations;
236
+ };
237
+ return {
238
+ prompt,
239
+ getAvailableModels,
240
+ getConversation,
241
+ getConversations,
242
+ addMessages
243
+ };
244
+ };
245
+ async function getUser(cache, userEntityRef, credentials, catalog) {
246
+ const cached = await cache.get(userEntityRef);
247
+ if (cached) {
248
+ return JSON.parse(String(cached));
249
+ }
250
+ const user = await catalog.getEntityByRef(userEntityRef, {
251
+ credentials
252
+ });
253
+ await cache.set(userEntityRef, JSON.stringify(user));
254
+ return user;
255
+ }
256
+
257
+ exports.createChatService = createChatService;
258
+ //# sourceMappingURL=chat.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat.cjs.js","sources":["../../src/services/chat.ts"],"sourcesContent":["import { Model } from '@sweetoburrito/backstage-plugin-ai-assistant-node';\nimport { CatalogService } from '@backstage/plugin-catalog-node';\nimport { UserEntity } from '@backstage/catalog-model';\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} 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 { Tool } 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 { createSummarizerService } from './summarizer';\nimport { CallbackHandler } from '@langfuse/langchain';\nimport { v4 as uuid } from 'uuid';\nimport type {\n BackstageCredentials,\n CacheService,\n} from '@backstage/backend-plugin-api';\nimport { AIMessage, ToolMessage } from '@langchain/core/messages';\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 langfuseEnabled: boolean;\n};\n\ntype PromptOptions = {\n modelId: string;\n messages: Message[];\n conversationId: string;\n stream?: boolean;\n userEntityRef: string;\n};\n\ntype GetConversationOptions = {\n conversationId: string;\n userEntityRef: string;\n};\n\ntype GetConversationsOptions = {\n userEntityRef: string;\n};\n\nexport type ChatService = {\n prompt: (options: PromptOptions) => Promise<Required<Message>[]>;\n getAvailableModels: () => Promise<string[]>;\n getConversation: (\n options: GetConversationOptions,\n ) => Promise<Required<Message>[]>;\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};\n\nexport const createChatService = async ({\n models,\n tools,\n logger,\n database,\n signals,\n config,\n catalog,\n cache,\n auth,\n langfuseEnabled,\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 const summarizer = await createSummarizerService({\n config,\n models,\n langfuseEnabled,\n });\n\n const agentTools = tools.map(tool => new DynamicStructuredTool(tool));\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.summarize(recentMessages, '25 characters');\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 userEntityRef,\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 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 addMessages(\n messages,\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 // Initialize Langfuse CallbackHandler for tracing if credentials are available\n const langfuseHandler = langfuseEnabled\n ? new CallbackHandler({\n sessionId: conversationId,\n userId: userEntityRef,\n tags: ['backstage-ai-assistant', 'chat'],\n })\n : undefined;\n\n const promptStream = await agent.stream(\n {\n messages: [...recentConversationMessages, ...messages],\n },\n {\n streamMode: ['values'],\n runName: 'ai-assistant-chat',\n metadata: {\n langfuseUserId: userEntityRef,\n langfuseSessionId: conversationId,\n langfuseTags: ['ai-assistant', 'chat', modelId],\n },\n callbacks: langfuseHandler ? [langfuseHandler] : [],\n },\n );\n\n const responseMessages: Required<Message>[] = [];\n\n for await (const [, chunk] of promptStream) {\n const { messages: promptMessages } = chunk;\n\n const newMessages: Required<Message>[] = promptMessages\n .filter(m => responseMessages.findIndex(rm => rm.id === m.id) === -1)\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 = m.id ?? '';\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\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 };\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(\n responseMessages.map(m => ({ ...m, id: uuid() })),\n userEntityRef,\n conversationId,\n [...recentConversationMessages, ...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 return {\n prompt,\n getAvailableModels,\n getConversation,\n getConversations,\n addMessages,\n };\n};\n\nasync function getUser(\n cache: CacheService,\n userEntityRef: string,\n credentials: BackstageCredentials,\n catalog: CatalogService,\n) {\n const cached = await cache.get(userEntityRef);\n\n if (cached) {\n return JSON.parse(String(cached));\n }\n\n const user = (await catalog.getEntityByRef(userEntityRef, {\n credentials,\n })) as UserEntity | undefined;\n await cache.set(userEntityRef, JSON.stringify(user));\n\n return user;\n}\n"],"names":["tools","DEFAULT_IDENTITY_PROMPT","DEFAULT_FORMATTING_PROMPT","DEFAULT_SYSTEM_PROMPT","DEFAULT_TOOL_GUIDELINE","chatStore","ChatStore","summarizer","createSummarizerService","DynamicStructuredTool","SystemMessagePromptTemplate","conversation","createReactAgent","CallbackHandler","uuid"],"mappings":"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"}
@@ -0,0 +1,89 @@
1
+ 'use strict';
2
+
3
+ var backendPluginApi = require('@backstage/backend-plugin-api');
4
+ var textsplitters = require('@langchain/textsplitters');
5
+
6
+ const DEFAULT_DATA_INGESTION_SCHEDULE = {
7
+ frequency: {
8
+ hours: 24
9
+ },
10
+ timeout: {
11
+ hours: 3
12
+ }
13
+ };
14
+ const createDataIngestionPipeline = ({
15
+ config,
16
+ logger,
17
+ scheduler,
18
+ ingestors,
19
+ vectorStore
20
+ }) => {
21
+ const schedule = config.has("aiAssistant.ingestion.schedule") ? backendPluginApi.readSchedulerServiceTaskScheduleDefinitionFromConfig(
22
+ config.getConfig("aiAssistant.ingestion.schedule")
23
+ ) : DEFAULT_DATA_INGESTION_SCHEDULE;
24
+ const taskRunner = scheduler.createScheduledTaskRunner(schedule);
25
+ const taskId = `ai-assistant.data-ingestion:start`;
26
+ const dataIngestion = async () => {
27
+ logger.info("Starting data ingestion...");
28
+ if (ingestors.length === 0) {
29
+ logger.warn("No ingestors available for data ingestion.");
30
+ return;
31
+ }
32
+ logger.info(`Ingestors available: ${ingestors.map((i) => i.id).join(", ")}`);
33
+ for await (const ingestor of ingestors) {
34
+ logger.info(`Running ingestor: ${ingestor.id}`);
35
+ const saveDocumentsBatch = async (documents2) => {
36
+ logger.info(
37
+ `Ingested documents for ${ingestor.id}: ${documents2.length}`
38
+ );
39
+ const splitter = new textsplitters.RecursiveCharacterTextSplitter({
40
+ chunkSize: 500,
41
+ // TODO: Make chunk size configurable
42
+ chunkOverlap: 50
43
+ // TODO: Make chunk overlap configurable
44
+ });
45
+ const docs = await Promise.all(
46
+ documents2.map(async (document) => {
47
+ logger.debug(
48
+ `Deleting existing documents with id: [${document.metadata.id}] and source: [${ingestor.id}]`
49
+ );
50
+ await vectorStore.deleteDocuments({
51
+ filter: { source: ingestor.id, id: document.metadata.id }
52
+ });
53
+ const chunks = await splitter.splitText(document.content);
54
+ const chunkDocs = chunks.flatMap(
55
+ (chunk, i) => ({
56
+ metadata: { ...document.metadata, chunk: String(i) },
57
+ content: chunk
58
+ })
59
+ );
60
+ return chunkDocs;
61
+ })
62
+ );
63
+ logger.info(`Adding documents to vector store...`);
64
+ await vectorStore.addDocuments(docs.flat());
65
+ logger.info(`Added documents to vector store for ${ingestor.id}`);
66
+ };
67
+ const documents = await ingestor.ingest({
68
+ saveDocumentsBatch
69
+ });
70
+ if (documents) {
71
+ saveDocumentsBatch(documents);
72
+ }
73
+ logger.info(`Finished processing ingestor: ${ingestor.id}`);
74
+ }
75
+ logger.info("Data ingestion completed.");
76
+ };
77
+ const start = async () => {
78
+ taskRunner.run({
79
+ id: taskId,
80
+ fn: dataIngestion
81
+ });
82
+ };
83
+ return {
84
+ start
85
+ };
86
+ };
87
+
88
+ exports.createDataIngestionPipeline = createDataIngestionPipeline;
89
+ //# sourceMappingURL=ingestor.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ingestor.cjs.js","sources":["../../src/services/ingestor.ts"],"sourcesContent":["import {\n DataIngestionPipeline,\n DataIngestionPipelineOptions,\n EmbeddingDocument,\n} from '@sweetoburrito/backstage-plugin-ai-assistant-node';\n\nimport {\n SchedulerServiceTaskScheduleDefinition,\n readSchedulerServiceTaskScheduleDefinitionFromConfig,\n} from '@backstage/backend-plugin-api';\n\nimport { RecursiveCharacterTextSplitter } from '@langchain/textsplitters';\n\nconst DEFAULT_DATA_INGESTION_SCHEDULE: SchedulerServiceTaskScheduleDefinition =\n {\n frequency: {\n hours: 24,\n },\n timeout: {\n hours: 3,\n },\n };\n\nexport const createDataIngestionPipeline = ({\n config,\n logger,\n scheduler,\n ingestors,\n vectorStore,\n}: DataIngestionPipelineOptions): DataIngestionPipeline => {\n const schedule = config.has('aiAssistant.ingestion.schedule')\n ? readSchedulerServiceTaskScheduleDefinitionFromConfig(\n config.getConfig('aiAssistant.ingestion.schedule'),\n )\n : DEFAULT_DATA_INGESTION_SCHEDULE;\n\n const taskRunner = scheduler.createScheduledTaskRunner(schedule);\n\n const taskId = `ai-assistant.data-ingestion:start`;\n\n const dataIngestion = async () => {\n logger.info('Starting data ingestion...');\n\n if (ingestors.length === 0) {\n logger.warn('No ingestors available for data ingestion.');\n return;\n }\n\n logger.info(`Ingestors available: ${ingestors.map(i => i.id).join(', ')}`);\n\n for await (const ingestor of ingestors) {\n logger.info(`Running ingestor: ${ingestor.id}`);\n\n const saveDocumentsBatch = async (documents: EmbeddingDocument[]) => {\n logger.info(\n `Ingested documents for ${ingestor.id}: ${documents.length}`,\n );\n\n const splitter = new RecursiveCharacterTextSplitter({\n chunkSize: 500, // TODO: Make chunk size configurable\n chunkOverlap: 50, // TODO: Make chunk overlap configurable\n });\n\n const docs = await Promise.all(\n documents.map(async document => {\n // Delete existing documents with this document id and ingestor source\n logger.debug(\n `Deleting existing documents with id: [${document.metadata.id}] and source: [${ingestor.id}]`,\n );\n await vectorStore.deleteDocuments({\n filter: { source: ingestor.id, id: document.metadata.id },\n });\n\n const chunks = await splitter.splitText(document.content);\n\n const chunkDocs: EmbeddingDocument[] = chunks.flatMap(\n (chunk, i) => ({\n metadata: { ...document.metadata, chunk: String(i) },\n content: chunk,\n }),\n );\n\n return chunkDocs;\n }),\n );\n\n logger.info(`Adding documents to vector store...`);\n await vectorStore.addDocuments(docs.flat());\n logger.info(`Added documents to vector store for ${ingestor.id}`);\n };\n\n const documents = await ingestor.ingest({\n saveDocumentsBatch,\n });\n\n if (documents) {\n saveDocumentsBatch(documents);\n }\n\n logger.info(`Finished processing ingestor: ${ingestor.id}`);\n }\n\n logger.info('Data ingestion completed.');\n };\n\n const start = async () => {\n taskRunner.run({\n id: taskId,\n fn: dataIngestion,\n });\n };\n\n return {\n start,\n };\n};\n"],"names":["readSchedulerServiceTaskScheduleDefinitionFromConfig","documents","RecursiveCharacterTextSplitter"],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ 'use strict';
2
+
3
+ var otel = require('@langfuse/otel');
4
+ var sdkNode = require('@opentelemetry/sdk-node');
5
+
6
+ function initLangfuse(config, logger) {
7
+ const langfuseSecret = config.getOptionalString(
8
+ "aiAssistant.langfuse.secretKey"
9
+ );
10
+ const langfusePublic = config.getOptionalString(
11
+ "aiAssistant.langfuse.publicKey"
12
+ );
13
+ const langfuseBaseUrl = config.getOptionalString(
14
+ "aiAssistant.langfuse.baseUrl"
15
+ );
16
+ let langfuseSpanProcessor = void 0;
17
+ if (langfuseSecret && langfusePublic && langfuseBaseUrl) {
18
+ langfuseSpanProcessor = new otel.LangfuseSpanProcessor({
19
+ secretKey: langfuseSecret,
20
+ publicKey: langfusePublic,
21
+ baseUrl: langfuseBaseUrl
22
+ });
23
+ const sdk = new sdkNode.NodeSDK({
24
+ spanProcessors: [langfuseSpanProcessor]
25
+ });
26
+ logger.info(
27
+ "Langfuse: Starting OpenTelemetry SDK with LangfuseSpanProcessor"
28
+ );
29
+ sdk.start();
30
+ return true;
31
+ }
32
+ logger.info(
33
+ "Langfuse: Skipping Langfuse initialization, credentials not found."
34
+ );
35
+ return false;
36
+ }
37
+
38
+ exports.initLangfuse = initLangfuse;
39
+ //# sourceMappingURL=langfuse.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"langfuse.cjs.js","sources":["../../src/services/langfuse.ts"],"sourcesContent":["import {\n RootConfigService,\n RootLoggerService,\n} from '@backstage/backend-plugin-api';\nimport { LangfuseSpanProcessor } from '@langfuse/otel';\nimport { NodeSDK } from '@opentelemetry/sdk-node';\n\nexport function initLangfuse(\n config: RootConfigService,\n logger: RootLoggerService,\n): boolean {\n const langfuseSecret = config.getOptionalString(\n 'aiAssistant.langfuse.secretKey',\n );\n const langfusePublic = config.getOptionalString(\n 'aiAssistant.langfuse.publicKey',\n );\n const langfuseBaseUrl = config.getOptionalString(\n 'aiAssistant.langfuse.baseUrl',\n );\n\n let langfuseSpanProcessor: LangfuseSpanProcessor | undefined = undefined;\n if (langfuseSecret && langfusePublic && langfuseBaseUrl) {\n langfuseSpanProcessor = new LangfuseSpanProcessor({\n secretKey: langfuseSecret,\n publicKey: langfusePublic,\n baseUrl: langfuseBaseUrl,\n });\n\n const sdk = new NodeSDK({\n spanProcessors: [langfuseSpanProcessor],\n });\n\n logger.info(\n 'Langfuse: Starting OpenTelemetry SDK with LangfuseSpanProcessor',\n );\n sdk.start();\n return true;\n }\n logger.info(\n 'Langfuse: Skipping Langfuse initialization, credentials not found.',\n );\n return false;\n}\n"],"names":["LangfuseSpanProcessor","NodeSDK"],"mappings":";;;;;AAOO,SAAS,YAAA,CACd,QACA,MAAA,EACS;AACT,EAAA,MAAM,iBAAiB,MAAA,CAAO,iBAAA;AAAA,IAC5B;AAAA,GACF;AACA,EAAA,MAAM,iBAAiB,MAAA,CAAO,iBAAA;AAAA,IAC5B;AAAA,GACF;AACA,EAAA,MAAM,kBAAkB,MAAA,CAAO,iBAAA;AAAA,IAC7B;AAAA,GACF;AAEA,EAAA,IAAI,qBAAA,GAA2D,MAAA;AAC/D,EAAA,IAAI,cAAA,IAAkB,kBAAkB,eAAA,EAAiB;AACvD,IAAA,qBAAA,GAAwB,IAAIA,0BAAA,CAAsB;AAAA,MAChD,SAAA,EAAW,cAAA;AAAA,MACX,SAAA,EAAW,cAAA;AAAA,MACX,OAAA,EAAS;AAAA,KACV,CAAA;AAED,IAAA,MAAM,GAAA,GAAM,IAAIC,eAAA,CAAQ;AAAA,MACtB,cAAA,EAAgB,CAAC,qBAAqB;AAAA,KACvC,CAAA;AAED,IAAA,MAAA,CAAO,IAAA;AAAA,MACL;AAAA,KACF;AACA,IAAA,GAAA,CAAI,KAAA,EAAM;AACV,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,MAAA,CAAO,IAAA;AAAA,IACL;AAAA,GACF;AACA,EAAA,OAAO,KAAA;AACT;;;;"}
@@ -0,0 +1,73 @@
1
+ 'use strict';
2
+
3
+ var Router = require('express-promise-router');
4
+ var z = require('zod');
5
+ var validation = require('./middleware/validation.cjs.js');
6
+ var uuid = require('uuid');
7
+
8
+ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
9
+
10
+ var Router__default = /*#__PURE__*/_interopDefaultCompat(Router);
11
+ var z__default = /*#__PURE__*/_interopDefaultCompat(z);
12
+
13
+ async function createChatRouter(options) {
14
+ const { chat, httpAuth, userInfo } = options;
15
+ const router = Router__default.default();
16
+ const messageSchema = z__default.default.object({
17
+ messages: z__default.default.array(
18
+ z__default.default.object({
19
+ id: z__default.default.string().uuid().optional().default(uuid.v4),
20
+ role: z__default.default.string(),
21
+ content: z__default.default.string()
22
+ })
23
+ ),
24
+ modelId: z__default.default.string(),
25
+ conversationId: z__default.default.string().uuid().optional().default(uuid.v4),
26
+ stream: z__default.default.boolean().optional()
27
+ });
28
+ router.post(
29
+ "/message",
30
+ validation.validation(messageSchema, "body"),
31
+ async (req, res) => {
32
+ const { messages, conversationId, modelId, stream } = req.body;
33
+ const credentials = await httpAuth.credentials(req);
34
+ const { userEntityRef } = await userInfo.getUserInfo(credentials);
35
+ const responseMessages = await chat.prompt({
36
+ modelId,
37
+ messages,
38
+ conversationId,
39
+ stream,
40
+ userEntityRef
41
+ });
42
+ res.json({
43
+ messages: responseMessages,
44
+ conversationId
45
+ });
46
+ }
47
+ );
48
+ const chatSchema = z__default.default.object({
49
+ id: z__default.default.string().uuid()
50
+ });
51
+ router.get("/conversations", async (req, res) => {
52
+ const credentials = await httpAuth.credentials(req);
53
+ const { userEntityRef } = await userInfo.getUserInfo(credentials);
54
+ const conversations = await chat.getConversations({
55
+ userEntityRef
56
+ });
57
+ res.json({ conversations });
58
+ });
59
+ router.get("/:id", validation.validation(chatSchema, "params"), async (req, res) => {
60
+ const { id } = req.params;
61
+ const credentials = await httpAuth.credentials(req);
62
+ const { userEntityRef } = await userInfo.getUserInfo(credentials);
63
+ const conversation = await chat.getConversation({
64
+ conversationId: id,
65
+ userEntityRef
66
+ });
67
+ res.json({ conversation });
68
+ });
69
+ return router;
70
+ }
71
+
72
+ exports.createChatRouter = createChatRouter;
73
+ //# sourceMappingURL=chat.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat.cjs.js","sources":["../../../src/services/router/chat.ts"],"sourcesContent":["import express from 'express';\nimport Router from 'express-promise-router';\nimport { ChatService } from '../chat';\nimport z from 'zod';\nimport { validation } from './middleware/validation';\nimport { v4 as uuid } from 'uuid';\nimport {\n DatabaseService,\n HttpAuthService,\n UserInfoService,\n} from '@backstage/backend-plugin-api';\n\nexport type ChatRouterOptions = {\n chat: ChatService;\n database: DatabaseService;\n httpAuth: HttpAuthService;\n userInfo: UserInfoService;\n};\n\nexport async function createChatRouter(\n options: ChatRouterOptions,\n): Promise<express.Router> {\n const { chat, httpAuth, userInfo } = options;\n\n const router = Router();\n\n const messageSchema = z.object({\n messages: z.array(\n z.object({\n id: z.string().uuid().optional().default(uuid),\n role: z.string(),\n content: z.string(),\n }),\n ),\n modelId: z.string(),\n conversationId: z.string().uuid().optional().default(uuid),\n stream: z.boolean().optional(),\n });\n\n router.post(\n '/message',\n validation(messageSchema, 'body'),\n async (req, res) => {\n const { messages, conversationId, modelId, stream } = req.body;\n\n const credentials = await httpAuth.credentials(req);\n const { userEntityRef } = await userInfo.getUserInfo(credentials);\n\n const responseMessages = await chat.prompt({\n modelId,\n messages,\n conversationId,\n stream,\n userEntityRef,\n });\n\n res.json({\n messages: responseMessages,\n conversationId,\n });\n },\n );\n\n const chatSchema = z.object({\n id: z.string().uuid(),\n });\n\n router.get('/conversations', async (req, res) => {\n const credentials = await httpAuth.credentials(req);\n const { userEntityRef } = await userInfo.getUserInfo(credentials);\n\n const conversations = await chat.getConversations({\n userEntityRef,\n });\n\n res.json({ conversations });\n });\n\n router.get('/:id', validation(chatSchema, 'params'), async (req, res) => {\n const { id } = req.params;\n\n const credentials = await httpAuth.credentials(req);\n const { userEntityRef } = await userInfo.getUserInfo(credentials);\n\n const conversation = await chat.getConversation({\n conversationId: id,\n userEntityRef,\n });\n\n res.json({ conversation });\n });\n\n return router;\n}\n"],"names":["Router","z","uuid","validation"],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ 'use strict';
2
+
3
+ var express = require('express');
4
+ var Router = require('express-promise-router');
5
+ var chat = require('./chat.cjs.js');
6
+ var models = require('./models.cjs.js');
7
+ var rootHttpRouter = require('@backstage/backend-defaults/rootHttpRouter');
8
+
9
+ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
10
+
11
+ var express__default = /*#__PURE__*/_interopDefaultCompat(express);
12
+ var Router__default = /*#__PURE__*/_interopDefaultCompat(Router);
13
+
14
+ async function createRouter(options) {
15
+ const router = Router__default.default();
16
+ router.use(express__default.default.json());
17
+ router.use("/chat", await chat.createChatRouter(options));
18
+ router.use("/models", await models.createModelRouter(options));
19
+ const middleware = rootHttpRouter.MiddlewareFactory.create(options);
20
+ router.use(middleware.error());
21
+ return router;
22
+ }
23
+
24
+ exports.createRouter = createRouter;
25
+ //# sourceMappingURL=index.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs.js","sources":["../../../src/services/router/index.ts"],"sourcesContent":["import express from 'express';\nimport Router from 'express-promise-router';\nimport { createChatRouter, ChatRouterOptions } from './chat';\nimport { createModelRouter } from './models';\nimport {\n LoggerService,\n RootConfigService,\n} from '@backstage/backend-plugin-api';\nimport { MiddlewareFactory } from '@backstage/backend-defaults/rootHttpRouter';\n\nexport type RouterOptions = ChatRouterOptions & {\n config: RootConfigService;\n logger: LoggerService;\n};\n\nexport async function createRouter(\n options: RouterOptions,\n): Promise<express.Router> {\n const router = Router();\n router.use(express.json());\n\n router.use('/chat', await createChatRouter(options));\n router.use('/models', await createModelRouter(options));\n\n const middleware = MiddlewareFactory.create(options);\n\n router.use(middleware.error());\n\n return router;\n}\n"],"names":["Router","express","createChatRouter","createModelRouter","MiddlewareFactory"],"mappings":";;;;;;;;;;;;;AAeA,eAAsB,aACpB,OAAA,EACyB;AACzB,EAAA,MAAM,SAASA,uBAAA,EAAO;AACtB,EAAA,MAAA,CAAO,GAAA,CAAIC,wBAAA,CAAQ,IAAA,EAAM,CAAA;AAEzB,EAAA,MAAA,CAAO,GAAA,CAAI,OAAA,EAAS,MAAMC,qBAAA,CAAiB,OAAO,CAAC,CAAA;AACnD,EAAA,MAAA,CAAO,GAAA,CAAI,SAAA,EAAW,MAAMC,wBAAA,CAAkB,OAAO,CAAC,CAAA;AAEtD,EAAA,MAAM,UAAA,GAAaC,gCAAA,CAAkB,MAAA,CAAO,OAAO,CAAA;AAEnD,EAAA,MAAA,CAAO,GAAA,CAAI,UAAA,CAAW,KAAA,EAAO,CAAA;AAE7B,EAAA,OAAO,MAAA;AACT;;;;"}
@@ -0,0 +1,19 @@
1
+ 'use strict';
2
+
3
+ const validation = (schema, key) => {
4
+ return (req, res, next) => {
5
+ const parsed = schema.safeParse(req[key]);
6
+ if (!parsed.success) {
7
+ const errors = parsed.error.issues.map(
8
+ (issue) => `Validation Error:Field ${issue.path.join(".")} - ${issue.message}`
9
+ );
10
+ res.status(400).send({ errors });
11
+ return;
12
+ }
13
+ req[key] = parsed.data;
14
+ next();
15
+ };
16
+ };
17
+
18
+ exports.validation = validation;
19
+ //# sourceMappingURL=validation.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.cjs.js","sources":["../../../../src/services/router/middleware/validation.ts"],"sourcesContent":["import express from 'express';\nimport { ZodObject } from 'zod';\n\ntype ValidationKey = 'body' | 'query' | 'params' | 'headers';\n\nexport const validation = (schema: ZodObject, key: ValidationKey) => {\n return (\n req: express.Request,\n res: express.Response,\n next: express.NextFunction,\n ) => {\n const parsed = schema.safeParse(req[key]);\n if (!parsed.success) {\n const errors = parsed.error.issues.map(\n issue =>\n `Validation Error:Field ${issue.path.join('.')} - ${issue.message}`,\n );\n res.status(400).send({ errors });\n return;\n }\n req[key] = parsed.data;\n next();\n };\n};\n"],"names":[],"mappings":";;AAKO,MAAM,UAAA,GAAa,CAAC,MAAA,EAAmB,GAAA,KAAuB;AACnE,EAAA,OAAO,CACL,GAAA,EACA,GAAA,EACA,IAAA,KACG;AACH,IAAA,MAAM,MAAA,GAAS,MAAA,CAAO,SAAA,CAAU,GAAA,CAAI,GAAG,CAAC,CAAA;AACxC,IAAA,IAAI,CAAC,OAAO,OAAA,EAAS;AACnB,MAAA,MAAM,MAAA,GAAS,MAAA,CAAO,KAAA,CAAM,MAAA,CAAO,GAAA;AAAA,QACjC,CAAA,KAAA,KACE,0BAA0B,KAAA,CAAM,IAAA,CAAK,KAAK,GAAG,CAAC,CAAA,GAAA,EAAM,KAAA,CAAM,OAAO,CAAA;AAAA,OACrE;AACA,MAAA,GAAA,CAAI,OAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,QAAQ,CAAA;AAC/B,MAAA;AAAA,IACF;AACA,IAAA,GAAA,CAAI,GAAG,IAAI,MAAA,CAAO,IAAA;AAClB,IAAA,IAAA,EAAK;AAAA,EACP,CAAA;AACF;;;;"}
@@ -0,0 +1,20 @@
1
+ 'use strict';
2
+
3
+ var Router = require('express-promise-router');
4
+
5
+ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
6
+
7
+ var Router__default = /*#__PURE__*/_interopDefaultCompat(Router);
8
+
9
+ async function createModelRouter(options) {
10
+ const { chat } = options;
11
+ const router = Router__default.default();
12
+ router.get("/", async (_req, res) => {
13
+ const models = await chat.getAvailableModels();
14
+ res.json({ models });
15
+ });
16
+ return router;
17
+ }
18
+
19
+ exports.createModelRouter = createModelRouter;
20
+ //# sourceMappingURL=models.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models.cjs.js","sources":["../../../src/services/router/models.ts"],"sourcesContent":["import express from 'express';\nimport Router from 'express-promise-router';\nimport { ChatService } from '../chat';\n\nexport type ModelRouterOptions = {\n chat: ChatService;\n};\n\nexport async function createModelRouter(\n options: ModelRouterOptions,\n): Promise<express.Router> {\n const { chat } = options;\n const router = Router();\n\n router.get('/', async (_req, res) => {\n const models = await chat.getAvailableModels();\n res.json({ models });\n });\n\n return router;\n}\n"],"names":["Router"],"mappings":";;;;;;;;AAQA,eAAsB,kBACpB,OAAA,EACyB;AACzB,EAAA,MAAM,EAAE,MAAK,GAAI,OAAA;AACjB,EAAA,MAAM,SAASA,uBAAA,EAAO;AAEtB,EAAA,MAAA,CAAO,GAAA,CAAI,GAAA,EAAK,OAAO,IAAA,EAAM,GAAA,KAAQ;AACnC,IAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,kBAAA,EAAmB;AAC7C,IAAA,GAAA,CAAI,IAAA,CAAK,EAAE,MAAA,EAAQ,CAAA;AAAA,EACrB,CAAC,CAAA;AAED,EAAA,OAAO,MAAA;AACT;;;;"}