@panguard-ai/core 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/adapters/adapter-registry.d.ts +150 -0
- package/dist/adapters/adapter-registry.d.ts.map +1 -0
- package/dist/adapters/adapter-registry.js +271 -0
- package/dist/adapters/adapter-registry.js.map +1 -0
- package/dist/adapters/base-adapter.d.ts +101 -0
- package/dist/adapters/base-adapter.d.ts.map +1 -0
- package/dist/adapters/base-adapter.js +160 -0
- package/dist/adapters/base-adapter.js.map +1 -0
- package/dist/adapters/defender-adapter.d.ts +90 -0
- package/dist/adapters/defender-adapter.d.ts.map +1 -0
- package/dist/adapters/defender-adapter.js +227 -0
- package/dist/adapters/defender-adapter.js.map +1 -0
- package/dist/adapters/index.d.ts +22 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +23 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/syslog-adapter.d.ts +207 -0
- package/dist/adapters/syslog-adapter.d.ts.map +1 -0
- package/dist/adapters/syslog-adapter.js +432 -0
- package/dist/adapters/syslog-adapter.js.map +1 -0
- package/dist/adapters/types.d.ts +135 -0
- package/dist/adapters/types.d.ts.map +1 -0
- package/dist/adapters/types.js +13 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/adapters/wazuh-adapter.d.ts +120 -0
- package/dist/adapters/wazuh-adapter.d.ts.map +1 -0
- package/dist/adapters/wazuh-adapter.js +266 -0
- package/dist/adapters/wazuh-adapter.js.map +1 -0
- package/dist/ai/claude-provider.d.ts +66 -0
- package/dist/ai/claude-provider.d.ts.map +1 -0
- package/dist/ai/claude-provider.js +166 -0
- package/dist/ai/claude-provider.js.map +1 -0
- package/dist/ai/funnel-router.d.ts +75 -0
- package/dist/ai/funnel-router.d.ts.map +1 -0
- package/dist/ai/funnel-router.js +173 -0
- package/dist/ai/funnel-router.js.map +1 -0
- package/dist/ai/index.d.ts +77 -0
- package/dist/ai/index.d.ts.map +1 -0
- package/dist/ai/index.js +95 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/ai/ollama-provider.d.ts +73 -0
- package/dist/ai/ollama-provider.d.ts.map +1 -0
- package/dist/ai/ollama-provider.js +200 -0
- package/dist/ai/ollama-provider.js.map +1 -0
- package/dist/ai/openai-provider.d.ts +70 -0
- package/dist/ai/openai-provider.d.ts.map +1 -0
- package/dist/ai/openai-provider.js +175 -0
- package/dist/ai/openai-provider.js.map +1 -0
- package/dist/ai/prompts/event-classifier.d.ts +25 -0
- package/dist/ai/prompts/event-classifier.d.ts.map +1 -0
- package/dist/ai/prompts/event-classifier.js +94 -0
- package/dist/ai/prompts/event-classifier.js.map +1 -0
- package/dist/ai/prompts/index.d.ts +13 -0
- package/dist/ai/prompts/index.d.ts.map +1 -0
- package/dist/ai/prompts/index.js +13 -0
- package/dist/ai/prompts/index.js.map +1 -0
- package/dist/ai/prompts/report-generator.d.ts +25 -0
- package/dist/ai/prompts/report-generator.d.ts.map +1 -0
- package/dist/ai/prompts/report-generator.js +131 -0
- package/dist/ai/prompts/report-generator.js.map +1 -0
- package/dist/ai/prompts/threat-analyzer.d.ts +26 -0
- package/dist/ai/prompts/threat-analyzer.d.ts.map +1 -0
- package/dist/ai/prompts/threat-analyzer.js +75 -0
- package/dist/ai/prompts/threat-analyzer.js.map +1 -0
- package/dist/ai/provider-base.d.ts +100 -0
- package/dist/ai/provider-base.d.ts.map +1 -0
- package/dist/ai/provider-base.js +166 -0
- package/dist/ai/provider-base.js.map +1 -0
- package/dist/ai/response-parser.d.ts +36 -0
- package/dist/ai/response-parser.d.ts.map +1 -0
- package/dist/ai/response-parser.js +195 -0
- package/dist/ai/response-parser.js.map +1 -0
- package/dist/ai/token-tracker.d.ts +72 -0
- package/dist/ai/token-tracker.d.ts.map +1 -0
- package/dist/ai/token-tracker.js +145 -0
- package/dist/ai/token-tracker.js.map +1 -0
- package/dist/ai/types.d.ts +138 -0
- package/dist/ai/types.d.ts.map +1 -0
- package/dist/ai/types.js +12 -0
- package/dist/ai/types.js.map +1 -0
- package/dist/cli/index.d.ts +146 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +515 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/prompts.d.ts +58 -0
- package/dist/cli/prompts.d.ts.map +1 -0
- package/dist/cli/prompts.js +327 -0
- package/dist/cli/prompts.js.map +1 -0
- package/dist/cli/wizard.d.ts +58 -0
- package/dist/cli/wizard.d.ts.map +1 -0
- package/dist/cli/wizard.js +200 -0
- package/dist/cli/wizard.js.map +1 -0
- package/dist/discovery/firewall-checker.d.ts +28 -0
- package/dist/discovery/firewall-checker.d.ts.map +1 -0
- package/dist/discovery/firewall-checker.js +379 -0
- package/dist/discovery/firewall-checker.js.map +1 -0
- package/dist/discovery/index.d.ts +23 -0
- package/dist/discovery/index.d.ts.map +1 -0
- package/dist/discovery/index.js +29 -0
- package/dist/discovery/index.js.map +1 -0
- package/dist/discovery/network-scanner.d.ts +60 -0
- package/dist/discovery/network-scanner.d.ts.map +1 -0
- package/dist/discovery/network-scanner.js +640 -0
- package/dist/discovery/network-scanner.js.map +1 -0
- package/dist/discovery/os-detector.d.ts +24 -0
- package/dist/discovery/os-detector.d.ts.map +1 -0
- package/dist/discovery/os-detector.js +253 -0
- package/dist/discovery/os-detector.js.map +1 -0
- package/dist/discovery/osquery-provider.d.ts +127 -0
- package/dist/discovery/osquery-provider.d.ts.map +1 -0
- package/dist/discovery/osquery-provider.js +214 -0
- package/dist/discovery/osquery-provider.js.map +1 -0
- package/dist/discovery/risk-scorer.d.ts +66 -0
- package/dist/discovery/risk-scorer.d.ts.map +1 -0
- package/dist/discovery/risk-scorer.js +294 -0
- package/dist/discovery/risk-scorer.js.map +1 -0
- package/dist/discovery/security-tools.d.ts +31 -0
- package/dist/discovery/security-tools.d.ts.map +1 -0
- package/dist/discovery/security-tools.js +346 -0
- package/dist/discovery/security-tools.js.map +1 -0
- package/dist/discovery/service-detector.d.ts +28 -0
- package/dist/discovery/service-detector.d.ts.map +1 -0
- package/dist/discovery/service-detector.js +300 -0
- package/dist/discovery/service-detector.js.map +1 -0
- package/dist/discovery/types.d.ts +502 -0
- package/dist/discovery/types.d.ts.map +1 -0
- package/dist/discovery/types.js +12 -0
- package/dist/discovery/types.js.map +1 -0
- package/dist/discovery/user-auditor.d.ts +28 -0
- package/dist/discovery/user-auditor.d.ts.map +1 -0
- package/dist/discovery/user-auditor.js +385 -0
- package/dist/discovery/user-auditor.js.map +1 -0
- package/dist/i18n/config.d.ts +45 -0
- package/dist/i18n/config.d.ts.map +1 -0
- package/dist/i18n/config.js +135 -0
- package/dist/i18n/config.js.map +1 -0
- package/dist/i18n/index.d.ts +8 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/i18n/index.js +8 -0
- package/dist/i18n/index.js.map +1 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/monitor/event-normalizer.d.ts +102 -0
- package/dist/monitor/event-normalizer.d.ts.map +1 -0
- package/dist/monitor/event-normalizer.js +195 -0
- package/dist/monitor/event-normalizer.js.map +1 -0
- package/dist/monitor/file-monitor.d.ts +90 -0
- package/dist/monitor/file-monitor.d.ts.map +1 -0
- package/dist/monitor/file-monitor.js +222 -0
- package/dist/monitor/file-monitor.js.map +1 -0
- package/dist/monitor/index.d.ts +147 -0
- package/dist/monitor/index.d.ts.map +1 -0
- package/dist/monitor/index.js +293 -0
- package/dist/monitor/index.js.map +1 -0
- package/dist/monitor/log-monitor.d.ts +102 -0
- package/dist/monitor/log-monitor.d.ts.map +1 -0
- package/dist/monitor/log-monitor.js +245 -0
- package/dist/monitor/log-monitor.js.map +1 -0
- package/dist/monitor/network-monitor.d.ts +103 -0
- package/dist/monitor/network-monitor.d.ts.map +1 -0
- package/dist/monitor/network-monitor.js +336 -0
- package/dist/monitor/network-monitor.js.map +1 -0
- package/dist/monitor/process-monitor.d.ts +108 -0
- package/dist/monitor/process-monitor.d.ts.map +1 -0
- package/dist/monitor/process-monitor.js +245 -0
- package/dist/monitor/process-monitor.js.map +1 -0
- package/dist/monitor/threat-intel-feeds.d.ts +141 -0
- package/dist/monitor/threat-intel-feeds.d.ts.map +1 -0
- package/dist/monitor/threat-intel-feeds.js +430 -0
- package/dist/monitor/threat-intel-feeds.js.map +1 -0
- package/dist/monitor/threat-intel.d.ts +83 -0
- package/dist/monitor/threat-intel.d.ts.map +1 -0
- package/dist/monitor/threat-intel.js +215 -0
- package/dist/monitor/threat-intel.js.map +1 -0
- package/dist/monitor/types.d.ts +65 -0
- package/dist/monitor/types.d.ts.map +1 -0
- package/dist/monitor/types.js +20 -0
- package/dist/monitor/types.js.map +1 -0
- package/dist/rules/index.d.ts +115 -0
- package/dist/rules/index.d.ts.map +1 -0
- package/dist/rules/index.js +244 -0
- package/dist/rules/index.js.map +1 -0
- package/dist/rules/rule-loader.d.ts +54 -0
- package/dist/rules/rule-loader.d.ts.map +1 -0
- package/dist/rules/rule-loader.js +167 -0
- package/dist/rules/rule-loader.js.map +1 -0
- package/dist/rules/sigma-matcher.d.ts +40 -0
- package/dist/rules/sigma-matcher.d.ts.map +1 -0
- package/dist/rules/sigma-matcher.js +447 -0
- package/dist/rules/sigma-matcher.js.map +1 -0
- package/dist/rules/sigma-parser.d.ts +36 -0
- package/dist/rules/sigma-parser.d.ts.map +1 -0
- package/dist/rules/sigma-parser.js +180 -0
- package/dist/rules/sigma-parser.js.map +1 -0
- package/dist/rules/types.d.ts +112 -0
- package/dist/rules/types.d.ts.map +1 -0
- package/dist/rules/types.js +11 -0
- package/dist/rules/types.js.map +1 -0
- package/dist/rules/yara-scanner.d.ts +103 -0
- package/dist/rules/yara-scanner.d.ts.map +1 -0
- package/dist/rules/yara-scanner.js +421 -0
- package/dist/rules/yara-scanner.js.map +1 -0
- package/dist/scoring/achievements.d.ts +76 -0
- package/dist/scoring/achievements.d.ts.map +1 -0
- package/dist/scoring/achievements.js +211 -0
- package/dist/scoring/achievements.js.map +1 -0
- package/dist/scoring/index.d.ts +3 -0
- package/dist/scoring/index.d.ts.map +1 -0
- package/dist/scoring/index.js +3 -0
- package/dist/scoring/index.js.map +1 -0
- package/dist/scoring/security-score.d.ts +60 -0
- package/dist/scoring/security-score.d.ts.map +1 -0
- package/dist/scoring/security-score.js +211 -0
- package/dist/scoring/security-score.js.map +1 -0
- package/dist/types.d.ts +71 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/index.d.ts +10 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +9 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/logger.d.ts +38 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +71 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/validation.d.ts +35 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +56 -0
- package/dist/utils/validation.js.map +1 -0
- package/package.json +60 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ollama LLM provider implementation
|
|
3
|
+
* Ollama LLM 供應商實作
|
|
4
|
+
*
|
|
5
|
+
* Communicates with a local Ollama instance via its HTTP API.
|
|
6
|
+
* Uses native fetch (Node 18+) with no external dependencies.
|
|
7
|
+
* 透過 HTTP API 與本地 Ollama 實例通訊。
|
|
8
|
+
* 使用原生 fetch(Node 18+),無需外部相依。
|
|
9
|
+
*
|
|
10
|
+
* @module @panguard-ai/core/ai/ollama-provider
|
|
11
|
+
*/
|
|
12
|
+
import type { LLMConfig } from './types.js';
|
|
13
|
+
import { LLMProviderBase } from './provider-base.js';
|
|
14
|
+
/**
|
|
15
|
+
* Ollama LLM provider using the local HTTP API
|
|
16
|
+
* 使用本地 HTTP API 的 Ollama LLM 供應商
|
|
17
|
+
*
|
|
18
|
+
* Connects to a running Ollama instance (default: localhost:11434)
|
|
19
|
+
* and uses the /api/generate endpoint for text generation.
|
|
20
|
+
* 連接到正在執行的 Ollama 實例(預設:localhost:11434),
|
|
21
|
+
* 並使用 /api/generate 端點進行文字生成。
|
|
22
|
+
*/
|
|
23
|
+
export declare class OllamaProvider extends LLMProviderBase {
|
|
24
|
+
/** Resolved API endpoint / 解析後的 API 端點 */
|
|
25
|
+
private readonly endpoint;
|
|
26
|
+
/**
|
|
27
|
+
* Create a new OllamaProvider instance
|
|
28
|
+
* 建立新的 OllamaProvider 實例
|
|
29
|
+
*
|
|
30
|
+
* @param config - LLM configuration / LLM 配置
|
|
31
|
+
*/
|
|
32
|
+
constructor(config: LLMConfig);
|
|
33
|
+
/**
|
|
34
|
+
* Check if the Ollama instance is reachable and running
|
|
35
|
+
* 檢查 Ollama 實例是否可連接且正在執行
|
|
36
|
+
*
|
|
37
|
+
* Sends a GET request to /api/tags to verify connectivity.
|
|
38
|
+
* 發送 GET 請求到 /api/tags 以驗證連接性。
|
|
39
|
+
*
|
|
40
|
+
* @returns True if Ollama is reachable / Ollama 可連接時回傳 true
|
|
41
|
+
*/
|
|
42
|
+
isAvailable(): Promise<boolean>;
|
|
43
|
+
/**
|
|
44
|
+
* Check if the configured model has been pulled in Ollama
|
|
45
|
+
* 檢查配置的模型是否已在 Ollama 中下載
|
|
46
|
+
*
|
|
47
|
+
* @returns True if model is available locally / 模型在本地可用時回傳 true
|
|
48
|
+
*/
|
|
49
|
+
isModelPulled(): Promise<boolean>;
|
|
50
|
+
/**
|
|
51
|
+
* Send a prompt to the Ollama /api/generate endpoint
|
|
52
|
+
* 向 Ollama /api/generate 端點發送提示詞
|
|
53
|
+
*
|
|
54
|
+
* @param prompt - The prompt to send / 要發送的提示詞
|
|
55
|
+
* @returns Raw response text / 原始回應文字
|
|
56
|
+
* @throws Error if the request fails or times out / 請求失敗或逾時時拋出錯誤
|
|
57
|
+
*/
|
|
58
|
+
protected sendRequest(prompt: string): Promise<string>;
|
|
59
|
+
/**
|
|
60
|
+
* Rough token count estimation (for when Ollama doesn't report counts)
|
|
61
|
+
* 粗略的 Token 計數估算(當 Ollama 不報告計數時使用)
|
|
62
|
+
*
|
|
63
|
+
* Uses a simple heuristic: ~4 characters per token for English,
|
|
64
|
+
* ~2 characters per token for CJK text.
|
|
65
|
+
* 使用簡單啟發式方法:英文約每 4 個字元一個 Token,CJK 文字約每 2 個字元一個 Token。
|
|
66
|
+
*
|
|
67
|
+
* @param text - Text to estimate / 要估算的文字
|
|
68
|
+
* @returns Estimated token count / 估算的 Token 數量
|
|
69
|
+
* @internal
|
|
70
|
+
*/
|
|
71
|
+
private estimateTokens;
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=ollama-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ollama-provider.d.ts","sourceRoot":"","sources":["../../src/ai/ollama-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAgCrD;;;;;;;;GAQG;AACH,qBAAa,cAAe,SAAQ,eAAe;IACjD,0CAA0C;IAC1C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAElC;;;;;OAKG;gBACS,MAAM,EAAE,SAAS;IAS7B;;;;;;;;OAQG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IA8CrC;;;;;OAKG;IACG,aAAa,IAAI,OAAO,CAAC,OAAO,CAAC;IAqBvC;;;;;;;OAOG;cACa,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAqE5D;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,cAAc;CAOvB"}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ollama LLM provider implementation
|
|
3
|
+
* Ollama LLM 供應商實作
|
|
4
|
+
*
|
|
5
|
+
* Communicates with a local Ollama instance via its HTTP API.
|
|
6
|
+
* Uses native fetch (Node 18+) with no external dependencies.
|
|
7
|
+
* 透過 HTTP API 與本地 Ollama 實例通訊。
|
|
8
|
+
* 使用原生 fetch(Node 18+),無需外部相依。
|
|
9
|
+
*
|
|
10
|
+
* @module @panguard-ai/core/ai/ollama-provider
|
|
11
|
+
*/
|
|
12
|
+
import { LLMProviderBase } from './provider-base.js';
|
|
13
|
+
/**
|
|
14
|
+
* Default Ollama API endpoint
|
|
15
|
+
* 預設 Ollama API 端點
|
|
16
|
+
* @internal
|
|
17
|
+
*/
|
|
18
|
+
const DEFAULT_ENDPOINT = 'http://localhost:11434';
|
|
19
|
+
/**
|
|
20
|
+
* Ollama LLM provider using the local HTTP API
|
|
21
|
+
* 使用本地 HTTP API 的 Ollama LLM 供應商
|
|
22
|
+
*
|
|
23
|
+
* Connects to a running Ollama instance (default: localhost:11434)
|
|
24
|
+
* and uses the /api/generate endpoint for text generation.
|
|
25
|
+
* 連接到正在執行的 Ollama 實例(預設:localhost:11434),
|
|
26
|
+
* 並使用 /api/generate 端點進行文字生成。
|
|
27
|
+
*/
|
|
28
|
+
export class OllamaProvider extends LLMProviderBase {
|
|
29
|
+
/** Resolved API endpoint / 解析後的 API 端點 */
|
|
30
|
+
endpoint;
|
|
31
|
+
/**
|
|
32
|
+
* Create a new OllamaProvider instance
|
|
33
|
+
* 建立新的 OllamaProvider 實例
|
|
34
|
+
*
|
|
35
|
+
* @param config - LLM configuration / LLM 配置
|
|
36
|
+
*/
|
|
37
|
+
constructor(config) {
|
|
38
|
+
super(config);
|
|
39
|
+
this.endpoint = (config.endpoint ?? DEFAULT_ENDPOINT).replace(/\/+$/, '');
|
|
40
|
+
this.logger.info('Ollama provider initialized', {
|
|
41
|
+
endpoint: this.endpoint,
|
|
42
|
+
model: this.model,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Check if the Ollama instance is reachable and running
|
|
47
|
+
* 檢查 Ollama 實例是否可連接且正在執行
|
|
48
|
+
*
|
|
49
|
+
* Sends a GET request to /api/tags to verify connectivity.
|
|
50
|
+
* 發送 GET 請求到 /api/tags 以驗證連接性。
|
|
51
|
+
*
|
|
52
|
+
* @returns True if Ollama is reachable / Ollama 可連接時回傳 true
|
|
53
|
+
*/
|
|
54
|
+
async isAvailable() {
|
|
55
|
+
try {
|
|
56
|
+
const controller = new AbortController();
|
|
57
|
+
const timeoutId = setTimeout(() => controller.abort(), 5_000);
|
|
58
|
+
const response = await fetch(`${this.endpoint}/api/tags`, {
|
|
59
|
+
method: 'GET',
|
|
60
|
+
signal: controller.signal,
|
|
61
|
+
});
|
|
62
|
+
clearTimeout(timeoutId);
|
|
63
|
+
if (!response.ok) {
|
|
64
|
+
this.logger.warn('Ollama returned non-OK status', {
|
|
65
|
+
status: response.status,
|
|
66
|
+
});
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
const data = (await response.json());
|
|
70
|
+
const models = data.models?.map((m) => m.name) ?? [];
|
|
71
|
+
// Check if the configured model is pulled
|
|
72
|
+
// 檢查配置的模型是否已下載
|
|
73
|
+
const modelPulled = models.some((m) => m === this.model || m.startsWith(`${this.model}:`));
|
|
74
|
+
if (!modelPulled && models.length > 0) {
|
|
75
|
+
this.logger.warn('Configured model not found in Ollama', {
|
|
76
|
+
requestedModel: this.model,
|
|
77
|
+
availableModels: models,
|
|
78
|
+
hint: `Run: ollama pull ${this.model}`,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
this.logger.debug('Ollama available', {
|
|
82
|
+
availableModels: models.length,
|
|
83
|
+
modelPulled,
|
|
84
|
+
});
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
this.logger.debug('Ollama not available', {
|
|
89
|
+
error: error instanceof Error ? error.message : String(error),
|
|
90
|
+
});
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Check if the configured model has been pulled in Ollama
|
|
96
|
+
* 檢查配置的模型是否已在 Ollama 中下載
|
|
97
|
+
*
|
|
98
|
+
* @returns True if model is available locally / 模型在本地可用時回傳 true
|
|
99
|
+
*/
|
|
100
|
+
async isModelPulled() {
|
|
101
|
+
try {
|
|
102
|
+
const controller = new AbortController();
|
|
103
|
+
const timeoutId = setTimeout(() => controller.abort(), 5_000);
|
|
104
|
+
const response = await fetch(`${this.endpoint}/api/tags`, {
|
|
105
|
+
method: 'GET',
|
|
106
|
+
signal: controller.signal,
|
|
107
|
+
});
|
|
108
|
+
clearTimeout(timeoutId);
|
|
109
|
+
if (!response.ok)
|
|
110
|
+
return false;
|
|
111
|
+
const data = (await response.json());
|
|
112
|
+
const models = data.models?.map((m) => m.name) ?? [];
|
|
113
|
+
return models.some((m) => m === this.model || m.startsWith(`${this.model}:`));
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Send a prompt to the Ollama /api/generate endpoint
|
|
121
|
+
* 向 Ollama /api/generate 端點發送提示詞
|
|
122
|
+
*
|
|
123
|
+
* @param prompt - The prompt to send / 要發送的提示詞
|
|
124
|
+
* @returns Raw response text / 原始回應文字
|
|
125
|
+
* @throws Error if the request fails or times out / 請求失敗或逾時時拋出錯誤
|
|
126
|
+
*/
|
|
127
|
+
async sendRequest(prompt) {
|
|
128
|
+
const controller = new AbortController();
|
|
129
|
+
const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
|
|
130
|
+
try {
|
|
131
|
+
const response = await fetch(`${this.endpoint}/api/generate`, {
|
|
132
|
+
method: 'POST',
|
|
133
|
+
headers: { 'Content-Type': 'application/json' },
|
|
134
|
+
body: JSON.stringify({
|
|
135
|
+
model: this.model,
|
|
136
|
+
prompt,
|
|
137
|
+
stream: false,
|
|
138
|
+
options: {
|
|
139
|
+
temperature: this.config.temperature,
|
|
140
|
+
num_predict: this.config.maxTokens,
|
|
141
|
+
},
|
|
142
|
+
}),
|
|
143
|
+
signal: controller.signal,
|
|
144
|
+
});
|
|
145
|
+
clearTimeout(timeoutId);
|
|
146
|
+
if (!response.ok) {
|
|
147
|
+
const errorText = await response.text().catch(() => 'Unknown error');
|
|
148
|
+
throw new Error(`Ollama API error (${response.status}): ${errorText}`);
|
|
149
|
+
}
|
|
150
|
+
const data = (await response.json());
|
|
151
|
+
// Track token usage from Ollama response metrics
|
|
152
|
+
// 從 Ollama 回應指標追蹤 Token 使用量
|
|
153
|
+
const promptTokens = data.prompt_eval_count ?? this.estimateTokens(prompt);
|
|
154
|
+
const completionTokens = data.eval_count ?? this.estimateTokens(data.response);
|
|
155
|
+
this.tokenTracker.track(promptTokens, completionTokens);
|
|
156
|
+
this.logger.debug('Ollama request completed', {
|
|
157
|
+
model: data.model,
|
|
158
|
+
done: data.done,
|
|
159
|
+
promptTokens,
|
|
160
|
+
completionTokens,
|
|
161
|
+
});
|
|
162
|
+
return data.response;
|
|
163
|
+
}
|
|
164
|
+
catch (error) {
|
|
165
|
+
clearTimeout(timeoutId);
|
|
166
|
+
if (error instanceof Error && error.name === 'AbortError') {
|
|
167
|
+
throw new Error(`Ollama request timed out after ${this.config.timeout}ms. ` +
|
|
168
|
+
`Ensure Ollama is running at ${this.endpoint} and the model "${this.model}" is available.`);
|
|
169
|
+
}
|
|
170
|
+
// Handle connection refused specifically
|
|
171
|
+
// 特別處理連線被拒絕的情況
|
|
172
|
+
if (error instanceof TypeError &&
|
|
173
|
+
(error.message.includes('fetch failed') || error.message.includes('ECONNREFUSED'))) {
|
|
174
|
+
throw new Error(`Cannot connect to Ollama at ${this.endpoint}. ` +
|
|
175
|
+
`Ensure Ollama is installed and running: https://ollama.ai`);
|
|
176
|
+
}
|
|
177
|
+
throw error;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Rough token count estimation (for when Ollama doesn't report counts)
|
|
182
|
+
* 粗略的 Token 計數估算(當 Ollama 不報告計數時使用)
|
|
183
|
+
*
|
|
184
|
+
* Uses a simple heuristic: ~4 characters per token for English,
|
|
185
|
+
* ~2 characters per token for CJK text.
|
|
186
|
+
* 使用簡單啟發式方法:英文約每 4 個字元一個 Token,CJK 文字約每 2 個字元一個 Token。
|
|
187
|
+
*
|
|
188
|
+
* @param text - Text to estimate / 要估算的文字
|
|
189
|
+
* @returns Estimated token count / 估算的 Token 數量
|
|
190
|
+
* @internal
|
|
191
|
+
*/
|
|
192
|
+
estimateTokens(text) {
|
|
193
|
+
// Count CJK characters
|
|
194
|
+
// 計算 CJK 字元數
|
|
195
|
+
const cjkCount = (text.match(/[\u4e00-\u9fff\u3400-\u4dbf]/g) ?? []).length;
|
|
196
|
+
const nonCjkLength = text.length - cjkCount;
|
|
197
|
+
return Math.ceil(nonCjkLength / 4) + Math.ceil(cjkCount / 1.5);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
//# sourceMappingURL=ollama-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ollama-provider.js","sourceRoot":"","sources":["../../src/ai/ollama-provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAI LLM provider implementation
|
|
3
|
+
* OpenAI LLM 供應商實作
|
|
4
|
+
*
|
|
5
|
+
* Uses the openai package via dynamic import to avoid hard dependencies.
|
|
6
|
+
* Users must install the SDK separately.
|
|
7
|
+
* 透過動態匯入使用 openai 套件以避免硬性相依。
|
|
8
|
+
* 使用者必須另外安裝 SDK。
|
|
9
|
+
*
|
|
10
|
+
* @module @panguard-ai/core/ai/openai-provider
|
|
11
|
+
*/
|
|
12
|
+
import type { LLMConfig } from './types.js';
|
|
13
|
+
import { LLMProviderBase } from './provider-base.js';
|
|
14
|
+
/**
|
|
15
|
+
* OpenAI LLM provider
|
|
16
|
+
* OpenAI LLM 供應商
|
|
17
|
+
*
|
|
18
|
+
* Requires the openai package to be installed separately.
|
|
19
|
+
* The SDK is loaded via dynamic import() on first use.
|
|
20
|
+
* 需要另外安裝 openai 套件。
|
|
21
|
+
* SDK 在首次使用時透過動態 import() 載入。
|
|
22
|
+
*/
|
|
23
|
+
export declare class OpenAIProvider extends LLMProviderBase {
|
|
24
|
+
/**
|
|
25
|
+
* Cached OpenAI client instance / 快取的 OpenAI 客戶端實例
|
|
26
|
+
* @internal
|
|
27
|
+
*/
|
|
28
|
+
private client;
|
|
29
|
+
/**
|
|
30
|
+
* Create a new OpenAIProvider instance
|
|
31
|
+
* 建立新的 OpenAIProvider 實例
|
|
32
|
+
*
|
|
33
|
+
* @param config - LLM configuration (apiKey required) / LLM 配置(需要 apiKey)
|
|
34
|
+
*/
|
|
35
|
+
constructor(config: LLMConfig);
|
|
36
|
+
/**
|
|
37
|
+
* Lazily initialize the OpenAI SDK client via dynamic import
|
|
38
|
+
* 透過動態匯入延遲初始化 OpenAI SDK 客戶端
|
|
39
|
+
*
|
|
40
|
+
* @returns Initialized OpenAI client / 初始化的 OpenAI 客戶端
|
|
41
|
+
* @throws Error if the SDK is not installed or API key is missing
|
|
42
|
+
* 如果 SDK 未安裝或 API 金鑰遺失則拋出錯誤
|
|
43
|
+
* @internal
|
|
44
|
+
*/
|
|
45
|
+
private getClient;
|
|
46
|
+
/**
|
|
47
|
+
* Check if the OpenAI API is available and the API key is valid
|
|
48
|
+
* 檢查 OpenAI API 是否可用且 API 金鑰有效
|
|
49
|
+
*
|
|
50
|
+
* Attempts to create a minimal chat completion to verify connectivity.
|
|
51
|
+
* 嘗試建立最小聊天完成以驗證連接性。
|
|
52
|
+
*
|
|
53
|
+
* @returns True if OpenAI API is reachable / OpenAI API 可連接時回傳 true
|
|
54
|
+
*/
|
|
55
|
+
isAvailable(): Promise<boolean>;
|
|
56
|
+
/**
|
|
57
|
+
* Send a prompt to the OpenAI Chat Completions API
|
|
58
|
+
* 向 OpenAI Chat Completions API 發送提示詞
|
|
59
|
+
*
|
|
60
|
+
* Uses a system message to establish the security analyst role,
|
|
61
|
+
* followed by the user prompt.
|
|
62
|
+
* 使用系統訊息建立安全分析師角色,接著是使用者提示詞。
|
|
63
|
+
*
|
|
64
|
+
* @param prompt - The prompt to send / 要發送的提示詞
|
|
65
|
+
* @returns Raw response text / 原始回應文字
|
|
66
|
+
* @throws Error if the API call fails / API 呼叫失敗時拋出錯誤
|
|
67
|
+
*/
|
|
68
|
+
protected sendRequest(prompt: string): Promise<string>;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=openai-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-provider.d.ts","sourceRoot":"","sources":["../../src/ai/openai-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAyCrD;;;;;;;;GAQG;AACH,qBAAa,cAAe,SAAQ,eAAe;IACjD;;;OAGG;IACH,OAAO,CAAC,MAAM,CAA6B;IAE3C;;;;;OAKG;gBACS,MAAM,EAAE,SAAS;IAK7B;;;;;;;;OAQG;YACW,SAAS;IAiCvB;;;;;;;;OAQG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IA4BrC;;;;;;;;;;;OAWG;cACa,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CA+D7D"}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAI LLM provider implementation
|
|
3
|
+
* OpenAI LLM 供應商實作
|
|
4
|
+
*
|
|
5
|
+
* Uses the openai package via dynamic import to avoid hard dependencies.
|
|
6
|
+
* Users must install the SDK separately.
|
|
7
|
+
* 透過動態匯入使用 openai 套件以避免硬性相依。
|
|
8
|
+
* 使用者必須另外安裝 SDK。
|
|
9
|
+
*
|
|
10
|
+
* @module @panguard-ai/core/ai/openai-provider
|
|
11
|
+
*/
|
|
12
|
+
import { LLMProviderBase } from './provider-base.js';
|
|
13
|
+
/**
|
|
14
|
+
* OpenAI LLM provider
|
|
15
|
+
* OpenAI LLM 供應商
|
|
16
|
+
*
|
|
17
|
+
* Requires the openai package to be installed separately.
|
|
18
|
+
* The SDK is loaded via dynamic import() on first use.
|
|
19
|
+
* 需要另外安裝 openai 套件。
|
|
20
|
+
* SDK 在首次使用時透過動態 import() 載入。
|
|
21
|
+
*/
|
|
22
|
+
export class OpenAIProvider extends LLMProviderBase {
|
|
23
|
+
/**
|
|
24
|
+
* Cached OpenAI client instance / 快取的 OpenAI 客戶端實例
|
|
25
|
+
* @internal
|
|
26
|
+
*/
|
|
27
|
+
client = null;
|
|
28
|
+
/**
|
|
29
|
+
* Create a new OpenAIProvider instance
|
|
30
|
+
* 建立新的 OpenAIProvider 實例
|
|
31
|
+
*
|
|
32
|
+
* @param config - LLM configuration (apiKey required) / LLM 配置(需要 apiKey)
|
|
33
|
+
*/
|
|
34
|
+
constructor(config) {
|
|
35
|
+
super(config);
|
|
36
|
+
this.logger.info('OpenAI provider initialized', { model: this.model });
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Lazily initialize the OpenAI SDK client via dynamic import
|
|
40
|
+
* 透過動態匯入延遲初始化 OpenAI SDK 客戶端
|
|
41
|
+
*
|
|
42
|
+
* @returns Initialized OpenAI client / 初始化的 OpenAI 客戶端
|
|
43
|
+
* @throws Error if the SDK is not installed or API key is missing
|
|
44
|
+
* 如果 SDK 未安裝或 API 金鑰遺失則拋出錯誤
|
|
45
|
+
* @internal
|
|
46
|
+
*/
|
|
47
|
+
async getClient() {
|
|
48
|
+
if (this.client) {
|
|
49
|
+
return this.client;
|
|
50
|
+
}
|
|
51
|
+
if (!this.config.apiKey) {
|
|
52
|
+
throw new Error('OpenAI API key is required. Set the apiKey field in LLMConfig or the OPENAI_API_KEY environment variable.');
|
|
53
|
+
}
|
|
54
|
+
let OpenAI;
|
|
55
|
+
try {
|
|
56
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
57
|
+
const module = await import('openai');
|
|
58
|
+
OpenAI = (module['default'] ?? module);
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
const message = error instanceof Error && error.message.includes('Cannot find')
|
|
62
|
+
? 'Install openai package to use OpenAI provider: npm install openai'
|
|
63
|
+
: `Failed to load openai package: ${error instanceof Error ? error.message : String(error)}. ` +
|
|
64
|
+
'Install it with: npm install openai';
|
|
65
|
+
throw new Error(message);
|
|
66
|
+
}
|
|
67
|
+
this.client = new OpenAI({
|
|
68
|
+
apiKey: this.config.apiKey,
|
|
69
|
+
timeout: this.config.timeout,
|
|
70
|
+
});
|
|
71
|
+
return this.client;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Check if the OpenAI API is available and the API key is valid
|
|
75
|
+
* 檢查 OpenAI API 是否可用且 API 金鑰有效
|
|
76
|
+
*
|
|
77
|
+
* Attempts to create a minimal chat completion to verify connectivity.
|
|
78
|
+
* 嘗試建立最小聊天完成以驗證連接性。
|
|
79
|
+
*
|
|
80
|
+
* @returns True if OpenAI API is reachable / OpenAI API 可連接時回傳 true
|
|
81
|
+
*/
|
|
82
|
+
async isAvailable() {
|
|
83
|
+
try {
|
|
84
|
+
if (!this.config.apiKey) {
|
|
85
|
+
this.logger.debug('OpenAI provider: no API key configured');
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
const client = await this.getClient();
|
|
89
|
+
// Send a minimal test request
|
|
90
|
+
// 發送最小測試請求
|
|
91
|
+
const response = await client.chat.completions.create({
|
|
92
|
+
model: this.model,
|
|
93
|
+
messages: [{ role: 'user', content: 'Reply with "ok".' }],
|
|
94
|
+
max_tokens: 10,
|
|
95
|
+
});
|
|
96
|
+
const isOk = response.choices.length > 0;
|
|
97
|
+
this.logger.debug('OpenAI availability check', { available: isOk });
|
|
98
|
+
return isOk;
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
this.logger.debug('OpenAI not available', {
|
|
102
|
+
error: error instanceof Error ? error.message : String(error),
|
|
103
|
+
});
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Send a prompt to the OpenAI Chat Completions API
|
|
109
|
+
* 向 OpenAI Chat Completions API 發送提示詞
|
|
110
|
+
*
|
|
111
|
+
* Uses a system message to establish the security analyst role,
|
|
112
|
+
* followed by the user prompt.
|
|
113
|
+
* 使用系統訊息建立安全分析師角色,接著是使用者提示詞。
|
|
114
|
+
*
|
|
115
|
+
* @param prompt - The prompt to send / 要發送的提示詞
|
|
116
|
+
* @returns Raw response text / 原始回應文字
|
|
117
|
+
* @throws Error if the API call fails / API 呼叫失敗時拋出錯誤
|
|
118
|
+
*/
|
|
119
|
+
async sendRequest(prompt) {
|
|
120
|
+
const client = await this.getClient();
|
|
121
|
+
const systemMessage = this.config.lang === 'zh-TW'
|
|
122
|
+
? '你是一位專業的資安分析師,專精於威脅偵測、事件分析和安全報告撰寫。請以繁體中文回應。'
|
|
123
|
+
: 'You are a professional cybersecurity analyst specializing in threat detection, incident analysis, and security report writing.';
|
|
124
|
+
try {
|
|
125
|
+
const response = await client.chat.completions.create({
|
|
126
|
+
model: this.model,
|
|
127
|
+
messages: [
|
|
128
|
+
{ role: 'system', content: systemMessage },
|
|
129
|
+
{ role: 'user', content: prompt },
|
|
130
|
+
],
|
|
131
|
+
temperature: this.config.temperature,
|
|
132
|
+
max_tokens: this.config.maxTokens,
|
|
133
|
+
});
|
|
134
|
+
// Track token usage from API response
|
|
135
|
+
// 從 API 回應追蹤 Token 使用量
|
|
136
|
+
if (response.usage) {
|
|
137
|
+
this.tokenTracker.track(response.usage.prompt_tokens, response.usage.completion_tokens);
|
|
138
|
+
}
|
|
139
|
+
// Extract the assistant's message content
|
|
140
|
+
// 提取助手的訊息內容
|
|
141
|
+
const choice = response.choices[0];
|
|
142
|
+
const content = choice?.message?.content ?? '';
|
|
143
|
+
this.logger.debug('OpenAI request completed', {
|
|
144
|
+
model: this.model,
|
|
145
|
+
finishReason: choice?.finish_reason,
|
|
146
|
+
promptTokens: response.usage?.prompt_tokens,
|
|
147
|
+
completionTokens: response.usage?.completion_tokens,
|
|
148
|
+
});
|
|
149
|
+
if (!content) {
|
|
150
|
+
throw new Error('OpenAI returned an empty response');
|
|
151
|
+
}
|
|
152
|
+
return content;
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
// Provide more specific error messages for common failures
|
|
156
|
+
// 為常見失敗提供更具體的錯誤訊息
|
|
157
|
+
if (error instanceof Error) {
|
|
158
|
+
if (error.message.includes('401') || error.message.includes('Incorrect API key')) {
|
|
159
|
+
throw new Error('OpenAI API authentication failed. Check your API key.');
|
|
160
|
+
}
|
|
161
|
+
if (error.message.includes('429') || error.message.includes('Rate limit')) {
|
|
162
|
+
throw new Error('OpenAI API rate limit exceeded. Please wait and try again.');
|
|
163
|
+
}
|
|
164
|
+
if (error.message.includes('timeout') || error.message.includes('ETIMEDOUT')) {
|
|
165
|
+
throw new Error(`OpenAI API request timed out after ${this.config.timeout}ms.`);
|
|
166
|
+
}
|
|
167
|
+
if (error.message.includes('model_not_found') || error.message.includes('does not exist')) {
|
|
168
|
+
throw new Error(`OpenAI model "${this.model}" not found. Check the model name.`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
throw error;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
//# sourceMappingURL=openai-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-provider.js","sourceRoot":"","sources":["../../src/ai/openai-provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event classification prompt templates
|
|
3
|
+
* 事件分類提示詞範本
|
|
4
|
+
*
|
|
5
|
+
* Generates prompts for classifying security events using
|
|
6
|
+
* the MITRE ATT&CK framework. Supports bilingual output.
|
|
7
|
+
* 產生使用 MITRE ATT&CK 框架分類安全事件的提示詞。支援雙語輸出。
|
|
8
|
+
*
|
|
9
|
+
* @module @panguard-ai/core/ai/prompts/event-classifier
|
|
10
|
+
*/
|
|
11
|
+
import type { Language, SecurityEvent } from '../../types.js';
|
|
12
|
+
/**
|
|
13
|
+
* Generate an event classification prompt for the given security event
|
|
14
|
+
* 為指定的安全事件產生事件分類提示詞
|
|
15
|
+
*
|
|
16
|
+
* The prompt instructs the LLM to classify the event according to
|
|
17
|
+
* MITRE ATT&CK framework and return structured JSON output.
|
|
18
|
+
* 提示詞指示 LLM 根據 MITRE ATT&CK 框架分類事件並回傳結構化 JSON 輸出。
|
|
19
|
+
*
|
|
20
|
+
* @param event - The security event to classify / 要分類的安全事件
|
|
21
|
+
* @param lang - Output language / 輸出語言
|
|
22
|
+
* @returns Formatted prompt string / 格式化的提示詞字串
|
|
23
|
+
*/
|
|
24
|
+
export declare function getEventClassifierPrompt(event: SecurityEvent, lang: Language): string;
|
|
25
|
+
//# sourceMappingURL=event-classifier.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-classifier.d.ts","sourceRoot":"","sources":["../../../src/ai/prompts/event-classifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAwB9D;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,QAAQ,GAAG,MAAM,CAuDrF"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event classification prompt templates
|
|
3
|
+
* 事件分類提示詞範本
|
|
4
|
+
*
|
|
5
|
+
* Generates prompts for classifying security events using
|
|
6
|
+
* the MITRE ATT&CK framework. Supports bilingual output.
|
|
7
|
+
* 產生使用 MITRE ATT&CK 框架分類安全事件的提示詞。支援雙語輸出。
|
|
8
|
+
*
|
|
9
|
+
* @module @panguard-ai/core/ai/prompts/event-classifier
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* MITRE ATT&CK tactic categories for reference in prompts
|
|
13
|
+
* MITRE ATT&CK 戰術分類(供提示詞參考)
|
|
14
|
+
* @internal
|
|
15
|
+
*/
|
|
16
|
+
const MITRE_TACTICS = [
|
|
17
|
+
'Reconnaissance',
|
|
18
|
+
'Resource Development',
|
|
19
|
+
'Initial Access',
|
|
20
|
+
'Execution',
|
|
21
|
+
'Persistence',
|
|
22
|
+
'Privilege Escalation',
|
|
23
|
+
'Defense Evasion',
|
|
24
|
+
'Credential Access',
|
|
25
|
+
'Discovery',
|
|
26
|
+
'Lateral Movement',
|
|
27
|
+
'Collection',
|
|
28
|
+
'Command and Control',
|
|
29
|
+
'Exfiltration',
|
|
30
|
+
'Impact',
|
|
31
|
+
];
|
|
32
|
+
/**
|
|
33
|
+
* Generate an event classification prompt for the given security event
|
|
34
|
+
* 為指定的安全事件產生事件分類提示詞
|
|
35
|
+
*
|
|
36
|
+
* The prompt instructs the LLM to classify the event according to
|
|
37
|
+
* MITRE ATT&CK framework and return structured JSON output.
|
|
38
|
+
* 提示詞指示 LLM 根據 MITRE ATT&CK 框架分類事件並回傳結構化 JSON 輸出。
|
|
39
|
+
*
|
|
40
|
+
* @param event - The security event to classify / 要分類的安全事件
|
|
41
|
+
* @param lang - Output language / 輸出語言
|
|
42
|
+
* @returns Formatted prompt string / 格式化的提示詞字串
|
|
43
|
+
*/
|
|
44
|
+
export function getEventClassifierPrompt(event, lang) {
|
|
45
|
+
const eventData = JSON.stringify({
|
|
46
|
+
id: event.id,
|
|
47
|
+
timestamp: event.timestamp instanceof Date ? event.timestamp.toISOString() : event.timestamp,
|
|
48
|
+
source: event.source,
|
|
49
|
+
severity: event.severity,
|
|
50
|
+
category: event.category,
|
|
51
|
+
description: event.description,
|
|
52
|
+
host: event.host,
|
|
53
|
+
metadata: event.metadata,
|
|
54
|
+
}, null, 2);
|
|
55
|
+
if (lang === 'zh-TW') {
|
|
56
|
+
return `你是一位專業的資安分析師。請根據 MITRE ATT&CK 框架分析以下安全事件。
|
|
57
|
+
|
|
58
|
+
安全事件資料:
|
|
59
|
+
${eventData}
|
|
60
|
+
|
|
61
|
+
可用的 MITRE ATT&CK 戰術分類:
|
|
62
|
+
${MITRE_TACTICS.join(', ')}
|
|
63
|
+
|
|
64
|
+
請以 JSON 格式回應,包含以下欄位:
|
|
65
|
+
{
|
|
66
|
+
"category": "MITRE ATT&CK 戰術分類(從上方清單中選擇)",
|
|
67
|
+
"technique": "MITRE ATT&CK 技術 ID(例如 T1059、T1548)",
|
|
68
|
+
"severity": "嚴重等級:info、low、medium、high 或 critical",
|
|
69
|
+
"confidence": "信心分數,0 到 1 之間的數字",
|
|
70
|
+
"description": "此分類的簡短說明"
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
只回傳 JSON,不要包含其他文字。`;
|
|
74
|
+
}
|
|
75
|
+
return `You are a professional cybersecurity analyst. Analyze the following security event according to the MITRE ATT&CK framework.
|
|
76
|
+
|
|
77
|
+
Security Event Data:
|
|
78
|
+
${eventData}
|
|
79
|
+
|
|
80
|
+
Available MITRE ATT&CK Tactic Categories:
|
|
81
|
+
${MITRE_TACTICS.join(', ')}
|
|
82
|
+
|
|
83
|
+
Respond in JSON format with the following fields:
|
|
84
|
+
{
|
|
85
|
+
"category": "MITRE ATT&CK tactic category (choose from the list above)",
|
|
86
|
+
"technique": "MITRE ATT&CK technique ID (e.g., T1059, T1548)",
|
|
87
|
+
"severity": "severity level: info, low, medium, high, or critical",
|
|
88
|
+
"confidence": "confidence score, a number between 0 and 1",
|
|
89
|
+
"description": "brief explanation of this classification"
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
Return only JSON, no additional text.`;
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=event-classifier.js.map
|