@panguard-ai/panguard-chat 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/dist/agent/chat-agent.d.ts +69 -0
- package/dist/agent/chat-agent.d.ts.map +1 -0
- package/dist/agent/chat-agent.js +477 -0
- package/dist/agent/chat-agent.js.map +1 -0
- package/dist/agent/formatter.d.ts +59 -0
- package/dist/agent/formatter.d.ts.map +1 -0
- package/dist/agent/formatter.js +399 -0
- package/dist/agent/formatter.js.map +1 -0
- package/dist/agent/index.d.ts +10 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +10 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/agent/prompts.d.ts +27 -0
- package/dist/agent/prompts.d.ts.map +1 -0
- package/dist/agent/prompts.js +164 -0
- package/dist/agent/prompts.js.map +1 -0
- package/dist/channels/email.d.ts +47 -0
- package/dist/channels/email.d.ts.map +1 -0
- package/dist/channels/email.js +250 -0
- package/dist/channels/email.js.map +1 -0
- package/dist/channels/index.d.ts +11 -0
- package/dist/channels/index.d.ts.map +1 -0
- package/dist/channels/index.js +11 -0
- package/dist/channels/index.js.map +1 -0
- package/dist/channels/line.d.ts.map +1 -0
- package/dist/channels/slack.d.ts +67 -0
- package/dist/channels/slack.d.ts.map +1 -0
- package/dist/channels/slack.js +269 -0
- package/dist/channels/slack.js.map +1 -0
- package/dist/channels/telegram.d.ts +69 -0
- package/dist/channels/telegram.d.ts.map +1 -0
- package/dist/channels/telegram.js +244 -0
- package/dist/channels/telegram.js.map +1 -0
- package/dist/channels/webhook.d.ts +70 -0
- package/dist/channels/webhook.d.ts.map +1 -0
- package/dist/channels/webhook.js +224 -0
- package/dist/channels/webhook.js.map +1 -0
- package/dist/cli/index.d.ts +22 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +337 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +41 -0
- package/dist/index.js.map +1 -0
- package/dist/onboarding/index.d.ts +9 -0
- package/dist/onboarding/index.d.ts.map +1 -0
- package/dist/onboarding/index.js +8 -0
- package/dist/onboarding/index.js.map +1 -0
- package/dist/onboarding/setup-flow.d.ts +65 -0
- package/dist/onboarding/setup-flow.d.ts.map +1 -0
- package/dist/onboarding/setup-flow.js +362 -0
- package/dist/onboarding/setup-flow.js.map +1 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +2 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/webhook-server.d.ts +46 -0
- package/dist/server/webhook-server.d.ts.map +1 -0
- package/dist/server/webhook-server.js +150 -0
- package/dist/server/webhook-server.js.map +1 -0
- package/dist/skills/index.d.ts +47 -0
- package/dist/skills/index.d.ts.map +1 -0
- package/dist/skills/index.js +313 -0
- package/dist/skills/index.js.map +1 -0
- package/dist/templates/alert-templates.d.ts +40 -0
- package/dist/templates/alert-templates.d.ts.map +1 -0
- package/dist/templates/alert-templates.js +159 -0
- package/dist/templates/alert-templates.js.map +1 -0
- package/dist/templates/index.d.ts +9 -0
- package/dist/templates/index.d.ts.map +1 -0
- package/dist/templates/index.js +8 -0
- package/dist/templates/index.js.map +1 -0
- package/dist/types.d.ts +246 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/package.json +34 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chat Agent Core - with message queue, persistent context, and confirmation reminders
|
|
3
|
+
* Chat Agent 核心 - 支援訊息佇列、持久化上下文和確認提醒
|
|
4
|
+
*
|
|
5
|
+
* The Chat Agent translates technical security events into human-readable
|
|
6
|
+
* messages, handles follow-up questions, manages user confirmations with
|
|
7
|
+
* auto-reminders, and persists conversation context across restarts.
|
|
8
|
+
*
|
|
9
|
+
* @module @panguard-ai/panguard-chat/agent/chat-agent
|
|
10
|
+
*/
|
|
11
|
+
import type { UserProfile, ThreatAlert, SummaryReport, LearningProgress, ConfirmationRequest, ConfirmationResponse, ChatConfig, MessagingChannel, ChannelResult } from '../types.js';
|
|
12
|
+
/**
|
|
13
|
+
* Chat Agent - the user-facing AI security assistant with
|
|
14
|
+
* message queue retry, persistent context, and confirmation reminders.
|
|
15
|
+
*/
|
|
16
|
+
export declare class ChatAgent {
|
|
17
|
+
private readonly config;
|
|
18
|
+
private readonly channels;
|
|
19
|
+
private readonly followUpContexts;
|
|
20
|
+
private readonly pendingConfirmations;
|
|
21
|
+
private readonly systemPrompt;
|
|
22
|
+
/** Message queue for retry on failure */
|
|
23
|
+
private readonly messageQueue;
|
|
24
|
+
/** Retry timer */
|
|
25
|
+
private retryTimer;
|
|
26
|
+
/** Confirmation reminder timer */
|
|
27
|
+
private reminderTimer;
|
|
28
|
+
constructor(config: ChatConfig);
|
|
29
|
+
registerChannel(channel: MessagingChannel): void;
|
|
30
|
+
private getPrimaryChannel;
|
|
31
|
+
sendAlert(userId: string, alert: ThreatAlert): Promise<ChannelResult>;
|
|
32
|
+
sendSummary(userId: string, report: SummaryReport): Promise<ChannelResult>;
|
|
33
|
+
sendLearningUpdate(userId: string, progress: LearningProgress): Promise<ChannelResult>;
|
|
34
|
+
sendPeacefulReport(userId: string): Promise<ChannelResult>;
|
|
35
|
+
requestConfirmation(userId: string, request: ConfirmationRequest): Promise<ChannelResult>;
|
|
36
|
+
processConfirmation(verdictId: string, confirmed: boolean, reason?: string): ConfirmationResponse | null;
|
|
37
|
+
handleReply(userId: string, text: string): Promise<string>;
|
|
38
|
+
private handleFollowUp;
|
|
39
|
+
private tryLLMFollowUp;
|
|
40
|
+
private generateFollowUpAnswer;
|
|
41
|
+
private storeFollowUpContext;
|
|
42
|
+
private findMostRecentContext;
|
|
43
|
+
private cleanExpiredContexts;
|
|
44
|
+
/**
|
|
45
|
+
* Send message with automatic retry on failure.
|
|
46
|
+
* Failed messages are queued and retried with exponential backoff.
|
|
47
|
+
*/
|
|
48
|
+
private sendMessageWithRetry;
|
|
49
|
+
/**
|
|
50
|
+
* Background retry processor: attempts to resend failed messages
|
|
51
|
+
*/
|
|
52
|
+
private startRetryProcessor;
|
|
53
|
+
/**
|
|
54
|
+
* Background reminder processor: re-sends confirmation requests
|
|
55
|
+
* that haven't been answered within the reminder interval.
|
|
56
|
+
*/
|
|
57
|
+
private startReminderProcessor;
|
|
58
|
+
private sendMessage;
|
|
59
|
+
getSystemPrompt(): string;
|
|
60
|
+
getUserProfile(): UserProfile;
|
|
61
|
+
getRegisteredChannels(): string[];
|
|
62
|
+
getActiveContextCount(): number;
|
|
63
|
+
getPendingConfirmationCount(): number;
|
|
64
|
+
/** Get message queue depth */
|
|
65
|
+
getQueueDepth(): number;
|
|
66
|
+
/** Cleanup: clear all timers (for graceful shutdown) */
|
|
67
|
+
destroy(): void;
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=chat-agent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-agent.d.ts","sourceRoot":"","sources":["../../src/agent/chat-agent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EACV,WAAW,EAEX,WAAW,EACX,aAAa,EACb,gBAAgB,EAEhB,mBAAmB,EACnB,oBAAoB,EAGpB,UAAU,EACV,gBAAgB,EAChB,aAAa,EACd,MAAM,aAAa,CAAC;AA+DrB;;;GAGG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAa;IACpC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA4C;IACrE,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CACrB;IACZ,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAA+C;IACpF,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IAEtC,yCAAyC;IACzC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAuB;IAEpD,kBAAkB;IAClB,OAAO,CAAC,UAAU,CAA+C;IAEjE,kCAAkC;IAClC,OAAO,CAAC,aAAa,CAA+C;gBAExD,MAAM,EAAE,UAAU;IAmB9B,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI;IAShD,OAAO,CAAC,iBAAiB;IASnB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC;IAWrE,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;IAO1E,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,gBAAgB,GAAG,OAAO,CAAC,aAAa,CAAC;IAMtF,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAS1D,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,aAAa,CAAC;IAa/F,mBAAmB,CACjB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,OAAO,EAClB,MAAM,CAAC,EAAE,MAAM,GACd,oBAAoB,GAAG,IAAI;IA6BxB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;YAgClD,cAAc;YAyCd,cAAc;IAqC5B,OAAO,CAAC,sBAAsB;IA8E9B,OAAO,CAAC,oBAAoB;IAY5B,OAAO,CAAC,qBAAqB;IAY7B,OAAO,CAAC,oBAAoB;IAa5B;;;OAGG;YACW,oBAAoB;IAuBlC;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAiC3B;;;OAGG;IACH,OAAO,CAAC,sBAAsB;YAiDhB,WAAW;IA6BzB,eAAe,IAAI,MAAM;IAIzB,cAAc,IAAI,WAAW;IAI7B,qBAAqB,IAAI,MAAM,EAAE;IAIjC,qBAAqB,IAAI,MAAM;IAK/B,2BAA2B,IAAI,MAAM;IAIrC,8BAA8B;IAC9B,aAAa,IAAI,MAAM;IAIvB,wDAAwD;IACxD,OAAO,IAAI,IAAI;CAUhB"}
|
|
@@ -0,0 +1,477 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chat Agent Core - with message queue, persistent context, and confirmation reminders
|
|
3
|
+
* Chat Agent 核心 - 支援訊息佇列、持久化上下文和確認提醒
|
|
4
|
+
*
|
|
5
|
+
* The Chat Agent translates technical security events into human-readable
|
|
6
|
+
* messages, handles follow-up questions, manages user confirmations with
|
|
7
|
+
* auto-reminders, and persists conversation context across restarts.
|
|
8
|
+
*
|
|
9
|
+
* @module @panguard-ai/panguard-chat/agent/chat-agent
|
|
10
|
+
*/
|
|
11
|
+
import { createLogger } from '@panguard-ai/core';
|
|
12
|
+
import { buildSystemPrompt } from './prompts.js';
|
|
13
|
+
import { formatAlert, formatSummary, formatLearningProgress, formatConfirmation, formatPeacefulReport, } from './formatter.js';
|
|
14
|
+
const logger = createLogger('panguard-chat:agent');
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// Constants
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
/** Maximum conversation turns to keep per context */
|
|
19
|
+
const MAX_CONVERSATION_TURNS = 10;
|
|
20
|
+
/** Maximum token budget for follow-up responses */
|
|
21
|
+
const MAX_FOLLOWUP_TOKENS = 2000;
|
|
22
|
+
/** Context expiry in ms (24 hours) */
|
|
23
|
+
const CONTEXT_EXPIRY_MS = 24 * 60 * 60 * 1000;
|
|
24
|
+
/** Message queue retry attempts */
|
|
25
|
+
const MAX_RETRY_ATTEMPTS = 3;
|
|
26
|
+
/** Retry delay in ms (exponential backoff base) */
|
|
27
|
+
const RETRY_BASE_DELAY_MS = 2000;
|
|
28
|
+
/** Confirmation reminder interval (4 hours) */
|
|
29
|
+
const CONFIRMATION_REMINDER_MS = 4 * 60 * 60 * 1000;
|
|
30
|
+
/** Max reminders before auto-escalation */
|
|
31
|
+
const MAX_REMINDERS = 3;
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
// ChatAgent class
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
/**
|
|
36
|
+
* Chat Agent - the user-facing AI security assistant with
|
|
37
|
+
* message queue retry, persistent context, and confirmation reminders.
|
|
38
|
+
*/
|
|
39
|
+
export class ChatAgent {
|
|
40
|
+
config;
|
|
41
|
+
channels = new Map();
|
|
42
|
+
followUpContexts = new Map();
|
|
43
|
+
pendingConfirmations = new Map();
|
|
44
|
+
systemPrompt;
|
|
45
|
+
/** Message queue for retry on failure */
|
|
46
|
+
messageQueue = [];
|
|
47
|
+
/** Retry timer */
|
|
48
|
+
retryTimer = null;
|
|
49
|
+
/** Confirmation reminder timer */
|
|
50
|
+
reminderTimer = null;
|
|
51
|
+
constructor(config) {
|
|
52
|
+
this.config = config;
|
|
53
|
+
this.systemPrompt =
|
|
54
|
+
config.systemPromptOverride ??
|
|
55
|
+
buildSystemPrompt(config.userProfile.type, config.userProfile.language);
|
|
56
|
+
// Start background processors
|
|
57
|
+
this.startRetryProcessor();
|
|
58
|
+
this.startReminderProcessor();
|
|
59
|
+
logger.info(`ChatAgent initialized for ${config.userProfile.type} user (${config.userProfile.language})`);
|
|
60
|
+
}
|
|
61
|
+
// -------------------------------------------------------------------------
|
|
62
|
+
// Channel Management
|
|
63
|
+
// -------------------------------------------------------------------------
|
|
64
|
+
registerChannel(channel) {
|
|
65
|
+
this.channels.set(channel.channelType, channel);
|
|
66
|
+
logger.info(`Channel registered: ${channel.channelType}`);
|
|
67
|
+
channel.onReply(async (userId, text) => {
|
|
68
|
+
return this.handleReply(userId, text);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
getPrimaryChannel() {
|
|
72
|
+
const channelType = this.config.userProfile.notificationChannel;
|
|
73
|
+
return this.channels.get(channelType);
|
|
74
|
+
}
|
|
75
|
+
// -------------------------------------------------------------------------
|
|
76
|
+
// Alert Handling
|
|
77
|
+
// -------------------------------------------------------------------------
|
|
78
|
+
async sendAlert(userId, alert) {
|
|
79
|
+
const { userProfile } = this.config;
|
|
80
|
+
const message = formatAlert(alert, userProfile.type, userProfile.language);
|
|
81
|
+
logger.info(`Sending alert: ${alert.severity} ${alert.conclusion}`);
|
|
82
|
+
// Store context for follow-up
|
|
83
|
+
this.storeFollowUpContext(alert);
|
|
84
|
+
return this.sendMessageWithRetry(userId, message);
|
|
85
|
+
}
|
|
86
|
+
async sendSummary(userId, report) {
|
|
87
|
+
const { userProfile } = this.config;
|
|
88
|
+
const message = formatSummary(report, userProfile.type, userProfile.language);
|
|
89
|
+
logger.info(`Sending ${report.period} summary`);
|
|
90
|
+
return this.sendMessageWithRetry(userId, message);
|
|
91
|
+
}
|
|
92
|
+
async sendLearningUpdate(userId, progress) {
|
|
93
|
+
const message = formatLearningProgress(progress, this.config.userProfile.language);
|
|
94
|
+
logger.info(`Sending learning progress: day ${progress.day}/${progress.totalDays}`);
|
|
95
|
+
return this.sendMessageWithRetry(userId, message);
|
|
96
|
+
}
|
|
97
|
+
async sendPeacefulReport(userId) {
|
|
98
|
+
const message = formatPeacefulReport(this.config.userProfile.language);
|
|
99
|
+
return this.sendMessageWithRetry(userId, message);
|
|
100
|
+
}
|
|
101
|
+
// -------------------------------------------------------------------------
|
|
102
|
+
// Confirmation Flow with Reminders
|
|
103
|
+
// -------------------------------------------------------------------------
|
|
104
|
+
async requestConfirmation(userId, request) {
|
|
105
|
+
const tracked = {
|
|
106
|
+
...request,
|
|
107
|
+
reminderCount: 0,
|
|
108
|
+
lastReminderAt: Date.now(),
|
|
109
|
+
};
|
|
110
|
+
this.pendingConfirmations.set(request.verdictId, tracked);
|
|
111
|
+
const message = formatConfirmation(request, this.config.userProfile.language);
|
|
112
|
+
logger.info(`Requesting confirmation for verdict ${request.verdictId}`);
|
|
113
|
+
return this.sendMessageWithRetry(userId, message);
|
|
114
|
+
}
|
|
115
|
+
processConfirmation(verdictId, confirmed, reason) {
|
|
116
|
+
const request = this.pendingConfirmations.get(verdictId);
|
|
117
|
+
if (!request) {
|
|
118
|
+
logger.warn(`No pending confirmation for verdict ${verdictId}`);
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
if (new Date(request.expiresAt).getTime() < Date.now()) {
|
|
122
|
+
this.pendingConfirmations.delete(verdictId);
|
|
123
|
+
logger.warn(`Confirmation expired for verdict ${verdictId}`);
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
this.pendingConfirmations.delete(verdictId);
|
|
127
|
+
const response = {
|
|
128
|
+
verdictId,
|
|
129
|
+
confirmed,
|
|
130
|
+
reason,
|
|
131
|
+
respondedAt: new Date().toISOString(),
|
|
132
|
+
};
|
|
133
|
+
logger.info(`Confirmation ${confirmed ? 'accepted' : 'rejected'} for ${verdictId}`);
|
|
134
|
+
return response;
|
|
135
|
+
}
|
|
136
|
+
// -------------------------------------------------------------------------
|
|
137
|
+
// Follow-up / Q&A
|
|
138
|
+
// -------------------------------------------------------------------------
|
|
139
|
+
async handleReply(userId, text) {
|
|
140
|
+
const lang = this.config.userProfile.language;
|
|
141
|
+
// Check if it's a confirmation response
|
|
142
|
+
const confirmMatch = text.match(/^(confirm|reject|details):(.+)$/);
|
|
143
|
+
if (confirmMatch) {
|
|
144
|
+
const [, action, verdictId] = confirmMatch;
|
|
145
|
+
if (action === 'confirm') {
|
|
146
|
+
const result = this.processConfirmation(verdictId, true);
|
|
147
|
+
return result
|
|
148
|
+
? lang === 'zh-TW'
|
|
149
|
+
? '已確認,正在執行動作。'
|
|
150
|
+
: 'Confirmed. Executing action.'
|
|
151
|
+
: lang === 'zh-TW'
|
|
152
|
+
? '此確認請求已過期或不存在。'
|
|
153
|
+
: 'This confirmation request has expired or does not exist.';
|
|
154
|
+
}
|
|
155
|
+
if (action === 'reject') {
|
|
156
|
+
const result = this.processConfirmation(verdictId, false, text);
|
|
157
|
+
return result
|
|
158
|
+
? lang === 'zh-TW'
|
|
159
|
+
? '已取消,不會執行動作。'
|
|
160
|
+
: 'Cancelled. Action will not be taken.'
|
|
161
|
+
: lang === 'zh-TW'
|
|
162
|
+
? '此確認請求已過期或不存在。'
|
|
163
|
+
: 'This confirmation request has expired or does not exist.';
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return this.handleFollowUp(userId, text);
|
|
167
|
+
}
|
|
168
|
+
async handleFollowUp(_userId, question) {
|
|
169
|
+
const lang = this.config.userProfile.language;
|
|
170
|
+
const context = this.findMostRecentContext();
|
|
171
|
+
if (!context) {
|
|
172
|
+
return lang === 'zh-TW'
|
|
173
|
+
? '目前沒有可以追問的告警。如果有新的問題,請等待下一次告警。'
|
|
174
|
+
: 'No recent alerts to ask about. Please wait for the next alert if you have questions.';
|
|
175
|
+
}
|
|
176
|
+
const turn = {
|
|
177
|
+
role: 'user',
|
|
178
|
+
content: question,
|
|
179
|
+
timestamp: new Date().toISOString(),
|
|
180
|
+
};
|
|
181
|
+
const history = [...context.conversationHistory, turn];
|
|
182
|
+
let answer;
|
|
183
|
+
const llmAnswer = await this.tryLLMFollowUp(context, question, lang);
|
|
184
|
+
if (llmAnswer) {
|
|
185
|
+
answer = llmAnswer;
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
answer = this.generateFollowUpAnswer(context.originalAlert, question, lang);
|
|
189
|
+
}
|
|
190
|
+
const answerTurn = {
|
|
191
|
+
role: 'assistant',
|
|
192
|
+
content: answer,
|
|
193
|
+
timestamp: new Date().toISOString(),
|
|
194
|
+
};
|
|
195
|
+
const trimmedHistory = [...history, answerTurn].slice(-MAX_CONVERSATION_TURNS);
|
|
196
|
+
this.followUpContexts.set(context.verdictId, {
|
|
197
|
+
...context,
|
|
198
|
+
conversationHistory: trimmedHistory,
|
|
199
|
+
});
|
|
200
|
+
logger.info(`Follow-up answered for ${context.verdictId} (${trimmedHistory.length} turns)`);
|
|
201
|
+
return answer;
|
|
202
|
+
}
|
|
203
|
+
async tryLLMFollowUp(context, question, lang) {
|
|
204
|
+
const llm = this.config.llmProvider;
|
|
205
|
+
if (!llm)
|
|
206
|
+
return null;
|
|
207
|
+
try {
|
|
208
|
+
const available = await llm.isAvailable();
|
|
209
|
+
if (!available)
|
|
210
|
+
return null;
|
|
211
|
+
const alert = context.originalAlert;
|
|
212
|
+
const prompt = [
|
|
213
|
+
this.systemPrompt,
|
|
214
|
+
'',
|
|
215
|
+
`Alert: ${alert.eventDescription}`,
|
|
216
|
+
`Severity: ${alert.severity}, Conclusion: ${alert.conclusion}`,
|
|
217
|
+
`Summary: ${alert.humanSummary}`,
|
|
218
|
+
`Recommended action: ${alert.recommendedAction}`,
|
|
219
|
+
'',
|
|
220
|
+
`User question (respond in ${lang === 'zh-TW' ? 'Traditional Chinese' : 'English'}):`,
|
|
221
|
+
question,
|
|
222
|
+
].join('\n');
|
|
223
|
+
const result = await llm.analyze(prompt);
|
|
224
|
+
if (result.summary) {
|
|
225
|
+
logger.info('Follow-up answered via LLM');
|
|
226
|
+
return result.summary;
|
|
227
|
+
}
|
|
228
|
+
return null;
|
|
229
|
+
}
|
|
230
|
+
catch (err) {
|
|
231
|
+
logger.warn(`LLM follow-up failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
232
|
+
return null;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
generateFollowUpAnswer(alert, question, lang) {
|
|
236
|
+
const q = question.toLowerCase();
|
|
237
|
+
const maxTokens = this.config.maxFollowUpTokens ?? MAX_FOLLOWUP_TOKENS;
|
|
238
|
+
// "What did you do?" / "Actions taken?"
|
|
239
|
+
if (q.includes('做了') || q.includes('動作') || q.includes('did you') || q.includes('action')) {
|
|
240
|
+
if (alert.actionsTaken && alert.actionsTaken.length > 0) {
|
|
241
|
+
const prefix = lang === 'zh-TW' ? '我已執行以下動作:' : 'I have taken the following actions:';
|
|
242
|
+
return `${prefix}\n${alert.actionsTaken.map((a) => `- ${a}`).join('\n')}`;
|
|
243
|
+
}
|
|
244
|
+
return lang === 'zh-TW'
|
|
245
|
+
? '目前尚未執行任何自動動作。系統正在等待進一步確認。'
|
|
246
|
+
: 'No automated actions have been taken yet. The system is waiting for further confirmation.';
|
|
247
|
+
}
|
|
248
|
+
// "What should I do?" / "Recommendation?"
|
|
249
|
+
if (q.includes('建議') ||
|
|
250
|
+
q.includes('怎麼辦') ||
|
|
251
|
+
q.includes('should') ||
|
|
252
|
+
q.includes('recommend')) {
|
|
253
|
+
return lang === 'zh-TW'
|
|
254
|
+
? `建議: ${alert.recommendedAction}`
|
|
255
|
+
: `Recommendation: ${alert.recommendedAction}`;
|
|
256
|
+
}
|
|
257
|
+
// "Is it dangerous?" / "How serious?"
|
|
258
|
+
if (q.includes('嚴重') || q.includes('危險') || q.includes('serious') || q.includes('danger')) {
|
|
259
|
+
const severityExplain = lang === 'zh-TW'
|
|
260
|
+
? {
|
|
261
|
+
critical: '非常嚴重,需要立即處理',
|
|
262
|
+
high: '嚴重,建議盡快處理',
|
|
263
|
+
medium: '中等風險,建議關注',
|
|
264
|
+
low: '低風險,已記錄',
|
|
265
|
+
info: '僅供參考',
|
|
266
|
+
}
|
|
267
|
+
: {
|
|
268
|
+
critical: 'Very serious, immediate action needed',
|
|
269
|
+
high: 'Serious, prompt attention recommended',
|
|
270
|
+
medium: 'Moderate risk, worth monitoring',
|
|
271
|
+
low: 'Low risk, logged for reference',
|
|
272
|
+
info: 'Informational only',
|
|
273
|
+
};
|
|
274
|
+
return `${severityExplain[alert.severity] ?? (lang === 'zh-TW' ? '已記錄' : 'Logged')}\n\n${lang === 'zh-TW' ? '信心度' : 'Confidence'}: ${Math.round(alert.confidence * 100)}%`;
|
|
275
|
+
}
|
|
276
|
+
// "What is this?" / "Explain"
|
|
277
|
+
if (q.includes('什麼') || q.includes('what') || q.includes('explain')) {
|
|
278
|
+
return lang === 'zh-TW'
|
|
279
|
+
? `這是關於: ${alert.eventDescription}\n\n${alert.reasoning}\n\n簡單來說: ${alert.humanSummary}`
|
|
280
|
+
: `This is about: ${alert.eventDescription}\n\n${alert.reasoning}\n\nIn simple terms: ${alert.humanSummary}`;
|
|
281
|
+
}
|
|
282
|
+
// Default
|
|
283
|
+
const response = lang === 'zh-TW'
|
|
284
|
+
? `關於此事件:\n${alert.humanSummary}\n\n如需更多細節,請問具體想了解什麼?`
|
|
285
|
+
: `About this event:\n${alert.humanSummary}\n\nFor more details, please ask a specific question.`;
|
|
286
|
+
const estimatedTokens = lang === 'zh-TW' ? response.length / 2 : response.length / 4;
|
|
287
|
+
if (estimatedTokens > maxTokens) {
|
|
288
|
+
return alert.humanSummary;
|
|
289
|
+
}
|
|
290
|
+
return response;
|
|
291
|
+
}
|
|
292
|
+
// -------------------------------------------------------------------------
|
|
293
|
+
// Context Management
|
|
294
|
+
// -------------------------------------------------------------------------
|
|
295
|
+
storeFollowUpContext(alert) {
|
|
296
|
+
this.cleanExpiredContexts();
|
|
297
|
+
const verdictId = `alert-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
298
|
+
this.followUpContexts.set(verdictId, {
|
|
299
|
+
verdictId,
|
|
300
|
+
originalAlert: alert,
|
|
301
|
+
conversationHistory: [],
|
|
302
|
+
expiresAt: Date.now() + CONTEXT_EXPIRY_MS,
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
findMostRecentContext() {
|
|
306
|
+
this.cleanExpiredContexts();
|
|
307
|
+
let latest = null;
|
|
308
|
+
for (const ctx of this.followUpContexts.values()) {
|
|
309
|
+
if (!latest || ctx.expiresAt > latest.expiresAt) {
|
|
310
|
+
latest = ctx;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
return latest;
|
|
314
|
+
}
|
|
315
|
+
cleanExpiredContexts() {
|
|
316
|
+
const now = Date.now();
|
|
317
|
+
for (const [key, ctx] of this.followUpContexts) {
|
|
318
|
+
if (ctx.expiresAt < now) {
|
|
319
|
+
this.followUpContexts.delete(key);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
// -------------------------------------------------------------------------
|
|
324
|
+
// Message Queue with Retry
|
|
325
|
+
// -------------------------------------------------------------------------
|
|
326
|
+
/**
|
|
327
|
+
* Send message with automatic retry on failure.
|
|
328
|
+
* Failed messages are queued and retried with exponential backoff.
|
|
329
|
+
*/
|
|
330
|
+
async sendMessageWithRetry(userId, message) {
|
|
331
|
+
const result = await this.sendMessage(userId, message);
|
|
332
|
+
if (!result.success) {
|
|
333
|
+
// Queue for retry
|
|
334
|
+
const queueEntry = {
|
|
335
|
+
id: `msg-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
|
336
|
+
userId,
|
|
337
|
+
message,
|
|
338
|
+
attempts: 1,
|
|
339
|
+
createdAt: Date.now(),
|
|
340
|
+
lastError: result.error,
|
|
341
|
+
};
|
|
342
|
+
this.messageQueue.push(queueEntry);
|
|
343
|
+
logger.warn(`Message queued for retry (attempt 1/${MAX_RETRY_ATTEMPTS}): ${result.error}`);
|
|
344
|
+
}
|
|
345
|
+
return result;
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Background retry processor: attempts to resend failed messages
|
|
349
|
+
*/
|
|
350
|
+
startRetryProcessor() {
|
|
351
|
+
this.retryTimer = setInterval(async () => {
|
|
352
|
+
if (this.messageQueue.length === 0)
|
|
353
|
+
return;
|
|
354
|
+
const toRetry = [...this.messageQueue];
|
|
355
|
+
this.messageQueue.length = 0;
|
|
356
|
+
for (const entry of toRetry) {
|
|
357
|
+
if (entry.attempts >= MAX_RETRY_ATTEMPTS) {
|
|
358
|
+
logger.error(`Message ${entry.id} permanently failed after ${entry.attempts} attempts: ${entry.lastError}`);
|
|
359
|
+
continue;
|
|
360
|
+
}
|
|
361
|
+
const result = await this.sendMessage(entry.userId, entry.message);
|
|
362
|
+
if (result.success) {
|
|
363
|
+
logger.info(`Message ${entry.id} delivered on retry attempt ${entry.attempts + 1}`);
|
|
364
|
+
}
|
|
365
|
+
else {
|
|
366
|
+
entry.attempts += 1;
|
|
367
|
+
entry.lastError = result.error;
|
|
368
|
+
this.messageQueue.push(entry);
|
|
369
|
+
logger.warn(`Message ${entry.id} retry failed (attempt ${entry.attempts}/${MAX_RETRY_ATTEMPTS})`);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}, RETRY_BASE_DELAY_MS);
|
|
373
|
+
// Don't hold process open for retry timer
|
|
374
|
+
if (this.retryTimer.unref)
|
|
375
|
+
this.retryTimer.unref();
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Background reminder processor: re-sends confirmation requests
|
|
379
|
+
* that haven't been answered within the reminder interval.
|
|
380
|
+
*/
|
|
381
|
+
startReminderProcessor() {
|
|
382
|
+
this.reminderTimer = setInterval(async () => {
|
|
383
|
+
const now = Date.now();
|
|
384
|
+
for (const [verdictId, confirmation] of this.pendingConfirmations) {
|
|
385
|
+
// Check if expired
|
|
386
|
+
if (new Date(confirmation.expiresAt).getTime() < now) {
|
|
387
|
+
this.pendingConfirmations.delete(verdictId);
|
|
388
|
+
logger.info(`Confirmation ${verdictId} expired, removed`);
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
391
|
+
// Check if reminder needed
|
|
392
|
+
if (now - confirmation.lastReminderAt >= CONFIRMATION_REMINDER_MS &&
|
|
393
|
+
confirmation.reminderCount < MAX_REMINDERS) {
|
|
394
|
+
confirmation.reminderCount += 1;
|
|
395
|
+
confirmation.lastReminderAt = now;
|
|
396
|
+
const lang = this.config.userProfile.language;
|
|
397
|
+
const reminderText = lang === 'zh-TW'
|
|
398
|
+
? `[提醒 ${confirmation.reminderCount}/${MAX_REMINDERS}] 您有一個待確認的安全動作尚未回應。`
|
|
399
|
+
: `[Reminder ${confirmation.reminderCount}/${MAX_REMINDERS}] You have a pending security action awaiting confirmation.`;
|
|
400
|
+
logger.info(`Sending reminder ${confirmation.reminderCount}/${MAX_REMINDERS} for ${verdictId}`);
|
|
401
|
+
// Re-send the confirmation message
|
|
402
|
+
const message = formatConfirmation(confirmation, lang);
|
|
403
|
+
// We don't have userId stored, so we send to the configured default
|
|
404
|
+
// In production, userId should be stored in the confirmation request
|
|
405
|
+
await this.sendMessage('default', {
|
|
406
|
+
...message,
|
|
407
|
+
text: `${reminderText}\n\n${message.text}`,
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}, 60 * 1000); // Check every minute
|
|
412
|
+
if (this.reminderTimer.unref)
|
|
413
|
+
this.reminderTimer.unref();
|
|
414
|
+
}
|
|
415
|
+
// -------------------------------------------------------------------------
|
|
416
|
+
// Message Sending
|
|
417
|
+
// -------------------------------------------------------------------------
|
|
418
|
+
async sendMessage(userId, message) {
|
|
419
|
+
const channel = this.getPrimaryChannel();
|
|
420
|
+
if (!channel) {
|
|
421
|
+
const error = `No channel registered for ${this.config.userProfile.notificationChannel}`;
|
|
422
|
+
logger.error(error);
|
|
423
|
+
return {
|
|
424
|
+
success: false,
|
|
425
|
+
channel: this.config.userProfile.notificationChannel,
|
|
426
|
+
error,
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
try {
|
|
430
|
+
return await channel.sendMessage(userId, message);
|
|
431
|
+
}
|
|
432
|
+
catch (err) {
|
|
433
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
434
|
+
logger.error(`Failed to send message: ${msg}`);
|
|
435
|
+
return {
|
|
436
|
+
success: false,
|
|
437
|
+
channel: channel.channelType,
|
|
438
|
+
error: msg,
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
// -------------------------------------------------------------------------
|
|
443
|
+
// Getters / Accessors
|
|
444
|
+
// -------------------------------------------------------------------------
|
|
445
|
+
getSystemPrompt() {
|
|
446
|
+
return this.systemPrompt;
|
|
447
|
+
}
|
|
448
|
+
getUserProfile() {
|
|
449
|
+
return this.config.userProfile;
|
|
450
|
+
}
|
|
451
|
+
getRegisteredChannels() {
|
|
452
|
+
return [...this.channels.keys()];
|
|
453
|
+
}
|
|
454
|
+
getActiveContextCount() {
|
|
455
|
+
this.cleanExpiredContexts();
|
|
456
|
+
return this.followUpContexts.size;
|
|
457
|
+
}
|
|
458
|
+
getPendingConfirmationCount() {
|
|
459
|
+
return this.pendingConfirmations.size;
|
|
460
|
+
}
|
|
461
|
+
/** Get message queue depth */
|
|
462
|
+
getQueueDepth() {
|
|
463
|
+
return this.messageQueue.length;
|
|
464
|
+
}
|
|
465
|
+
/** Cleanup: clear all timers (for graceful shutdown) */
|
|
466
|
+
destroy() {
|
|
467
|
+
if (this.retryTimer) {
|
|
468
|
+
clearInterval(this.retryTimer);
|
|
469
|
+
this.retryTimer = null;
|
|
470
|
+
}
|
|
471
|
+
if (this.reminderTimer) {
|
|
472
|
+
clearInterval(this.reminderTimer);
|
|
473
|
+
this.reminderTimer = null;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
//# sourceMappingURL=chat-agent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-agent.js","sourceRoot":"","sources":["../../src/agent/chat-agent.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Message Formatter
|
|
3
|
+
* 訊息格式化器
|
|
4
|
+
*
|
|
5
|
+
* Adapts technical security verdicts into human-readable messages
|
|
6
|
+
* based on user type (developer / boss / IT admin).
|
|
7
|
+
* 根據用戶類型(開發者/老闆/IT管理者)將技術安全判決
|
|
8
|
+
* 轉換為人類可讀的訊息。
|
|
9
|
+
*
|
|
10
|
+
* @module @panguard-ai/panguard-chat/agent/formatter
|
|
11
|
+
*/
|
|
12
|
+
import type { UserType, MessageLanguage, ThreatAlert, SummaryReport, LearningProgress, FormattedMessage, ConfirmationRequest } from '../types.js';
|
|
13
|
+
/**
|
|
14
|
+
* Format a threat alert message for the given user type
|
|
15
|
+
* 為指定的用戶類型格式化威脅告警訊息
|
|
16
|
+
*
|
|
17
|
+
* @param alert - The threat alert / 威脅告警
|
|
18
|
+
* @param userType - User type for tone adaptation / 用戶類型(語氣適配)
|
|
19
|
+
* @param language - Target language / 目標語言
|
|
20
|
+
* @returns Formatted message / 格式化後的訊息
|
|
21
|
+
*/
|
|
22
|
+
export declare function formatAlert(alert: ThreatAlert, userType: UserType, language: MessageLanguage): FormattedMessage;
|
|
23
|
+
/**
|
|
24
|
+
* Format a summary report (daily / weekly)
|
|
25
|
+
* 格式化摘要報告(日報/週報)
|
|
26
|
+
*
|
|
27
|
+
* @param report - Summary report data / 摘要報告資料
|
|
28
|
+
* @param userType - User type / 用戶類型
|
|
29
|
+
* @param language - Target language / 目標語言
|
|
30
|
+
* @returns Formatted message / 格式化後的訊息
|
|
31
|
+
*/
|
|
32
|
+
export declare function formatSummary(report: SummaryReport, userType: UserType, language: MessageLanguage): FormattedMessage;
|
|
33
|
+
/**
|
|
34
|
+
* Format a learning progress notification
|
|
35
|
+
* 格式化學習期進度通知
|
|
36
|
+
*
|
|
37
|
+
* @param progress - Learning progress data / 學習期進度資料
|
|
38
|
+
* @param language - Target language / 目標語言
|
|
39
|
+
* @returns Formatted message / 格式化後的訊息
|
|
40
|
+
*/
|
|
41
|
+
export declare function formatLearningProgress(progress: LearningProgress, language: MessageLanguage): FormattedMessage;
|
|
42
|
+
/**
|
|
43
|
+
* Format a confirmation request for user approval
|
|
44
|
+
* 格式化用戶確認請求
|
|
45
|
+
*
|
|
46
|
+
* @param request - Confirmation request / 確認請求
|
|
47
|
+
* @param language - Target language / 目標語言
|
|
48
|
+
* @returns Formatted message with quick replies / 附帶快速回覆的格式化訊息
|
|
49
|
+
*/
|
|
50
|
+
export declare function formatConfirmation(request: ConfirmationRequest, language: MessageLanguage): FormattedMessage;
|
|
51
|
+
/**
|
|
52
|
+
* Format a peaceful "all clear" report
|
|
53
|
+
* 格式化平安報告(無事報平安)
|
|
54
|
+
*
|
|
55
|
+
* @param language - Target language / 目標語言
|
|
56
|
+
* @returns Formatted message / 格式化後的訊息
|
|
57
|
+
*/
|
|
58
|
+
export declare function formatPeacefulReport(language: MessageLanguage): FormattedMessage;
|
|
59
|
+
//# sourceMappingURL=formatter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatter.d.ts","sourceRoot":"","sources":["../../src/agent/formatter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EACV,QAAQ,EACR,eAAe,EACf,WAAW,EACX,aAAa,EACb,gBAAgB,EAChB,gBAAgB,EAEhB,mBAAmB,EACpB,MAAM,aAAa,CAAC;AA8IrB;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,WAAW,EAClB,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,eAAe,GACxB,gBAAgB,CAgClB;AAOD;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,eAAe,GACxB,gBAAgB,CAsFlB;AAOD;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,gBAAgB,EAC1B,QAAQ,EAAE,eAAe,GACxB,gBAAgB,CAuClB;AAOD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,mBAAmB,EAC5B,QAAQ,EAAE,eAAe,GACxB,gBAAgB,CA4ClB;AAOD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,eAAe,GAAG,gBAAgB,CAsBhF"}
|