@steadwing/openalerts 0.2.5 → 0.2.6
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/README.md +198 -141
- package/dist/channels/console.d.ts +6 -0
- package/dist/channels/console.d.ts.map +1 -0
- package/dist/channels/console.js +10 -0
- package/dist/channels/console.js.map +1 -0
- package/dist/channels/telegram.d.ts +12 -0
- package/dist/channels/telegram.d.ts.map +1 -0
- package/dist/channels/telegram.js +28 -0
- package/dist/channels/telegram.js.map +1 -0
- package/dist/channels/webhook.d.ts +8 -0
- package/dist/channels/webhook.d.ts.map +1 -0
- package/dist/channels/webhook.js +15 -0
- package/dist/channels/webhook.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +234 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +51 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +86 -0
- package/dist/config.js.map +1 -0
- package/dist/core/alert-channel.d.ts +3 -10
- package/dist/core/alert-channel.d.ts.map +1 -0
- package/dist/core/alert-channel.js +9 -30
- package/dist/core/alert-channel.js.map +1 -0
- package/dist/core/bounded-map.d.ts +1 -0
- package/dist/core/bounded-map.d.ts.map +1 -0
- package/dist/core/bounded-map.js +1 -0
- package/dist/core/bounded-map.js.map +1 -0
- package/dist/core/engine.d.ts +6 -18
- package/dist/core/engine.d.ts.map +1 -0
- package/dist/core/engine.js +48 -98
- package/dist/core/engine.js.map +1 -0
- package/dist/core/evaluator.d.ts +1 -0
- package/dist/core/evaluator.d.ts.map +1 -0
- package/dist/core/evaluator.js +1 -0
- package/dist/core/evaluator.js.map +1 -0
- package/dist/core/event-bus.d.ts +1 -0
- package/dist/core/event-bus.d.ts.map +1 -0
- package/dist/core/event-bus.js +1 -0
- package/dist/core/event-bus.js.map +1 -0
- package/dist/core/formatter.d.ts +1 -0
- package/dist/core/formatter.d.ts.map +1 -0
- package/dist/core/formatter.js +1 -0
- package/dist/core/formatter.js.map +1 -0
- package/dist/core/rules.d.ts +1 -0
- package/dist/core/rules.d.ts.map +1 -0
- package/dist/core/rules.js +1 -0
- package/dist/core/rules.js.map +1 -0
- package/dist/core/store.d.ts +6 -9
- package/dist/core/store.d.ts.map +1 -0
- package/dist/core/store.js +43 -96
- package/dist/core/store.js.map +1 -0
- package/dist/core/types.d.ts +1 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +1 -0
- package/dist/core/types.js.map +1 -0
- package/dist/db/index.d.ts +6 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +31 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/queries.d.ts +157 -0
- package/dist/db/queries.d.ts.map +1 -0
- package/dist/db/queries.js +221 -0
- package/dist/db/queries.js.map +1 -0
- package/dist/db/schema.d.ts +5 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +177 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/readers/openclaw.d.ts +11 -0
- package/dist/readers/openclaw.d.ts.map +1 -0
- package/dist/readers/openclaw.js +267 -0
- package/dist/readers/openclaw.js.map +1 -0
- package/dist/server/dashboard.d.ts +2 -0
- package/dist/server/dashboard.d.ts.map +1 -0
- package/dist/server/dashboard.js +765 -0
- package/dist/server/dashboard.js.map +1 -0
- package/dist/server/index.d.ts +10 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +28 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/routes.d.ts +6 -0
- package/dist/server/routes.d.ts.map +1 -0
- package/dist/server/routes.js +146 -0
- package/dist/server/routes.js.map +1 -0
- package/dist/server/sse.d.ts +21 -0
- package/dist/server/sse.d.ts.map +1 -0
- package/dist/server/sse.js +53 -0
- package/dist/server/sse.js.map +1 -0
- package/dist/watchers/files.d.ts +19 -0
- package/dist/watchers/files.d.ts.map +1 -0
- package/dist/watchers/files.js +105 -0
- package/dist/watchers/files.js.map +1 -0
- package/dist/watchers/gateway-adapter.d.ts +18 -0
- package/dist/watchers/gateway-adapter.d.ts.map +1 -0
- package/dist/watchers/gateway-adapter.js +273 -0
- package/dist/watchers/gateway-adapter.js.map +1 -0
- package/dist/watchers/gateway.d.ts +27 -0
- package/dist/watchers/gateway.d.ts.map +1 -0
- package/dist/watchers/gateway.js +131 -0
- package/dist/watchers/gateway.js.map +1 -0
- package/package.json +29 -43
- package/LICENSE +0 -201
- package/dist/collections/collection-manager.d.ts +0 -50
- package/dist/collections/collection-manager.js +0 -583
- package/dist/collections/event-parser.d.ts +0 -27
- package/dist/collections/event-parser.js +0 -321
- package/dist/collections/index.d.ts +0 -6
- package/dist/collections/index.js +0 -6
- package/dist/collections/persistence.d.ts +0 -25
- package/dist/collections/persistence.js +0 -213
- package/dist/collections/types.d.ts +0 -177
- package/dist/collections/types.js +0 -15
- package/dist/core/index.d.ts +0 -13
- package/dist/core/index.js +0 -23
- package/dist/core/llm-enrichment.d.ts +0 -21
- package/dist/core/llm-enrichment.js +0 -180
- package/dist/core/platform.d.ts +0 -17
- package/dist/core/platform.js +0 -93
- package/dist/index.d.ts +0 -8
- package/dist/index.js +0 -600
- package/dist/plugin/adapter.d.ts +0 -150
- package/dist/plugin/adapter.js +0 -530
- package/dist/plugin/commands.d.ts +0 -18
- package/dist/plugin/commands.js +0 -103
- package/dist/plugin/dashboard-html.d.ts +0 -7
- package/dist/plugin/dashboard-html.js +0 -968
- package/dist/plugin/dashboard-routes.d.ts +0 -12
- package/dist/plugin/dashboard-routes.js +0 -444
- package/dist/plugin/gateway-client.d.ts +0 -39
- package/dist/plugin/gateway-client.js +0 -200
- package/dist/plugin/log-bridge.d.ts +0 -22
- package/dist/plugin/log-bridge.js +0 -363
- package/openclaw.plugin.json +0 -87
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
export interface MonitorSession {
|
|
2
|
-
key: string;
|
|
3
|
-
agentId: string;
|
|
4
|
-
platform: string;
|
|
5
|
-
recipient: string;
|
|
6
|
-
isGroup: boolean;
|
|
7
|
-
lastActivityAt: number;
|
|
8
|
-
status: "idle" | "active" | "thinking";
|
|
9
|
-
spawnedBy?: string;
|
|
10
|
-
messageCount?: number;
|
|
11
|
-
totalCostUsd?: number;
|
|
12
|
-
totalInputTokens?: number;
|
|
13
|
-
totalOutputTokens?: number;
|
|
14
|
-
}
|
|
15
|
-
export type MonitorActionType = "start" | "streaming" | "complete" | "aborted" | "error" | "tool_call" | "tool_result";
|
|
16
|
-
export type MonitorActionEventType = "chat" | "agent" | "system";
|
|
17
|
-
export interface MonitorAction {
|
|
18
|
-
id: string;
|
|
19
|
-
runId: string;
|
|
20
|
-
sessionKey: string;
|
|
21
|
-
seq: number;
|
|
22
|
-
type: MonitorActionType;
|
|
23
|
-
eventType: MonitorActionEventType;
|
|
24
|
-
timestamp: number;
|
|
25
|
-
content?: string;
|
|
26
|
-
toolName?: string;
|
|
27
|
-
toolArgs?: unknown;
|
|
28
|
-
startedAt?: number;
|
|
29
|
-
endedAt?: number;
|
|
30
|
-
duration?: number;
|
|
31
|
-
inputTokens?: number;
|
|
32
|
-
outputTokens?: number;
|
|
33
|
-
stopReason?: string;
|
|
34
|
-
costUsd?: number;
|
|
35
|
-
model?: string;
|
|
36
|
-
provider?: string;
|
|
37
|
-
}
|
|
38
|
-
export type MonitorExecEventType = "started" | "output" | "completed";
|
|
39
|
-
export type MonitorExecProcessStatus = "running" | "completed" | "failed";
|
|
40
|
-
export interface MonitorExecOutputChunk {
|
|
41
|
-
id: string;
|
|
42
|
-
stream: "stdout" | "stderr" | string;
|
|
43
|
-
text: string;
|
|
44
|
-
timestamp: number;
|
|
45
|
-
}
|
|
46
|
-
export interface MonitorExecEvent {
|
|
47
|
-
id: string;
|
|
48
|
-
execId: string;
|
|
49
|
-
runId: string;
|
|
50
|
-
pid: number;
|
|
51
|
-
sessionId?: string;
|
|
52
|
-
sessionKey?: string;
|
|
53
|
-
eventType: MonitorExecEventType;
|
|
54
|
-
command?: string;
|
|
55
|
-
stream?: "stdout" | "stderr" | string;
|
|
56
|
-
output?: string;
|
|
57
|
-
startedAt?: number;
|
|
58
|
-
durationMs?: number;
|
|
59
|
-
exitCode?: number;
|
|
60
|
-
status?: string;
|
|
61
|
-
timestamp: number;
|
|
62
|
-
}
|
|
63
|
-
export interface MonitorExecProcess {
|
|
64
|
-
id: string;
|
|
65
|
-
runId: string;
|
|
66
|
-
pid: number;
|
|
67
|
-
command: string;
|
|
68
|
-
sessionId?: string;
|
|
69
|
-
sessionKey?: string;
|
|
70
|
-
status: MonitorExecProcessStatus;
|
|
71
|
-
startedAt: number;
|
|
72
|
-
completedAt?: number;
|
|
73
|
-
durationMs?: number;
|
|
74
|
-
exitCode?: number;
|
|
75
|
-
outputs: MonitorExecOutputChunk[];
|
|
76
|
-
outputTruncated?: boolean;
|
|
77
|
-
timestamp: number;
|
|
78
|
-
lastActivityAt: number;
|
|
79
|
-
}
|
|
80
|
-
export interface ChatEvent {
|
|
81
|
-
runId: string;
|
|
82
|
-
sessionKey: string;
|
|
83
|
-
seq: number;
|
|
84
|
-
state: "delta" | "final" | "aborted" | "error";
|
|
85
|
-
message?: unknown;
|
|
86
|
-
errorMessage?: string;
|
|
87
|
-
usage?: {
|
|
88
|
-
inputTokens?: number;
|
|
89
|
-
outputTokens?: number;
|
|
90
|
-
};
|
|
91
|
-
stopReason?: string;
|
|
92
|
-
}
|
|
93
|
-
export interface AgentEvent {
|
|
94
|
-
runId: string;
|
|
95
|
-
seq: number;
|
|
96
|
-
stream: string;
|
|
97
|
-
ts: number;
|
|
98
|
-
data: Record<string, unknown>;
|
|
99
|
-
sessionKey?: string;
|
|
100
|
-
}
|
|
101
|
-
export interface ExecStartedEvent {
|
|
102
|
-
pid: number;
|
|
103
|
-
command: string;
|
|
104
|
-
sessionId: string;
|
|
105
|
-
runId: string;
|
|
106
|
-
startedAt: number;
|
|
107
|
-
}
|
|
108
|
-
export interface ExecOutputEvent {
|
|
109
|
-
pid: number;
|
|
110
|
-
runId: string;
|
|
111
|
-
sessionId?: string;
|
|
112
|
-
stream: "stdout" | "stderr" | string;
|
|
113
|
-
output: string;
|
|
114
|
-
}
|
|
115
|
-
export interface ExecCompletedEvent {
|
|
116
|
-
pid: number;
|
|
117
|
-
runId: string;
|
|
118
|
-
sessionId?: string;
|
|
119
|
-
exitCode: number;
|
|
120
|
-
durationMs: number;
|
|
121
|
-
status: string;
|
|
122
|
-
}
|
|
123
|
-
export declare function parseSessionKey(key: string): {
|
|
124
|
-
agentId: string;
|
|
125
|
-
platform: string;
|
|
126
|
-
recipient: string;
|
|
127
|
-
isGroup: boolean;
|
|
128
|
-
};
|
|
129
|
-
export interface CollectionStats {
|
|
130
|
-
sessions: number;
|
|
131
|
-
actions: number;
|
|
132
|
-
execs: number;
|
|
133
|
-
runSessionMapSize: number;
|
|
134
|
-
totalCostUsd?: number;
|
|
135
|
-
}
|
|
136
|
-
export interface DiagnosticUsageEvent {
|
|
137
|
-
type: "model.usage";
|
|
138
|
-
ts: number;
|
|
139
|
-
seq: number;
|
|
140
|
-
sessionKey?: string;
|
|
141
|
-
sessionId?: string;
|
|
142
|
-
channel?: string;
|
|
143
|
-
provider?: string;
|
|
144
|
-
model?: string;
|
|
145
|
-
usage: {
|
|
146
|
-
input?: number;
|
|
147
|
-
output?: number;
|
|
148
|
-
cacheRead?: number;
|
|
149
|
-
cacheWrite?: number;
|
|
150
|
-
promptTokens?: number;
|
|
151
|
-
total?: number;
|
|
152
|
-
};
|
|
153
|
-
context?: {
|
|
154
|
-
limit?: number;
|
|
155
|
-
used?: number;
|
|
156
|
-
};
|
|
157
|
-
costUsd?: number;
|
|
158
|
-
durationMs?: number;
|
|
159
|
-
}
|
|
160
|
-
export interface CostUsageTotals {
|
|
161
|
-
input: number;
|
|
162
|
-
output: number;
|
|
163
|
-
cacheRead: number;
|
|
164
|
-
cacheWrite: number;
|
|
165
|
-
totalTokens: number;
|
|
166
|
-
totalCost: number;
|
|
167
|
-
inputCost: number;
|
|
168
|
-
outputCost: number;
|
|
169
|
-
cacheReadCost: number;
|
|
170
|
-
cacheWriteCost: number;
|
|
171
|
-
missingCostEntries: number;
|
|
172
|
-
}
|
|
173
|
-
export interface CostUsageSummary {
|
|
174
|
-
totals: CostUsageTotals;
|
|
175
|
-
byModel?: Record<string, CostUsageTotals>;
|
|
176
|
-
bySession?: Record<string, CostUsageTotals>;
|
|
177
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
// ─── Session Types ───────────────────────────────────────────────────────────
|
|
2
|
-
// ─── Utility Functions ───────────────────────────────────────────────────────
|
|
3
|
-
export function parseSessionKey(key) {
|
|
4
|
-
// Format: "agent:main:discord:channel:1234567890"
|
|
5
|
-
// Or: "agent:main:telegram:group:12345"
|
|
6
|
-
// Or: "agent:main:whatsapp:+1234567890"
|
|
7
|
-
const parts = key.split(":");
|
|
8
|
-
const agentId = parts[1] || "unknown";
|
|
9
|
-
const platform = parts[2] || "unknown";
|
|
10
|
-
// Check if 4th part indicates a type (channel, group, dm, etc)
|
|
11
|
-
const hasType = ["channel", "group", "dm", "thread"].includes(parts[3] || "");
|
|
12
|
-
const isGroup = parts[3] === "group" || parts[3] === "channel";
|
|
13
|
-
const recipient = hasType ? parts.slice(3).join(":") : parts.slice(3).join(":");
|
|
14
|
-
return { agentId, platform, recipient, isGroup };
|
|
15
|
-
}
|
package/dist/core/index.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export type { AlertChannel, AlertEnricher, AlertEvent, AlertRuleDefinition, AlertSeverity, AlertTarget, DiagnosticSnapshot, EvaluatorState, HeartbeatSnapshot, MonitorConfig, RuleContext, RuleOverride, OpenAlertsEvent, OpenAlertsEventType, OpenAlertsInitOptions, OpenAlertsLogger, StoredEvent, WindowEntry, } from "./types.js";
|
|
2
|
-
export { DEFAULTS, LOG_FILENAME, STORE_DIR_NAME } from "./types.js";
|
|
3
|
-
export { OpenAlertsEngine } from "./engine.js";
|
|
4
|
-
export { OpenAlertsEventBus } from "./event-bus.js";
|
|
5
|
-
export { AlertDispatcher } from "./alert-channel.js";
|
|
6
|
-
export { createEvaluatorState, processEvent, processWatchdogTick, warmFromHistory, } from "./evaluator.js";
|
|
7
|
-
export { ALL_RULES } from "./rules.js";
|
|
8
|
-
export { appendEvent, pruneLog, readAllEvents, readRecentEvents, } from "./store.js";
|
|
9
|
-
export { createLlmEnricher, type LlmEnricherOptions } from "./llm-enrichment.js";
|
|
10
|
-
export { formatAlertMessage, formatAlertsOutput, formatHealthOutput, } from "./formatter.js";
|
|
11
|
-
export { createPlatformSync, type PlatformSync } from "./platform.js";
|
|
12
|
-
export { BoundedMap, type BoundedMapOptions, type BoundedMapStats, } from "./bounded-map.js";
|
|
13
|
-
export type { MonitorSession, MonitorActionType, MonitorActionEventType, MonitorAction, MonitorExecEventType, MonitorExecProcessStatus, MonitorExecOutputChunk, MonitorExecEvent, MonitorExecProcess, CollectionStats, DiagnosticUsageEvent, CostUsageTotals, CostUsageSummary, } from "../collections/types.js";
|
package/dist/core/index.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
// OpenAlerts core — engine, rules, evaluator, store
|
|
2
|
-
// Constants
|
|
3
|
-
export { DEFAULTS, LOG_FILENAME, STORE_DIR_NAME } from "./types.js";
|
|
4
|
-
// Engine
|
|
5
|
-
export { OpenAlertsEngine } from "./engine.js";
|
|
6
|
-
// Event Bus
|
|
7
|
-
export { OpenAlertsEventBus } from "./event-bus.js";
|
|
8
|
-
// Alert Dispatcher
|
|
9
|
-
export { AlertDispatcher } from "./alert-channel.js";
|
|
10
|
-
// Evaluator
|
|
11
|
-
export { createEvaluatorState, processEvent, processWatchdogTick, warmFromHistory, } from "./evaluator.js";
|
|
12
|
-
// Rules
|
|
13
|
-
export { ALL_RULES } from "./rules.js";
|
|
14
|
-
// Store
|
|
15
|
-
export { appendEvent, pruneLog, readAllEvents, readRecentEvents, } from "./store.js";
|
|
16
|
-
// LLM Enrichment
|
|
17
|
-
export { createLlmEnricher } from "./llm-enrichment.js";
|
|
18
|
-
// Formatter
|
|
19
|
-
export { formatAlertMessage, formatAlertsOutput, formatHealthOutput, } from "./formatter.js";
|
|
20
|
-
// Platform
|
|
21
|
-
export { createPlatformSync } from "./platform.js";
|
|
22
|
-
// Bounded Map
|
|
23
|
-
export { BoundedMap, } from "./bounded-map.js";
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { AlertEnricher, OpenAlertsLogger } from "./types.js";
|
|
2
|
-
export type LlmEnricherOptions = {
|
|
3
|
-
/** Model string from config, e.g. "openai/gpt-5-nano" */
|
|
4
|
-
modelString: string;
|
|
5
|
-
/** Pre-resolved API key (caller reads from env to avoid env+fetch in same file) */
|
|
6
|
-
apiKey: string;
|
|
7
|
-
/** Logger for debug/warn messages */
|
|
8
|
-
logger?: OpenAlertsLogger;
|
|
9
|
-
/** Timeout in ms (default: 10000) */
|
|
10
|
-
timeoutMs?: number;
|
|
11
|
-
};
|
|
12
|
-
/**
|
|
13
|
-
* Resolve the environment variable name for a given model string's provider.
|
|
14
|
-
* Returns null if the model string is invalid or the provider is unknown.
|
|
15
|
-
*/
|
|
16
|
-
export declare function resolveApiKeyEnvVar(modelString: string): string | null;
|
|
17
|
-
/**
|
|
18
|
-
* Create an AlertEnricher that calls an LLM to add a summary + action to alerts.
|
|
19
|
-
* Returns null if provider can't be resolved.
|
|
20
|
-
*/
|
|
21
|
-
export declare function createLlmEnricher(opts: LlmEnricherOptions): AlertEnricher | null;
|
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
const PROVIDER_MAP = {
|
|
2
|
-
openai: {
|
|
3
|
-
type: "openai-compatible",
|
|
4
|
-
baseUrl: "https://api.openai.com/v1",
|
|
5
|
-
apiKeyEnvVar: "OPENAI_API_KEY",
|
|
6
|
-
},
|
|
7
|
-
groq: {
|
|
8
|
-
type: "openai-compatible",
|
|
9
|
-
baseUrl: "https://api.groq.com/openai/v1",
|
|
10
|
-
apiKeyEnvVar: "GROQ_API_KEY",
|
|
11
|
-
},
|
|
12
|
-
together: {
|
|
13
|
-
type: "openai-compatible",
|
|
14
|
-
baseUrl: "https://api.together.xyz/v1",
|
|
15
|
-
apiKeyEnvVar: "TOGETHER_API_KEY",
|
|
16
|
-
},
|
|
17
|
-
deepseek: {
|
|
18
|
-
type: "openai-compatible",
|
|
19
|
-
baseUrl: "https://api.deepseek.com/v1",
|
|
20
|
-
apiKeyEnvVar: "DEEPSEEK_API_KEY",
|
|
21
|
-
},
|
|
22
|
-
anthropic: {
|
|
23
|
-
type: "anthropic",
|
|
24
|
-
baseUrl: "https://api.anthropic.com/v1",
|
|
25
|
-
apiKeyEnvVar: "ANTHROPIC_API_KEY",
|
|
26
|
-
},
|
|
27
|
-
};
|
|
28
|
-
// ─── Prompt ─────────────────────────────────────────────────────────────────
|
|
29
|
-
function buildPrompt(alert) {
|
|
30
|
-
return `You are a concise DevOps alert analyst. Given this monitoring alert, provide:
|
|
31
|
-
1. A brief human-friendly summary (1 sentence, plain language)
|
|
32
|
-
2. One actionable suggestion to resolve it
|
|
33
|
-
|
|
34
|
-
Alert:
|
|
35
|
-
- Rule: ${alert.ruleId}
|
|
36
|
-
- Severity: ${alert.severity}
|
|
37
|
-
- Title: ${alert.title}
|
|
38
|
-
- Detail: ${alert.detail}
|
|
39
|
-
|
|
40
|
-
Reply in exactly this format (2 lines only):
|
|
41
|
-
Summary: <your summary>
|
|
42
|
-
Action: <your suggestion>`;
|
|
43
|
-
}
|
|
44
|
-
// ─── Response Parsing ───────────────────────────────────────────────────────
|
|
45
|
-
function parseEnrichment(text) {
|
|
46
|
-
const lines = text.trim().split("\n");
|
|
47
|
-
let summary = "";
|
|
48
|
-
let action = "";
|
|
49
|
-
for (const line of lines) {
|
|
50
|
-
const trimmed = line.trim();
|
|
51
|
-
if (trimmed.toLowerCase().startsWith("summary:")) {
|
|
52
|
-
summary = trimmed.slice("summary:".length).trim();
|
|
53
|
-
}
|
|
54
|
-
else if (trimmed.toLowerCase().startsWith("action:")) {
|
|
55
|
-
action = trimmed.slice("action:".length).trim();
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
if (!summary && !action)
|
|
59
|
-
return null;
|
|
60
|
-
return { summary, action };
|
|
61
|
-
}
|
|
62
|
-
// ─── HTTP Calls ─────────────────────────────────────────────────────────────
|
|
63
|
-
async function callOpenAICompatible(baseUrl, apiKey, model, prompt, timeoutMs) {
|
|
64
|
-
const controller = new AbortController();
|
|
65
|
-
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
66
|
-
try {
|
|
67
|
-
const res = await fetch(`${baseUrl}/chat/completions`, {
|
|
68
|
-
method: "POST",
|
|
69
|
-
headers: {
|
|
70
|
-
"Content-Type": "application/json",
|
|
71
|
-
Authorization: `Bearer ${apiKey}`,
|
|
72
|
-
},
|
|
73
|
-
body: JSON.stringify({
|
|
74
|
-
model,
|
|
75
|
-
messages: [{ role: "user", content: prompt }],
|
|
76
|
-
max_tokens: 200,
|
|
77
|
-
temperature: 0.3,
|
|
78
|
-
}),
|
|
79
|
-
signal: controller.signal,
|
|
80
|
-
});
|
|
81
|
-
if (!res.ok)
|
|
82
|
-
return null;
|
|
83
|
-
const data = (await res.json());
|
|
84
|
-
return data.choices?.[0]?.message?.content ?? null;
|
|
85
|
-
}
|
|
86
|
-
catch {
|
|
87
|
-
return null;
|
|
88
|
-
}
|
|
89
|
-
finally {
|
|
90
|
-
clearTimeout(timer);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
async function callAnthropic(baseUrl, apiKey, model, prompt, timeoutMs) {
|
|
94
|
-
const controller = new AbortController();
|
|
95
|
-
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
96
|
-
try {
|
|
97
|
-
const res = await fetch(`${baseUrl}/messages`, {
|
|
98
|
-
method: "POST",
|
|
99
|
-
headers: {
|
|
100
|
-
"Content-Type": "application/json",
|
|
101
|
-
"x-api-key": apiKey,
|
|
102
|
-
"anthropic-version": "2023-06-01",
|
|
103
|
-
},
|
|
104
|
-
body: JSON.stringify({
|
|
105
|
-
model,
|
|
106
|
-
max_tokens: 200,
|
|
107
|
-
messages: [{ role: "user", content: prompt }],
|
|
108
|
-
}),
|
|
109
|
-
signal: controller.signal,
|
|
110
|
-
});
|
|
111
|
-
if (!res.ok)
|
|
112
|
-
return null;
|
|
113
|
-
const data = (await res.json());
|
|
114
|
-
const textBlock = data.content?.find((b) => b.type === "text");
|
|
115
|
-
return textBlock?.text ?? null;
|
|
116
|
-
}
|
|
117
|
-
catch {
|
|
118
|
-
return null;
|
|
119
|
-
}
|
|
120
|
-
finally {
|
|
121
|
-
clearTimeout(timer);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
// ─── Factory ────────────────────────────────────────────────────────────────
|
|
125
|
-
/**
|
|
126
|
-
* Resolve the environment variable name for a given model string's provider.
|
|
127
|
-
* Returns null if the model string is invalid or the provider is unknown.
|
|
128
|
-
*/
|
|
129
|
-
export function resolveApiKeyEnvVar(modelString) {
|
|
130
|
-
const slashIdx = modelString.indexOf("/");
|
|
131
|
-
if (slashIdx < 1)
|
|
132
|
-
return null;
|
|
133
|
-
const providerKey = modelString.slice(0, slashIdx).toLowerCase();
|
|
134
|
-
return PROVIDER_MAP[providerKey]?.apiKeyEnvVar ?? null;
|
|
135
|
-
}
|
|
136
|
-
/**
|
|
137
|
-
* Create an AlertEnricher that calls an LLM to add a summary + action to alerts.
|
|
138
|
-
* Returns null if provider can't be resolved.
|
|
139
|
-
*/
|
|
140
|
-
export function createLlmEnricher(opts) {
|
|
141
|
-
const { modelString, apiKey, logger, timeoutMs = 10_000 } = opts;
|
|
142
|
-
// Parse "provider/model-name" format
|
|
143
|
-
const slashIdx = modelString.indexOf("/");
|
|
144
|
-
if (slashIdx < 1) {
|
|
145
|
-
logger?.warn(`openalerts: llm-enrichment skipped — invalid model string "${modelString}"`);
|
|
146
|
-
return null;
|
|
147
|
-
}
|
|
148
|
-
const providerKey = modelString.slice(0, slashIdx).toLowerCase();
|
|
149
|
-
const model = modelString.slice(slashIdx + 1);
|
|
150
|
-
const providerConfig = PROVIDER_MAP[providerKey];
|
|
151
|
-
if (!providerConfig) {
|
|
152
|
-
logger?.warn(`openalerts: llm-enrichment skipped — unknown provider "${providerKey}"`);
|
|
153
|
-
return null;
|
|
154
|
-
}
|
|
155
|
-
logger?.info(`openalerts: llm-enrichment enabled (${providerKey}/${model})`);
|
|
156
|
-
return async (alert) => {
|
|
157
|
-
const prompt = buildPrompt(alert);
|
|
158
|
-
let responseText = null;
|
|
159
|
-
if (providerConfig.type === "anthropic") {
|
|
160
|
-
responseText = await callAnthropic(providerConfig.baseUrl, apiKey, model, prompt, timeoutMs);
|
|
161
|
-
}
|
|
162
|
-
else {
|
|
163
|
-
responseText = await callOpenAICompatible(providerConfig.baseUrl, apiKey, model, prompt, timeoutMs);
|
|
164
|
-
}
|
|
165
|
-
if (!responseText)
|
|
166
|
-
return null;
|
|
167
|
-
const parsed = parseEnrichment(responseText);
|
|
168
|
-
if (!parsed)
|
|
169
|
-
return null;
|
|
170
|
-
// Append enrichment to the original detail
|
|
171
|
-
let enrichedDetail = alert.detail;
|
|
172
|
-
if (parsed.summary) {
|
|
173
|
-
enrichedDetail += `\n\nSummary: ${parsed.summary}`;
|
|
174
|
-
}
|
|
175
|
-
if (parsed.action) {
|
|
176
|
-
enrichedDetail += `\nAction: ${parsed.action}`;
|
|
177
|
-
}
|
|
178
|
-
return { ...alert, detail: enrichedDetail };
|
|
179
|
-
};
|
|
180
|
-
}
|
package/dist/core/platform.d.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { type OpenAlertsLogger, type StoredEvent } from "./types.js";
|
|
2
|
-
export type PlatformSync = {
|
|
3
|
-
enqueue: (event: StoredEvent) => void;
|
|
4
|
-
flush: () => Promise<void>;
|
|
5
|
-
stop: () => void;
|
|
6
|
-
isConnected: () => boolean;
|
|
7
|
-
};
|
|
8
|
-
/**
|
|
9
|
-
* Create a platform sync instance that batches events and pushes them
|
|
10
|
-
* to the OpenAlerts backend API. Only active when apiKey is provided.
|
|
11
|
-
*/
|
|
12
|
-
export declare function createPlatformSync(opts: {
|
|
13
|
-
apiKey: string;
|
|
14
|
-
baseUrl?: string;
|
|
15
|
-
logger: OpenAlertsLogger;
|
|
16
|
-
logPrefix?: string;
|
|
17
|
-
}): PlatformSync;
|
package/dist/core/platform.js
DELETED
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import { DEFAULTS } from "./types.js";
|
|
2
|
-
/**
|
|
3
|
-
* Create a platform sync instance that batches events and pushes them
|
|
4
|
-
* to the OpenAlerts backend API. Only active when apiKey is provided.
|
|
5
|
-
*/
|
|
6
|
-
export function createPlatformSync(opts) {
|
|
7
|
-
const { apiKey, logger } = opts;
|
|
8
|
-
const baseUrl = opts.baseUrl?.replace(/\/+$/, "") ?? "https://api.openalerts.dev";
|
|
9
|
-
const prefix = opts.logPrefix ?? "openalerts";
|
|
10
|
-
let batch = [];
|
|
11
|
-
let flushTimer = null;
|
|
12
|
-
let disabled = false;
|
|
13
|
-
let connected = true;
|
|
14
|
-
// Start periodic flush
|
|
15
|
-
flushTimer = setInterval(() => {
|
|
16
|
-
void doFlush().catch(() => { });
|
|
17
|
-
}, DEFAULTS.platformFlushIntervalMs);
|
|
18
|
-
async function doFlush() {
|
|
19
|
-
if (disabled || batch.length === 0)
|
|
20
|
-
return;
|
|
21
|
-
const events = batch.splice(0, DEFAULTS.platformBatchSize);
|
|
22
|
-
const body = JSON.stringify({
|
|
23
|
-
events,
|
|
24
|
-
plugin_version: "0.1.0",
|
|
25
|
-
ts: Date.now(),
|
|
26
|
-
});
|
|
27
|
-
let lastErr;
|
|
28
|
-
for (let attempt = 0; attempt < 2; attempt++) {
|
|
29
|
-
try {
|
|
30
|
-
const res = await fetch(`${baseUrl}/api/monitor/ingest`, {
|
|
31
|
-
method: "POST",
|
|
32
|
-
headers: {
|
|
33
|
-
"Content-Type": "application/json",
|
|
34
|
-
Authorization: `Bearer ${apiKey}`,
|
|
35
|
-
},
|
|
36
|
-
body,
|
|
37
|
-
signal: AbortSignal.timeout(15_000),
|
|
38
|
-
});
|
|
39
|
-
if (res.ok) {
|
|
40
|
-
connected = true;
|
|
41
|
-
return; // Success
|
|
42
|
-
}
|
|
43
|
-
if (res.status === 401 || res.status === 403) {
|
|
44
|
-
logger.warn(`${prefix}: invalid API key (${res.status}). Platform sync disabled. Check your key at app.openalerts.dev.`);
|
|
45
|
-
disabled = true;
|
|
46
|
-
connected = false;
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
lastErr = `HTTP ${res.status}`;
|
|
50
|
-
}
|
|
51
|
-
catch (err) {
|
|
52
|
-
lastErr = err;
|
|
53
|
-
}
|
|
54
|
-
// Wait before retry
|
|
55
|
-
if (attempt < 1) {
|
|
56
|
-
await new Promise((r) => setTimeout(r, 5000));
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
// Failed after retries — put events back and log
|
|
60
|
-
batch.unshift(...events);
|
|
61
|
-
// Cap batch to prevent unbounded growth
|
|
62
|
-
if (batch.length > DEFAULTS.platformBatchSize * 2) {
|
|
63
|
-
batch = batch.slice(-DEFAULTS.platformBatchSize);
|
|
64
|
-
}
|
|
65
|
-
connected = false;
|
|
66
|
-
logger.warn(`${prefix}: platform sync failed: ${String(lastErr)}`);
|
|
67
|
-
}
|
|
68
|
-
return {
|
|
69
|
-
enqueue(event) {
|
|
70
|
-
if (disabled)
|
|
71
|
-
return;
|
|
72
|
-
batch.push(event);
|
|
73
|
-
// Auto-flush if batch full
|
|
74
|
-
if (batch.length >= DEFAULTS.platformBatchSize) {
|
|
75
|
-
void doFlush().catch(() => { });
|
|
76
|
-
}
|
|
77
|
-
},
|
|
78
|
-
async flush() {
|
|
79
|
-
await doFlush();
|
|
80
|
-
},
|
|
81
|
-
stop() {
|
|
82
|
-
if (flushTimer) {
|
|
83
|
-
clearInterval(flushTimer);
|
|
84
|
-
flushTimer = null;
|
|
85
|
-
}
|
|
86
|
-
// Final flush attempt (best-effort, don't await in stop)
|
|
87
|
-
void doFlush().catch(() => { });
|
|
88
|
-
},
|
|
89
|
-
isConnected() {
|
|
90
|
-
return connected && !disabled;
|
|
91
|
-
},
|
|
92
|
-
};
|
|
93
|
-
}
|