easyoref 1.14.2 → 1.15.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.
@@ -1,79 +1,18 @@
1
1
  /**
2
2
  * LangGraph.js enrichment pipeline — phase-aware, time-validated.
3
3
  *
4
- * KEY DESIGN PRINCIPLES:
5
- * 1. TIME IS KING every post is validated against the alert time window.
6
- * LLM receives alert time + post time and scores time_relevance.
7
- * Posts about previous/different attacks are rejected.
8
- * 2. PHASE-AWARE each phase extracts only what's relevant:
9
- * - early_warning: origin, ETA, rocket count, cassette
10
- * - siren: carries early data + adds interception, impacts
11
- * - resolved: carries all + adds casualties, injuries, final stats
12
- * 3. CARRY-FORWARD — results persist in Redis (EnrichmentData).
13
- * Each phase inherits previous phase's findings.
14
- * 4. INLINE CITATIONS — no superscripts, no footer sources.
15
- * Format: [[1]](url) right after each data point.
16
- * 5. DEDUP EDITS — hash-based check prevents "message not modified" spam.
4
+ * Lean orchestrator: connects filter → extract → vote → edit.
5
+ * All logic lives in dedicated modules:
6
+ * - filters.ts: deterministic noise filter, channel tracking
7
+ * - extract.ts: cheap LLM pre-filter, expensive extraction, post-filter
8
+ * - vote.ts: consensus voting (deterministic)
9
+ * - message.ts: message building, Telegram editing
10
+ * - helpers.ts: toIsraelTime, textHash
17
11
  *
18
12
  * Pipeline:
19
- * preFilterextractAndValidatepostFiltervote[clarify] → editMessage
13
+ * collectAndFilterextractvote[clarifyrevote] → editMessage
20
14
  */
21
- import { ChatOpenAI } from "@langchain/openai";
22
- import type { ChannelPost } from "./store.js";
23
- import type { AlertType, CitedSource, EnrichmentData, InlineCite, ValidatedExtraction, VotedResult } from "./types.js";
24
- declare const AgentState: import("@langchain/langgraph").AnnotationRoot<{
25
- alertId: import("@langchain/langgraph").BaseChannel<string, string | import("@langchain/langgraph").OverwriteValue<string>, unknown>;
26
- alertTs: import("@langchain/langgraph").BaseChannel<number, number | import("@langchain/langgraph").OverwriteValue<number>, unknown>;
27
- alertType: import("@langchain/langgraph").BaseChannel<AlertType, AlertType | import("@langchain/langgraph").OverwriteValue<AlertType>, unknown>;
28
- alertAreas: import("@langchain/langgraph").BaseChannel<string[], string[] | import("@langchain/langgraph").OverwriteValue<string[]>, unknown>;
29
- chatId: import("@langchain/langgraph").BaseChannel<string, string | import("@langchain/langgraph").OverwriteValue<string>, unknown>;
30
- messageId: import("@langchain/langgraph").BaseChannel<number, number | import("@langchain/langgraph").OverwriteValue<number>, unknown>;
31
- isCaption: import("@langchain/langgraph").BaseChannel<boolean, boolean | import("@langchain/langgraph").OverwriteValue<boolean>, unknown>;
32
- currentText: import("@langchain/langgraph").BaseChannel<string, string | import("@langchain/langgraph").OverwriteValue<string>, unknown>;
33
- channelPosts: import("@langchain/langgraph").BaseChannel<ChannelPost[], ChannelPost[] | import("@langchain/langgraph").OverwriteValue<ChannelPost[]>, unknown>;
34
- filteredPosts: import("@langchain/langgraph").BaseChannel<ChannelPost[], ChannelPost[] | import("@langchain/langgraph").OverwriteValue<ChannelPost[]>, unknown>;
35
- extractions: import("@langchain/langgraph").BaseChannel<ValidatedExtraction[], ValidatedExtraction[] | import("@langchain/langgraph").OverwriteValue<ValidatedExtraction[]>, unknown>;
36
- votedResult: import("@langchain/langgraph").BaseChannel<VotedResult | null, VotedResult | import("@langchain/langgraph").OverwriteValue<VotedResult | null> | null, unknown>;
37
- /** Tracks whether clarify has already run (prevents infinite loop) */
38
- clarifyAttempted: import("@langchain/langgraph").BaseChannel<boolean, boolean | import("@langchain/langgraph").OverwriteValue<boolean>, unknown>;
39
- /** Cross-phase enrichment data loaded at start */
40
- previousEnrichment: import("@langchain/langgraph").BaseChannel<EnrichmentData, EnrichmentData | import("@langchain/langgraph").OverwriteValue<EnrichmentData>, unknown>;
41
- /** Session start timestamp for time window calculations */
42
- sessionStartTs: import("@langchain/langgraph").BaseChannel<number, number | import("@langchain/langgraph").OverwriteValue<number>, unknown>;
43
- /** Phase start timestamp */
44
- phaseStartTs: import("@langchain/langgraph").BaseChannel<number, number | import("@langchain/langgraph").OverwriteValue<number>, unknown>;
45
- }>;
46
- type AgentStateType = typeof AgentState.State;
47
- declare function getLLM(): ChatOpenAI;
48
- declare function buildRegionKeywords(): string[];
49
- /** Format timestamp as HH:MM Israel time */
50
- declare function toIsraelTime(ts: number): string;
51
- /** MD5 hash for edit dedup */
52
- declare function textHash(text: string): string;
53
- /** Phase-specific extraction instructions */
54
- declare function getPhaseInstructions(alertType: AlertType): string;
55
- declare function postFilter(state: AgentStateType): Partial<AgentStateType>;
56
- declare function vote(state: AgentStateType): Partial<AgentStateType>;
57
- /** Format inline citations: [[1]](url), [[2]](url) */
58
- declare function inlineCites(indices: number[], citedSources: CitedSource[]): string;
59
- /** Get InlineCite[] from citation indices */
60
- declare function extractCites(indices: number[], citedSources: CitedSource[]): InlineCite[];
61
- /** Format inline citations from InlineCite[] (for carry-forward data) */
62
- declare function inlineCitesFromData(cites: InlineCite[]): string;
63
- /**
64
- * Build enrichment data from current vote + previous enrichment (carry-forward).
65
- * Returns updated EnrichmentData for Redis persistence.
66
- */
67
- declare function buildEnrichmentFromVote(r: VotedResult, prev: EnrichmentData, alertType: AlertType, alertTs: number): EnrichmentData;
68
- /**
69
- * Build the enriched message text from current message + enrichment data.
70
- * Uses inline [[1]](url) citations. No superscripts. No footer sources.
71
- */
72
- declare function buildEnrichedMessage(currentText: string, alertType: AlertType, alertTs: number, enrichment: EnrichmentData): string;
73
- /**
74
- * Insert a line before the time line (last "Время" / "Time" / "שעת" line).
75
- */
76
- declare function insertBeforeTimeLine(text: string, line: string): string;
15
+ import type { AlertType } from "./types.js";
77
16
  export interface RunEnrichmentInput {
78
17
  alertId: string;
79
18
  alertTs: number;
@@ -85,27 +24,4 @@ export interface RunEnrichmentInput {
85
24
  currentText: string;
86
25
  }
87
26
  export declare function runEnrichment(input: RunEnrichmentInput): Promise<void>;
88
- export declare const _test: {
89
- readonly getLLM: typeof getLLM;
90
- readonly buildRegionKeywords: typeof buildRegionKeywords;
91
- readonly LAUNCH_KEYWORDS: string[];
92
- readonly TIME_WINDOW_MS: Record<AlertType, number>;
93
- readonly toIsraelTime: typeof toIsraelTime;
94
- readonly textHash: typeof textHash;
95
- readonly postFilter: typeof postFilter;
96
- readonly vote: typeof vote;
97
- readonly buildEnrichmentFromVote: typeof buildEnrichmentFromVote;
98
- readonly buildEnrichedMessage: typeof buildEnrichedMessage;
99
- readonly insertBeforeTimeLine: typeof insertBeforeTimeLine;
100
- readonly inlineCites: typeof inlineCites;
101
- readonly inlineCitesFromData: typeof inlineCitesFromData;
102
- readonly extractCites: typeof extractCites;
103
- readonly COUNTRY_RU: Record<string, string>;
104
- readonly SYSTEM_PROMPT_BASE: "You analyze Telegram channel messages about a missile/rocket attack on Israel.\nYour job: extract factual data, assess quality, AND validate temporal relevance.\n\nCRITICAL — TIME VALIDATION:\nYou will receive the alert time and the post time. You MUST determine if this post\nis about the CURRENT attack or about a previous/different event.\n- If post discusses events clearly BEFORE the alert time → time_relevance=0\n- If post is generic military news not specific to this attack → time_relevance=0.2\n- If post discusses the current attack → time_relevance=1.0\n- If uncertain → time_relevance=0.5 (the system will use alert_history to verify)\n\nReturn ONLY valid JSON (no markdown, no explanation):\n{\n \"region_relevance\": float, // 0–1: does this message discuss the specified alert region?\n \"source_trust\": float, // 0–1: factual reporting (1.0) vs unverified rumors/panic (0.0)\n \"tone\": \"calm\"|\"neutral\"|\"alarmist\",\n \"time_relevance\": float, // 0–1: is this post about the CURRENT attack? (see rules above)\n \"country_origin\": string|null, // \"Iran\",\"Yemen\",\"Lebanon\",\"Gaza\",\"Iraq\",\"Syria\" or null\n \"rocket_count\": int|null,\n \"is_cassette\": bool|null,\n \"intercepted\": int|null,\n \"intercepted_qual\": \"all\"|\"most\"|\"many\"|\"few\"|\"exists\"|\"none\"|\"more_than\"|\"less_than\"|null,\n \"intercepted_qual_num\": int|null,\n \"sea_impact\": int|null,\n \"sea_impact_qual\": \"all\"|\"most\"|\"many\"|\"few\"|\"exists\"|\"none\"|\"more_than\"|\"less_than\"|null,\n \"sea_impact_qual_num\": int|null,\n \"open_area_impact\": int|null,\n \"open_area_impact_qual\": \"all\"|\"most\"|\"many\"|\"few\"|\"exists\"|\"none\"|\"more_than\"|\"less_than\"|null,\n \"open_area_impact_qual_num\": int|null,\n \"hits_confirmed\": int|null,\n \"casualties\": int|null,\n \"injuries\": int|null,\n \"eta_refined_minutes\": int|null,\n \"confidence\": float\n}\n\nRules:\n- If unrelated to the alert region, set region_relevance=0 and all data fields to null.\n- If message is speculative/unconfirmed rumor, set source_trust < 0.4.\n- If message uses excessive caps, exclamation marks, panic language → tone=\"alarmist\".\n- Only extract concrete numbers explicitly stated in the text. Never guess.\n- *_qual fields: use ONLY when NO exact count is given. If exact number present, set *_qual=null.\n- \"none\" qual is only valid if explicitly stated (e.g., \"все перехвачены\", \"не упало в море\").\n- For IDF (@idf_telegram) posts about ongoing operations (not this specific attack) → time_relevance=0.\n- LANGUAGE NEUTRALITY: Posts may be in Hebrew, Russian, Arabic, or English. The language of the post\n MUST NOT affect source_trust or confidence. Russian-language Israeli channels are equally reliable\n and often break news faster than Hebrew ones. Judge ONLY by factual content and tone.\n- TRUST INTERCEPTION & IMPACT REPORTS: When a channel explicitly states interception results\n (e.g., \"перехвачены\", \"intercepted\", \"יירוט\", \"упали в море\", \"fell in the sea\", \"נפלו בים\",\n \"open area impact\", \"שטח פתוח\"), trust these claims with source_trust >= 0.7 and confidence >= 0.7.\n Israeli Telegram channels often report interception results before official confirmation,\n and these reports are typically accurate. Do NOT downgrade these just because they lack official source.";
105
- readonly getPhaseInstructions: typeof getPhaseInstructions;
106
- readonly SKIP: 0.6;
107
- readonly UNCERTAIN: 0.75;
108
- readonly CERTAIN: 0.95;
109
- };
110
- export {};
111
27
  //# sourceMappingURL=graph.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../../src/agent/graph.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAGH,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAM/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAS9C,OAAO,KAAK,EACV,SAAS,EACT,WAAW,EACX,cAAc,EAEd,UAAU,EAEV,mBAAmB,EACnB,WAAW,EACZ,MAAM,YAAY,CAAC;AAKpB,QAAA,MAAM,UAAU;;;;;;;;;;;;;IAad,sEAAsE;;IAEtE,kDAAkD;;IAElD,2DAA2D;;IAE3D,4BAA4B;;EAE5B,CAAC;AAEH,KAAK,cAAc,GAAG,OAAO,UAAU,CAAC,KAAK,CAAC;AAI9C,iBAAS,MAAM,IAAI,UAAU,CAc5B;AAID,iBAAS,mBAAmB,IAAI,MAAM,EAAE,CAiCvC;AAsDD,4CAA4C;AAC5C,iBAAS,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAMxC;AAED,8BAA8B;AAC9B,iBAAS,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEtC;AAmID,6CAA6C;AAC7C,iBAAS,oBAAoB,CAAC,SAAS,EAAE,SAAS,GAAG,MAAM,CAmB1D;AAkPD,iBAAS,UAAU,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,CAqDlE;AAMD,iBAAS,IAAI,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,CAiP5D;AAiBD,sDAAsD;AACtD,iBAAS,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,YAAY,EAAE,WAAW,EAAE,GAAG,MAAM,CAS3E;AAED,6CAA6C;AAC7C,iBAAS,YAAY,CACnB,OAAO,EAAE,MAAM,EAAE,EACjB,YAAY,EAAE,WAAW,EAAE,GAC1B,UAAU,EAAE,CASd;AAED,yEAAyE;AACzE,iBAAS,mBAAmB,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,MAAM,CAKxD;AA0CD;;;GAGG;AACH,iBAAS,uBAAuB,CAC9B,CAAC,EAAE,WAAW,EACd,IAAI,EAAE,cAAc,EACpB,SAAS,EAAE,SAAS,EACpB,OAAO,EAAE,MAAM,GACd,cAAc,CAqGhB;AAED;;;GAGG;AACH,iBAAS,oBAAoB,CAC3B,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,SAAS,EACpB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,cAAc,GACzB,MAAM,CAyGR;AAED;;GAEG;AACH,iBAAS,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAUhE;AA2SD,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,SAAS,CAAC;IACrB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,wBAAsB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAwB5E;AAID,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;;;;;;;CAqBR,CAAC"}
1
+ {"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../../src/agent/graph.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAqBH,OAAO,KAAK,EACV,SAAS,EAMV,MAAM,YAAY,CAAC;AA8PpB,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,SAAS,CAAC;IACrB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,wBAAsB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmB5E"}