copilot-chat-analyzer 0.0.2 → 0.0.3
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/AI_USAGE.md +93 -0
- package/README.md +65 -7
- package/dist/index.cjs +126 -4
- package/dist/index.d.cts +47 -1
- package/dist/index.d.ts +47 -1
- package/dist/index.mjs +126 -4
- package/package.json +43 -4
package/AI_USAGE.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# AI Usage Guide for copilot-chat-analyzer
|
|
2
|
+
|
|
3
|
+
This is a TypeScript/JavaScript library for analyzing GitHub Copilot chat exports.
|
|
4
|
+
|
|
5
|
+
## Quick Start for AI Assistants
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import CopilotChatAnalyzer, { DialogStatus } from "copilot-chat-analyzer";
|
|
9
|
+
import { readFileSync } from "fs";
|
|
10
|
+
|
|
11
|
+
// Load chat data from JSON export
|
|
12
|
+
const chatData = JSON.parse(readFileSync("chat.json", "utf8"));
|
|
13
|
+
const analyzer = new CopilotChatAnalyzer();
|
|
14
|
+
|
|
15
|
+
// Basic analysis
|
|
16
|
+
const status = analyzer.getDialogStatus(chatData);
|
|
17
|
+
const requestCount = analyzer.getRequestsCount(chatData);
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Core Methods
|
|
21
|
+
|
|
22
|
+
### getDialogStatus(chatData)
|
|
23
|
+
|
|
24
|
+
Returns one of four status strings:
|
|
25
|
+
|
|
26
|
+
- `"pending"` - Chat created but no requests made (empty requests array)
|
|
27
|
+
- `"in_progress"` - Chat has requests but not completed
|
|
28
|
+
- `"completed"` - Chat finished successfully (has followups: [])
|
|
29
|
+
- `"canceled"` - Chat was canceled (isCanceled: true)
|
|
30
|
+
|
|
31
|
+
### getRequestsCount(chatData)
|
|
32
|
+
|
|
33
|
+
Returns number of requests in the chat.
|
|
34
|
+
|
|
35
|
+
### getDialogStatusDetails(chatData)
|
|
36
|
+
|
|
37
|
+
Returns detailed object:
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
{
|
|
41
|
+
status: DialogStatusType,
|
|
42
|
+
statusText: string, // Human readable status
|
|
43
|
+
hasResult: boolean, // Has result data
|
|
44
|
+
hasFollowups: boolean, // Has followups property
|
|
45
|
+
isCanceled: boolean, // Was canceled
|
|
46
|
+
lastRequestId?: string // ID of last request
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### getMcpToolMonitoring(chatData, toolName?)
|
|
51
|
+
|
|
52
|
+
Monitor MCP (Model Context Protocol) tool usage:
|
|
53
|
+
|
|
54
|
+
- Without toolName: Returns summary of all tools
|
|
55
|
+
- With toolName: Returns detailed stats for specific tool
|
|
56
|
+
|
|
57
|
+
## Chat Data Structure
|
|
58
|
+
|
|
59
|
+
Expected JSON structure from GitHub Copilot export:
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
{
|
|
63
|
+
requesterUsername: string,
|
|
64
|
+
responderUsername: string,
|
|
65
|
+
requests: Array<{
|
|
66
|
+
requestId: string,
|
|
67
|
+
isCanceled?: boolean,
|
|
68
|
+
followups?: any[],
|
|
69
|
+
result?: any,
|
|
70
|
+
response?: any[]
|
|
71
|
+
}>
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Status Detection Logic
|
|
76
|
+
|
|
77
|
+
1. No requests or empty array → `"pending"`
|
|
78
|
+
2. Last request has `isCanceled: true` → `"canceled"`
|
|
79
|
+
3. Last request has `followups: []` (empty array) → `"completed"`
|
|
80
|
+
4. Otherwise → `"in_progress"`
|
|
81
|
+
|
|
82
|
+
## MCP Tool Analysis
|
|
83
|
+
|
|
84
|
+
The library can extract and analyze Model Context Protocol tool calls from chat responses, providing:
|
|
85
|
+
|
|
86
|
+
- Tool success rates
|
|
87
|
+
- Call counts
|
|
88
|
+
- Input/output data
|
|
89
|
+
- Error tracking
|
|
90
|
+
|
|
91
|
+
## Examples Directory
|
|
92
|
+
|
|
93
|
+
Check `/examples` folder for complete usage examples with sample data.
|
package/README.md
CHANGED
|
@@ -4,14 +4,39 @@
|
|
|
4
4
|
[](https://github.com/dealenx/copilot-chat-analyzer/actions/workflows/quality.yml)
|
|
5
5
|
[](https://badge.fury.io/js/copilot-chat-analyzer)
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
TypeScript библиотека для анализа экспортированных чатов GitHub Copilot с поддержкой мониторинга MCP инструментов.
|
|
8
|
+
|
|
9
|
+
## 🤖 AI Assistant Quick Reference
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
// Basic import and usage
|
|
13
|
+
import CopilotChatAnalyzer, { DialogStatus } from "copilot-chat-analyzer";
|
|
14
|
+
|
|
15
|
+
const analyzer = new CopilotChatAnalyzer();
|
|
16
|
+
const chatData = JSON.parse(fs.readFileSync("chat.json", "utf8"));
|
|
17
|
+
|
|
18
|
+
// Core methods:
|
|
19
|
+
analyzer.getDialogStatus(chatData); // Returns: 'pending' | 'in_progress' | 'completed' | 'canceled'
|
|
20
|
+
analyzer.getRequestsCount(chatData); // Returns: number
|
|
21
|
+
analyzer.getDialogStatusDetails(chatData); // Returns: { status, statusText, hasResult, hasFollowups, isCanceled, lastRequestId }
|
|
22
|
+
analyzer.getMcpToolMonitoring(chatData); // Returns: MCP tool usage statistics
|
|
23
|
+
|
|
24
|
+
// Dialog statuses:
|
|
25
|
+
// - 'pending': Empty requests array, chat not started
|
|
26
|
+
// - 'in_progress': Has requests but not finished
|
|
27
|
+
// - 'completed': Has followups:[] and not canceled
|
|
28
|
+
// - 'canceled': isCanceled:true in last request
|
|
29
|
+
```
|
|
8
30
|
|
|
9
31
|
## Особенности
|
|
10
32
|
|
|
11
|
-
- 📊
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
33
|
+
- 📊 **Анализ статусов диалога** - автоматическое определение состояния чата
|
|
34
|
+
- 🔢 **Подсчет запросов** - точный подсчет количества запросов в диалоге
|
|
35
|
+
- 🔍 **Детальная диагностика** - получение развернутой информации о статусе
|
|
36
|
+
- �️ **MCP мониторинг** - отслеживание использования Model Context Protocol инструментов
|
|
37
|
+
- 📈 **Статистика успешности** - анализ успешности выполнения MCP вызовов
|
|
38
|
+
- 🚀 **Простой API** - интуитивно понятный интерфейс
|
|
39
|
+
- 💪 **TypeScript** - полная поддержка типов
|
|
15
40
|
|
|
16
41
|
## Установка
|
|
17
42
|
|
|
@@ -59,7 +84,7 @@ console.log(`Количество запросов: ${requestsCount}`);
|
|
|
59
84
|
|
|
60
85
|
// Определение статуса диалога
|
|
61
86
|
const status = analyzer.getDialogStatus(chatData);
|
|
62
|
-
console.log(`Статус: ${status}`); // 'completed', 'canceled', 'in_progress'
|
|
87
|
+
console.log(`Статус: ${status}`); // 'pending', 'completed', 'canceled', 'in_progress'
|
|
63
88
|
|
|
64
89
|
// Получение детальной информации о статусе
|
|
65
90
|
const details = analyzer.getDialogStatusDetails(chatData);
|
|
@@ -73,10 +98,43 @@ console.log({
|
|
|
73
98
|
});
|
|
74
99
|
```
|
|
75
100
|
|
|
101
|
+
### Мониторинг MCP инструментов
|
|
102
|
+
|
|
103
|
+
```javascript
|
|
104
|
+
// Получить список всех MCP инструментов в чате
|
|
105
|
+
const toolNames = analyzer.getMcpToolNames(chatData);
|
|
106
|
+
console.log("Инструменты:", toolNames);
|
|
107
|
+
|
|
108
|
+
// Получить все вызовы конкретного инструмента
|
|
109
|
+
const calls = analyzer.getMcpToolCalls(chatData, "update_entry_fields");
|
|
110
|
+
calls.forEach((call, i) => {
|
|
111
|
+
console.log(
|
|
112
|
+
`${i + 1}. ${call.isError ? "❌ Ошибка" : "✅ Успех"}: ${JSON.stringify(
|
|
113
|
+
call.input
|
|
114
|
+
)}`
|
|
115
|
+
);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// Получить только успешные или только ошибочные вызовы
|
|
119
|
+
const successCalls = analyzer.getMcpToolSuccessfulCalls(
|
|
120
|
+
chatData,
|
|
121
|
+
"update_entry_fields"
|
|
122
|
+
);
|
|
123
|
+
const errorCalls = analyzer.getMcpToolErrorCalls(
|
|
124
|
+
chatData,
|
|
125
|
+
"update_entry_fields"
|
|
126
|
+
);
|
|
127
|
+
```
|
|
128
|
+
|
|
76
129
|
## Статусы диалога
|
|
77
130
|
|
|
78
131
|
Библиотека автоматически определяет текущий статус чата при экспорте:
|
|
79
132
|
|
|
133
|
+
- **`DialogStatus.PENDING`** (`"pending"`) - Диалог еще не начат
|
|
134
|
+
|
|
135
|
+
- Массив `requests` пустой или отсутствует
|
|
136
|
+
- Еще не было сделано ни одного запроса к Copilot
|
|
137
|
+
|
|
80
138
|
- **`DialogStatus.COMPLETED`** (`"completed"`) - Диалог завершен успешно
|
|
81
139
|
|
|
82
140
|
- Есть поле `followups: []` (пустой массив)
|
|
@@ -158,7 +216,7 @@ interface CopilotChatData {
|
|
|
158
216
|
[key: string]: any;
|
|
159
217
|
}
|
|
160
218
|
|
|
161
|
-
type DialogStatusType = "completed" | "canceled" | "in_progress";
|
|
219
|
+
type DialogStatusType = "pending" | "completed" | "canceled" | "in_progress";
|
|
162
220
|
|
|
163
221
|
interface DialogStatusDetails {
|
|
164
222
|
status: DialogStatusType;
|
package/dist/index.cjs
CHANGED
|
@@ -26,6 +26,7 @@ __export(index_exports, {
|
|
|
26
26
|
});
|
|
27
27
|
module.exports = __toCommonJS(index_exports);
|
|
28
28
|
var DialogStatus = {
|
|
29
|
+
PENDING: "pending",
|
|
29
30
|
COMPLETED: "completed",
|
|
30
31
|
CANCELED: "canceled",
|
|
31
32
|
IN_PROGRESS: "in_progress"
|
|
@@ -48,11 +49,11 @@ var CopilotChatAnalyzer = class {
|
|
|
48
49
|
}
|
|
49
50
|
getDialogStatus(chatData) {
|
|
50
51
|
if (!this.hasRequests(chatData)) {
|
|
51
|
-
return DialogStatus.
|
|
52
|
+
return DialogStatus.PENDING;
|
|
52
53
|
}
|
|
53
54
|
const lastRequest = this.getLastRequest(chatData);
|
|
54
55
|
if (!lastRequest) {
|
|
55
|
-
return DialogStatus.
|
|
56
|
+
return DialogStatus.PENDING;
|
|
56
57
|
}
|
|
57
58
|
if (lastRequest.isCanceled === true) {
|
|
58
59
|
return DialogStatus.CANCELED;
|
|
@@ -71,8 +72,8 @@ var CopilotChatAnalyzer = class {
|
|
|
71
72
|
const status = this.getDialogStatus(chatData);
|
|
72
73
|
if (!this.hasRequests(chatData)) {
|
|
73
74
|
return {
|
|
74
|
-
status: DialogStatus.
|
|
75
|
-
statusText: "\
|
|
75
|
+
status: DialogStatus.PENDING,
|
|
76
|
+
statusText: "\u0414\u0438\u0430\u043B\u043E\u0433 \u0435\u0449\u0435 \u043D\u0435 \u043D\u0430\u0447\u0430\u0442",
|
|
76
77
|
hasResult: false,
|
|
77
78
|
hasFollowups: false,
|
|
78
79
|
isCanceled: false
|
|
@@ -80,6 +81,7 @@ var CopilotChatAnalyzer = class {
|
|
|
80
81
|
}
|
|
81
82
|
const lastRequest = this.getLastRequest(chatData);
|
|
82
83
|
const statusTexts = {
|
|
84
|
+
[DialogStatus.PENDING]: "\u0414\u0438\u0430\u043B\u043E\u0433 \u0435\u0449\u0435 \u043D\u0435 \u043D\u0430\u0447\u0430\u0442",
|
|
83
85
|
[DialogStatus.COMPLETED]: "\u0414\u0438\u0430\u043B\u043E\u0433 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D \u0443\u0441\u043F\u0435\u0448\u043D\u043E",
|
|
84
86
|
[DialogStatus.CANCELED]: "\u0414\u0438\u0430\u043B\u043E\u0433 \u0431\u044B\u043B \u043E\u0442\u043C\u0435\u043D\u0435\u043D",
|
|
85
87
|
[DialogStatus.IN_PROGRESS]: "\u0414\u0438\u0430\u043B\u043E\u0433 \u0432 \u043F\u0440\u043E\u0446\u0435\u0441\u0441\u0435 \u0432\u044B\u043F\u043E\u043B\u043D\u0435\u043D\u0438\u044F"
|
|
@@ -93,6 +95,126 @@ var CopilotChatAnalyzer = class {
|
|
|
93
95
|
lastRequestId: lastRequest?.requestId
|
|
94
96
|
};
|
|
95
97
|
}
|
|
98
|
+
extractMcpToolCalls(chatData) {
|
|
99
|
+
if (!this.hasRequests(chatData)) {
|
|
100
|
+
return [];
|
|
101
|
+
}
|
|
102
|
+
const toolCalls = [];
|
|
103
|
+
chatData.requests.forEach((request) => {
|
|
104
|
+
if (!request.response || !Array.isArray(request.response)) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
request.response.forEach((responseItem) => {
|
|
108
|
+
if (responseItem.kind === "toolInvocationSerialized" && responseItem.source?.type === "mcp") {
|
|
109
|
+
const toolCall = {
|
|
110
|
+
toolId: responseItem.toolId || responseItem.toolName || "unknown",
|
|
111
|
+
toolName: responseItem.toolName || responseItem.toolId || "unknown",
|
|
112
|
+
requestId: request.requestId,
|
|
113
|
+
input: responseItem.resultDetails?.input || responseItem.toolSpecificData?.rawInput || null,
|
|
114
|
+
output: responseItem.resultDetails?.output || null,
|
|
115
|
+
isError: responseItem.resultDetails?.isError || false,
|
|
116
|
+
timestamp: request.timestamp,
|
|
117
|
+
source: responseItem.source
|
|
118
|
+
};
|
|
119
|
+
toolCalls.push(toolCall);
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
return toolCalls;
|
|
124
|
+
}
|
|
125
|
+
getMcpToolMonitoring(chatData, toolName) {
|
|
126
|
+
const allToolCalls = this.extractMcpToolCalls(chatData);
|
|
127
|
+
if (toolName) {
|
|
128
|
+
const toolCalls = allToolCalls.filter(
|
|
129
|
+
(call) => call.toolName.includes(toolName) || call.toolId.includes(toolName)
|
|
130
|
+
);
|
|
131
|
+
const successfulCalls = toolCalls.filter((call) => !call.isError).length;
|
|
132
|
+
const errorCalls = toolCalls.filter((call) => call.isError).length;
|
|
133
|
+
const successRate = toolCalls.length > 0 ? successfulCalls / toolCalls.length * 100 : 0;
|
|
134
|
+
return {
|
|
135
|
+
toolName,
|
|
136
|
+
totalCalls: toolCalls.length,
|
|
137
|
+
successfulCalls,
|
|
138
|
+
errorCalls,
|
|
139
|
+
successRate: Math.round(successRate * 100) / 100,
|
|
140
|
+
calls: toolCalls
|
|
141
|
+
};
|
|
142
|
+
} else {
|
|
143
|
+
const toolsMap = /* @__PURE__ */ new Map();
|
|
144
|
+
allToolCalls.forEach((call) => {
|
|
145
|
+
const key = call.toolName || call.toolId;
|
|
146
|
+
if (!toolsMap.has(key)) {
|
|
147
|
+
toolsMap.set(key, []);
|
|
148
|
+
}
|
|
149
|
+
toolsMap.get(key).push(call);
|
|
150
|
+
});
|
|
151
|
+
const tools = Array.from(toolsMap.entries()).map(
|
|
152
|
+
([toolName2, calls]) => {
|
|
153
|
+
const successfulCalls = calls.filter((call) => !call.isError).length;
|
|
154
|
+
const errorCalls = calls.filter((call) => call.isError).length;
|
|
155
|
+
const successRate = calls.length > 0 ? successfulCalls / calls.length * 100 : 0;
|
|
156
|
+
return {
|
|
157
|
+
toolName: toolName2,
|
|
158
|
+
totalCalls: calls.length,
|
|
159
|
+
successfulCalls,
|
|
160
|
+
errorCalls,
|
|
161
|
+
successRate: Math.round(successRate * 100) / 100,
|
|
162
|
+
calls
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
);
|
|
166
|
+
const totalCalls = allToolCalls.length;
|
|
167
|
+
const totalSuccessful = allToolCalls.filter(
|
|
168
|
+
(call) => !call.isError
|
|
169
|
+
).length;
|
|
170
|
+
const overallSuccessRate = totalCalls > 0 ? totalSuccessful / totalCalls * 100 : 0;
|
|
171
|
+
return {
|
|
172
|
+
totalTools: tools.length,
|
|
173
|
+
totalCalls,
|
|
174
|
+
overallSuccessRate: Math.round(overallSuccessRate * 100) / 100,
|
|
175
|
+
tools
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
getMcpToolSuccessfulCalls(chatData, toolName) {
|
|
180
|
+
const monitoring = this.getMcpToolMonitoring(
|
|
181
|
+
chatData,
|
|
182
|
+
toolName
|
|
183
|
+
);
|
|
184
|
+
return monitoring.calls.filter((call) => !call.isError);
|
|
185
|
+
}
|
|
186
|
+
getMcpToolErrorCalls(chatData, toolName) {
|
|
187
|
+
const monitoring = this.getMcpToolMonitoring(
|
|
188
|
+
chatData,
|
|
189
|
+
toolName
|
|
190
|
+
);
|
|
191
|
+
return monitoring.calls.filter((call) => call.isError);
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Простой метод для получения всех вызовов конкретного MCP инструмента
|
|
195
|
+
* @param chatData - данные чата
|
|
196
|
+
* @param toolName - название инструмента (например, 'update_entry_fields')
|
|
197
|
+
* @returns массив всех вызовов инструмента
|
|
198
|
+
*/
|
|
199
|
+
getMcpToolCalls(chatData, toolName) {
|
|
200
|
+
const allToolCalls = this.extractMcpToolCalls(chatData);
|
|
201
|
+
return allToolCalls.filter(
|
|
202
|
+
(call) => call.toolName.includes(toolName) || call.toolId.includes(toolName)
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Получить список всех уникальных MCP инструментов, использованных в чате
|
|
207
|
+
* @param chatData - данные чата
|
|
208
|
+
* @returns массив названий инструментов
|
|
209
|
+
*/
|
|
210
|
+
getMcpToolNames(chatData) {
|
|
211
|
+
const allToolCalls = this.extractMcpToolCalls(chatData);
|
|
212
|
+
const uniqueNames = /* @__PURE__ */ new Set();
|
|
213
|
+
allToolCalls.forEach((call) => {
|
|
214
|
+
uniqueNames.add(call.toolName || call.toolId);
|
|
215
|
+
});
|
|
216
|
+
return Array.from(uniqueNames);
|
|
217
|
+
}
|
|
96
218
|
};
|
|
97
219
|
var index_default = CopilotChatAnalyzer;
|
|
98
220
|
// Annotate the CommonJS export names for ESM import in node:
|
package/dist/index.d.cts
CHANGED
|
@@ -10,7 +10,36 @@ interface DialogStatusDetails {
|
|
|
10
10
|
isCanceled: boolean;
|
|
11
11
|
lastRequestId?: string;
|
|
12
12
|
}
|
|
13
|
+
interface McpToolCall {
|
|
14
|
+
toolId: string;
|
|
15
|
+
toolName: string;
|
|
16
|
+
requestId: string;
|
|
17
|
+
input: any;
|
|
18
|
+
output: any;
|
|
19
|
+
isError: boolean;
|
|
20
|
+
timestamp?: number;
|
|
21
|
+
source?: {
|
|
22
|
+
type: string;
|
|
23
|
+
serverLabel: string;
|
|
24
|
+
label: string;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
interface McpToolMonitoring {
|
|
28
|
+
toolName: string;
|
|
29
|
+
totalCalls: number;
|
|
30
|
+
successfulCalls: number;
|
|
31
|
+
errorCalls: number;
|
|
32
|
+
successRate: number;
|
|
33
|
+
calls: McpToolCall[];
|
|
34
|
+
}
|
|
35
|
+
interface McpMonitoringSummary {
|
|
36
|
+
totalTools: number;
|
|
37
|
+
totalCalls: number;
|
|
38
|
+
overallSuccessRate: number;
|
|
39
|
+
tools: McpToolMonitoring[];
|
|
40
|
+
}
|
|
13
41
|
declare const DialogStatus: {
|
|
42
|
+
readonly PENDING: "pending";
|
|
14
43
|
readonly COMPLETED: "completed";
|
|
15
44
|
readonly CANCELED: "canceled";
|
|
16
45
|
readonly IN_PROGRESS: "in_progress";
|
|
@@ -22,6 +51,23 @@ declare class CopilotChatAnalyzer {
|
|
|
22
51
|
private getLastRequest;
|
|
23
52
|
getDialogStatus(chatData: CopilotChatData): DialogStatusType;
|
|
24
53
|
getDialogStatusDetails(chatData: CopilotChatData): DialogStatusDetails;
|
|
54
|
+
private extractMcpToolCalls;
|
|
55
|
+
getMcpToolMonitoring(chatData: CopilotChatData, toolName?: string): McpToolMonitoring | McpMonitoringSummary;
|
|
56
|
+
getMcpToolSuccessfulCalls(chatData: CopilotChatData, toolName: string): McpToolCall[];
|
|
57
|
+
getMcpToolErrorCalls(chatData: CopilotChatData, toolName: string): McpToolCall[];
|
|
58
|
+
/**
|
|
59
|
+
* Простой метод для получения всех вызовов конкретного MCP инструмента
|
|
60
|
+
* @param chatData - данные чата
|
|
61
|
+
* @param toolName - название инструмента (например, 'update_entry_fields')
|
|
62
|
+
* @returns массив всех вызовов инструмента
|
|
63
|
+
*/
|
|
64
|
+
getMcpToolCalls(chatData: CopilotChatData, toolName: string): McpToolCall[];
|
|
65
|
+
/**
|
|
66
|
+
* Получить список всех уникальных MCP инструментов, использованных в чате
|
|
67
|
+
* @param chatData - данные чата
|
|
68
|
+
* @returns массив названий инструментов
|
|
69
|
+
*/
|
|
70
|
+
getMcpToolNames(chatData: CopilotChatData): string[];
|
|
25
71
|
}
|
|
26
72
|
|
|
27
|
-
export { CopilotChatAnalyzer, DialogStatus, type DialogStatusType, CopilotChatAnalyzer as default };
|
|
73
|
+
export { CopilotChatAnalyzer, DialogStatus, type DialogStatusType, type McpMonitoringSummary, type McpToolCall, type McpToolMonitoring, CopilotChatAnalyzer as default };
|
package/dist/index.d.ts
CHANGED
|
@@ -10,7 +10,36 @@ interface DialogStatusDetails {
|
|
|
10
10
|
isCanceled: boolean;
|
|
11
11
|
lastRequestId?: string;
|
|
12
12
|
}
|
|
13
|
+
interface McpToolCall {
|
|
14
|
+
toolId: string;
|
|
15
|
+
toolName: string;
|
|
16
|
+
requestId: string;
|
|
17
|
+
input: any;
|
|
18
|
+
output: any;
|
|
19
|
+
isError: boolean;
|
|
20
|
+
timestamp?: number;
|
|
21
|
+
source?: {
|
|
22
|
+
type: string;
|
|
23
|
+
serverLabel: string;
|
|
24
|
+
label: string;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
interface McpToolMonitoring {
|
|
28
|
+
toolName: string;
|
|
29
|
+
totalCalls: number;
|
|
30
|
+
successfulCalls: number;
|
|
31
|
+
errorCalls: number;
|
|
32
|
+
successRate: number;
|
|
33
|
+
calls: McpToolCall[];
|
|
34
|
+
}
|
|
35
|
+
interface McpMonitoringSummary {
|
|
36
|
+
totalTools: number;
|
|
37
|
+
totalCalls: number;
|
|
38
|
+
overallSuccessRate: number;
|
|
39
|
+
tools: McpToolMonitoring[];
|
|
40
|
+
}
|
|
13
41
|
declare const DialogStatus: {
|
|
42
|
+
readonly PENDING: "pending";
|
|
14
43
|
readonly COMPLETED: "completed";
|
|
15
44
|
readonly CANCELED: "canceled";
|
|
16
45
|
readonly IN_PROGRESS: "in_progress";
|
|
@@ -22,6 +51,23 @@ declare class CopilotChatAnalyzer {
|
|
|
22
51
|
private getLastRequest;
|
|
23
52
|
getDialogStatus(chatData: CopilotChatData): DialogStatusType;
|
|
24
53
|
getDialogStatusDetails(chatData: CopilotChatData): DialogStatusDetails;
|
|
54
|
+
private extractMcpToolCalls;
|
|
55
|
+
getMcpToolMonitoring(chatData: CopilotChatData, toolName?: string): McpToolMonitoring | McpMonitoringSummary;
|
|
56
|
+
getMcpToolSuccessfulCalls(chatData: CopilotChatData, toolName: string): McpToolCall[];
|
|
57
|
+
getMcpToolErrorCalls(chatData: CopilotChatData, toolName: string): McpToolCall[];
|
|
58
|
+
/**
|
|
59
|
+
* Простой метод для получения всех вызовов конкретного MCP инструмента
|
|
60
|
+
* @param chatData - данные чата
|
|
61
|
+
* @param toolName - название инструмента (например, 'update_entry_fields')
|
|
62
|
+
* @returns массив всех вызовов инструмента
|
|
63
|
+
*/
|
|
64
|
+
getMcpToolCalls(chatData: CopilotChatData, toolName: string): McpToolCall[];
|
|
65
|
+
/**
|
|
66
|
+
* Получить список всех уникальных MCP инструментов, использованных в чате
|
|
67
|
+
* @param chatData - данные чата
|
|
68
|
+
* @returns массив названий инструментов
|
|
69
|
+
*/
|
|
70
|
+
getMcpToolNames(chatData: CopilotChatData): string[];
|
|
25
71
|
}
|
|
26
72
|
|
|
27
|
-
export { CopilotChatAnalyzer, DialogStatus, type DialogStatusType, CopilotChatAnalyzer as default };
|
|
73
|
+
export { CopilotChatAnalyzer, DialogStatus, type DialogStatusType, type McpMonitoringSummary, type McpToolCall, type McpToolMonitoring, CopilotChatAnalyzer as default };
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
var DialogStatus = {
|
|
3
|
+
PENDING: "pending",
|
|
3
4
|
COMPLETED: "completed",
|
|
4
5
|
CANCELED: "canceled",
|
|
5
6
|
IN_PROGRESS: "in_progress"
|
|
@@ -22,11 +23,11 @@ var CopilotChatAnalyzer = class {
|
|
|
22
23
|
}
|
|
23
24
|
getDialogStatus(chatData) {
|
|
24
25
|
if (!this.hasRequests(chatData)) {
|
|
25
|
-
return DialogStatus.
|
|
26
|
+
return DialogStatus.PENDING;
|
|
26
27
|
}
|
|
27
28
|
const lastRequest = this.getLastRequest(chatData);
|
|
28
29
|
if (!lastRequest) {
|
|
29
|
-
return DialogStatus.
|
|
30
|
+
return DialogStatus.PENDING;
|
|
30
31
|
}
|
|
31
32
|
if (lastRequest.isCanceled === true) {
|
|
32
33
|
return DialogStatus.CANCELED;
|
|
@@ -45,8 +46,8 @@ var CopilotChatAnalyzer = class {
|
|
|
45
46
|
const status = this.getDialogStatus(chatData);
|
|
46
47
|
if (!this.hasRequests(chatData)) {
|
|
47
48
|
return {
|
|
48
|
-
status: DialogStatus.
|
|
49
|
-
statusText: "\
|
|
49
|
+
status: DialogStatus.PENDING,
|
|
50
|
+
statusText: "\u0414\u0438\u0430\u043B\u043E\u0433 \u0435\u0449\u0435 \u043D\u0435 \u043D\u0430\u0447\u0430\u0442",
|
|
50
51
|
hasResult: false,
|
|
51
52
|
hasFollowups: false,
|
|
52
53
|
isCanceled: false
|
|
@@ -54,6 +55,7 @@ var CopilotChatAnalyzer = class {
|
|
|
54
55
|
}
|
|
55
56
|
const lastRequest = this.getLastRequest(chatData);
|
|
56
57
|
const statusTexts = {
|
|
58
|
+
[DialogStatus.PENDING]: "\u0414\u0438\u0430\u043B\u043E\u0433 \u0435\u0449\u0435 \u043D\u0435 \u043D\u0430\u0447\u0430\u0442",
|
|
57
59
|
[DialogStatus.COMPLETED]: "\u0414\u0438\u0430\u043B\u043E\u0433 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D \u0443\u0441\u043F\u0435\u0448\u043D\u043E",
|
|
58
60
|
[DialogStatus.CANCELED]: "\u0414\u0438\u0430\u043B\u043E\u0433 \u0431\u044B\u043B \u043E\u0442\u043C\u0435\u043D\u0435\u043D",
|
|
59
61
|
[DialogStatus.IN_PROGRESS]: "\u0414\u0438\u0430\u043B\u043E\u0433 \u0432 \u043F\u0440\u043E\u0446\u0435\u0441\u0441\u0435 \u0432\u044B\u043F\u043E\u043B\u043D\u0435\u043D\u0438\u044F"
|
|
@@ -67,6 +69,126 @@ var CopilotChatAnalyzer = class {
|
|
|
67
69
|
lastRequestId: lastRequest?.requestId
|
|
68
70
|
};
|
|
69
71
|
}
|
|
72
|
+
extractMcpToolCalls(chatData) {
|
|
73
|
+
if (!this.hasRequests(chatData)) {
|
|
74
|
+
return [];
|
|
75
|
+
}
|
|
76
|
+
const toolCalls = [];
|
|
77
|
+
chatData.requests.forEach((request) => {
|
|
78
|
+
if (!request.response || !Array.isArray(request.response)) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
request.response.forEach((responseItem) => {
|
|
82
|
+
if (responseItem.kind === "toolInvocationSerialized" && responseItem.source?.type === "mcp") {
|
|
83
|
+
const toolCall = {
|
|
84
|
+
toolId: responseItem.toolId || responseItem.toolName || "unknown",
|
|
85
|
+
toolName: responseItem.toolName || responseItem.toolId || "unknown",
|
|
86
|
+
requestId: request.requestId,
|
|
87
|
+
input: responseItem.resultDetails?.input || responseItem.toolSpecificData?.rawInput || null,
|
|
88
|
+
output: responseItem.resultDetails?.output || null,
|
|
89
|
+
isError: responseItem.resultDetails?.isError || false,
|
|
90
|
+
timestamp: request.timestamp,
|
|
91
|
+
source: responseItem.source
|
|
92
|
+
};
|
|
93
|
+
toolCalls.push(toolCall);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
return toolCalls;
|
|
98
|
+
}
|
|
99
|
+
getMcpToolMonitoring(chatData, toolName) {
|
|
100
|
+
const allToolCalls = this.extractMcpToolCalls(chatData);
|
|
101
|
+
if (toolName) {
|
|
102
|
+
const toolCalls = allToolCalls.filter(
|
|
103
|
+
(call) => call.toolName.includes(toolName) || call.toolId.includes(toolName)
|
|
104
|
+
);
|
|
105
|
+
const successfulCalls = toolCalls.filter((call) => !call.isError).length;
|
|
106
|
+
const errorCalls = toolCalls.filter((call) => call.isError).length;
|
|
107
|
+
const successRate = toolCalls.length > 0 ? successfulCalls / toolCalls.length * 100 : 0;
|
|
108
|
+
return {
|
|
109
|
+
toolName,
|
|
110
|
+
totalCalls: toolCalls.length,
|
|
111
|
+
successfulCalls,
|
|
112
|
+
errorCalls,
|
|
113
|
+
successRate: Math.round(successRate * 100) / 100,
|
|
114
|
+
calls: toolCalls
|
|
115
|
+
};
|
|
116
|
+
} else {
|
|
117
|
+
const toolsMap = /* @__PURE__ */ new Map();
|
|
118
|
+
allToolCalls.forEach((call) => {
|
|
119
|
+
const key = call.toolName || call.toolId;
|
|
120
|
+
if (!toolsMap.has(key)) {
|
|
121
|
+
toolsMap.set(key, []);
|
|
122
|
+
}
|
|
123
|
+
toolsMap.get(key).push(call);
|
|
124
|
+
});
|
|
125
|
+
const tools = Array.from(toolsMap.entries()).map(
|
|
126
|
+
([toolName2, calls]) => {
|
|
127
|
+
const successfulCalls = calls.filter((call) => !call.isError).length;
|
|
128
|
+
const errorCalls = calls.filter((call) => call.isError).length;
|
|
129
|
+
const successRate = calls.length > 0 ? successfulCalls / calls.length * 100 : 0;
|
|
130
|
+
return {
|
|
131
|
+
toolName: toolName2,
|
|
132
|
+
totalCalls: calls.length,
|
|
133
|
+
successfulCalls,
|
|
134
|
+
errorCalls,
|
|
135
|
+
successRate: Math.round(successRate * 100) / 100,
|
|
136
|
+
calls
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
);
|
|
140
|
+
const totalCalls = allToolCalls.length;
|
|
141
|
+
const totalSuccessful = allToolCalls.filter(
|
|
142
|
+
(call) => !call.isError
|
|
143
|
+
).length;
|
|
144
|
+
const overallSuccessRate = totalCalls > 0 ? totalSuccessful / totalCalls * 100 : 0;
|
|
145
|
+
return {
|
|
146
|
+
totalTools: tools.length,
|
|
147
|
+
totalCalls,
|
|
148
|
+
overallSuccessRate: Math.round(overallSuccessRate * 100) / 100,
|
|
149
|
+
tools
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
getMcpToolSuccessfulCalls(chatData, toolName) {
|
|
154
|
+
const monitoring = this.getMcpToolMonitoring(
|
|
155
|
+
chatData,
|
|
156
|
+
toolName
|
|
157
|
+
);
|
|
158
|
+
return monitoring.calls.filter((call) => !call.isError);
|
|
159
|
+
}
|
|
160
|
+
getMcpToolErrorCalls(chatData, toolName) {
|
|
161
|
+
const monitoring = this.getMcpToolMonitoring(
|
|
162
|
+
chatData,
|
|
163
|
+
toolName
|
|
164
|
+
);
|
|
165
|
+
return monitoring.calls.filter((call) => call.isError);
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Простой метод для получения всех вызовов конкретного MCP инструмента
|
|
169
|
+
* @param chatData - данные чата
|
|
170
|
+
* @param toolName - название инструмента (например, 'update_entry_fields')
|
|
171
|
+
* @returns массив всех вызовов инструмента
|
|
172
|
+
*/
|
|
173
|
+
getMcpToolCalls(chatData, toolName) {
|
|
174
|
+
const allToolCalls = this.extractMcpToolCalls(chatData);
|
|
175
|
+
return allToolCalls.filter(
|
|
176
|
+
(call) => call.toolName.includes(toolName) || call.toolId.includes(toolName)
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Получить список всех уникальных MCP инструментов, использованных в чате
|
|
181
|
+
* @param chatData - данные чата
|
|
182
|
+
* @returns массив названий инструментов
|
|
183
|
+
*/
|
|
184
|
+
getMcpToolNames(chatData) {
|
|
185
|
+
const allToolCalls = this.extractMcpToolCalls(chatData);
|
|
186
|
+
const uniqueNames = /* @__PURE__ */ new Set();
|
|
187
|
+
allToolCalls.forEach((call) => {
|
|
188
|
+
uniqueNames.add(call.toolName || call.toolId);
|
|
189
|
+
});
|
|
190
|
+
return Array.from(uniqueNames);
|
|
191
|
+
}
|
|
70
192
|
};
|
|
71
193
|
var index_default = CopilotChatAnalyzer;
|
|
72
194
|
export {
|
package/package.json
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "copilot-chat-analyzer",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "0.0.
|
|
5
|
-
"description": "
|
|
4
|
+
"version": "0.0.3",
|
|
5
|
+
"description": "TypeScript library for analyzing and monitoring GitHub Copilot chat exports with status detection, request counting, and MCP tool tracking",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"copilot",
|
|
8
8
|
"chat",
|
|
9
9
|
"analyzer",
|
|
10
10
|
"github",
|
|
11
|
-
"typescript"
|
|
11
|
+
"typescript",
|
|
12
|
+
"mcp",
|
|
13
|
+
"model-context-protocol",
|
|
14
|
+
"monitoring",
|
|
15
|
+
"status-detection",
|
|
16
|
+
"dialog-analysis",
|
|
17
|
+
"ai-tools",
|
|
18
|
+
"export-analysis"
|
|
12
19
|
],
|
|
13
20
|
"author": "dealenx",
|
|
14
21
|
"license": "MIT",
|
|
@@ -20,6 +27,35 @@
|
|
|
20
27
|
"url": "https://github.com/dealenx/copilot-chat-analyzer/issues"
|
|
21
28
|
},
|
|
22
29
|
"homepage": "https://github.com/dealenx/copilot-chat-analyzer#readme",
|
|
30
|
+
"funding": {
|
|
31
|
+
"type": "github",
|
|
32
|
+
"url": "https://github.com/sponsors/dealenx"
|
|
33
|
+
},
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=16.0.0"
|
|
36
|
+
},
|
|
37
|
+
"ai-usage": {
|
|
38
|
+
"purpose": "Analyze GitHub Copilot chat exports for dialog status, request counting, and MCP tool monitoring",
|
|
39
|
+
"quick-start": "import CopilotChatAnalyzer, { DialogStatus } from 'copilot-chat-analyzer'; const analyzer = new CopilotChatAnalyzer(); const status = analyzer.getDialogStatus(chatData);",
|
|
40
|
+
"main-features": [
|
|
41
|
+
"Dialog status detection (pending, in_progress, completed, canceled)",
|
|
42
|
+
"Request counting and analysis",
|
|
43
|
+
"MCP (Model Context Protocol) tool monitoring",
|
|
44
|
+
"Chat export validation and parsing"
|
|
45
|
+
],
|
|
46
|
+
"common-methods": {
|
|
47
|
+
"getDialogStatus": "Returns dialog status: 'pending' | 'completed' | 'canceled' | 'in_progress'",
|
|
48
|
+
"getRequestsCount": "Returns number of requests in chat",
|
|
49
|
+
"getDialogStatusDetails": "Returns detailed status information with flags",
|
|
50
|
+
"getMcpToolMonitoring": "Returns MCP tool usage statistics and monitoring data"
|
|
51
|
+
},
|
|
52
|
+
"status-meanings": {
|
|
53
|
+
"pending": "Chat created but no requests made yet (requests: [])",
|
|
54
|
+
"in_progress": "Chat has requests but not completed",
|
|
55
|
+
"completed": "Chat finished successfully (has followups: [])",
|
|
56
|
+
"canceled": "Chat was canceled (isCanceled: true)"
|
|
57
|
+
}
|
|
58
|
+
},
|
|
23
59
|
"type": "module",
|
|
24
60
|
"main": "dist/index.cjs",
|
|
25
61
|
"module": "dist/index.mjs",
|
|
@@ -33,7 +69,10 @@
|
|
|
33
69
|
}
|
|
34
70
|
},
|
|
35
71
|
"files": [
|
|
36
|
-
"dist"
|
|
72
|
+
"dist",
|
|
73
|
+
"README.md",
|
|
74
|
+
"AI_USAGE.md",
|
|
75
|
+
"LICENSE"
|
|
37
76
|
],
|
|
38
77
|
"devDependencies": {
|
|
39
78
|
"@types/jest": "^30.0.0",
|