@snap-agent/analytics-console 0.1.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/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 ViloTech
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
package/README.md ADDED
@@ -0,0 +1,195 @@
1
+ # @snap-agent/analytics-console
2
+
3
+ Console analytics plugin for SnapAgent SDK - Pretty-print metrics to terminal for debugging.
4
+
5
+ ## Features
6
+
7
+ - **Pretty Console Output** - Color-coded, formatted logs
8
+ - **Three Log Levels** - Minimal, standard, verbose
9
+ - **Periodic Summaries** - Automatic stats output
10
+ - **Colorful** - Easy to scan terminal output
11
+ - **Perfect for Dev** - Quick debugging during development
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ npm install @snap-agent/analytics-console @snap-agent/core
17
+ ```
18
+
19
+ ## Quick Start
20
+
21
+ ```typescript
22
+ import { createClient, MemoryStorage } from '@snap-agent/core';
23
+ import { ConsoleAnalytics } from '@snap-agent/analytics-console';
24
+
25
+ const client = createClient({
26
+ storage: new MemoryStorage(),
27
+ providers: {
28
+ openai: { apiKey: process.env.OPENAI_API_KEY! },
29
+ },
30
+ });
31
+
32
+ const agent = await client.createAgent({
33
+ name: 'Debug Demo',
34
+ instructions: 'You are helpful.',
35
+ model: 'gpt-4o',
36
+ userId: 'user-123',
37
+ plugins: [
38
+ new ConsoleAnalytics({
39
+ level: 'verbose',
40
+ }),
41
+ ],
42
+ });
43
+
44
+ // Use the agent - see pretty logs!
45
+ ```
46
+
47
+ ## Output Examples
48
+
49
+ ### Standard Level
50
+ ```
51
+ [14:32:15.123] [SnapAgent] -> Request agent:abc12345 thread:xyz98765
52
+ [14:32:16.456] [SnapAgent] <- Response 1333ms 450 tokens agent:abc12345
53
+ ```
54
+
55
+ ### Verbose Level
56
+ ```
57
+ [14:32:15.123] [SnapAgent] -> Request agent:abc12345 thread:xyz98765
58
+ Message: Hello, can you help me with...
59
+
60
+ [14:32:16.456] [SnapAgent] <- Response 1333ms 450 tokens agent:abc12345
61
+ Response: Of course! I'd be happy to help you with...
62
+ ```
63
+
64
+ ### Error
65
+ ```
66
+ [14:32:17.789] [SnapAgent] x Error rate_limit agent:abc12345
67
+ Message: Rate limit exceeded. Please retry after 60 seconds.
68
+ ```
69
+
70
+ ### Summary
71
+ ```
72
+ [SnapAgent] Summary
73
+ ----------------------------------------
74
+ Requests: 25
75
+ Responses: 24
76
+ Errors: 1
77
+ Avg Latency: 892ms
78
+ Avg Tokens: 380
79
+ Total Tokens: 9120
80
+ ----------------------------------------
81
+ ```
82
+
83
+ ## Configuration
84
+
85
+ ```typescript
86
+ new ConsoleAnalytics({
87
+ // Log level: 'minimal' | 'standard' | 'verbose'
88
+ level: 'standard',
89
+
90
+ // Enable colored output
91
+ colors: true,
92
+
93
+ // Show timestamps
94
+ timestamps: true,
95
+
96
+ // Custom prefix
97
+ prefix: '[SnapAgent]',
98
+
99
+ // What to log
100
+ logRequests: true,
101
+ logResponses: true,
102
+ logErrors: true,
103
+
104
+ // Print summary every N ms (0 = disabled)
105
+ summaryInterval: 60000, // Every minute
106
+ });
107
+ ```
108
+
109
+ ## Log Levels
110
+
111
+ ### `minimal`
112
+ Just counts, no details:
113
+ ```
114
+ [SnapAgent] -> Request
115
+ [SnapAgent] <- Response 450ms
116
+ ```
117
+
118
+ ### `standard` (default)
119
+ Includes agent/thread IDs and tokens:
120
+ ```
121
+ [SnapAgent] -> Request agent:abc12345 thread:xyz98765
122
+ [SnapAgent] <- Response 450ms 380 tokens agent:abc12345
123
+ ```
124
+
125
+ ### `verbose`
126
+ Full message content:
127
+ ```
128
+ [SnapAgent] -> Request agent:abc12345 thread:xyz98765
129
+ Message: What is the weather like today?
130
+
131
+ [SnapAgent] <- Response 450ms 380 tokens agent:abc12345
132
+ Response: I don't have access to real-time weather data...
133
+ ```
134
+
135
+ ## API
136
+
137
+ ### `printSummary()`
138
+ Manually print the current summary:
139
+ ```typescript
140
+ const analytics = new ConsoleAnalytics();
141
+ // ... use agent ...
142
+ analytics.printSummary();
143
+ ```
144
+
145
+ ### `reset()`
146
+ Reset all counters:
147
+ ```typescript
148
+ analytics.reset();
149
+ ```
150
+
151
+ ### `getStats()`
152
+ Get current stats as object:
153
+ ```typescript
154
+ const stats = analytics.getStats();
155
+ // { requests: 25, responses: 24, errors: 1, avgLatency: 892, totalTokens: 9120 }
156
+ ```
157
+
158
+ ### `destroy()`
159
+ Clean up (stops summary timer):
160
+ ```typescript
161
+ analytics.destroy();
162
+ ```
163
+
164
+ ## Color Reference
165
+
166
+ | Color | Meaning |
167
+ |-------|---------|
168
+ | Cyan | Requests |
169
+ | Green | Successful responses, fast latency (<500ms) |
170
+ | Yellow | Medium latency (500-2000ms) |
171
+ | Red | Errors, slow latency (>2000ms) |
172
+ | Dim | Metadata, IDs |
173
+
174
+ ## Disable Colors
175
+
176
+ For CI/CD or piping to files:
177
+ ```typescript
178
+ new ConsoleAnalytics({
179
+ colors: false,
180
+ });
181
+ ```
182
+
183
+ ## Use Cases
184
+
185
+ - **Local Development** - Quick visibility into agent behavior
186
+ - **Debugging** - See what's happening in real-time
187
+ - **Demos** - Show activity during presentations
188
+ - **Learning** - Understand the request/response flow
189
+
190
+ For production monitoring, use [@snap-agent/analytics](../core) instead.
191
+
192
+ ## License
193
+
194
+ MIT © ViloTech
195
+
@@ -0,0 +1,111 @@
1
+ import { AnalyticsPlugin } from '@snap-agent/core';
2
+
3
+ type LogLevel = 'minimal' | 'standard' | 'verbose';
4
+ interface ConsoleAnalyticsConfig {
5
+ /**
6
+ * Log level
7
+ * - minimal: Just request/response counts
8
+ * - standard: Include latency and tokens
9
+ * - verbose: Include all details
10
+ * @default 'standard'
11
+ */
12
+ level?: LogLevel;
13
+ /**
14
+ * Enable colored output
15
+ * @default true
16
+ */
17
+ colors?: boolean;
18
+ /**
19
+ * Show timestamps
20
+ * @default true
21
+ */
22
+ timestamps?: boolean;
23
+ /**
24
+ * Prefix for log messages
25
+ * @default '[SnapAgent]'
26
+ */
27
+ prefix?: string;
28
+ /**
29
+ * Log requests
30
+ * @default true
31
+ */
32
+ logRequests?: boolean;
33
+ /**
34
+ * Log responses
35
+ * @default true
36
+ */
37
+ logResponses?: boolean;
38
+ /**
39
+ * Log errors
40
+ * @default true
41
+ */
42
+ logErrors?: boolean;
43
+ /**
44
+ * Show periodic summaries (interval in ms, 0 = disabled)
45
+ * @default 0
46
+ */
47
+ summaryInterval?: number;
48
+ }
49
+ /**
50
+ * Console Analytics Plugin
51
+ *
52
+ * Simple plugin that pretty-prints analytics to the console.
53
+ * Perfect for development and debugging.
54
+ */
55
+ declare class ConsoleAnalytics implements AnalyticsPlugin {
56
+ name: string;
57
+ type: "analytics";
58
+ private config;
59
+ private requestCount;
60
+ private responseCount;
61
+ private errorCount;
62
+ private totalLatency;
63
+ private totalTokens;
64
+ private summaryTimer?;
65
+ constructor(config?: ConsoleAnalyticsConfig);
66
+ trackRequest(data: {
67
+ agentId: string;
68
+ threadId?: string;
69
+ message: string;
70
+ timestamp: Date;
71
+ }): Promise<void>;
72
+ trackResponse(data: {
73
+ agentId: string;
74
+ threadId?: string;
75
+ response: string;
76
+ latency: number;
77
+ tokensUsed?: number;
78
+ timestamp: Date;
79
+ }): Promise<void>;
80
+ trackError(data: {
81
+ agentId: string;
82
+ threadId?: string;
83
+ timestamp: Date;
84
+ errorType: string;
85
+ errorMessage: string;
86
+ }): Promise<void>;
87
+ printSummary(): void;
88
+ /**
89
+ * Reset counters
90
+ */
91
+ reset(): void;
92
+ /**
93
+ * Get current stats
94
+ */
95
+ getStats(): Record<string, number>;
96
+ /**
97
+ * Stop summary timer
98
+ */
99
+ destroy(): void;
100
+ private formatTime;
101
+ private truncate;
102
+ private formatLatency;
103
+ private bold;
104
+ private dim;
105
+ private green;
106
+ private yellow;
107
+ private red;
108
+ private cyan;
109
+ }
110
+
111
+ export { ConsoleAnalytics, type ConsoleAnalyticsConfig, type LogLevel };
@@ -0,0 +1,111 @@
1
+ import { AnalyticsPlugin } from '@snap-agent/core';
2
+
3
+ type LogLevel = 'minimal' | 'standard' | 'verbose';
4
+ interface ConsoleAnalyticsConfig {
5
+ /**
6
+ * Log level
7
+ * - minimal: Just request/response counts
8
+ * - standard: Include latency and tokens
9
+ * - verbose: Include all details
10
+ * @default 'standard'
11
+ */
12
+ level?: LogLevel;
13
+ /**
14
+ * Enable colored output
15
+ * @default true
16
+ */
17
+ colors?: boolean;
18
+ /**
19
+ * Show timestamps
20
+ * @default true
21
+ */
22
+ timestamps?: boolean;
23
+ /**
24
+ * Prefix for log messages
25
+ * @default '[SnapAgent]'
26
+ */
27
+ prefix?: string;
28
+ /**
29
+ * Log requests
30
+ * @default true
31
+ */
32
+ logRequests?: boolean;
33
+ /**
34
+ * Log responses
35
+ * @default true
36
+ */
37
+ logResponses?: boolean;
38
+ /**
39
+ * Log errors
40
+ * @default true
41
+ */
42
+ logErrors?: boolean;
43
+ /**
44
+ * Show periodic summaries (interval in ms, 0 = disabled)
45
+ * @default 0
46
+ */
47
+ summaryInterval?: number;
48
+ }
49
+ /**
50
+ * Console Analytics Plugin
51
+ *
52
+ * Simple plugin that pretty-prints analytics to the console.
53
+ * Perfect for development and debugging.
54
+ */
55
+ declare class ConsoleAnalytics implements AnalyticsPlugin {
56
+ name: string;
57
+ type: "analytics";
58
+ private config;
59
+ private requestCount;
60
+ private responseCount;
61
+ private errorCount;
62
+ private totalLatency;
63
+ private totalTokens;
64
+ private summaryTimer?;
65
+ constructor(config?: ConsoleAnalyticsConfig);
66
+ trackRequest(data: {
67
+ agentId: string;
68
+ threadId?: string;
69
+ message: string;
70
+ timestamp: Date;
71
+ }): Promise<void>;
72
+ trackResponse(data: {
73
+ agentId: string;
74
+ threadId?: string;
75
+ response: string;
76
+ latency: number;
77
+ tokensUsed?: number;
78
+ timestamp: Date;
79
+ }): Promise<void>;
80
+ trackError(data: {
81
+ agentId: string;
82
+ threadId?: string;
83
+ timestamp: Date;
84
+ errorType: string;
85
+ errorMessage: string;
86
+ }): Promise<void>;
87
+ printSummary(): void;
88
+ /**
89
+ * Reset counters
90
+ */
91
+ reset(): void;
92
+ /**
93
+ * Get current stats
94
+ */
95
+ getStats(): Record<string, number>;
96
+ /**
97
+ * Stop summary timer
98
+ */
99
+ destroy(): void;
100
+ private formatTime;
101
+ private truncate;
102
+ private formatLatency;
103
+ private bold;
104
+ private dim;
105
+ private green;
106
+ private yellow;
107
+ private red;
108
+ private cyan;
109
+ }
110
+
111
+ export { ConsoleAnalytics, type ConsoleAnalyticsConfig, type LogLevel };
package/dist/index.js ADDED
@@ -0,0 +1,214 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ ConsoleAnalytics: () => ConsoleAnalytics
24
+ });
25
+ module.exports = __toCommonJS(index_exports);
26
+
27
+ // src/ConsoleAnalytics.ts
28
+ var ConsoleAnalytics = class {
29
+ constructor(config = {}) {
30
+ this.name = "console-analytics";
31
+ this.type = "analytics";
32
+ this.requestCount = 0;
33
+ this.responseCount = 0;
34
+ this.errorCount = 0;
35
+ this.totalLatency = 0;
36
+ this.totalTokens = 0;
37
+ this.config = {
38
+ level: config.level || "standard",
39
+ colors: config.colors !== false,
40
+ timestamps: config.timestamps !== false,
41
+ prefix: config.prefix || "[SnapAgent]",
42
+ logRequests: config.logRequests !== false,
43
+ logResponses: config.logResponses !== false,
44
+ logErrors: config.logErrors !== false,
45
+ summaryInterval: config.summaryInterval || 0
46
+ };
47
+ if (this.config.summaryInterval > 0) {
48
+ this.summaryTimer = setInterval(
49
+ () => this.printSummary(),
50
+ this.config.summaryInterval
51
+ );
52
+ }
53
+ }
54
+ // ============================================================================
55
+ // Plugin Interface
56
+ // ============================================================================
57
+ async trackRequest(data) {
58
+ this.requestCount++;
59
+ if (!this.config.logRequests) return;
60
+ const parts = [];
61
+ if (this.config.timestamps) {
62
+ parts.push(this.dim(`[${this.formatTime(data.timestamp)}]`));
63
+ }
64
+ parts.push(this.config.prefix);
65
+ parts.push(this.cyan("\u2192 Request"));
66
+ if (this.config.level !== "minimal") {
67
+ parts.push(this.dim(`agent:${data.agentId.slice(0, 8)}`));
68
+ if (data.threadId) {
69
+ parts.push(this.dim(`thread:${data.threadId.slice(0, 8)}`));
70
+ }
71
+ }
72
+ if (this.config.level === "verbose") {
73
+ parts.push(`
74
+ ${this.dim("Message:")} ${this.truncate(data.message, 100)}`);
75
+ }
76
+ console.log(parts.join(" "));
77
+ }
78
+ async trackResponse(data) {
79
+ this.responseCount++;
80
+ this.totalLatency += data.latency;
81
+ this.totalTokens += data.tokensUsed || 0;
82
+ if (!this.config.logResponses) return;
83
+ const parts = [];
84
+ if (this.config.timestamps) {
85
+ parts.push(this.dim(`[${this.formatTime(data.timestamp)}]`));
86
+ }
87
+ parts.push(this.config.prefix);
88
+ parts.push(this.green("\u2190 Response"));
89
+ const latencyColor = data.latency < 500 ? "green" : data.latency < 2e3 ? "yellow" : "red";
90
+ parts.push(this[latencyColor](`${data.latency}ms`));
91
+ if (this.config.level !== "minimal" && data.tokensUsed) {
92
+ parts.push(this.dim(`${data.tokensUsed} tokens`));
93
+ }
94
+ if (this.config.level !== "minimal") {
95
+ parts.push(this.dim(`agent:${data.agentId.slice(0, 8)}`));
96
+ }
97
+ if (this.config.level === "verbose") {
98
+ parts.push(`
99
+ ${this.dim("Response:")} ${this.truncate(data.response, 150)}`);
100
+ }
101
+ console.log(parts.join(" "));
102
+ }
103
+ // ============================================================================
104
+ // Extended Tracking (Optional)
105
+ // ============================================================================
106
+ async trackError(data) {
107
+ this.errorCount++;
108
+ if (!this.config.logErrors) return;
109
+ const parts = [];
110
+ if (this.config.timestamps) {
111
+ parts.push(this.dim(`[${this.formatTime(data.timestamp)}]`));
112
+ }
113
+ parts.push(this.config.prefix);
114
+ parts.push(this.red("x Error"));
115
+ parts.push(this.red(data.errorType));
116
+ if (this.config.level !== "minimal") {
117
+ parts.push(this.dim(`agent:${data.agentId.slice(0, 8)}`));
118
+ }
119
+ if (this.config.level === "verbose") {
120
+ parts.push(`
121
+ ${this.dim("Message:")} ${data.errorMessage}`);
122
+ }
123
+ console.log(parts.join(" "));
124
+ }
125
+ // ============================================================================
126
+ // Summary
127
+ // ============================================================================
128
+ printSummary() {
129
+ const avgLatency = this.responseCount > 0 ? Math.round(this.totalLatency / this.responseCount) : 0;
130
+ const avgTokens = this.responseCount > 0 ? Math.round(this.totalTokens / this.responseCount) : 0;
131
+ console.log("");
132
+ console.log(this.bold(`${this.config.prefix} Summary`));
133
+ console.log(this.dim("\u2500".repeat(40)));
134
+ console.log(` Requests: ${this.cyan(this.requestCount.toString())}`);
135
+ console.log(` Responses: ${this.green(this.responseCount.toString())}`);
136
+ console.log(` Errors: ${this.errorCount > 0 ? this.red(this.errorCount.toString()) : this.dim("0")}`);
137
+ console.log(` Avg Latency: ${this.formatLatency(avgLatency)}`);
138
+ console.log(` Avg Tokens: ${this.dim(avgTokens.toString())}`);
139
+ console.log(` Total Tokens: ${this.dim(this.totalTokens.toString())}`);
140
+ console.log(this.dim("\u2500".repeat(40)));
141
+ console.log("");
142
+ }
143
+ /**
144
+ * Reset counters
145
+ */
146
+ reset() {
147
+ this.requestCount = 0;
148
+ this.responseCount = 0;
149
+ this.errorCount = 0;
150
+ this.totalLatency = 0;
151
+ this.totalTokens = 0;
152
+ }
153
+ /**
154
+ * Get current stats
155
+ */
156
+ getStats() {
157
+ return {
158
+ requests: this.requestCount,
159
+ responses: this.responseCount,
160
+ errors: this.errorCount,
161
+ avgLatency: this.responseCount > 0 ? Math.round(this.totalLatency / this.responseCount) : 0,
162
+ totalTokens: this.totalTokens
163
+ };
164
+ }
165
+ /**
166
+ * Stop summary timer
167
+ */
168
+ destroy() {
169
+ if (this.summaryTimer) {
170
+ clearInterval(this.summaryTimer);
171
+ }
172
+ }
173
+ // ============================================================================
174
+ // Formatting Helpers
175
+ // ============================================================================
176
+ formatTime(date) {
177
+ return date.toISOString().slice(11, 23);
178
+ }
179
+ truncate(str, maxLen) {
180
+ const cleaned = str.replace(/\n/g, " ").trim();
181
+ if (cleaned.length <= maxLen) return cleaned;
182
+ return cleaned.slice(0, maxLen - 3) + "...";
183
+ }
184
+ formatLatency(ms) {
185
+ if (ms < 500) return this.green(`${ms}ms`);
186
+ if (ms < 2e3) return this.yellow(`${ms}ms`);
187
+ return this.red(`${ms}ms`);
188
+ }
189
+ // ============================================================================
190
+ // Color Helpers
191
+ // ============================================================================
192
+ bold(text) {
193
+ return this.config.colors ? `\x1B[1m${text}\x1B[0m` : text;
194
+ }
195
+ dim(text) {
196
+ return this.config.colors ? `\x1B[2m${text}\x1B[0m` : text;
197
+ }
198
+ green(text) {
199
+ return this.config.colors ? `\x1B[32m${text}\x1B[0m` : text;
200
+ }
201
+ yellow(text) {
202
+ return this.config.colors ? `\x1B[33m${text}\x1B[0m` : text;
203
+ }
204
+ red(text) {
205
+ return this.config.colors ? `\x1B[31m${text}\x1B[0m` : text;
206
+ }
207
+ cyan(text) {
208
+ return this.config.colors ? `\x1B[36m${text}\x1B[0m` : text;
209
+ }
210
+ };
211
+ // Annotate the CommonJS export names for ESM import in node:
212
+ 0 && (module.exports = {
213
+ ConsoleAnalytics
214
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,187 @@
1
+ // src/ConsoleAnalytics.ts
2
+ var ConsoleAnalytics = class {
3
+ constructor(config = {}) {
4
+ this.name = "console-analytics";
5
+ this.type = "analytics";
6
+ this.requestCount = 0;
7
+ this.responseCount = 0;
8
+ this.errorCount = 0;
9
+ this.totalLatency = 0;
10
+ this.totalTokens = 0;
11
+ this.config = {
12
+ level: config.level || "standard",
13
+ colors: config.colors !== false,
14
+ timestamps: config.timestamps !== false,
15
+ prefix: config.prefix || "[SnapAgent]",
16
+ logRequests: config.logRequests !== false,
17
+ logResponses: config.logResponses !== false,
18
+ logErrors: config.logErrors !== false,
19
+ summaryInterval: config.summaryInterval || 0
20
+ };
21
+ if (this.config.summaryInterval > 0) {
22
+ this.summaryTimer = setInterval(
23
+ () => this.printSummary(),
24
+ this.config.summaryInterval
25
+ );
26
+ }
27
+ }
28
+ // ============================================================================
29
+ // Plugin Interface
30
+ // ============================================================================
31
+ async trackRequest(data) {
32
+ this.requestCount++;
33
+ if (!this.config.logRequests) return;
34
+ const parts = [];
35
+ if (this.config.timestamps) {
36
+ parts.push(this.dim(`[${this.formatTime(data.timestamp)}]`));
37
+ }
38
+ parts.push(this.config.prefix);
39
+ parts.push(this.cyan("\u2192 Request"));
40
+ if (this.config.level !== "minimal") {
41
+ parts.push(this.dim(`agent:${data.agentId.slice(0, 8)}`));
42
+ if (data.threadId) {
43
+ parts.push(this.dim(`thread:${data.threadId.slice(0, 8)}`));
44
+ }
45
+ }
46
+ if (this.config.level === "verbose") {
47
+ parts.push(`
48
+ ${this.dim("Message:")} ${this.truncate(data.message, 100)}`);
49
+ }
50
+ console.log(parts.join(" "));
51
+ }
52
+ async trackResponse(data) {
53
+ this.responseCount++;
54
+ this.totalLatency += data.latency;
55
+ this.totalTokens += data.tokensUsed || 0;
56
+ if (!this.config.logResponses) return;
57
+ const parts = [];
58
+ if (this.config.timestamps) {
59
+ parts.push(this.dim(`[${this.formatTime(data.timestamp)}]`));
60
+ }
61
+ parts.push(this.config.prefix);
62
+ parts.push(this.green("\u2190 Response"));
63
+ const latencyColor = data.latency < 500 ? "green" : data.latency < 2e3 ? "yellow" : "red";
64
+ parts.push(this[latencyColor](`${data.latency}ms`));
65
+ if (this.config.level !== "minimal" && data.tokensUsed) {
66
+ parts.push(this.dim(`${data.tokensUsed} tokens`));
67
+ }
68
+ if (this.config.level !== "minimal") {
69
+ parts.push(this.dim(`agent:${data.agentId.slice(0, 8)}`));
70
+ }
71
+ if (this.config.level === "verbose") {
72
+ parts.push(`
73
+ ${this.dim("Response:")} ${this.truncate(data.response, 150)}`);
74
+ }
75
+ console.log(parts.join(" "));
76
+ }
77
+ // ============================================================================
78
+ // Extended Tracking (Optional)
79
+ // ============================================================================
80
+ async trackError(data) {
81
+ this.errorCount++;
82
+ if (!this.config.logErrors) return;
83
+ const parts = [];
84
+ if (this.config.timestamps) {
85
+ parts.push(this.dim(`[${this.formatTime(data.timestamp)}]`));
86
+ }
87
+ parts.push(this.config.prefix);
88
+ parts.push(this.red("x Error"));
89
+ parts.push(this.red(data.errorType));
90
+ if (this.config.level !== "minimal") {
91
+ parts.push(this.dim(`agent:${data.agentId.slice(0, 8)}`));
92
+ }
93
+ if (this.config.level === "verbose") {
94
+ parts.push(`
95
+ ${this.dim("Message:")} ${data.errorMessage}`);
96
+ }
97
+ console.log(parts.join(" "));
98
+ }
99
+ // ============================================================================
100
+ // Summary
101
+ // ============================================================================
102
+ printSummary() {
103
+ const avgLatency = this.responseCount > 0 ? Math.round(this.totalLatency / this.responseCount) : 0;
104
+ const avgTokens = this.responseCount > 0 ? Math.round(this.totalTokens / this.responseCount) : 0;
105
+ console.log("");
106
+ console.log(this.bold(`${this.config.prefix} Summary`));
107
+ console.log(this.dim("\u2500".repeat(40)));
108
+ console.log(` Requests: ${this.cyan(this.requestCount.toString())}`);
109
+ console.log(` Responses: ${this.green(this.responseCount.toString())}`);
110
+ console.log(` Errors: ${this.errorCount > 0 ? this.red(this.errorCount.toString()) : this.dim("0")}`);
111
+ console.log(` Avg Latency: ${this.formatLatency(avgLatency)}`);
112
+ console.log(` Avg Tokens: ${this.dim(avgTokens.toString())}`);
113
+ console.log(` Total Tokens: ${this.dim(this.totalTokens.toString())}`);
114
+ console.log(this.dim("\u2500".repeat(40)));
115
+ console.log("");
116
+ }
117
+ /**
118
+ * Reset counters
119
+ */
120
+ reset() {
121
+ this.requestCount = 0;
122
+ this.responseCount = 0;
123
+ this.errorCount = 0;
124
+ this.totalLatency = 0;
125
+ this.totalTokens = 0;
126
+ }
127
+ /**
128
+ * Get current stats
129
+ */
130
+ getStats() {
131
+ return {
132
+ requests: this.requestCount,
133
+ responses: this.responseCount,
134
+ errors: this.errorCount,
135
+ avgLatency: this.responseCount > 0 ? Math.round(this.totalLatency / this.responseCount) : 0,
136
+ totalTokens: this.totalTokens
137
+ };
138
+ }
139
+ /**
140
+ * Stop summary timer
141
+ */
142
+ destroy() {
143
+ if (this.summaryTimer) {
144
+ clearInterval(this.summaryTimer);
145
+ }
146
+ }
147
+ // ============================================================================
148
+ // Formatting Helpers
149
+ // ============================================================================
150
+ formatTime(date) {
151
+ return date.toISOString().slice(11, 23);
152
+ }
153
+ truncate(str, maxLen) {
154
+ const cleaned = str.replace(/\n/g, " ").trim();
155
+ if (cleaned.length <= maxLen) return cleaned;
156
+ return cleaned.slice(0, maxLen - 3) + "...";
157
+ }
158
+ formatLatency(ms) {
159
+ if (ms < 500) return this.green(`${ms}ms`);
160
+ if (ms < 2e3) return this.yellow(`${ms}ms`);
161
+ return this.red(`${ms}ms`);
162
+ }
163
+ // ============================================================================
164
+ // Color Helpers
165
+ // ============================================================================
166
+ bold(text) {
167
+ return this.config.colors ? `\x1B[1m${text}\x1B[0m` : text;
168
+ }
169
+ dim(text) {
170
+ return this.config.colors ? `\x1B[2m${text}\x1B[0m` : text;
171
+ }
172
+ green(text) {
173
+ return this.config.colors ? `\x1B[32m${text}\x1B[0m` : text;
174
+ }
175
+ yellow(text) {
176
+ return this.config.colors ? `\x1B[33m${text}\x1B[0m` : text;
177
+ }
178
+ red(text) {
179
+ return this.config.colors ? `\x1B[31m${text}\x1B[0m` : text;
180
+ }
181
+ cyan(text) {
182
+ return this.config.colors ? `\x1B[36m${text}\x1B[0m` : text;
183
+ }
184
+ };
185
+ export {
186
+ ConsoleAnalytics
187
+ };
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "@snap-agent/analytics-console",
3
+ "version": "0.1.0",
4
+ "description": "Console analytics plugin for SnapAgent SDK - Pretty-print metrics to terminal for debugging",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "README.md",
18
+ "LICENSE"
19
+ ],
20
+ "scripts": {
21
+ "build": "tsup src/index.ts --format cjs,esm --dts --clean",
22
+ "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
23
+ "test": "vitest run",
24
+ "test:watch": "vitest",
25
+ "prepublishOnly": "npm run build"
26
+ },
27
+ "keywords": [
28
+ "snap-agent",
29
+ "analytics",
30
+ "console",
31
+ "debugging",
32
+ "logging",
33
+ "metrics"
34
+ ],
35
+ "author": "ViloTech",
36
+ "license": "MIT",
37
+ "publishConfig": {
38
+ "access": "public"
39
+ },
40
+ "peerDependencies": {
41
+ "@snap-agent/core": "^0.1.0"
42
+ },
43
+ "devDependencies": {
44
+ "@types/node": "^24.0.0",
45
+ "tsup": "^8.0.0",
46
+ "typescript": "^5.8.0",
47
+ "vitest": "^3.2.4"
48
+ },
49
+ "repository": {
50
+ "type": "git",
51
+ "url": "git+https://github.com/vilo-hq/snap-agent.git",
52
+ "directory": "plugins/analytics/console"
53
+ },
54
+ "homepage": "https://github.com/vilo-hq/snap-agent/tree/main/plugins/analytics/console",
55
+ "bugs": {
56
+ "url": "https://github.com/vilo-hq/snap-agent/issues"
57
+ }
58
+ }
59
+