@easyoref/agent 1.21.1
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/__tests__/clarify.test.ts +827 -0
- package/__tests__/config.test.ts +304 -0
- package/__tests__/enrichment.integration.test.ts +871 -0
- package/__tests__/graph.test.ts +661 -0
- package/dist/auth.d.ts +11 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +54 -0
- package/dist/auth.js.map +1 -0
- package/dist/dry-run.d.ts +12 -0
- package/dist/dry-run.d.ts.map +1 -0
- package/dist/dry-run.js +236 -0
- package/dist/dry-run.js.map +1 -0
- package/dist/extract.d.ts +180 -0
- package/dist/extract.d.ts.map +1 -0
- package/dist/extract.js +210 -0
- package/dist/extract.js.map +1 -0
- package/dist/graph.d.ts +4083 -0
- package/dist/graph.d.ts.map +1 -0
- package/dist/graph.js +162 -0
- package/dist/graph.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/models.d.ts +7 -0
- package/dist/models.d.ts.map +1 -0
- package/dist/models.js +18 -0
- package/dist/models.js.map +1 -0
- package/dist/nodes/clarify-node.d.ts +132 -0
- package/dist/nodes/clarify-node.d.ts.map +1 -0
- package/dist/nodes/clarify-node.js +118 -0
- package/dist/nodes/clarify-node.js.map +1 -0
- package/dist/nodes/clarify.d.ts +6 -0
- package/dist/nodes/clarify.d.ts.map +1 -0
- package/dist/nodes/clarify.js +124 -0
- package/dist/nodes/clarify.js.map +1 -0
- package/dist/nodes/edit-node.d.ts +71 -0
- package/dist/nodes/edit-node.d.ts.map +1 -0
- package/dist/nodes/edit-node.js +496 -0
- package/dist/nodes/edit-node.js.map +1 -0
- package/dist/nodes/edit.d.ts +6 -0
- package/dist/nodes/edit.d.ts.map +1 -0
- package/dist/nodes/edit.js +22 -0
- package/dist/nodes/edit.js.map +1 -0
- package/dist/nodes/extract-node.d.ts +174 -0
- package/dist/nodes/extract-node.d.ts.map +1 -0
- package/dist/nodes/extract-node.js +233 -0
- package/dist/nodes/extract-node.js.map +1 -0
- package/dist/nodes/extract.d.ts +6 -0
- package/dist/nodes/extract.d.ts.map +1 -0
- package/dist/nodes/extract.js +49 -0
- package/dist/nodes/extract.js.map +1 -0
- package/dist/nodes/filter-agent.d.ts +11 -0
- package/dist/nodes/filter-agent.d.ts.map +1 -0
- package/dist/nodes/filter-agent.js +60 -0
- package/dist/nodes/filter-agent.js.map +1 -0
- package/dist/nodes/filter-node.d.ts +9 -0
- package/dist/nodes/filter-node.d.ts.map +1 -0
- package/dist/nodes/filter-node.js +111 -0
- package/dist/nodes/filter-node.js.map +1 -0
- package/dist/nodes/filters.d.ts +13 -0
- package/dist/nodes/filters.d.ts.map +1 -0
- package/dist/nodes/filters.js +111 -0
- package/dist/nodes/filters.js.map +1 -0
- package/dist/nodes/message-node.d.ts +71 -0
- package/dist/nodes/message-node.d.ts.map +1 -0
- package/dist/nodes/message-node.js +491 -0
- package/dist/nodes/message-node.js.map +1 -0
- package/dist/nodes/message.d.ts +71 -0
- package/dist/nodes/message.d.ts.map +1 -0
- package/dist/nodes/message.js +496 -0
- package/dist/nodes/message.js.map +1 -0
- package/dist/nodes/vote-node.d.ts +13 -0
- package/dist/nodes/vote-node.d.ts.map +1 -0
- package/dist/nodes/vote-node.js +232 -0
- package/dist/nodes/vote-node.js.map +1 -0
- package/dist/nodes/vote.d.ts +13 -0
- package/dist/nodes/vote.d.ts.map +1 -0
- package/dist/nodes/vote.js +232 -0
- package/dist/nodes/vote.js.map +1 -0
- package/dist/queue.d.ts +15 -0
- package/dist/queue.d.ts.map +1 -0
- package/dist/queue.js +41 -0
- package/dist/queue.js.map +1 -0
- package/dist/redis.d.ts +8 -0
- package/dist/redis.d.ts.map +1 -0
- package/dist/redis.js +33 -0
- package/dist/redis.js.map +1 -0
- package/dist/runtime/auth.d.ts +11 -0
- package/dist/runtime/auth.d.ts.map +1 -0
- package/dist/runtime/auth.js +54 -0
- package/dist/runtime/auth.js.map +1 -0
- package/dist/runtime/dry-run.d.ts +12 -0
- package/dist/runtime/dry-run.d.ts.map +1 -0
- package/dist/runtime/dry-run.js +236 -0
- package/dist/runtime/dry-run.js.map +1 -0
- package/dist/runtime/queue.d.ts +15 -0
- package/dist/runtime/queue.d.ts.map +1 -0
- package/dist/runtime/queue.js +41 -0
- package/dist/runtime/queue.js.map +1 -0
- package/dist/runtime/redis.d.ts +8 -0
- package/dist/runtime/redis.d.ts.map +1 -0
- package/dist/runtime/redis.js +33 -0
- package/dist/runtime/redis.js.map +1 -0
- package/dist/runtime/worker.d.ts +14 -0
- package/dist/runtime/worker.d.ts.map +1 -0
- package/dist/runtime/worker.js +135 -0
- package/dist/runtime/worker.js.map +1 -0
- package/dist/tools/alert-history.d.ts +18 -0
- package/dist/tools/alert-history.d.ts.map +1 -0
- package/dist/tools/alert-history.js +98 -0
- package/dist/tools/alert-history.js.map +1 -0
- package/dist/tools/betterstack-log.d.ts +15 -0
- package/dist/tools/betterstack-log.d.ts.map +1 -0
- package/dist/tools/betterstack-log.js +80 -0
- package/dist/tools/betterstack-log.js.map +1 -0
- package/dist/tools/index.d.ts +44 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +20 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/read-sources.d.ts +15 -0
- package/dist/tools/read-sources.d.ts.map +1 -0
- package/dist/tools/read-sources.js +67 -0
- package/dist/tools/read-sources.js.map +1 -0
- package/dist/tools/resolve-area.d.ts +19 -0
- package/dist/tools/resolve-area.d.ts.map +1 -0
- package/dist/tools/resolve-area.js +147 -0
- package/dist/tools/resolve-area.js.map +1 -0
- package/dist/tools.d.ts +115 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +439 -0
- package/dist/tools.js.map +1 -0
- package/dist/worker.d.ts +14 -0
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +135 -0
- package/dist/worker.js.map +1 -0
- package/package.json +26 -0
- package/src/graph.ts +200 -0
- package/src/index.ts +27 -0
- package/src/models.ts +20 -0
- package/src/nodes/clarify-node.ts +172 -0
- package/src/nodes/edit-node.ts +695 -0
- package/src/nodes/extract-node.ts +299 -0
- package/src/nodes/filter-node.ts +139 -0
- package/src/nodes/message.ts +695 -0
- package/src/nodes/vote-node.ts +354 -0
- package/src/nodes/vote.ts +354 -0
- package/src/runtime/auth.ts +63 -0
- package/src/runtime/dry-run.ts +303 -0
- package/src/runtime/queue.ts +53 -0
- package/src/runtime/redis.ts +38 -0
- package/src/runtime/worker.ts +167 -0
- package/src/tools/alert-history.ts +120 -0
- package/src/tools/betterstack-log.ts +102 -0
- package/src/tools/index.ts +23 -0
- package/src/tools/read-sources.ts +86 -0
- package/src/tools/resolve-area.ts +202 -0
- package/tsconfig.json +14 -0
package/dist/worker.js
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BullMQ worker — processes "enrich-alert" jobs.
|
|
3
|
+
*
|
|
4
|
+
* Session-aware scheduling:
|
|
5
|
+
* early_warning → every 20s, up to 30 min
|
|
6
|
+
* siren → every 20s, up to 15 min
|
|
7
|
+
* resolved → every 60s, up to 10 min (tail — detailed intel)
|
|
8
|
+
*
|
|
9
|
+
* After each job, checks the session phase and re-enqueues
|
|
10
|
+
* with the appropriate delay. Stops when phase expires.
|
|
11
|
+
*/
|
|
12
|
+
import * as logger from "@easyoref/monitoring";
|
|
13
|
+
import { clearSession, config, getActiveSession, getLanguagePack, isPhaseExpired, PHASE_ENRICH_DELAY_MS, } from "@easyoref/shared";
|
|
14
|
+
import { Worker } from "bullmq";
|
|
15
|
+
import { Bot } from "grammy";
|
|
16
|
+
import { runEnrichment } from "./graph.js";
|
|
17
|
+
import { MONITORING_RE, stripMonitoring } from "./nodes/edit-node.js";
|
|
18
|
+
import { enqueueEnrich } from "./runtime/queue.js";
|
|
19
|
+
let _worker = undefined;
|
|
20
|
+
/** Remove ⏳ monitoring indicator from all chat messages (best-effort) */
|
|
21
|
+
async function removeMonitoringIndicator(session) {
|
|
22
|
+
if (!config.botToken || !MONITORING_RE.test(session.currentText))
|
|
23
|
+
return;
|
|
24
|
+
const cleaned = stripMonitoring(session.currentText);
|
|
25
|
+
const tgBot = new Bot(config.botToken);
|
|
26
|
+
const targets = session.telegramMessages ?? [
|
|
27
|
+
{
|
|
28
|
+
chatId: session.chatId,
|
|
29
|
+
messageId: session.latestMessageId,
|
|
30
|
+
isCaption: session.isCaption,
|
|
31
|
+
},
|
|
32
|
+
];
|
|
33
|
+
for (const cm of targets) {
|
|
34
|
+
try {
|
|
35
|
+
if (cm.isCaption) {
|
|
36
|
+
await tgBot.api.editMessageCaption(cm.chatId, cm.messageId, {
|
|
37
|
+
caption: cleaned,
|
|
38
|
+
parse_mode: "HTML",
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
await tgBot.api.editMessageText(cm.chatId, cm.messageId, cleaned, {
|
|
43
|
+
parse_mode: "HTML",
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
const errStr = String(err);
|
|
49
|
+
if (!errStr.includes("message is not modified")) {
|
|
50
|
+
logger.error("Failed to remove monitoring indicator", {
|
|
51
|
+
error: errStr,
|
|
52
|
+
chatId: cm.chatId,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
logger.info("Removed monitoring indicator", { targets: targets.length });
|
|
58
|
+
}
|
|
59
|
+
export function startEnrichWorker() {
|
|
60
|
+
if (!config.agent.enabled)
|
|
61
|
+
return;
|
|
62
|
+
const connection = {
|
|
63
|
+
host: new URL(config.agent.redisUrl).hostname,
|
|
64
|
+
port: Number(new URL(config.agent.redisUrl).port || 6379),
|
|
65
|
+
password: new URL(config.agent.redisUrl).password || undefined,
|
|
66
|
+
};
|
|
67
|
+
_worker = new Worker("enrich-alert", async (job) => {
|
|
68
|
+
const { alertId } = job.data;
|
|
69
|
+
logger.info("Enrich worker: processing job", { alertId, jobId: job.id });
|
|
70
|
+
const session = await getActiveSession();
|
|
71
|
+
if (!session) {
|
|
72
|
+
logger.info("Enrich worker: no active session — skipping", { alertId });
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
// Phase expired → end session
|
|
76
|
+
if (isPhaseExpired(session)) {
|
|
77
|
+
logger.info("Enrich worker: phase expired — ending session", {
|
|
78
|
+
alertId: session.latestAlertId,
|
|
79
|
+
phase: session.phase,
|
|
80
|
+
});
|
|
81
|
+
await removeMonitoringIndicator(session);
|
|
82
|
+
await clearSession();
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const langPack = getLanguagePack(config.language);
|
|
86
|
+
// Run enrichment using latest alert's message as edit target
|
|
87
|
+
await runEnrichment({
|
|
88
|
+
alertId: session.latestAlertId,
|
|
89
|
+
alertTs: session.latestAlertTs,
|
|
90
|
+
alertType: session.phase,
|
|
91
|
+
alertAreas: session.alertAreas,
|
|
92
|
+
chatId: session.chatId,
|
|
93
|
+
messageId: session.latestMessageId,
|
|
94
|
+
isCaption: session.isCaption,
|
|
95
|
+
telegramMessages: session.telegramMessages,
|
|
96
|
+
currentText: session.baseText ?? session.currentText,
|
|
97
|
+
monitoringLabel: langPack.labels.monitoring,
|
|
98
|
+
});
|
|
99
|
+
// Re-check session after enrichment (may have changed phase)
|
|
100
|
+
const after = await getActiveSession();
|
|
101
|
+
if (!after)
|
|
102
|
+
return;
|
|
103
|
+
if (isPhaseExpired(after)) {
|
|
104
|
+
logger.info("Enrich worker: phase expired post-enrich — ending session", {
|
|
105
|
+
phase: after.phase,
|
|
106
|
+
});
|
|
107
|
+
await removeMonitoringIndicator(after);
|
|
108
|
+
await clearSession();
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
// Re-enqueue with phase-appropriate delay
|
|
112
|
+
const delay = PHASE_ENRICH_DELAY_MS[after.phase];
|
|
113
|
+
await enqueueEnrich(after.latestAlertId, after.latestAlertTs, delay);
|
|
114
|
+
}, {
|
|
115
|
+
connection,
|
|
116
|
+
concurrency: 1,
|
|
117
|
+
});
|
|
118
|
+
_worker.on("completed", (job) => {
|
|
119
|
+
logger.info("Enrich worker: job completed", { jobId: job.id });
|
|
120
|
+
});
|
|
121
|
+
_worker.on("failed", (job, err) => {
|
|
122
|
+
logger.error("Enrich worker: job failed", {
|
|
123
|
+
jobId: job?.id,
|
|
124
|
+
error: String(err),
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
logger.info("Enrich worker started");
|
|
128
|
+
}
|
|
129
|
+
export async function stopEnrichWorker() {
|
|
130
|
+
if (_worker) {
|
|
131
|
+
await _worker.close();
|
|
132
|
+
_worker = undefined;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker.js","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@easyoref/agent",
|
|
3
|
+
"version": "1.21.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc",
|
|
9
|
+
"typecheck": "tsc --noEmit"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@langchain/core": "^1.1.31",
|
|
13
|
+
"@langchain/langgraph": "^1.2.1",
|
|
14
|
+
"@langchain/openai": "^1.2.12",
|
|
15
|
+
"bullmq": "^5.0.0",
|
|
16
|
+
"ioredis": "^5.3.0",
|
|
17
|
+
"@easyoref/shared": "*",
|
|
18
|
+
"@easyoref/monitoring": "*",
|
|
19
|
+
"@easyoref/gramjs": "*",
|
|
20
|
+
"zod": "4.3.6"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@types/node": "^22.0.0",
|
|
24
|
+
"typescript": "^5.7.0"
|
|
25
|
+
}
|
|
26
|
+
}
|
package/src/graph.ts
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LangGraph.js enrichment pipeline — phase-aware, time-validated.
|
|
3
|
+
*
|
|
4
|
+
* ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌──────────---──┐
|
|
5
|
+
* │ filter │───▶│ extract │───▶│ vote │───▶│ shouldClarify │
|
|
6
|
+
* └─────────┘ └─────────┘ └─────────┘ └──────┬───---──┘
|
|
7
|
+
* │
|
|
8
|
+
* ┌──────────────┴──────────────┐
|
|
9
|
+
* │ │
|
|
10
|
+
* [low conf] [high conf]
|
|
11
|
+
* │ │
|
|
12
|
+
* ▼ ▼
|
|
13
|
+
* ┌────────────┐ ┌─────────┐
|
|
14
|
+
* │ clarify │ │ edit │
|
|
15
|
+
* └──────┬─────┘ └─────────┘
|
|
16
|
+
* │ ▲
|
|
17
|
+
* ▼ │
|
|
18
|
+
* ┌────────────┐ │
|
|
19
|
+
* │ revote │───────────────────────┘
|
|
20
|
+
* └────────────┘
|
|
21
|
+
*
|
|
22
|
+
* ── Node responsibilities ──────────────────────────────────────────────────
|
|
23
|
+
*
|
|
24
|
+
* filter: Collect Telegram posts from Redis, apply deterministic noise
|
|
25
|
+
* filters (area lists, summaries, IDF press releases). Returns
|
|
26
|
+
* ChannelTracking structure.
|
|
27
|
+
*
|
|
28
|
+
* extract: LLM-powered extraction pipeline:
|
|
29
|
+
* 1. Cheap model → which channels have relevant intel?
|
|
30
|
+
* 2. Expensive model → extract structured data per post
|
|
31
|
+
* 3. Post-filter → deterministic validation
|
|
32
|
+
*
|
|
33
|
+
* vote: Consensus voting (deterministic, 0 tokens). Aggregates multiple
|
|
34
|
+
* extractions into a single VotedResult using median/majority.
|
|
35
|
+
*
|
|
36
|
+
* shouldClarify: Conditional routing:
|
|
37
|
+
* - Low confidence (< threshold) → clarify
|
|
38
|
+
* - Single-source Lebanon for central Israel → clarify (suspicious)
|
|
39
|
+
* - Already clarified → edit
|
|
40
|
+
* - MCP tools disabled → edit
|
|
41
|
+
*
|
|
42
|
+
* clarify: ReAct agent with tools (read_telegram, alert_history,
|
|
43
|
+
* resolve_area, betterstack_log). Fetches more data to resolve
|
|
44
|
+
* contradictions. Output: new extractions.
|
|
45
|
+
*
|
|
46
|
+
* revote: Re-run vote with additional extractions from clarify.
|
|
47
|
+
*
|
|
48
|
+
* edit: Build enriched message text and edit Telegram message.
|
|
49
|
+
*
|
|
50
|
+
* ── Why this pipeline? ─────────────────────────────────────────────────────
|
|
51
|
+
*
|
|
52
|
+
* 1. Cheap → Expensive: Saves tokens. Pre-filter with cheap model ($0.001)
|
|
53
|
+
* before spending on per-post extraction ($0.01 each).
|
|
54
|
+
*
|
|
55
|
+
* 2. ReAct clarification: Low-confidence results aren't "failed" —
|
|
56
|
+
* they're signals that more data is needed. The LLM decides what tools
|
|
57
|
+
* to use rather than a hardcoded threshold.
|
|
58
|
+
*
|
|
59
|
+
* 3. Carry-forward: previousEnrichment preserves data between phases.
|
|
60
|
+
* If origin was confirmed in early_warning, it carries to red_alert/resolved.
|
|
61
|
+
*
|
|
62
|
+
* 4. Time validation: LLM instructions emphasize checking if sources
|
|
63
|
+
* are about THIS alert vs. previous attacks. Critical for accuracy.
|
|
64
|
+
*/
|
|
65
|
+
|
|
66
|
+
import * as logger from "@easyoref/monitoring";
|
|
67
|
+
import {
|
|
68
|
+
AlertTypeSchema,
|
|
69
|
+
ChannelTrackingSchema,
|
|
70
|
+
EnrichmentDataSchema,
|
|
71
|
+
RunEnrichmentInputSchema,
|
|
72
|
+
TelegramMessageSchema,
|
|
73
|
+
ValidatedExtractionSchema,
|
|
74
|
+
VotedResultSchema,
|
|
75
|
+
config,
|
|
76
|
+
createEmptyEnrichmentData,
|
|
77
|
+
validateSafe,
|
|
78
|
+
} from "@easyoref/shared";
|
|
79
|
+
import {
|
|
80
|
+
END,
|
|
81
|
+
MemorySaver,
|
|
82
|
+
ReducedValue,
|
|
83
|
+
START,
|
|
84
|
+
StateGraph,
|
|
85
|
+
StateSchema,
|
|
86
|
+
} from "@langchain/langgraph";
|
|
87
|
+
import { z } from "zod";
|
|
88
|
+
import { clarifyNode } from "./nodes/clarify-node.js";
|
|
89
|
+
import { editNode } from "./nodes/edit-node.js";
|
|
90
|
+
import { extractNode } from "./nodes/extract-node.js";
|
|
91
|
+
import { filterNode } from "./nodes/filter-node.js";
|
|
92
|
+
import { voteNode } from "./nodes/vote-node.js";
|
|
93
|
+
|
|
94
|
+
export const AgentState = new StateSchema({
|
|
95
|
+
alertId: z.string(),
|
|
96
|
+
alertTs: z.number(),
|
|
97
|
+
alertType: AlertTypeSchema,
|
|
98
|
+
alertAreas: z.array(z.string()),
|
|
99
|
+
chatId: z.string(),
|
|
100
|
+
messageId: z.number(),
|
|
101
|
+
isCaption: z.boolean(),
|
|
102
|
+
currentText: z.string(),
|
|
103
|
+
tracking: ChannelTrackingSchema.optional(),
|
|
104
|
+
extractions: new ReducedValue(z.array(ValidatedExtractionSchema), {
|
|
105
|
+
reducer: (previous, current) => [...previous, ...current],
|
|
106
|
+
}),
|
|
107
|
+
votedResult: VotedResultSchema.optional(),
|
|
108
|
+
clarifyAttempted: z.boolean().default(false),
|
|
109
|
+
previousEnrichment: EnrichmentDataSchema.optional(),
|
|
110
|
+
monitoringLabel: z.string().optional(),
|
|
111
|
+
telegramMessages: new ReducedValue(z.array(TelegramMessageSchema), {
|
|
112
|
+
reducer: (previous, current) => [...previous, ...current],
|
|
113
|
+
}),
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
export type AgentStateType = typeof AgentState.State;
|
|
117
|
+
|
|
118
|
+
const shouldClarify = (state: AgentStateType): "clarify" | "edit" => {
|
|
119
|
+
if (state.clarifyAttempted) return "edit";
|
|
120
|
+
if (!config.agent.mcpTools) return "edit";
|
|
121
|
+
if (!state.votedResult) return "edit";
|
|
122
|
+
|
|
123
|
+
if (state.votedResult.confidence < config.agent.confidenceThreshold) {
|
|
124
|
+
logger.info("Agent: routing to clarify (low confidence)", {
|
|
125
|
+
confidence: state.votedResult.confidence,
|
|
126
|
+
});
|
|
127
|
+
return "clarify";
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const origins = state.votedResult.countryOrigins;
|
|
131
|
+
if (origins && origins.length === 1 && state.votedResult.sourcesCount === 1) {
|
|
132
|
+
if (
|
|
133
|
+
origins[0]!.name === "Lebanon" &&
|
|
134
|
+
state.alertAreas.some(
|
|
135
|
+
(area) =>
|
|
136
|
+
area.includes("תל אביב") ||
|
|
137
|
+
area.includes("גוש דן") ||
|
|
138
|
+
area.includes("שרון") ||
|
|
139
|
+
area.includes("מרכז"),
|
|
140
|
+
)
|
|
141
|
+
) {
|
|
142
|
+
logger.info("Agent: routing to clarify (suspicious Lebanon origin)", {});
|
|
143
|
+
return "clarify";
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return "edit";
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
const checkpointer = new MemorySaver();
|
|
151
|
+
|
|
152
|
+
export const buildGraph = () =>
|
|
153
|
+
new StateGraph(AgentState)
|
|
154
|
+
.addNode("filter", filterNode)
|
|
155
|
+
.addNode("extract", extractNode)
|
|
156
|
+
.addNode("vote", voteNode)
|
|
157
|
+
.addNode("clarify", clarifyNode)
|
|
158
|
+
.addNode("revote", voteNode)
|
|
159
|
+
.addNode("edit", editNode)
|
|
160
|
+
.addEdge(START, "filter")
|
|
161
|
+
.addEdge("filter", "extract")
|
|
162
|
+
.addEdge("extract", "vote")
|
|
163
|
+
.addConditionalEdges("vote", shouldClarify, {
|
|
164
|
+
clarify: "clarify",
|
|
165
|
+
edit: "edit",
|
|
166
|
+
})
|
|
167
|
+
.addEdge("clarify", "revote")
|
|
168
|
+
.addEdge("revote", "edit")
|
|
169
|
+
.addEdge("edit", END)
|
|
170
|
+
.compile({ checkpointer });
|
|
171
|
+
|
|
172
|
+
export type { RunEnrichmentInput } from "@easyoref/shared";
|
|
173
|
+
export { RunEnrichmentInputSchema };
|
|
174
|
+
|
|
175
|
+
export const runEnrichment = async (input: unknown): Promise<void> => {
|
|
176
|
+
const validation = validateSafe(RunEnrichmentInputSchema, input);
|
|
177
|
+
if (!validation.ok) {
|
|
178
|
+
logger.error("Enrichment: invalid input", { error: validation.error });
|
|
179
|
+
throw new Error(`Invalid enrichment input: ${validation.error}`);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const validInput = validation.data;
|
|
183
|
+
|
|
184
|
+
await buildGraph().invoke(
|
|
185
|
+
{
|
|
186
|
+
alertId: validInput.alertId,
|
|
187
|
+
alertTs: validInput.alertTs,
|
|
188
|
+
alertType: validInput.alertType,
|
|
189
|
+
alertAreas: validInput.alertAreas,
|
|
190
|
+
chatId: validInput.chatId,
|
|
191
|
+
messageId: validInput.messageId,
|
|
192
|
+
isCaption: validInput.isCaption,
|
|
193
|
+
telegramMessages: validInput.telegramMessages,
|
|
194
|
+
currentText: validInput.currentText,
|
|
195
|
+
previousEnrichment: createEmptyEnrichmentData(),
|
|
196
|
+
monitoringLabel: validInput.monitoringLabel,
|
|
197
|
+
},
|
|
198
|
+
{ configurable: { thread_id: validInput.alertId } },
|
|
199
|
+
);
|
|
200
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EasyOref Agent Package
|
|
3
|
+
*
|
|
4
|
+
* LangGraph-based enrichment pipeline for Israeli missile alert processing.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export * from "./graph.js";
|
|
8
|
+
|
|
9
|
+
export * from "./nodes/clarify-node.js";
|
|
10
|
+
export * from "./nodes/edit-node.js";
|
|
11
|
+
export * from "./nodes/extract-node.js";
|
|
12
|
+
export * from "./nodes/filter-node.js";
|
|
13
|
+
export * from "./nodes/vote-node.js";
|
|
14
|
+
|
|
15
|
+
export * from "./models.js";
|
|
16
|
+
|
|
17
|
+
export * from "./runtime/auth.js";
|
|
18
|
+
export * from "./runtime/dry-run.js";
|
|
19
|
+
export * from "./runtime/queue.js";
|
|
20
|
+
export * from "./runtime/redis.js";
|
|
21
|
+
export * from "./runtime/worker.js";
|
|
22
|
+
|
|
23
|
+
export { alertHistoryTool } from "./tools/alert-history.js";
|
|
24
|
+
export { betterstackLogTool } from "./tools/betterstack-log.js";
|
|
25
|
+
export { clarifyTools } from "./tools/index.js";
|
|
26
|
+
export { readSourcesTool } from "./tools/read-sources.js";
|
|
27
|
+
export { resolveAreaTool } from "./tools/resolve-area.js";
|
package/src/models.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM models configuration.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { ChatOpenRouter } from "@langchain/openrouter";
|
|
6
|
+
import { config } from "@easyoref/shared";
|
|
7
|
+
|
|
8
|
+
export const filterModel = new ChatOpenRouter({
|
|
9
|
+
apiKey: config.agent.apiKey,
|
|
10
|
+
model: config.agent.filterModel,
|
|
11
|
+
temperature: 0,
|
|
12
|
+
maxTokens: 200,
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export const extractModel = new ChatOpenRouter({
|
|
16
|
+
apiKey: config.agent.apiKey,
|
|
17
|
+
model: config.agent.extractModel,
|
|
18
|
+
temperature: 0,
|
|
19
|
+
maxTokens: 500,
|
|
20
|
+
});
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clarify Node — optional ReAct tool calling for low-confidence enrichment.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import * as logger from "@easyoref/monitoring";
|
|
6
|
+
import {
|
|
7
|
+
ClarifyOutputSchema,
|
|
8
|
+
pushSessionPost,
|
|
9
|
+
type ChannelPost,
|
|
10
|
+
type ValidatedExtraction,
|
|
11
|
+
} from "@easyoref/shared";
|
|
12
|
+
import { createAgent, toolStrategy } from "langchain";
|
|
13
|
+
import type { AgentStateType } from "../graph.js";
|
|
14
|
+
import { filterModel } from "../models.js";
|
|
15
|
+
import { clarifyTools } from "../tools/index.js";
|
|
16
|
+
|
|
17
|
+
export const clarifyAgent = createAgent({
|
|
18
|
+
model: filterModel,
|
|
19
|
+
tools: clarifyTools,
|
|
20
|
+
responseFormat: toolStrategy(ClarifyOutputSchema),
|
|
21
|
+
systemPrompt: `
|
|
22
|
+
You are the clarification agent for EasyOref — an Israeli missile alert enrichment system.
|
|
23
|
+
|
|
24
|
+
The voting pipeline analyzed Telegram channel posts and produced a result with
|
|
25
|
+
low confidence or contradictions. You have access to 4 tools:
|
|
26
|
+
|
|
27
|
+
1. read_telegram_sources — fetch last N posts from a Telegram news channel
|
|
28
|
+
2. alert_history — get recent alert history from Pikud HaOref.
|
|
29
|
+
3. resolve_area — check if a location mentioned in news is relevant to user's areas.
|
|
30
|
+
4. betterstack_log — query recent EasyOref logs from Better Stack.
|
|
31
|
+
|
|
32
|
+
CRITICAL — TIME VALIDATION:
|
|
33
|
+
You receive the alert time (Israel timezone). Channel posts may be about PREVIOUS
|
|
34
|
+
attacks or ongoing military operations (not THIS specific alert). When in doubt:
|
|
35
|
+
- Use alert_history to verify if an alert really occurred at the claimed time/area.
|
|
36
|
+
- If a post discusses events from hours ago, it is STALE — ignore it.
|
|
37
|
+
|
|
38
|
+
You decide whether tools would help:
|
|
39
|
+
- If contradictions can be resolved with existing data → respond immediately, no tools.
|
|
40
|
+
- If an authoritative source (IDF, N12) could settle a disagreement → fetch 1-4 posts.
|
|
41
|
+
- If you need to verify whether an alert occurred → check alert_history.
|
|
42
|
+
|
|
43
|
+
Always respect an output format.
|
|
44
|
+
`,
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
function describeContradictions(
|
|
48
|
+
extractions: ValidatedExtraction[],
|
|
49
|
+
voted: {
|
|
50
|
+
countryOrigins?: { name: string }[];
|
|
51
|
+
rocketCountMin?: number;
|
|
52
|
+
rocketCountMax?: number;
|
|
53
|
+
interceptedConfidence?: number;
|
|
54
|
+
intercepted?: number;
|
|
55
|
+
hitsConfidence?: number;
|
|
56
|
+
hitsConfirmed?: number;
|
|
57
|
+
confidence: number;
|
|
58
|
+
sourcesCount: number;
|
|
59
|
+
},
|
|
60
|
+
): string {
|
|
61
|
+
const issues: string[] = [];
|
|
62
|
+
|
|
63
|
+
if (voted.countryOrigins && voted.countryOrigins.length > 1) {
|
|
64
|
+
const names = voted.countryOrigins.map((c) => c.name).join(", ");
|
|
65
|
+
issues.push(`Multiple origin countries reported: ${names}`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (
|
|
69
|
+
voted.rocketCountMin &&
|
|
70
|
+
voted.rocketCountMax &&
|
|
71
|
+
voted.rocketCountMax - voted.rocketCountMin > 3
|
|
72
|
+
) {
|
|
73
|
+
issues.push(
|
|
74
|
+
`Wide rocket count range: ${voted.rocketCountMin}–${voted.rocketCountMax}`,
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (
|
|
79
|
+
(voted.interceptedConfidence ?? 0) < 0.5 &&
|
|
80
|
+
voted.intercepted !== undefined
|
|
81
|
+
) {
|
|
82
|
+
issues.push(
|
|
83
|
+
`Intercepted count (${voted.intercepted}) has low confidence: ${(
|
|
84
|
+
voted.interceptedConfidence ?? 0
|
|
85
|
+
).toFixed(2)}`,
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
issues.push(`Overall confidence: ${voted.confidence}`);
|
|
90
|
+
issues.push(`Sources count: ${voted.sourcesCount}`);
|
|
91
|
+
|
|
92
|
+
return issues.join("\n");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export const clarifyNode = async (
|
|
96
|
+
state: AgentStateType,
|
|
97
|
+
): Promise<Partial<AgentStateType>> => {
|
|
98
|
+
if (!state.votedResult) {
|
|
99
|
+
logger.info("Agent: clarify skipped — no voted result", {
|
|
100
|
+
alertId: state.alertId,
|
|
101
|
+
});
|
|
102
|
+
return { clarifyAttempted: true };
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
logger.info("Agent: clarify triggered", {
|
|
106
|
+
alertId: state.alertId,
|
|
107
|
+
confidence: state.votedResult.confidence,
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
try {
|
|
111
|
+
const contradictions = describeContradictions(
|
|
112
|
+
state.extractions,
|
|
113
|
+
state.votedResult,
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
const alertTimeIL = new Date(state.alertTs).toLocaleTimeString("he-IL", {
|
|
117
|
+
hour: "2-digit",
|
|
118
|
+
minute: "2-digit",
|
|
119
|
+
timeZone: "Asia/Jerusalem",
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
const userPrompt =
|
|
123
|
+
`Alert region: ${state.alertAreas.join(", ")}\n` +
|
|
124
|
+
`Alert type: ${state.alertType}\n` +
|
|
125
|
+
`Alert time: ${alertTimeIL} (Israel)\n` +
|
|
126
|
+
`Message ID: ${state.messageId}\n\n` +
|
|
127
|
+
`Current voted result:\n` +
|
|
128
|
+
JSON.stringify(state.votedResult, undefined, 2) +
|
|
129
|
+
`\n\nContradictions & issues:\n${contradictions}\n\n` +
|
|
130
|
+
`Existing extractions (${
|
|
131
|
+
state.extractions.filter((e) => e.valid).length
|
|
132
|
+
} valid):\n` +
|
|
133
|
+
state.extractions
|
|
134
|
+
.filter((e) => e.valid)
|
|
135
|
+
.map(
|
|
136
|
+
(e) =>
|
|
137
|
+
` [${e.channel}] country=${e.countryOrigin}, rockets=${e.rocketCount}, ` +
|
|
138
|
+
`intercepted=${e.intercepted}, hits=${e.hitsConfirmed}, conf=${e.confidence}`,
|
|
139
|
+
)
|
|
140
|
+
.join("\n") +
|
|
141
|
+
`\n\nDecide: would fetching more data from authoritative channels resolve these issues?`;
|
|
142
|
+
|
|
143
|
+
const result = await clarifyAgent.invoke({ messages: [userPrompt] });
|
|
144
|
+
const output = result.structuredResponse;
|
|
145
|
+
|
|
146
|
+
const newPosts: ChannelPost[] = [];
|
|
147
|
+
if (output?.newPosts) {
|
|
148
|
+
for (const p of output.newPosts) {
|
|
149
|
+
const post: ChannelPost = {
|
|
150
|
+
channel: p.channel,
|
|
151
|
+
text: p.text,
|
|
152
|
+
ts: p.ts,
|
|
153
|
+
messageUrl: p.messageUrl,
|
|
154
|
+
};
|
|
155
|
+
newPosts.push(post);
|
|
156
|
+
await pushSessionPost(post);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return {
|
|
161
|
+
extractions: [...state.extractions, ...(output?.newExtractions ?? [])],
|
|
162
|
+
votedResult: undefined,
|
|
163
|
+
clarifyAttempted: true,
|
|
164
|
+
};
|
|
165
|
+
} catch (err) {
|
|
166
|
+
logger.error("Agent: clarify failed", {
|
|
167
|
+
alertId: state.alertId,
|
|
168
|
+
error: String(err),
|
|
169
|
+
});
|
|
170
|
+
return { clarifyAttempted: true };
|
|
171
|
+
}
|
|
172
|
+
};
|