@oas-tools/oas-telemetry 0.7.0-alpha.5 → 0.7.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/.env.example +2 -0
- package/README.md +35 -17
- package/dist/cjs/config/bootConfig.cjs +3 -1
- package/dist/cjs/docs/openapi.yaml +1399 -0
- package/dist/cjs/routesManager.cjs +1 -1
- package/dist/cjs/telemetry/custom-implementations/exporters/InMemoryDbLogExporter.cjs +43 -13
- package/dist/cjs/telemetry/custom-implementations/exporters/InMemoryDbMetricExporter.cjs +10 -2
- package/dist/cjs/telemetry/custom-implementations/exporters/InMemoryDbSpanExporter.cjs +21 -16
- package/dist/cjs/telemetry/initializeTelemetry.cjs +39 -15
- package/dist/cjs/telemetry/telemetryConfigurator.cjs +6 -9
- package/dist/cjs/telemetry/telemetryRegistry.cjs +11 -8
- package/dist/cjs/tlm-ai/agent.cjs +54 -84
- package/dist/cjs/tlm-ai/aiController.cjs +69 -47
- package/dist/cjs/tlm-ai/aiRoutes.cjs +10 -3
- package/dist/cjs/tlm-ai/aiService.cjs +109 -0
- package/dist/cjs/tlm-ai/tools.cjs +30 -268
- package/dist/cjs/tlm-auth/authController.cjs +9 -9
- package/dist/cjs/tlm-auth/authMiddleware.cjs +1 -1
- package/dist/cjs/tlm-log/logController.cjs +30 -36
- package/dist/cjs/tlm-log/logRoutes.cjs +3 -2
- package/dist/cjs/tlm-metric/metricsController.cjs +15 -8
- package/dist/cjs/tlm-metric/metricsRoutes.cjs +2 -1
- package/dist/cjs/tlm-plugin/pluginController.cjs +11 -1
- package/dist/cjs/tlm-plugin/pluginProcess.cjs +4 -2
- package/dist/cjs/tlm-plugin/pluginService.cjs +3 -0
- package/dist/cjs/tlm-trace/traceController.cjs +16 -9
- package/dist/cjs/tlm-trace/traceRoutes.cjs +2 -1
- package/dist/cjs/tlm-util/utilController.cjs +23 -2
- package/dist/cjs/tlm-util/utilRoutes.cjs +44 -5
- package/dist/cjs/utils/logger.cjs +35 -13
- package/dist/esm/config/bootConfig.js +2 -0
- package/dist/esm/docs/openapi.yaml +1399 -0
- package/dist/esm/routesManager.js +1 -1
- package/dist/esm/telemetry/custom-implementations/exporters/InMemoryDbLogExporter.js +32 -11
- package/dist/esm/telemetry/custom-implementations/exporters/InMemoryDbMetricExporter.js +10 -2
- package/dist/esm/telemetry/custom-implementations/exporters/InMemoryDbSpanExporter.js +20 -13
- package/dist/esm/telemetry/initializeTelemetry.js +22 -14
- package/dist/esm/telemetry/telemetryConfigurator.js +7 -10
- package/dist/esm/telemetry/telemetryRegistry.js +10 -7
- package/dist/esm/tlm-ai/agent.js +37 -78
- package/dist/esm/tlm-ai/aiController.js +56 -39
- package/dist/esm/tlm-ai/aiRoutes.js +11 -4
- package/dist/esm/tlm-ai/aiService.js +94 -0
- package/dist/esm/tlm-ai/tools.js +29 -255
- package/dist/esm/tlm-auth/authController.js +8 -8
- package/dist/esm/tlm-auth/authMiddleware.js +1 -1
- package/dist/esm/tlm-log/logController.js +26 -28
- package/dist/esm/tlm-log/logRoutes.js +4 -3
- package/dist/esm/tlm-metric/metricsController.js +10 -6
- package/dist/esm/tlm-metric/metricsRoutes.js +3 -2
- package/dist/esm/tlm-plugin/pluginController.js +2 -1
- package/dist/esm/tlm-plugin/pluginProcess.js +4 -2
- package/dist/esm/tlm-plugin/pluginService.js +4 -0
- package/dist/esm/tlm-trace/traceController.js +11 -7
- package/dist/esm/tlm-trace/traceRoutes.js +3 -2
- package/dist/esm/tlm-util/utilController.js +22 -0
- package/dist/esm/tlm-util/utilRoutes.js +40 -5
- package/dist/esm/utils/logger.js +35 -12
- package/dist/types/config/bootConfig.d.ts +1 -0
- package/dist/types/telemetry/custom-implementations/exporters/InMemoryDbLogExporter.d.ts +7 -1
- package/dist/types/telemetry/custom-implementations/exporters/InMemoryDbMetricExporter.d.ts +1 -0
- package/dist/types/telemetry/custom-implementations/exporters/InMemoryDbSpanExporter.d.ts +1 -0
- package/dist/types/telemetry/telemetryRegistry.d.ts +22 -6
- package/dist/types/tlm-ai/agent.d.ts +2 -2
- package/dist/types/tlm-ai/aiController.d.ts +5 -4
- package/dist/types/tlm-ai/aiRoutes.d.ts +1 -1
- package/dist/types/tlm-ai/aiService.d.ts +38 -0
- package/dist/types/tlm-ai/tools.d.ts +5 -14
- package/dist/types/tlm-log/logController.d.ts +2 -2
- package/dist/types/tlm-metric/metricsController.d.ts +2 -1
- package/dist/types/tlm-plugin/pluginService.d.ts +2 -0
- package/dist/types/tlm-trace/traceController.d.ts +2 -1
- package/dist/types/tlm-util/utilController.d.ts +1 -0
- package/dist/types/utils/logger.d.ts +5 -5
- package/dist/ui/assets/ApiDocsPage-C_VVPPHa.js +16 -0
- package/dist/ui/assets/CollapsibleCard-B3KR_8mL.js +1 -0
- package/dist/ui/assets/DevToolsPage-OyZcDcmw.js +1 -0
- package/dist/ui/assets/LandingPage-CppFBA6K.js +6 -0
- package/dist/ui/assets/LogsPage-9Fq8GArS.js +26 -0
- package/dist/ui/assets/NotFoundPage-B3quk3P1.js +1 -0
- package/dist/ui/assets/PluginCreatePage-X_aCH4t4.js +50 -0
- package/dist/ui/assets/PluginPage-DMDSihrZ.js +27 -0
- package/dist/ui/assets/alert-jQ9HCPIf.js +1133 -0
- package/dist/ui/assets/badge-CNq0-mH5.js +1 -0
- package/dist/ui/assets/card-DFAwwhN3.js +1 -0
- package/dist/ui/assets/chevron-down-CPsvsmqj.js +6 -0
- package/dist/ui/assets/chevron-up-Df9jMo1X.js +6 -0
- package/dist/ui/assets/circle-alert-DOPQPvU8.js +6 -0
- package/dist/ui/assets/index-BkD6DijD.js +15 -0
- package/dist/ui/assets/index-CERGVYZK.js +292 -0
- package/dist/ui/assets/index-CSIPf9qw.css +1 -0
- package/dist/ui/assets/input-Dzvg_ZEZ.js +1 -0
- package/dist/ui/assets/label-DuVnkZ4q.js +1 -0
- package/dist/ui/assets/loader-circle-CrvlRy5o.js +6 -0
- package/dist/ui/assets/loginPage-qa4V-B70.js +6 -0
- package/dist/ui/assets/select-DhS8YUtJ.js +1 -0
- package/dist/ui/assets/separator-isK4chBP.js +6 -0
- package/dist/ui/assets/severityOptions-O38dSOfk.js +11 -0
- package/dist/ui/assets/switch-Z3mImG9n.js +1 -0
- package/dist/ui/assets/tabs-_77MUUQe.js +16 -0
- package/dist/ui/assets/upload-C1LT4Gkb.js +16 -0
- package/dist/ui/assets/utilService-DNyqzwj0.js +1 -0
- package/dist/ui/index.html +2 -2
- package/package.json +17 -6
- package/dist/ui/assets/index-Bgd7fFFH.js +0 -1743
- package/dist/ui/assets/index-Cz3N1n1Q.css +0 -1
|
@@ -3,68 +3,90 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
exports.createConversation = createConversation;
|
|
7
|
+
exports.deleteConversation = deleteConversation;
|
|
8
|
+
exports.getConversationHistory = getConversationHistory;
|
|
9
|
+
exports.listConversations = listConversations;
|
|
10
|
+
exports.sendMessage = sendMessage;
|
|
11
|
+
var _aiService = require("./aiService.cjs");
|
|
12
|
+
async function createConversation(req, res) {
|
|
12
13
|
try {
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
error:
|
|
18
|
-
});
|
|
19
|
-
const getAgentResponse = (0, _agent.getAgent)(oasTlmConfig);
|
|
20
|
-
const answer = await getAgentResponse(question);
|
|
21
|
-
res.json({
|
|
22
|
-
answer
|
|
14
|
+
const conversation = (0, _aiService.getAiService)().createConversation();
|
|
15
|
+
res.status(201).json(conversation);
|
|
16
|
+
} catch (err) {
|
|
17
|
+
res.status(500).json({
|
|
18
|
+
error: err.message
|
|
23
19
|
});
|
|
24
|
-
}
|
|
25
|
-
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
async function listConversations(req, res) {
|
|
23
|
+
try {
|
|
24
|
+
// Only return id and name for each conversation
|
|
25
|
+
const conversations = (0, _aiService.getAiService)().listConversationsMinimal();
|
|
26
|
+
res.json(conversations);
|
|
27
|
+
} catch (err) {
|
|
26
28
|
res.status(500).json({
|
|
27
|
-
error:
|
|
29
|
+
error: err.message
|
|
28
30
|
});
|
|
29
31
|
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const setKnownMicroservicesHandler = () => (req, res) => {
|
|
32
|
+
}
|
|
33
|
+
async function getConversationHistory(req, res) {
|
|
33
34
|
try {
|
|
34
35
|
const {
|
|
35
|
-
|
|
36
|
-
} = req.
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
conversationId
|
|
37
|
+
} = req.params;
|
|
38
|
+
const conversation = (0, _aiService.getAiService)().getConversation(conversationId);
|
|
39
|
+
if (!conversation) {
|
|
40
|
+
res.status(404).json({
|
|
41
|
+
error: 'Not found'
|
|
40
42
|
});
|
|
41
43
|
return;
|
|
42
44
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
message: "Microservices configuration updated successfully.",
|
|
46
|
-
knownMicroservices: (0, _knownMicroservices.getKnownMicroservices)(),
|
|
47
|
-
note: "In the future, OAS-Telemetry will support autodiscovery, making this configuration unnecessary."
|
|
48
|
-
});
|
|
49
|
-
} catch (error) {
|
|
50
|
-
_logger.default.error(error);
|
|
45
|
+
res.json(conversation);
|
|
46
|
+
} catch (err) {
|
|
51
47
|
res.status(500).json({
|
|
52
|
-
error:
|
|
48
|
+
error: err.message
|
|
53
49
|
});
|
|
54
50
|
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const getKnownMicroservicesHandler = () => (req, res) => {
|
|
51
|
+
}
|
|
52
|
+
async function deleteConversation(req, res) {
|
|
58
53
|
try {
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
54
|
+
const {
|
|
55
|
+
conversationId
|
|
56
|
+
} = req.params;
|
|
57
|
+
const deleted = (0, _aiService.getAiService)().deleteConversation(conversationId);
|
|
58
|
+
if (!deleted) {
|
|
59
|
+
res.status(404).json({
|
|
60
|
+
error: 'Not found'
|
|
61
|
+
});
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
res.status(204).send();
|
|
65
|
+
} catch (err) {
|
|
66
|
+
res.status(500).json({
|
|
67
|
+
error: err.message
|
|
62
68
|
});
|
|
63
|
-
}
|
|
64
|
-
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
async function sendMessage(req, res) {
|
|
72
|
+
try {
|
|
73
|
+
const {
|
|
74
|
+
conversationId
|
|
75
|
+
} = req.params;
|
|
76
|
+
const {
|
|
77
|
+
content
|
|
78
|
+
} = req.body;
|
|
79
|
+
if (!content) {
|
|
80
|
+
res.status(400).json({
|
|
81
|
+
error: 'Missing content'
|
|
82
|
+
});
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const messages = await (0, _aiService.getAiService)().sendMessage(conversationId, content);
|
|
86
|
+
res.json(messages);
|
|
87
|
+
} catch (err) {
|
|
65
88
|
res.status(500).json({
|
|
66
|
-
error:
|
|
89
|
+
error: err.message
|
|
67
90
|
});
|
|
68
91
|
}
|
|
69
|
-
}
|
|
70
|
-
exports.getKnownMicroservicesHandler = getKnownMicroservicesHandler;
|
|
92
|
+
}
|
|
@@ -6,11 +6,18 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.getAIRoutes = void 0;
|
|
7
7
|
var _express = require("express");
|
|
8
8
|
var _aiController = require("./aiController.cjs");
|
|
9
|
+
var _aiService = require("./aiService.cjs");
|
|
9
10
|
const getAIRoutes = oasTlmConfig => {
|
|
10
11
|
const router = (0, _express.Router)();
|
|
11
|
-
|
|
12
|
-
router.
|
|
13
|
-
|
|
12
|
+
(0, _aiService.configureAiService)(oasTlmConfig); //oasTlmConfig.ai.openAIKey
|
|
13
|
+
router.get('/chat/health', (req, res) => {
|
|
14
|
+
res.status(200).send('AI service is healthy');
|
|
15
|
+
});
|
|
16
|
+
router.get('/chat', _aiController.listConversations);
|
|
17
|
+
router.post('/chat', _aiController.createConversation);
|
|
18
|
+
router.get('/chat/:conversationId', _aiController.getConversationHistory);
|
|
19
|
+
router.post('/chat/:conversationId/message', _aiController.sendMessage);
|
|
20
|
+
router.delete('/chat/:conversationId', _aiController.deleteConversation);
|
|
14
21
|
return router;
|
|
15
22
|
};
|
|
16
23
|
exports.getAIRoutes = getAIRoutes;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.configureAiService = configureAiService;
|
|
7
|
+
exports.getAiService = getAiService;
|
|
8
|
+
var _openai = _interopRequireDefault(require("openai"));
|
|
9
|
+
var _agent = require("./agent.cjs");
|
|
10
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
|
+
class AIService {
|
|
12
|
+
constructor(config) {
|
|
13
|
+
this.config = config;
|
|
14
|
+
this.conversations = new Map();
|
|
15
|
+
this.openai = new _openai.default({
|
|
16
|
+
apiKey: this.config.apiKey
|
|
17
|
+
});
|
|
18
|
+
this.model = config.model;
|
|
19
|
+
this.extraPrompts = config.extraPrompts || [];
|
|
20
|
+
}
|
|
21
|
+
createConversation() {
|
|
22
|
+
const id = Math.random().toString(36).substring(2, 15);
|
|
23
|
+
const conversation = {
|
|
24
|
+
id,
|
|
25
|
+
messages: []
|
|
26
|
+
};
|
|
27
|
+
this.conversations.set(id, conversation);
|
|
28
|
+
return conversation;
|
|
29
|
+
}
|
|
30
|
+
listConversations() {
|
|
31
|
+
return Array.from(this.conversations.values());
|
|
32
|
+
}
|
|
33
|
+
getConversation(id) {
|
|
34
|
+
return this.conversations.get(id);
|
|
35
|
+
}
|
|
36
|
+
deleteConversation(id) {
|
|
37
|
+
return this.conversations.delete(id);
|
|
38
|
+
}
|
|
39
|
+
async sendMessage(conversationId, content, model) {
|
|
40
|
+
const conversation = this.conversations.get(conversationId);
|
|
41
|
+
if (!conversation) throw new Error('Conversation not found');
|
|
42
|
+
conversation.messages.push({
|
|
43
|
+
role: 'system',
|
|
44
|
+
timestamp: new Date().toISOString(),
|
|
45
|
+
content: "This is a telemetry chat. Focus your replies strictly on the topics and instructions defined by the system prompts and the available tools. Do not answer outside of these boundaries. Reply in the same language as the question."
|
|
46
|
+
});
|
|
47
|
+
if (this.extraPrompts.length > 0) {
|
|
48
|
+
this.extraPrompts.forEach(prompt => {
|
|
49
|
+
conversation.messages.push({
|
|
50
|
+
role: 'system',
|
|
51
|
+
content: prompt,
|
|
52
|
+
timestamp: new Date().toISOString()
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
conversation.messages.push({
|
|
57
|
+
role: 'user',
|
|
58
|
+
content,
|
|
59
|
+
timestamp: new Date().toISOString()
|
|
60
|
+
});
|
|
61
|
+
// Set conversation name if not set
|
|
62
|
+
if (!('name' in conversation) || !conversation.name) {
|
|
63
|
+
conversation.name = content.slice(0, 30);
|
|
64
|
+
}
|
|
65
|
+
// Use the agent function with tools
|
|
66
|
+
// Internaly pushes new messages to conversation.messages
|
|
67
|
+
const currentMessagesCount = conversation.messages.length;
|
|
68
|
+
await (0, _agent.agent)(this.openai, conversation.messages, model || this.model, this.extraPrompts);
|
|
69
|
+
// Return the last assistant message (the one just added by agent)
|
|
70
|
+
const generatedMessages = conversation.messages.slice(currentMessagesCount);
|
|
71
|
+
return generatedMessages;
|
|
72
|
+
}
|
|
73
|
+
listConversationsMinimal() {
|
|
74
|
+
return Array.from(this.conversations.values()).map(c => ({
|
|
75
|
+
id: c.id,
|
|
76
|
+
name: c.name
|
|
77
|
+
}));
|
|
78
|
+
}
|
|
79
|
+
async listModels() {
|
|
80
|
+
const {
|
|
81
|
+
data
|
|
82
|
+
} = await this.openai.models.list();
|
|
83
|
+
return data.map(m => m.id).sort();
|
|
84
|
+
}
|
|
85
|
+
async isValidModel(modelId) {
|
|
86
|
+
try {
|
|
87
|
+
await this.openai.models.retrieve(modelId);
|
|
88
|
+
return true;
|
|
89
|
+
} catch {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
let aiService;
|
|
95
|
+
function configureAiService(config) {
|
|
96
|
+
const openAIKey = config.ai?.openAIKey;
|
|
97
|
+
const model = config.ai.openAIModel;
|
|
98
|
+
const extraPrompts = config.ai.extraContextPrompts;
|
|
99
|
+
if (!openAIKey) throw new Error('OpenAI API key is required');
|
|
100
|
+
aiService = new AIService({
|
|
101
|
+
apiKey: openAIKey,
|
|
102
|
+
model,
|
|
103
|
+
extraPrompts
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
function getAiService() {
|
|
107
|
+
if (!aiService) throw new Error('AI Service not configured');
|
|
108
|
+
return aiService;
|
|
109
|
+
}
|
|
@@ -4,9 +4,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.tools = exports.availableTools = void 0;
|
|
7
|
-
var _axios = _interopRequireDefault(require("axios"));
|
|
8
7
|
var _logger = _interopRequireDefault(require("../utils/logger.cjs"));
|
|
9
|
-
var _knownMicroservices = require("./knownMicroservices.cjs");
|
|
10
8
|
var _telemetryRegistry = require("../telemetry/telemetryRegistry.cjs");
|
|
11
9
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
12
10
|
const getTraces = async searchInput => {
|
|
@@ -32,31 +30,22 @@ const getTraces = async searchInput => {
|
|
|
32
30
|
const getLogs = async (startDate, endDate) => {
|
|
33
31
|
_logger.default.debug("getLogs called with startDate:", startDate, "endDate:", endDate);
|
|
34
32
|
try {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
if (err) {
|
|
52
|
-
reject(err);
|
|
53
|
-
} else {
|
|
54
|
-
logs.push(...docs);
|
|
55
|
-
_logger.default.debug(`Found ${logs.length} logs in the specified range.`);
|
|
56
|
-
resolve();
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
});
|
|
33
|
+
// Timestamps are stored in microseconds in the DB (must multiply by 1000)
|
|
34
|
+
const startEpoch = startDate ? new Date(startDate).getTime() * 1000 : 0;
|
|
35
|
+
const endEpoch = endDate ? new Date(endDate).getTime() * 1000 : Date.now() * 1000;
|
|
36
|
+
_logger.default.debug(`Fetching logs from ${startEpoch} to ${endEpoch}`);
|
|
37
|
+
const nedbQuery = {
|
|
38
|
+
timestamp: {
|
|
39
|
+
$gte: startEpoch,
|
|
40
|
+
$lte: endEpoch
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
const logs = (await _telemetryRegistry.inMemoryDbLogExporter.find({
|
|
44
|
+
query: nedbQuery,
|
|
45
|
+
messageSearch: null,
|
|
46
|
+
limit: 50 // or any appropriate limit
|
|
47
|
+
})) || [];
|
|
48
|
+
_logger.default.debug(`Found ${logs.length} logs in the specified range.`);
|
|
60
49
|
const simplifiedLogs = getSimplifiedLogs(logs);
|
|
61
50
|
return {
|
|
62
51
|
logs: simplifiedLogs
|
|
@@ -66,34 +55,6 @@ const getLogs = async (startDate, endDate) => {
|
|
|
66
55
|
throw error;
|
|
67
56
|
}
|
|
68
57
|
};
|
|
69
|
-
const getMetrics = async searchInput => {
|
|
70
|
-
_logger.default.debug("getMetrics called with searchInput:", searchInput);
|
|
71
|
-
try {
|
|
72
|
-
const search = searchInput || {};
|
|
73
|
-
const metrics = await new Promise((resolve, reject) => {
|
|
74
|
-
_telemetryRegistry.inMemoryDbMetricExporter.find(search, (err, docs) => {
|
|
75
|
-
if (err) reject(err);else resolve(docs || []);
|
|
76
|
-
});
|
|
77
|
-
});
|
|
78
|
-
const simplifiedMetrics = getSimplifiedMetrics(metrics);
|
|
79
|
-
_logger.default.debug(`Searching for metrics with searchInput: ${JSON.stringify(search)}`);
|
|
80
|
-
_logger.default.debug(`Metrics found: ${JSON.stringify(simplifiedMetrics.length)}`);
|
|
81
|
-
return {
|
|
82
|
-
metrics: simplifiedMetrics
|
|
83
|
-
};
|
|
84
|
-
} catch (error) {
|
|
85
|
-
_logger.default.error('Error fetching metrics:', error);
|
|
86
|
-
throw error;
|
|
87
|
-
}
|
|
88
|
-
};
|
|
89
|
-
const getCurrentTimestampInEpoch = () => {
|
|
90
|
-
_logger.default.debug("Getting the current timestamp in epoch format...");
|
|
91
|
-
const now = new Date();
|
|
92
|
-
return {
|
|
93
|
-
currentTimestampInEpoch: now.getTime(),
|
|
94
|
-
currentTimestampInEpochSeconds: Math.floor(now.getTime() / 1000)
|
|
95
|
-
};
|
|
96
|
-
};
|
|
97
58
|
const startTelemetry = () => {
|
|
98
59
|
_logger.default.debug("Starting telemetry...");
|
|
99
60
|
_telemetryRegistry.inMemoryDbSpanExporter.enable();
|
|
@@ -120,29 +81,13 @@ const getTelemetryStatus = () => {
|
|
|
120
81
|
metricsEnabled: _telemetryRegistry.inMemoryDbMetricExporter.isEnabled()
|
|
121
82
|
};
|
|
122
83
|
};
|
|
123
|
-
const
|
|
124
|
-
_logger.default.debug("
|
|
125
|
-
const
|
|
126
|
-
const identifiedMicroservice = knownMicroservices.find(m => m.id === microserviceId);
|
|
127
|
-
if (!identifiedMicroservice) {
|
|
128
|
-
_logger.default.error(`Agent tried to call an unknown microservice: ${microserviceId}, available microservices: ${knownMicroservices.map(m => m.id).join(', ')}`);
|
|
129
|
-
return {
|
|
130
|
-
microservice: microserviceId,
|
|
131
|
-
response: `I cannot help with that. The microservice ${microserviceId} is not recognized. Available microservices are: ${knownMicroservices.map(m => m.id).join(', ')}`
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
const microserviceResponse = await _axios.default.post(identifiedMicroservice.url, {
|
|
135
|
-
question: message
|
|
136
|
-
});
|
|
84
|
+
const getCurrentDate = () => {
|
|
85
|
+
_logger.default.debug("Getting the current date in ISO format...");
|
|
86
|
+
const now = new Date();
|
|
137
87
|
return {
|
|
138
|
-
|
|
139
|
-
response: microserviceResponse.data
|
|
88
|
+
currentDateISO: now.toISOString()
|
|
140
89
|
};
|
|
141
90
|
};
|
|
142
|
-
const getMicroserviceAgents = () => {
|
|
143
|
-
_logger.default.debug("Getting microservice agents...");
|
|
144
|
-
return (0, _knownMicroservices.getKnownMicroservices)();
|
|
145
|
-
};
|
|
146
91
|
const tools = exports.tools = [{
|
|
147
92
|
type: "function",
|
|
148
93
|
function: {
|
|
@@ -231,7 +176,8 @@ const tools = exports.tools = [{
|
|
|
231
176
|
description: `Fetches log data for the microservice.
|
|
232
177
|
Logs provide information about system events, including timestamps, log levels (e.g., info, error), and messages.
|
|
233
178
|
The 'startDate' and 'endDate' parameters define the time range for fetching logs.
|
|
234
|
-
If
|
|
179
|
+
If you need a date, you MUST first call the "getCurrentDate" tool to obtain the current date in ISO format, and then use it as a parameter.
|
|
180
|
+
If you don't provide a range, all logs will be fetched. Providing a specific range improves performance.
|
|
235
181
|
Example 'startDate' and 'endDate':
|
|
236
182
|
{
|
|
237
183
|
"startDate": "2023-10-01T00:00:00Z",
|
|
@@ -250,54 +196,6 @@ const tools = exports.tools = [{
|
|
|
250
196
|
}
|
|
251
197
|
}
|
|
252
198
|
}
|
|
253
|
-
}, {
|
|
254
|
-
type: "function",
|
|
255
|
-
function: {
|
|
256
|
-
name: "getMetrics",
|
|
257
|
-
description: `Fetches metrics data for the microservice.
|
|
258
|
-
Metrics provide performance-related data, such as CPU usage, memory usage, and process-specific metrics.
|
|
259
|
-
The 'searchInput' parameter is an object used to filter metrics based on specific criteria.
|
|
260
|
-
This is a NeDB query using MongoDB-like (NeDB) syntax. If 'searchInput' is null, all metrics will be fetched. Providing specific filters improves performance.
|
|
261
|
-
|
|
262
|
-
Example 'searchInput':
|
|
263
|
-
{
|
|
264
|
-
"timestamp": { "$gte": 1747651105757, "$lte": 1747651200935 }
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
Common filters include timestamps.`,
|
|
268
|
-
parameters: {
|
|
269
|
-
type: "object",
|
|
270
|
-
properties: {
|
|
271
|
-
searchInput: {
|
|
272
|
-
type: "object",
|
|
273
|
-
description: `Optional search criteria for filtering metrics.
|
|
274
|
-
This is a NeDB query using MongoDB-like (NeDB) syntax.
|
|
275
|
-
For example, you can filter by timestamps.
|
|
276
|
-
If null, all metrics will be returned.`,
|
|
277
|
-
properties: {
|
|
278
|
-
"timestamp": {
|
|
279
|
-
type: "object",
|
|
280
|
-
properties: {
|
|
281
|
-
"$gte": {
|
|
282
|
-
type: "integer"
|
|
283
|
-
},
|
|
284
|
-
"$lte": {
|
|
285
|
-
type: "integer"
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
},
|
|
289
|
-
"cpuUsageData.cpuNumber": {
|
|
290
|
-
type: "string"
|
|
291
|
-
},
|
|
292
|
-
"memoryData.used": {
|
|
293
|
-
type: "integer"
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
},
|
|
298
|
-
required: ["searchInput"]
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
199
|
}, {
|
|
302
200
|
type: "function",
|
|
303
201
|
function: {
|
|
@@ -333,158 +231,21 @@ const tools = exports.tools = [{
|
|
|
333
231
|
}, {
|
|
334
232
|
type: "function",
|
|
335
233
|
function: {
|
|
336
|
-
name: "
|
|
337
|
-
description: `
|
|
338
|
-
|
|
339
|
-
parameters: {}
|
|
340
|
-
}
|
|
341
|
-
}, {
|
|
342
|
-
type: "function",
|
|
343
|
-
function: {
|
|
344
|
-
name: "talkToExternalMicroserviceAgent",
|
|
345
|
-
description: `Use this function to communicate with external microservice agent.
|
|
346
|
-
if you want to talk to a microservice agent, you must provide the message and the microservice you want to talk to.
|
|
347
|
-
When you call this function, it will send the message to the specified microservice and return the response.
|
|
348
|
-
|
|
349
|
-
Example 'message':
|
|
350
|
-
{
|
|
351
|
-
"message": "What is the status of the service?",
|
|
352
|
-
"microservice": "Reporter"
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
Microservices Availables (by ID):
|
|
356
|
-
${(0, _knownMicroservices.getKnownMicroservices)().map(m => m.id).join(", ")}
|
|
357
|
-
`,
|
|
358
|
-
parameters: {
|
|
359
|
-
type: "object",
|
|
360
|
-
properties: {
|
|
361
|
-
message: {
|
|
362
|
-
type: "string",
|
|
363
|
-
description: `The message to be sent to the external microservice agent.`
|
|
364
|
-
},
|
|
365
|
-
microservice: {
|
|
366
|
-
type: "string"
|
|
367
|
-
}
|
|
368
|
-
},
|
|
369
|
-
required: ["message", "microservice"]
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
}, {
|
|
373
|
-
type: "function",
|
|
374
|
-
function: {
|
|
375
|
-
name: "getMicroserviceAgents",
|
|
376
|
-
description: `Retrieves the list of available microservice agents.
|
|
377
|
-
This function provides information about the microservices that can be communicated with.`,
|
|
234
|
+
name: "getCurrentDate",
|
|
235
|
+
description: `Returns the current date in ISO 8601 format (e.g., "2024-06-07T12:34:56.789Z").
|
|
236
|
+
Use this tool to obtain the current date when you need to specify a date for other tools, such as "getLogs".`,
|
|
378
237
|
parameters: {}
|
|
379
238
|
}
|
|
380
239
|
}];
|
|
381
240
|
const availableTools = exports.availableTools = {
|
|
382
241
|
getTraces,
|
|
383
242
|
getLogs,
|
|
384
|
-
getMetrics,
|
|
385
243
|
startTelemetry,
|
|
386
244
|
stopTelemetry,
|
|
387
245
|
resetTelemetry,
|
|
388
246
|
getTelemetryStatus,
|
|
389
|
-
|
|
390
|
-
talkToExternalMicroserviceAgent,
|
|
391
|
-
getMicroserviceAgents
|
|
247
|
+
getCurrentDate
|
|
392
248
|
};
|
|
393
|
-
function getSimplifiedMetrics(metrics) {
|
|
394
|
-
return metrics.map(resourceMetric => {
|
|
395
|
-
const serviceName = resourceMetric.resource?._memoizedAttributes?.service?.name || 'unknown-service';
|
|
396
|
-
const cpuUtilization = {};
|
|
397
|
-
let cpuCount = 0;
|
|
398
|
-
const memoryUsageMB = {
|
|
399
|
-
used: 0,
|
|
400
|
-
free: 0
|
|
401
|
-
};
|
|
402
|
-
const memoryUtilizationPercent = {
|
|
403
|
-
used: 0,
|
|
404
|
-
free: 0
|
|
405
|
-
};
|
|
406
|
-
const networkIO = {
|
|
407
|
-
transmit: 0,
|
|
408
|
-
receive: 0
|
|
409
|
-
};
|
|
410
|
-
const processCPU = {};
|
|
411
|
-
let processMemoryUsage = 0;
|
|
412
|
-
for (const scopeMetric of resourceMetric.scopeMetrics) {
|
|
413
|
-
for (const metric of scopeMetric.metrics) {
|
|
414
|
-
const name = metric.descriptor.name;
|
|
415
|
-
if (name === 'system.cpu.utilization') {
|
|
416
|
-
const stateSums = {};
|
|
417
|
-
const stateCounts = {};
|
|
418
|
-
for (const dp of metric.dataPoints) {
|
|
419
|
-
const state = dp.attributes?.system?.cpu?.state;
|
|
420
|
-
if (!state) continue;
|
|
421
|
-
// @ts-expect-error index signature
|
|
422
|
-
stateSums[state] = (stateSums[state] || 0) + dp.value;
|
|
423
|
-
// @ts-expect-error index signature
|
|
424
|
-
stateCounts[state] = (stateCounts[state] || 0) + 1;
|
|
425
|
-
}
|
|
426
|
-
for (const state in stateSums) {
|
|
427
|
-
// @ts-expect-error index signature
|
|
428
|
-
cpuUtilization[state] = stateSums[state] / stateCounts[state];
|
|
429
|
-
}
|
|
430
|
-
cpuCount = Math.max(...metric.dataPoints.map(dp => parseInt(dp.attributes?.system?.cpu?.logical_number || 0, 10))) + 1;
|
|
431
|
-
}
|
|
432
|
-
if (name === 'system.memory.usage') {
|
|
433
|
-
for (const dp of metric.dataPoints) {
|
|
434
|
-
const state = dp.attributes?.system?.memory?.state;
|
|
435
|
-
// @ts-expect-error index signature
|
|
436
|
-
if (state) memoryUsageMB[state] = dp.value;
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
if (name === 'system.memory.utilization') {
|
|
440
|
-
for (const dp of metric.dataPoints) {
|
|
441
|
-
const state = dp.attributes?.system?.memory?.state;
|
|
442
|
-
// @ts-expect-error index signature
|
|
443
|
-
if (state) memoryUtilizationPercent[state] = dp.value;
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
if (name === 'system.network.io') {
|
|
447
|
-
for (const dp of metric.dataPoints) {
|
|
448
|
-
const direction = dp.attributes?.network?.io?.direction;
|
|
449
|
-
// @ts-expect-error index signature
|
|
450
|
-
if (direction) networkIO[direction] += dp.value;
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
if (name === 'process.cpu.time') {
|
|
454
|
-
for (const dp of metric.dataPoints) {
|
|
455
|
-
const state = dp.attributes?.process?.cpu?.state;
|
|
456
|
-
// @ts-expect-error index signature
|
|
457
|
-
if (state) processCPU[state] = dp.value;
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
if (name === 'process.memory.usage') {
|
|
461
|
-
processMemoryUsage = metric.dataPoints[0]?.value || 0;
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
return {
|
|
466
|
-
service: serviceName,
|
|
467
|
-
cpu: {
|
|
468
|
-
avgUtilization: cpuUtilization,
|
|
469
|
-
cores: cpuCount
|
|
470
|
-
},
|
|
471
|
-
memory: {
|
|
472
|
-
usedGB: (memoryUsageMB.used || 0) / 1024 ** 3,
|
|
473
|
-
freeGB: (memoryUsageMB.free || 0) / 1024 ** 3,
|
|
474
|
-
usedPercent: (memoryUtilizationPercent.used || 0) * 100,
|
|
475
|
-
freePercent: (1 - (memoryUtilizationPercent.used || 0)) * 100
|
|
476
|
-
},
|
|
477
|
-
network: {
|
|
478
|
-
transmittedMB: networkIO.transmit / 1024 ** 2,
|
|
479
|
-
receivedMB: networkIO.receive / 1024 ** 2
|
|
480
|
-
},
|
|
481
|
-
process: {
|
|
482
|
-
cpuTimeSec: processCPU,
|
|
483
|
-
memoryUsageMB: processMemoryUsage / 1024 ** 2
|
|
484
|
-
}
|
|
485
|
-
};
|
|
486
|
-
});
|
|
487
|
-
}
|
|
488
249
|
function getSimplifiedTraces(spans) {
|
|
489
250
|
return spans.map(span => {
|
|
490
251
|
return {
|
|
@@ -502,10 +263,11 @@ function getSimplifiedTraces(spans) {
|
|
|
502
263
|
function getSimplifiedLogs(logs) {
|
|
503
264
|
return logs.map(log => ({
|
|
504
265
|
service: log.resource?.attributes?.service?.name || undefined,
|
|
505
|
-
timestamp: log.timestamp,
|
|
266
|
+
timestamp: new Date(log.timestamp / 1000).toISOString(),
|
|
267
|
+
// converting microseconds to milliseconds
|
|
268
|
+
severityText: log.severityText,
|
|
506
269
|
message: log.body,
|
|
507
270
|
traceId: log.traceId,
|
|
508
|
-
|
|
509
|
-
source: log.attributes?.source?.source || undefined
|
|
271
|
+
source: log.attributes?.source || undefined
|
|
510
272
|
}));
|
|
511
273
|
}
|