@sweetoburrito/backstage-plugin-qeta-backend-module-ai-assistant 0.0.0-snapshot-20251210121031

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/README.md ADDED
@@ -0,0 +1,5 @@
1
+ # @sweetoburrito/backstage-plugin-qeta-backend-module-ai-assistant
2
+
3
+ The ai-assistant backend module for the qeta plugin.
4
+
5
+ _This plugin was created through the Backstage CLI_
@@ -0,0 +1,10 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var module$1 = require('./module.cjs.js');
6
+
7
+
8
+
9
+ exports.default = module$1.qetaModuleAiAssistant;
10
+ //# sourceMappingURL=index.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;"}
@@ -0,0 +1,5 @@
1
+ import * as _backstage_backend_plugin_api from '@backstage/backend-plugin-api';
2
+
3
+ declare const qetaModuleAiAssistant: _backstage_backend_plugin_api.BackendFeature;
4
+
5
+ export { qetaModuleAiAssistant as default };
@@ -0,0 +1,27 @@
1
+ 'use strict';
2
+
3
+ var backendPluginApi = require('@backstage/backend-plugin-api');
4
+ var backstagePluginQetaNode = require('@drodil/backstage-plugin-qeta-node');
5
+ var aiHandler = require('./services/ai-handler.cjs.js');
6
+ var backstagePluginAiAssistantNode = require('@sweetoburrito/backstage-plugin-ai-assistant-node');
7
+
8
+ const qetaModuleAiAssistant = backendPluginApi.createBackendModule({
9
+ pluginId: "qeta",
10
+ moduleId: "ai-assistant",
11
+ register(reg) {
12
+ reg.registerInit({
13
+ deps: {
14
+ qetaAi: backstagePluginQetaNode.qetaAIExtensionPoint,
15
+ aiAssistant: backstagePluginAiAssistantNode.aiAssistantServiceRef,
16
+ auth: backendPluginApi.coreServices.auth
17
+ },
18
+ async init(options) {
19
+ const { qetaAi, ...rest } = options;
20
+ qetaAi.setAIHandler(aiHandler.createQetaAiHandler(rest));
21
+ }
22
+ });
23
+ }
24
+ });
25
+
26
+ exports.qetaModuleAiAssistant = qetaModuleAiAssistant;
27
+ //# sourceMappingURL=module.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module.cjs.js","sources":["../src/module.ts"],"sourcesContent":["import {\n coreServices,\n createBackendModule,\n} from '@backstage/backend-plugin-api';\nimport { qetaAIExtensionPoint } from '@drodil/backstage-plugin-qeta-node';\nimport { createQetaAiHandler } from './services/ai-handler';\nimport { aiAssistantServiceRef } from '@sweetoburrito/backstage-plugin-ai-assistant-node';\n\nexport const qetaModuleAiAssistant = createBackendModule({\n pluginId: 'qeta',\n moduleId: 'ai-assistant',\n register(reg) {\n reg.registerInit({\n deps: {\n qetaAi: qetaAIExtensionPoint,\n aiAssistant: aiAssistantServiceRef,\n auth: coreServices.auth,\n },\n async init(options) {\n const { qetaAi, ...rest } = options;\n qetaAi.setAIHandler(createQetaAiHandler(rest));\n },\n });\n },\n});\n"],"names":["createBackendModule","qetaAIExtensionPoint","aiAssistantServiceRef","coreServices","createQetaAiHandler"],"mappings":";;;;;;;AAQO,MAAM,wBAAwBA,oCAAA,CAAoB;AAAA,EACvD,QAAA,EAAU,MAAA;AAAA,EACV,QAAA,EAAU,cAAA;AAAA,EACV,SAAS,GAAA,EAAK;AACZ,IAAA,GAAA,CAAI,YAAA,CAAa;AAAA,MACf,IAAA,EAAM;AAAA,QACJ,MAAA,EAAQC,4CAAA;AAAA,QACR,WAAA,EAAaC,oDAAA;AAAA,QACb,MAAMC,6BAAA,CAAa;AAAA,OACrB;AAAA,MACA,MAAM,KAAK,OAAA,EAAS;AAClB,QAAA,MAAM,EAAE,MAAA,EAAQ,GAAG,IAAA,EAAK,GAAI,OAAA;AAC5B,QAAA,MAAA,CAAO,YAAA,CAAaC,6BAAA,CAAoB,IAAI,CAAC,CAAA;AAAA,MAC/C;AAAA,KACD,CAAA;AAAA,EACH;AACF,CAAC;;;;"}
@@ -0,0 +1,126 @@
1
+ 'use strict';
2
+
3
+ const ANSWER_SYSTEM_PROMPT = `You are an expert assistant that helps answer questions based on provided content.
4
+ Use the tools available to you to try answer the question as accurately as possible.
5
+ Do not ask for further information from the user or further calls to action.
6
+ `;
7
+ const TAG_SUGGESTION_SYSTEM_PROMPT = `You are an expert assistant that suggests relevant tags for content based on provided content.
8
+ Use the tools available to you to suggest the most relevant tags.
9
+ Return the tags as a comma-separated list.
10
+ Do not ask for further information from the user or further calls to action.
11
+ `;
12
+ const createQetaAiHandler = ({
13
+ auth,
14
+ aiAssistant
15
+ }) => {
16
+ const summarizeArticle = async (article) => {
17
+ const credentials = await auth.getOwnServiceCredentials();
18
+ const content = `Title: ${article.title}
19
+ Content: ${article.content}`;
20
+ const answer = await aiAssistant.summarize({
21
+ credentials,
22
+ content,
23
+ length: "a few sentences"
24
+ });
25
+ return {
26
+ answer
27
+ };
28
+ };
29
+ const suggestTags = async (title, description) => {
30
+ const credentials = await auth.getOwnServiceCredentials();
31
+ const content = `
32
+ Title: ${title}
33
+ Description: ${description}`;
34
+ const { messages } = await aiAssistant.prompt({
35
+ messages: [
36
+ {
37
+ role: "human",
38
+ content,
39
+ metadata: {},
40
+ score: 0
41
+ }
42
+ ],
43
+ credentials,
44
+ metadata: {
45
+ runName: "qeta-answer-suggest-tags",
46
+ userId: "system: qeta-ai-service"
47
+ },
48
+ systemPrompt: TAG_SUGGESTION_SYSTEM_PROMPT
49
+ });
50
+ const aiMessages = messages.filter((m) => m.role === "ai");
51
+ const tagString = aiMessages.pop()?.content ?? "";
52
+ const tags = tagString.split(",").map((tag) => tag.trim()).filter((tag) => tag.length > 0);
53
+ return {
54
+ tags
55
+ };
56
+ };
57
+ const answerNewQuestion = async (title, description) => {
58
+ const credentials = await auth.getOwnServiceCredentials();
59
+ const content = `
60
+ Title: ${title}
61
+ Description: ${description}
62
+ `;
63
+ const { messages } = await aiAssistant.prompt({
64
+ messages: [
65
+ {
66
+ role: "human",
67
+ content,
68
+ metadata: {},
69
+ score: 0
70
+ }
71
+ ],
72
+ credentials,
73
+ metadata: {
74
+ runName: "qeta-answer-new-question",
75
+ userId: "system: qeta-ai-service"
76
+ },
77
+ systemPrompt: ANSWER_SYSTEM_PROMPT
78
+ });
79
+ const aiMessages = messages.filter((m) => m.role === "ai");
80
+ const answer = aiMessages.pop()?.content ?? "No answer generated.";
81
+ return {
82
+ answer
83
+ };
84
+ };
85
+ const answerExistingQuestion = async (question) => {
86
+ const credentials = await auth.getOwnServiceCredentials();
87
+ const content = `
88
+ Title: ${question.title}
89
+ Content: ${question.content}
90
+ Tags: ${question.tags ? question.tags.join(", ") : "None"}
91
+ Author: ${question.author}
92
+ Experts: ${question.experts ? question.experts.join(", ") : "None"}
93
+ Answers: ${question.answers ? question.answers.map((answer2) => `
94
+ - Answer by ${answer2.author}: ${answer2.content}`).join("") : "None"}`;
95
+ const { messages } = await aiAssistant.prompt({
96
+ messages: [
97
+ {
98
+ role: "human",
99
+ content,
100
+ metadata: {},
101
+ score: 0
102
+ }
103
+ ],
104
+ credentials,
105
+ metadata: {
106
+ runName: "qeta-answer-existing-question",
107
+ userId: "system: qeta-ai-service"
108
+ },
109
+ systemPrompt: ANSWER_SYSTEM_PROMPT
110
+ });
111
+ const aiMessages = messages.filter((m) => m.role === "ai");
112
+ const answer = aiMessages.pop()?.content ?? "No answer generated.";
113
+ return {
114
+ answer
115
+ };
116
+ };
117
+ return {
118
+ answerNewQuestion,
119
+ answerExistingQuestion,
120
+ summarizeArticle,
121
+ suggestTags
122
+ };
123
+ };
124
+
125
+ exports.createQetaAiHandler = createQetaAiHandler;
126
+ //# sourceMappingURL=ai-handler.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-handler.cjs.js","sources":["../../src/services/ai-handler.ts"],"sourcesContent":["import { AuthService } from '@backstage/backend-plugin-api';\nimport { AIHandler } from '@drodil/backstage-plugin-qeta-node';\nimport { AiAssistantService } from '@sweetoburrito/backstage-plugin-ai-assistant-node';\n\ntype QetaAiHandlerOptions = {\n aiAssistant: AiAssistantService;\n auth: AuthService;\n};\n\nconst ANSWER_SYSTEM_PROMPT = `You are an expert assistant that helps answer questions based on provided content.\nUse the tools available to you to try answer the question as accurately as possible.\nDo not ask for further information from the user or further calls to action.\n`;\n\nconst TAG_SUGGESTION_SYSTEM_PROMPT = `You are an expert assistant that suggests relevant tags for content based on provided content.\nUse the tools available to you to suggest the most relevant tags.\nReturn the tags as a comma-separated list.\nDo not ask for further information from the user or further calls to action.\n`;\n\nexport const createQetaAiHandler = ({\n auth,\n aiAssistant,\n}: QetaAiHandlerOptions): AIHandler => {\n const summarizeArticle: AIHandler['summarizeArticle'] = async article => {\n const credentials = await auth.getOwnServiceCredentials();\n\n const content = `Title: ${article.title}\\nContent: ${article.content}`;\n\n const answer = await aiAssistant.summarize({\n credentials,\n content,\n length: 'a few sentences',\n });\n\n return {\n answer,\n };\n };\n\n const suggestTags: AIHandler['suggestTags'] = async (title, description) => {\n const credentials = await auth.getOwnServiceCredentials();\n\n const content = `\n Title: ${title}\n Description: ${description}`;\n\n const { messages } = await aiAssistant.prompt({\n messages: [\n {\n role: 'human',\n content,\n metadata: {},\n score: 0,\n },\n ],\n credentials,\n metadata: {\n runName: 'qeta-answer-suggest-tags',\n userId: 'system: qeta-ai-service',\n },\n systemPrompt: TAG_SUGGESTION_SYSTEM_PROMPT,\n });\n\n const aiMessages = messages.filter(m => m.role === 'ai');\n\n const tagString = aiMessages.pop()?.content ?? '';\n\n const tags = tagString\n .split(',')\n .map(tag => tag.trim())\n .filter(tag => tag.length > 0);\n\n return {\n tags,\n };\n };\n\n const answerNewQuestion: AIHandler['answerNewQuestion'] = async (\n title,\n description,\n ) => {\n const credentials = await auth.getOwnServiceCredentials();\n\n const content = `\n Title: ${title}\n Description: ${description}\n `;\n\n const { messages } = await aiAssistant.prompt({\n messages: [\n {\n role: 'human',\n content,\n metadata: {},\n score: 0,\n },\n ],\n credentials,\n metadata: {\n runName: 'qeta-answer-new-question',\n userId: 'system: qeta-ai-service',\n },\n systemPrompt: ANSWER_SYSTEM_PROMPT,\n });\n\n const aiMessages = messages.filter(m => m.role === 'ai');\n\n const answer = aiMessages.pop()?.content ?? 'No answer generated.';\n\n return {\n answer,\n };\n };\n\n const answerExistingQuestion: AIHandler['answerExistingQuestion'] =\n async question => {\n const credentials = await auth.getOwnServiceCredentials();\n\n const content = `\n Title: ${question.title}\n Content: ${question.content}\n Tags: ${question.tags ? question.tags.join(', ') : 'None'}\n Author: ${question.author}\n Experts: ${question.experts ? question.experts.join(', ') : 'None'}\n Answers: ${\n question.answers\n ? question.answers\n .map(answer => `\\n- Answer by ${answer.author}: ${answer.content}`)\n .join('')\n : 'None'\n }`;\n\n const { messages } = await aiAssistant.prompt({\n messages: [\n {\n role: 'human',\n content,\n metadata: {},\n score: 0,\n },\n ],\n credentials,\n metadata: {\n runName: 'qeta-answer-existing-question',\n userId: 'system: qeta-ai-service',\n },\n systemPrompt: ANSWER_SYSTEM_PROMPT,\n });\n\n const aiMessages = messages.filter(m => m.role === 'ai');\n\n const answer = aiMessages.pop()?.content ?? 'No answer generated.';\n\n return {\n answer,\n };\n };\n\n return {\n answerNewQuestion,\n answerExistingQuestion,\n summarizeArticle,\n suggestTags,\n };\n};\n"],"names":["answer"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@sweetoburrito/backstage-plugin-qeta-backend-module-ai-assistant",
3
+ "version": "0.0.0-snapshot-20251210121031",
4
+ "license": "Apache-2.0",
5
+ "description": "The ai-assistant backend module for the qeta plugin.",
6
+ "main": "dist/index.cjs.js",
7
+ "types": "dist/index.d.ts",
8
+ "publishConfig": {
9
+ "access": "public",
10
+ "main": "dist/index.cjs.js",
11
+ "types": "dist/index.d.ts"
12
+ },
13
+ "backstage": {
14
+ "role": "backend-plugin-module",
15
+ "pluginId": "qeta",
16
+ "pluginPackage": "@drodil/backstage-plugin-qeta-backend",
17
+ "features": {
18
+ ".": "@backstage/BackendFeature"
19
+ }
20
+ },
21
+ "scripts": {
22
+ "start": "backstage-cli package start",
23
+ "build": "backstage-cli package build",
24
+ "lint": "backstage-cli package lint",
25
+ "test": "backstage-cli package test",
26
+ "clean": "backstage-cli package clean",
27
+ "prepack": "backstage-cli package prepack",
28
+ "postpack": "backstage-cli package postpack"
29
+ },
30
+ "dependencies": {
31
+ "@backstage/backend-plugin-api": "backstage:^",
32
+ "@drodil/backstage-plugin-qeta-node": "^3.46.0",
33
+ "@sweetoburrito/backstage-plugin-ai-assistant-node": "workspace:^"
34
+ },
35
+ "devDependencies": {
36
+ "@backstage/backend-test-utils": "backstage:^",
37
+ "@backstage/cli": "backstage:^"
38
+ },
39
+ "files": [
40
+ "dist"
41
+ ],
42
+ "typesVersions": {
43
+ "*": {
44
+ "package.json": [
45
+ "package.json"
46
+ ]
47
+ }
48
+ }
49
+ }