easyoref 1.18.5 → 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.
Files changed (86) hide show
  1. package/dist/agent/extract.d.ts +5 -5
  2. package/dist/agent/extract.d.ts.map +1 -1
  3. package/dist/agent/extract.js +86 -129
  4. package/dist/agent/extract.js.map +1 -1
  5. package/dist/agent/types.d.ts +6 -217
  6. package/dist/agent/types.d.ts.map +1 -1
  7. package/dist/agent/types.js +3 -32
  8. package/dist/agent/types.js.map +1 -1
  9. package/dist/bot.d.ts +1 -1
  10. package/dist/bot.js +39 -42
  11. package/dist/bot.js.map +1 -1
  12. package/dist/gif-state.js +1 -1
  13. package/dist/gif-state.js.map +1 -1
  14. package/dist/init.js +1 -1
  15. package/dist/init.js.map +1 -1
  16. package/package.json +5 -9
  17. package/dist/agent/auth.d.ts +0 -11
  18. package/dist/agent/auth.d.ts.map +0 -1
  19. package/dist/agent/auth.js +0 -54
  20. package/dist/agent/auth.js.map +0 -1
  21. package/dist/agent/clarify.d.ts +0 -44
  22. package/dist/agent/clarify.d.ts.map +0 -1
  23. package/dist/agent/clarify.js +0 -285
  24. package/dist/agent/clarify.js.map +0 -1
  25. package/dist/agent/dry-run.d.ts +0 -12
  26. package/dist/agent/dry-run.d.ts.map +0 -1
  27. package/dist/agent/dry-run.js +0 -236
  28. package/dist/agent/dry-run.js.map +0 -1
  29. package/dist/agent/filters.d.ts +0 -48
  30. package/dist/agent/filters.d.ts.map +0 -1
  31. package/dist/agent/filters.js +0 -124
  32. package/dist/agent/filters.js.map +0 -1
  33. package/dist/agent/gramjs-monitor.d.ts +0 -26
  34. package/dist/agent/gramjs-monitor.d.ts.map +0 -1
  35. package/dist/agent/gramjs-monitor.js +0 -325
  36. package/dist/agent/gramjs-monitor.js.map +0 -1
  37. package/dist/agent/graph.d.ts +0 -30
  38. package/dist/agent/graph.d.ts.map +0 -1
  39. package/dist/agent/graph.js +0 -240
  40. package/dist/agent/graph.js.map +0 -1
  41. package/dist/agent/helpers.d.ts +0 -6
  42. package/dist/agent/helpers.d.ts.map +0 -1
  43. package/dist/agent/helpers.js +0 -15
  44. package/dist/agent/helpers.js.map +0 -1
  45. package/dist/agent/message.d.ts +0 -69
  46. package/dist/agent/message.d.ts.map +0 -1
  47. package/dist/agent/message.js +0 -479
  48. package/dist/agent/message.js.map +0 -1
  49. package/dist/agent/queue.d.ts +0 -15
  50. package/dist/agent/queue.d.ts.map +0 -1
  51. package/dist/agent/queue.js +0 -41
  52. package/dist/agent/queue.js.map +0 -1
  53. package/dist/agent/redis.d.ts +0 -8
  54. package/dist/agent/redis.d.ts.map +0 -1
  55. package/dist/agent/redis.js +0 -33
  56. package/dist/agent/redis.js.map +0 -1
  57. package/dist/agent/store.d.ts +0 -93
  58. package/dist/agent/store.d.ts.map +0 -1
  59. package/dist/agent/store.js +0 -145
  60. package/dist/agent/store.js.map +0 -1
  61. package/dist/agent/tools.d.ts +0 -159
  62. package/dist/agent/tools.d.ts.map +0 -1
  63. package/dist/agent/tools.js +0 -439
  64. package/dist/agent/tools.js.map +0 -1
  65. package/dist/agent/vote.d.ts +0 -13
  66. package/dist/agent/vote.d.ts.map +0 -1
  67. package/dist/agent/vote.js +0 -246
  68. package/dist/agent/vote.js.map +0 -1
  69. package/dist/agent/worker.d.ts +0 -14
  70. package/dist/agent/worker.d.ts.map +0 -1
  71. package/dist/agent/worker.js +0 -137
  72. package/dist/agent/worker.js.map +0 -1
  73. package/dist/config.d.ts +0 -129
  74. package/dist/config.d.ts.map +0 -1
  75. package/dist/config.js +0 -157
  76. package/dist/config.js.map +0 -1
  77. package/dist/i18n.d.ts +0 -49
  78. package/dist/i18n.d.ts.map +0 -1
  79. package/dist/i18n.js +0 -229
  80. package/dist/i18n.js.map +0 -1
  81. package/dist/logger.d.ts +0 -14
  82. package/dist/logger.d.ts.map +0 -1
  83. package/dist/logger.js +0 -45
  84. package/dist/logger.js.map +0 -1
  85. package/dist/service.js +0 -165
  86. package/dist/service.js.map +0 -1
@@ -5,8 +5,8 @@
5
5
  * 2. Expensive model: per-post — "extract structured data"
6
6
  * 3. Post-filter: deterministic validation on extraction results.
7
7
  */
8
+ import type { AlertType, ChannelTracking, EnrichmentData, TrackedMessage, ValidatedExtraction } from "@easyoref/shared";
8
9
  import { ChatOpenAI } from "@langchain/openai";
9
- import type { AlertType, ChannelTracking, TrackedMessage, ValidatedExtraction } from "./types.js";
10
10
  /** Cheap model for channel pre-filtering (single call, short output) */
11
11
  export declare function getFilterLLM(): ChatOpenAI;
12
12
  /** Expensive model for structured data extraction (per-post) */
@@ -17,8 +17,8 @@ export declare function getExtractLLM(): ChatOpenAI;
17
17
  */
18
18
  export declare function filterChannelsCheap(tracking: ChannelTracking, alertAreas: string[], alertTs: number, alertType: AlertType): Promise<string[]>;
19
19
  /** Phase-specific extraction instructions */
20
- export declare function getPhaseInstructions(alertType: AlertType): string;
21
- export declare const EXTRACT_SYSTEM_PROMPT = "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 \u2014 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 \u2192 time_relevance=0\n- If post is generic military news not specific to this attack \u2192 time_relevance=0.2\n- If post discusses the current attack \u2192 time_relevance=1.0\n- If uncertain \u2192 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\u20131: does this message discuss the specified alert region?\n \"source_trust\": float, // 0\u20131: factual reporting (1.0) vs unverified rumors/panic (0.0)\n \"tone\": \"calm\"|\"neutral\"|\"alarmist\",\n \"time_relevance\": float, // 0\u20131: 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 \"hit_location\": string|null,\n \"hit_type\": \"direct\"|\"shrapnel\"|null,\n \"hit_detail\": string|null,\n \"casualties\": int|null,\n \"injuries\": int|null,\n \"injuries_cause\": \"rocket\"|\"rushing_to_shelter\"|null,\n \"eta_refined_minutes\": int|null,\n \"rocket_detail\": string|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 \u2192 tone=\"alarmist\".\n- Only extract concrete numbers explicitly stated in the text. Never guess.\n- NEVER invent specific interception numbers. If source says \"all intercepted\" without a count, use intercepted=null, intercepted_qual=\"all\". If source says \"no impacts\" without specifying interceptions, set hits_confirmed=0 and intercepted=null.\n- rocket_detail: If the source splits rocket count by region (e.g. \"2 to the center, 3 to the north\"), put the regional breakdown in rocket_detail and the TOTAL in rocket_count. If no regional split, set rocket_detail=null.\n- hit_location: If hits_confirmed > 0, prefer SPECIFIC city/town names over macro-regions (e.g. \"\u0420\u0430\u043C\u043B\u0435\" > \"\u0426\u0435\u043D\u0442\u0440\", \"\u0420\u0438\u0448\u043E\u043D-\u043B\u0435-\u0426\u0438\u043E\u043D\" > \"\u0413\u0443\u0448-\u0414\u0430\u043D\"). Use macro-region ONLY if no specific city is mentioned. null if unknown or hits_confirmed == 0.\n- hit_type: \"direct\" (direct hit on structure/infrastructure) | \"shrapnel\" (debris/fragments/shrapnel). null if unknown or hits_confirmed == 0.\n- hit_detail: If hits_confirmed > 0, describe WHERE/HOW the impact occurred. Examples: \"\u043D\u0430 \u043E\u0442\u043A\u0440\u044B\u0442\u043E\u0439 \u043C\u0435\u0441\u0442\u043D\u043E\u0441\u0442\u0438\" (open area), \"\u0437\u0434\u0430\u043D\u0438\u0435\" (building), \"\u0432 \u043C\u043E\u0440\u0435\" (sea), \"\u0431\u0435\u0437 \u0440\u0430\u0437\u0440\u0443\u0448\u0435\u043D\u0438\u0439\" (no damage). Must be written in UI language. Translate appropriately: \"\u05E9\u05D8\u05D7 \u05E4\u05EA\u05D5\u05D7\" \u2192 \"\u043D\u0430 \u043E\u0442\u043A\u0440\u044B\u0442\u043E\u0439 \u043C\u0435\u0441\u0442\u043D\u043E\u0441\u0442\u0438\", \"\u05E0\u05E4\u05D9\u05DC\u05D4 \u05D1\u05E9\u05D8\u05D7 \u05E4\u05EA\u05D5\u05D7\" \u2192 \"\u043D\u0430 \u043E\u0442\u043A\u0440\u044B\u0442\u043E\u0439 \u043C\u0435\u0441\u0442\u043D\u043E\u0441\u0442\u0438\". null if unknown or hits_confirmed == 0.\n- LANGUAGE: rocket_detail, hit_location, hit_detail MUST be written in the UI language (see context header). Translate from Hebrew/Arabic/English as needed. Do NOT output verbatim Hebrew if UI language is Russian, etc.\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., \"\u0432\u0441\u0435 \u043F\u0435\u0440\u0435\u0445\u0432\u0430\u0447\u0435\u043D\u044B\", \"\u043D\u0435 \u0443\u043F\u0430\u043B\u043E \u0432 \u043C\u043E\u0440\u0435\").\n- For IDF (@idf_telegram) posts about ongoing operations (not this specific attack) \u2192 time_relevance=0.\n- CASUALTIES \u2014 HIGHEST THRESHOLD: Only set casualties > 0 if the source text EXPLICITLY uses words\n meaning \"killed\", \"dead\", \"died\", \"fatality\" (Hebrew: \u05E0\u05D4\u05E8\u05D2/\u05DE\u05EA/\u05E7\u05D8\u05DC; Russian: \u043F\u043E\u0433\u0438\u0431/\u0443\u0431\u0438\u0442/\u0441\u043C\u0435\u0440\u0442\u044C;\n English: killed/dead/died/fatality). NEVER infer deaths from \"serious injury\", \"critical condition\",\n or \"suspected\". If you are not 100% certain the word is in the source, set casualties=null.\n confidence for casualties MUST be >= 0.95 or set to null.\n- INJURY RETRACTIONS: If a source explicitly states \"no injured\", \"false report of injury\",\n \"\u043B\u043E\u0436\u043D\u043E\u0435 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435 \u043E \u0440\u0430\u043D\u0435\u043D\u043E\u043C\", \"\u05D0\u05D9\u05DF \u05E4\u05E6\u05D5\u05E2\u05D9\u05DD\", set injuries=0 with high confidence (>= 0.8).\n This overrides earlier injury reports.- INJURIES CAUSE: injuries_cause distinguishes:\n - \"rocket\" = injured by rocket fragment, blast, or structural damage from impact\n - \"rushing_to_shelter\" = injured while running to shelter (fell, stampede, heart attack, panic)\n - null = unknown or no injuries. ALWAYS set this when injuries > 0.- GEO-RELEVANCE FOR HITS: hits_confirmed, hit_location, hit_detail and hit_type must refer to\n the CONFIGURED ALERT ZONE only. If the source describes damage/debris in a DIFFERENT city\n or area (e.g., Rishon LeZion when the zone is Tel Aviv South), set hit_location to that city\n name with a note, set region_relevance proportionally lower, and describe the actual location\n in hit_detail. Do NOT report hits as \"confirmed\" in the alert zone if the source says a\n different city. If the damage is in a nearby but different city (~10-30km), report it in\n hit_detail as \"<city> (~X\u043A\u043C)\".\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., \"\u043F\u0435\u0440\u0435\u0445\u0432\u0430\u0447\u0435\u043D\u044B\", \"intercepted\", \"\u05D9\u05D9\u05E8\u05D5\u05D8\", \"\u0443\u043F\u0430\u043B\u0438 \u0432 \u043C\u043E\u0440\u0435\", \"fell in the sea\", \"\u05E0\u05E4\u05DC\u05D5 \u05D1\u05D9\u05DD\",\n \"open area impact\", \"\u05E9\u05D8\u05D7 \u05E4\u05EA\u05D5\u05D7\"), 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.\n- EXISTING ENRICHMENT CROSS-REFERENCE: If the context includes \"EXISTING ENRICHMENT\", previous phases\n already established facts with high confidence. Cross-reference against them:\n - If this post discusses a DIFFERENT country_origin than what\u2019s established, be skeptical.\n Security officials summarizing past operations or different events should get time_relevance=0.\n - Only override existing enrichment if this post has DIRECT, specific information about the current attack.\n - General security news that appeared right after a siren but doesn't mention THIS specific attack = time_relevance=0.\n- OFFICIAL PHASE ANNOUNCEMENTS \u2260 INCIDENT DATA: Messages from IDF / Home Front Command (Pikud HaOref)\n that announce alert phases \u2014 \"siren issued\", \"alert in effect\", \"can leave the shelter\", \"all clear\" \u2014\n are ADMINISTRATIVE NOTICES. They say nothing about rocket count, country of origin, interceptions,\n hits, casualties, or damage. Extract NO data fields from these messages. Set time_relevance=0 and\n all data fields to null.";
20
+ export declare function getPhaseInstructions(alertType: AlertType): string | undefined;
21
+ export declare const EXTRACT_SYSTEM_PROMPT = "You analyze Telegram channel messages about a missile/rocket attack on Israel.\nExtract structured data from the message and return ONLY valid JSON (no markdown).\nAll field definitions and type info are in your ExtractionResultSchema.\n\nCRITICAL \u2014 TIME VALIDATION:\n- If post discusses events BEFORE alert time \u2192 timeRelevance=0\n- If post is generic military news not specific to THIS attack \u2192 timeRelevance=0.2\n- If post discusses current attack \u2192 timeRelevance=1.0\n- If uncertain \u2192 timeRelevance=0.5\n\nMANDATORY METADATA (ALWAYS INCLUDE):\n- timeRelevance, regionRelevance, confidence, sourceTrust, tone.\n- These fields MUST always be present in the JSON. Never omit them.\n- Use numbers (0.0 to 1.0) for relevance/confidence/trust and strings for tone.\n\nPHASE-SPECIFIC CONSTRAINTS:\n- If unrelated to the alert region, set regionRelevance=0 and all data fields to null.\n- If message is speculative/unconfirmed rumor, set sourceTrust < 0.4.\n- If message uses excessive caps, exclamation marks, panic language \u2192 tone=\"alarmist\".\n- Only extract concrete numbers explicitly stated in the text. Never guess.\n- NEVER invent specific interception numbers. If source says \"all intercepted\" without a count, use intercepted=null, interceptedQual=\"all\". If source says \"no impacts\" without specifying interceptions, set hitsConfirmed=0 and intercepted=null.\n- rocketDetail: If the source splits rocket count by region (e.g. \"2 to the center, 3 to the north\"), put the regional breakdown in rocketDetail and the TOTAL in rocketCount. If no regional split, set rocketDetail=null.\n- hit_location: If hitsConfirmed > 0, prefer SPECIFIC city/town names over macro-regions (e.g. \"\u0420\u0430\u043C\u043B\u0435\" > \"\u0426\u0435\u043D\u0442\u0440\", \"\u0420\u0438\u0448\u043E\u043D-\u043B\u0435-\u0426\u0438\u043E\u043D\" > \"\u0413\u0443\u0448-\u0414\u0430\u043D\"). Use macro-region ONLY if no specific city is mentioned. null if unknown or hitsConfirmed == 0.\n- hit_type: \"direct\" (direct hit on structure/infrastructure) | \"shrapnel\" (debris/fragments/shrapnel). null if unknown or hitsConfirmed == 0.\n- hit_detail: If hitsConfirmed > 0, describe WHERE/HOW the impact occurred. Examples: \"\u043D\u0430 \u043E\u0442\u043A\u0440\u044B\u0442\u043E\u0439 \u043C\u0435\u0441\u0442\u043D\u043E\u0441\u0442\u0438\" (open area), \"\u0437\u0434\u0430\u043D\u0438\u0435\" (building), \"\u0432 \u043C\u043E\u0440\u0435\" (sea), \"\u0431\u0435\u0437 \u0440\u0430\u0437\u0440\u0443\u0448\u0435\u043D\u0438\u0439\" (no damage). Must be written in UI language. Translate appropriately: \"\u05E9\u05D8\u05D7 \u05E4\u05EA\u05D5\u05D7\" \u2192 \"\u043D\u0430 \u043E\u0442\u043A\u0440\u044B\u0442\u043E\u0439 \u043C\u0435\u0441\u0442\u043D\u043E\u0441\u0442\u0438\", \"\u05E0\u05E4\u05D9\u05DC\u05D4 \u05D1\u05E9\u05D8\u05D7 \u05E4\u05EA\u05D5\u05D7\" \u2192 \"\u043D\u0430 \u043E\u0442\u043A\u0440\u044B\u0442\u043E\u0439 \u043C\u0435\u0441\u0442\u043D\u043E\u0441\u0442\u0438\". null if unknown or hitsConfirmed == 0.\n- LANGUAGE: rocketDetail, hit_location, hit_detail MUST be written in the UI language (see context header). Translate from Hebrew/Arabic/English as needed. Do NOT output verbatim Hebrew if UI language is Russian, etc.\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., \"\u0432\u0441\u0435 \u043F\u0435\u0440\u0435\u0445\u0432\u0430\u0447\u0435\u043D\u044B\", \"\u043D\u0435 \u0443\u043F\u0430\u043B\u043E \u0432 \u043C\u043E\u0440\u0435\").\n- For IDF (@idf_telegram) posts about ongoing operations (not this specific attack) \u2192 timeRelevance=0.\n- CASUALTIES \u2014 HIGHEST THRESHOLD: Only set casualties > 0 if the source text EXPLICITLY uses words\n meaning \"killed\", \"dead\", \"died\", \"fatality\" (Hebrew: \u05E0\u05D4\u05E8\u05D2/\u05DE\u05EA/\u05E7\u05D8\u05DC; Russian: \u043F\u043E\u0433\u0438\u0431/\u0443\u0431\u0438\u0442/\u0441\u043C\u0435\u0440\u0442\u044C;\n English: killed/dead/died/fatality). NEVER infer deaths from \"serious injury\", \"critical condition\",\n or \"suspected\". If you are not 100% certain the word is in the source, set casualties=null.\n confidence for casualties MUST be >= 0.95 or set to null.\n- INJURY RETRACTIONS: If a source explicitly states \"no injured\", \"false report of injury\",\n \"\u043B\u043E\u0436\u043D\u043E\u0435 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435 \u043E \u0440\u0430\u043D\u0435\u043D\u043E\u043C\", \"\u05D0\u05D9\u05DF \u05E4\u05E6\u05D5\u05E2\u05D9\u05DD\", set injuries=0 with high confidence (>= 0.8).\n This overrides earlier injury reports.\n- INJURIES CAUSE: injuries_cause distinguishes:\n - \"rocket\" = injured by rocket fragment, blast, or structural damage from impact\n - \"rushing_to_shelter\" = injured while running to shelter (fell, stampede, heart attack, panic)\n - null = unknown or no injuries. ALWAYS set this when injuries > 0.\n- GEO-RELEVANCE FOR HITS: hitsConfirmed, hit_location, hit_detail and hit_type must refer to\n the CONFIGURED ALERT ZONE only. If the source describes damage/debris in a DIFFERENT city\n or area (e.g., Rishon LeZion when the zone is Tel Aviv South), set hit_location to that city\n name with a note, set regionRelevance proportionally lower, and describe the actual location\n in hit_detail. Do NOT report hits as \"confirmed\" in the alert zone if the source says a\n different city. If the damage is in a nearby but different city (~10-30km), report it in\n hit_detail as \"<city> (~X\u043A\u043C)\".\n- LANGUAGE NEUTRALITY: Posts may be in Hebrew, Russian, Arabic, or English. The language of the post\n MUST NOT affect sourceTrust 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., \"\u043F\u0435\u0440\u0435\u0445\u0432\u0430\u0447\u0435\u043D\u044B\", \"intercepted\", \"\u05D9\u05D9\u05E8\u05D5\u05D8\", \"\u0443\u043F\u0430\u043B\u0438 \u0432 \u043C\u043E\u0440\u0435\", \"fell in the sea\", \"\u05E0\u05E4\u05DC\u05D5 \u05D1\u05D9\u05DD\",\n \"open area impact\", \"\u05E9\u05D8\u05D7 \u05E4\u05EA\u05D5\u05D7\"), trust these claims with sourceTrust >= 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.\n- EXISTING ENRICHMENT CROSS-REFERENCE: If the context includes \"EXISTING ENRICHMENT\", previous phases\n already established facts with high confidence. Cross-reference against them:\n - If this post discusses a DIFFERENT countryOrigin than what\u2019s established, be skeptical.\n Security officials summarizing past operations or different events should get timeRelevance=0.\n - Only override existing enrichment if this post has DIRECT, specific information about the current attack.\n - General security news that appeared right after a siren but doesn't mention THIS specific attack = timeRelevance=0.\n- OFFICIAL PHASE ANNOUNCEMENTS \u2260 INCIDENT DATA: Messages from IDF / Home Front Command (Pikud HaOref)\n that announce alert phases \u2014 \"siren issued\", \"alert in effect\", \"can leave the shelter\", \"all clear\" \u2014\n are ADMINISTRATIVE NOTICES. They say nothing about rocket count, country of origin, interceptions,\n hits, casualties, or damage. Extract NO data fields from these messages. Set timeRelevance=0 and\n all data fields to null.";
22
22
  export interface ExtractContext {
23
23
  alertTs: number;
24
24
  alertType: AlertType;
@@ -26,7 +26,7 @@ export interface ExtractContext {
26
26
  alertId: string;
27
27
  language: string;
28
28
  /** Existing enrichment from earlier phases — for cross-reference */
29
- existingEnrichment?: import("./types.js").EnrichmentData;
29
+ existingEnrichment?: EnrichmentData;
30
30
  }
31
31
  /**
32
32
  * Extract structured data from posts using expensive LLM.
@@ -43,7 +43,7 @@ export declare const _test: {
43
43
  readonly getFilterLLM: typeof getFilterLLM;
44
44
  readonly getExtractLLM: typeof getExtractLLM;
45
45
  readonly getPhaseInstructions: typeof getPhaseInstructions;
46
- readonly EXTRACT_SYSTEM_PROMPT: "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 \"hit_location\": string|null,\n \"hit_type\": \"direct\"|\"shrapnel\"|null,\n \"hit_detail\": string|null,\n \"casualties\": int|null,\n \"injuries\": int|null,\n \"injuries_cause\": \"rocket\"|\"rushing_to_shelter\"|null,\n \"eta_refined_minutes\": int|null,\n \"rocket_detail\": string|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- NEVER invent specific interception numbers. If source says \"all intercepted\" without a count, use intercepted=null, intercepted_qual=\"all\". If source says \"no impacts\" without specifying interceptions, set hits_confirmed=0 and intercepted=null.\n- rocket_detail: If the source splits rocket count by region (e.g. \"2 to the center, 3 to the north\"), put the regional breakdown in rocket_detail and the TOTAL in rocket_count. If no regional split, set rocket_detail=null.\n- hit_location: If hits_confirmed > 0, prefer SPECIFIC city/town names over macro-regions (e.g. \"Рамле\" > \"Центр\", \"Ришон-ле-Цион\" > \"Гуш-Дан\"). Use macro-region ONLY if no specific city is mentioned. null if unknown or hits_confirmed == 0.\n- hit_type: \"direct\" (direct hit on structure/infrastructure) | \"shrapnel\" (debris/fragments/shrapnel). null if unknown or hits_confirmed == 0.\n- hit_detail: If hits_confirmed > 0, describe WHERE/HOW the impact occurred. Examples: \"на открытой местности\" (open area), \"здание\" (building), \"в море\" (sea), \"без разрушений\" (no damage). Must be written in UI language. Translate appropriately: \"שטח פתוח\" → \"на открытой местности\", \"נפילה בשטח פתוח\" → \"на открытой местности\". null if unknown or hits_confirmed == 0.\n- LANGUAGE: rocket_detail, hit_location, hit_detail MUST be written in the UI language (see context header). Translate from Hebrew/Arabic/English as needed. Do NOT output verbatim Hebrew if UI language is Russian, etc.\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- CASUALTIES — HIGHEST THRESHOLD: Only set casualties > 0 if the source text EXPLICITLY uses words\n meaning \"killed\", \"dead\", \"died\", \"fatality\" (Hebrew: נהרג/מת/קטל; Russian: погиб/убит/смерть;\n English: killed/dead/died/fatality). NEVER infer deaths from \"serious injury\", \"critical condition\",\n or \"suspected\". If you are not 100% certain the word is in the source, set casualties=null.\n confidence for casualties MUST be >= 0.95 or set to null.\n- INJURY RETRACTIONS: If a source explicitly states \"no injured\", \"false report of injury\",\n \"ложное сообщение о раненом\", \"אין פצועים\", set injuries=0 with high confidence (>= 0.8).\n This overrides earlier injury reports.- INJURIES CAUSE: injuries_cause distinguishes:\n - \"rocket\" = injured by rocket fragment, blast, or structural damage from impact\n - \"rushing_to_shelter\" = injured while running to shelter (fell, stampede, heart attack, panic)\n - null = unknown or no injuries. ALWAYS set this when injuries > 0.- GEO-RELEVANCE FOR HITS: hits_confirmed, hit_location, hit_detail and hit_type must refer to\n the CONFIGURED ALERT ZONE only. If the source describes damage/debris in a DIFFERENT city\n or area (e.g., Rishon LeZion when the zone is Tel Aviv South), set hit_location to that city\n name with a note, set region_relevance proportionally lower, and describe the actual location\n in hit_detail. Do NOT report hits as \"confirmed\" in the alert zone if the source says a\n different city. If the damage is in a nearby but different city (~10-30km), report it in\n hit_detail as \"<city> (~Xкм)\".\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.\n- EXISTING ENRICHMENT CROSS-REFERENCE: If the context includes \"EXISTING ENRICHMENT\", previous phases\n already established facts with high confidence. Cross-reference against them:\n - If this post discusses a DIFFERENT country_origin than what’s established, be skeptical.\n Security officials summarizing past operations or different events should get time_relevance=0.\n - Only override existing enrichment if this post has DIRECT, specific information about the current attack.\n - General security news that appeared right after a siren but doesn't mention THIS specific attack = time_relevance=0.\n- OFFICIAL PHASE ANNOUNCEMENTS ≠ INCIDENT DATA: Messages from IDF / Home Front Command (Pikud HaOref)\n that announce alert phases — \"siren issued\", \"alert in effect\", \"can leave the shelter\", \"all clear\" —\n are ADMINISTRATIVE NOTICES. They say nothing about rocket count, country of origin, interceptions,\n hits, casualties, or damage. Extract NO data fields from these messages. Set time_relevance=0 and\n all data fields to null.";
46
+ readonly EXTRACT_SYSTEM_PROMPT: "You analyze Telegram channel messages about a missile/rocket attack on Israel.\nExtract structured data from the message and return ONLY valid JSON (no markdown).\nAll field definitions and type info are in your ExtractionResultSchema.\n\nCRITICAL TIME VALIDATION:\n- If post discusses events BEFORE alert time → timeRelevance=0\n- If post is generic military news not specific to THIS attack → timeRelevance=0.2\n- If post discusses current attack → timeRelevance=1.0\n- If uncertain → timeRelevance=0.5\n\nMANDATORY METADATA (ALWAYS INCLUDE):\n- timeRelevance, regionRelevance, confidence, sourceTrust, tone.\n- These fields MUST always be present in the JSON. Never omit them.\n- Use numbers (0.0 to 1.0) for relevance/confidence/trust and strings for tone.\n\nPHASE-SPECIFIC CONSTRAINTS:\n- If unrelated to the alert region, set regionRelevance=0 and all data fields to null.\n- If message is speculative/unconfirmed rumor, set sourceTrust < 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- NEVER invent specific interception numbers. If source says \"all intercepted\" without a count, use intercepted=null, interceptedQual=\"all\". If source says \"no impacts\" without specifying interceptions, set hitsConfirmed=0 and intercepted=null.\n- rocketDetail: If the source splits rocket count by region (e.g. \"2 to the center, 3 to the north\"), put the regional breakdown in rocketDetail and the TOTAL in rocketCount. If no regional split, set rocketDetail=null.\n- hit_location: If hitsConfirmed > 0, prefer SPECIFIC city/town names over macro-regions (e.g. \"Рамле\" > \"Центр\", \"Ришон-ле-Цион\" > \"Гуш-Дан\"). Use macro-region ONLY if no specific city is mentioned. null if unknown or hitsConfirmed == 0.\n- hit_type: \"direct\" (direct hit on structure/infrastructure) | \"shrapnel\" (debris/fragments/shrapnel). null if unknown or hitsConfirmed == 0.\n- hit_detail: If hitsConfirmed > 0, describe WHERE/HOW the impact occurred. Examples: \"на открытой местности\" (open area), \"здание\" (building), \"в море\" (sea), \"без разрушений\" (no damage). Must be written in UI language. Translate appropriately: \"שטח פתוח\" → \"на открытой местности\", \"נפילה בשטח פתוח\" → \"на открытой местности\". null if unknown or hitsConfirmed == 0.\n- LANGUAGE: rocketDetail, hit_location, hit_detail MUST be written in the UI language (see context header). Translate from Hebrew/Arabic/English as needed. Do NOT output verbatim Hebrew if UI language is Russian, etc.\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) → timeRelevance=0.\n- CASUALTIES — HIGHEST THRESHOLD: Only set casualties > 0 if the source text EXPLICITLY uses words\n meaning \"killed\", \"dead\", \"died\", \"fatality\" (Hebrew: נהרג/מת/קטל; Russian: погиб/убит/смерть;\n English: killed/dead/died/fatality). NEVER infer deaths from \"serious injury\", \"critical condition\",\n or \"suspected\". If you are not 100% certain the word is in the source, set casualties=null.\n confidence for casualties MUST be >= 0.95 or set to null.\n- INJURY RETRACTIONS: If a source explicitly states \"no injured\", \"false report of injury\",\n \"ложное сообщение о раненом\", \"אין פצועים\", set injuries=0 with high confidence (>= 0.8).\n This overrides earlier injury reports.\n- INJURIES CAUSE: injuries_cause distinguishes:\n - \"rocket\" = injured by rocket fragment, blast, or structural damage from impact\n - \"rushing_to_shelter\" = injured while running to shelter (fell, stampede, heart attack, panic)\n - null = unknown or no injuries. ALWAYS set this when injuries > 0.\n- GEO-RELEVANCE FOR HITS: hitsConfirmed, hit_location, hit_detail and hit_type must refer to\n the CONFIGURED ALERT ZONE only. If the source describes damage/debris in a DIFFERENT city\n or area (e.g., Rishon LeZion when the zone is Tel Aviv South), set hit_location to that city\n name with a note, set regionRelevance proportionally lower, and describe the actual location\n in hit_detail. Do NOT report hits as \"confirmed\" in the alert zone if the source says a\n different city. If the damage is in a nearby but different city (~10-30km), report it in\n hit_detail as \"<city> (~Xкм)\".\n- LANGUAGE NEUTRALITY: Posts may be in Hebrew, Russian, Arabic, or English. The language of the post\n MUST NOT affect sourceTrust 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 sourceTrust >= 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.\n- EXISTING ENRICHMENT CROSS-REFERENCE: If the context includes \"EXISTING ENRICHMENT\", previous phases\n already established facts with high confidence. Cross-reference against them:\n - If this post discusses a DIFFERENT countryOrigin than what’s established, be skeptical.\n Security officials summarizing past operations or different events should get timeRelevance=0.\n - Only override existing enrichment if this post has DIRECT, specific information about the current attack.\n - General security news that appeared right after a siren but doesn't mention THIS specific attack = timeRelevance=0.\n- OFFICIAL PHASE ANNOUNCEMENTS ≠ INCIDENT DATA: Messages from IDF / Home Front Command (Pikud HaOref)\n that announce alert phases — \"siren issued\", \"alert in effect\", \"can leave the shelter\", \"all clear\" —\n are ADMINISTRATIVE NOTICES. They say nothing about rocket count, country of origin, interceptions,\n hits, casualties, or damage. Extract NO data fields from these messages. Set timeRelevance=0 and\n all data fields to null.";
47
47
  readonly FILTER_SYSTEM_PROMPT: "You pre-filter Telegram channels for an Israeli missile alert system.\nGiven channels with their latest messages, identify which contain IMPORTANT military intel:\n- Country of origin (where rockets/missiles launched from)\n- Impact location (where they hit)\n- Warhead type / cassette munitions\n- Weapon type (ballistic, cruise, drones)\n- Damage / destruction reports\n- Interception reports (Iron Dome, David's Sling)\n- Casualty / injury reports\n\nIGNORE channels that only contain:\n- Panic, speculation, or unverified rumors\n- Rehashes of official alerts without new data\n- General commentary without actionable facts\n\nReturn ONLY valid JSON (no markdown):\n{\"relevant_channels\": [\"@channel1\", \"@channel2\"]}\nIf NO channels have important intel, return: {\"relevant_channels\": []}";
48
48
  readonly postFilter: typeof postFilter;
49
49
  };
@@ -1 +1 @@
1
- {"version":3,"file":"extract.d.ts","sourceRoot":"","sources":["../../src/agent/extract.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAK/C,OAAO,KAAK,EACV,SAAS,EACT,eAAe,EAEf,cAAc,EACd,mBAAmB,EACpB,MAAM,YAAY,CAAC;AAIpB,wEAAwE;AACxE,wBAAgB,YAAY,IAAI,UAAU,CAczC;AAED,gEAAgE;AAChE,wBAAgB,aAAa,IAAI,UAAU,CAc1C;AAuBD;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,eAAe,EACzB,UAAU,EAAE,MAAM,EAAE,EACpB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,SAAS,GACnB,OAAO,CAAC,MAAM,EAAE,CAAC,CAkDnB;AAOD,6CAA6C;AAC7C,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,SAAS,GAAG,MAAM,CAmBjE;AAED,eAAO,MAAM,qBAAqB,25RA0FP,CAAC;AAE5B,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,SAAS,CAAC;IACrB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,oEAAoE;IACpE,kBAAkB,CAAC,EAAE,OAAO,YAAY,EAAE,cAAc,CAAC;CAC1D;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAChC,KAAK,EAAE,cAAc,EAAE,EACvB,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAmKhC;AAID;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,WAAW,EAAE,mBAAmB,EAAE,EAClC,OAAO,EAAE,MAAM,GACd,mBAAmB,EAAE,CA8DvB;AAID,eAAO,MAAM,KAAK;;;;;;;CAOR,CAAC"}
1
+ {"version":3,"file":"extract.d.ts","sourceRoot":"","sources":["../../src/agent/extract.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EACV,SAAS,EACT,eAAe,EACf,cAAc,EAEd,cAAc,EACd,mBAAmB,EACpB,MAAM,kBAAkB,CAAC;AAQ1B,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAI/C,wEAAwE;AACxE,wBAAgB,YAAY,IAAI,UAAU,CAczC;AAED,gEAAgE;AAChE,wBAAgB,aAAa,IAAI,UAAU,CAc1C;AAuBD;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,eAAe,EACzB,UAAU,EAAE,MAAM,EAAE,EACpB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,SAAS,GACnB,OAAO,CAAC,MAAM,EAAE,CAAC,CA0DnB;AAOD,6CAA6C;AAC7C,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,SAAS,GAAG,MAAM,GAAG,SAAS,CAmB7E;AAED,eAAO,MAAM,qBAAqB,6hPAkEP,CAAC;AAE5B,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,SAAS,CAAC;IACrB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,oEAAoE;IACpE,kBAAkB,CAAC,EAAE,cAAc,CAAC;CACrC;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAChC,KAAK,EAAE,cAAc,EAAE,EACvB,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAoJhC;AAID;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,WAAW,EAAE,mBAAmB,EAAE,EAClC,OAAO,EAAE,MAAM,GACd,mBAAmB,EAAE,CA8DvB;AAID,eAAO,MAAM,KAAK;;;;;;;CAOR,CAAC"}
@@ -5,11 +5,9 @@
5
5
  * 2. Expensive model: per-post — "extract structured data"
6
6
  * 3. Post-filter: deterministic validation on extraction results.
7
7
  */
8
+ import * as logger from "@easyoref/monitoring";
9
+ import { config, getCachedExtractions, saveCachedExtractions, textHash, toIsraelTime, } from "@easyoref/shared";
8
10
  import { ChatOpenAI } from "@langchain/openai";
9
- import { config } from "../config.js";
10
- import * as logger from "../logger.js";
11
- import { textHash, toIsraelTime } from "./helpers.js";
12
- import { getCachedExtractions, saveCachedExtractions } from "./store.js";
13
11
  // ── LLM instances ──────────────────────────────────────
14
12
  /** Cheap model for channel pre-filtering (single call, short output) */
15
13
  export function getFilterLLM() {
@@ -67,15 +65,15 @@ If NO channels have important intel, return: {"relevant_channels": []}`;
67
65
  * Returns channel names containing important military intel.
68
66
  */
69
67
  export async function filterChannelsCheap(tracking, alertAreas, alertTs, alertType) {
70
- const channels = tracking.channels_with_updates;
68
+ const channels = tracking.channelsWithUpdates;
71
69
  if (channels.length === 0)
72
70
  return [];
73
71
  const channelSummaries = channels
74
72
  .map((ch) => {
75
- const posts = ch.last_tracked_messages
73
+ const messages = ch.unprocessedMessages
76
74
  .map((m) => ` [${toIsraelTime(m.timestamp)}] ${m.text.slice(0, 200)}`)
77
75
  .join("\n");
78
- return `${ch.channel} (${ch.last_tracked_messages.length} new):\n${posts}`;
76
+ return `${ch.channel} (${ch.unprocessedMessages.length} new):\n${messages}`;
79
77
  })
80
78
  .join("\n\n");
81
79
  const regionHint = alertAreas.length > 0 ? alertAreas.join(", ") : "Israel";
@@ -115,75 +113,49 @@ export function getPhaseInstructions(alertType) {
115
113
  switch (alertType) {
116
114
  case "early_warning":
117
115
  return `PHASE: EARLY WARNING (radar detected launches, sirens not yet).
118
- Focus on: country_origin (WHERE were rockets launched from?), eta_refined_minutes, rocket_count, is_cassette.
119
- Do NOT extract: intercepted, sea_impact, open_area_impact, hits_confirmed, casualties, injuries — these are IMPOSSIBLE at this stage.
120
- If a message discusses interception results, it is about a PREVIOUS attack — set time_relevance=0.`;
121
- case "siren":
122
- return `PHASE: SIREN (rockets incoming, impact imminent).
123
- Focus on: country_origin (if not known yet), rocket_count, intercepted, sea_impact, open_area_impact, is_cassette.
124
- Do NOT extract: hits_confirmed, casualties, injuries — too early for confirmed damage reports.
116
+ Focus on: countryOrigin (WHERE were rockets launched from?), eta_refined_minutes, rocketCount, isCassette.
117
+ Do NOT extract: intercepted, seaImpact, open_area_impact, hitsConfirmed, casualties, injuries — these are IMPOSSIBLE at this stage.
118
+ If a message discusses interception results, it is about a PREVIOUS attack — set timeRelevance=0.`;
119
+ case "red_alert":
120
+ return `PHASE: RED ALERT (rockets incoming, impact imminent).
121
+ Focus on: countryOrigin (if not known yet), rocketCount, intercepted, seaImpact, open_area_impact, isCassette.
122
+ Do NOT extract: hitsConfirmed, casualties, injuries — too early for confirmed damage reports.
125
123
  If a message discusses casualties or confirmed hits, verify the timing carefully - it may be about a previous attack.`;
126
124
  case "resolved":
127
125
  return `PHASE: RESOLVED (incident over, assessing damage).
128
- Focus on: intercepted (final count), hits_confirmed, casualties, injuries, open_area_impact.
126
+ Focus on: countryOrigin, intercepted (final count), hitsConfirmed, casualties, injuries, open_area_impact.
129
127
  All fields are valid at this stage. Prioritize confirmed official reports.`;
130
128
  }
131
129
  }
132
130
  export const EXTRACT_SYSTEM_PROMPT = `You analyze Telegram channel messages about a missile/rocket attack on Israel.
133
- Your job: extract factual data, assess quality, AND validate temporal relevance.
131
+ Extract structured data from the message and return ONLY valid JSON (no markdown).
132
+ All field definitions and type info are in your ExtractionResultSchema.
134
133
 
135
134
  CRITICAL — TIME VALIDATION:
136
- You will receive the alert time and the post time. You MUST determine if this post
137
- is about the CURRENT attack or about a previous/different event.
138
- - If post discusses events clearly BEFORE the alert time time_relevance=0
139
- - If post is generic military news not specific to this attack time_relevance=0.2
140
- - If post discusses the current attack → time_relevance=1.0
141
- - If uncertain → time_relevance=0.5 (the system will use alert_history to verify)
135
+ - If post discusses events BEFORE alert time timeRelevance=0
136
+ - If post is generic military news not specific to THIS attack → timeRelevance=0.2
137
+ - If post discusses current attacktimeRelevance=1.0
138
+ - If uncertaintimeRelevance=0.5
142
139
 
143
- Return ONLY valid JSON (no markdown, no explanation):
144
- {
145
- "region_relevance": float, // 0–1: does this message discuss the specified alert region?
146
- "source_trust": float, // 0–1: factual reporting (1.0) vs unverified rumors/panic (0.0)
147
- "tone": "calm"|"neutral"|"alarmist",
148
- "time_relevance": float, // 0–1: is this post about the CURRENT attack? (see rules above)
149
- "country_origin": string|null, // "Iran","Yemen","Lebanon","Gaza","Iraq","Syria" or null
150
- "rocket_count": int|null,
151
- "is_cassette": bool|null,
152
- "intercepted": int|null,
153
- "intercepted_qual": ${QUAL_VALUES}|null,
154
- "intercepted_qual_num": int|null,
155
- "sea_impact": int|null,
156
- "sea_impact_qual": ${QUAL_VALUES}|null,
157
- "sea_impact_qual_num": int|null,
158
- "open_area_impact": int|null,
159
- "open_area_impact_qual": ${QUAL_VALUES}|null,
160
- "open_area_impact_qual_num": int|null,
161
- "hits_confirmed": int|null,
162
- "hit_location": string|null,
163
- "hit_type": "direct"|"shrapnel"|null,
164
- "hit_detail": string|null,
165
- "casualties": int|null,
166
- "injuries": int|null,
167
- "injuries_cause": "rocket"|"rushing_to_shelter"|null,
168
- "eta_refined_minutes": int|null,
169
- "rocket_detail": string|null,
170
- "confidence": float
171
- }
140
+ MANDATORY METADATA (ALWAYS INCLUDE):
141
+ - timeRelevance, regionRelevance, confidence, sourceTrust, tone.
142
+ - These fields MUST always be present in the JSON. Never omit them.
143
+ - Use numbers (0.0 to 1.0) for relevance/confidence/trust and strings for tone.
172
144
 
173
- Rules:
174
- - If unrelated to the alert region, set region_relevance=0 and all data fields to null.
175
- - If message is speculative/unconfirmed rumor, set source_trust < 0.4.
145
+ PHASE-SPECIFIC CONSTRAINTS:
146
+ - If unrelated to the alert region, set regionRelevance=0 and all data fields to null.
147
+ - If message is speculative/unconfirmed rumor, set sourceTrust < 0.4.
176
148
  - If message uses excessive caps, exclamation marks, panic language → tone="alarmist".
177
149
  - Only extract concrete numbers explicitly stated in the text. Never guess.
178
- - NEVER invent specific interception numbers. If source says "all intercepted" without a count, use intercepted=null, intercepted_qual="all". If source says "no impacts" without specifying interceptions, set hits_confirmed=0 and intercepted=null.
179
- - rocket_detail: If the source splits rocket count by region (e.g. "2 to the center, 3 to the north"), put the regional breakdown in rocket_detail and the TOTAL in rocket_count. If no regional split, set rocket_detail=null.
180
- - hit_location: If hits_confirmed > 0, prefer SPECIFIC city/town names over macro-regions (e.g. "Рамле" > "Центр", "Ришон-ле-Цион" > "Гуш-Дан"). Use macro-region ONLY if no specific city is mentioned. null if unknown or hits_confirmed == 0.
181
- - hit_type: "direct" (direct hit on structure/infrastructure) | "shrapnel" (debris/fragments/shrapnel). null if unknown or hits_confirmed == 0.
182
- - hit_detail: If hits_confirmed > 0, describe WHERE/HOW the impact occurred. Examples: "на открытой местности" (open area), "здание" (building), "в море" (sea), "без разрушений" (no damage). Must be written in UI language. Translate appropriately: "שטח פתוח" → "на открытой местности", "נפילה בשטח פתוח" → "на открытой местности". null if unknown or hits_confirmed == 0.
183
- - LANGUAGE: rocket_detail, hit_location, hit_detail MUST be written in the UI language (see context header). Translate from Hebrew/Arabic/English as needed. Do NOT output verbatim Hebrew if UI language is Russian, etc.
150
+ - NEVER invent specific interception numbers. If source says "all intercepted" without a count, use intercepted=null, interceptedQual="all". If source says "no impacts" without specifying interceptions, set hitsConfirmed=0 and intercepted=null.
151
+ - rocketDetail: If the source splits rocket count by region (e.g. "2 to the center, 3 to the north"), put the regional breakdown in rocketDetail and the TOTAL in rocketCount. If no regional split, set rocketDetail=null.
152
+ - hit_location: If hitsConfirmed > 0, prefer SPECIFIC city/town names over macro-regions (e.g. "Рамле" > "Центр", "Ришон-ле-Цион" > "Гуш-Дан"). Use macro-region ONLY if no specific city is mentioned. null if unknown or hitsConfirmed == 0.
153
+ - hit_type: "direct" (direct hit on structure/infrastructure) | "shrapnel" (debris/fragments/shrapnel). null if unknown or hitsConfirmed == 0.
154
+ - hit_detail: If hitsConfirmed > 0, describe WHERE/HOW the impact occurred. Examples: "на открытой местности" (open area), "здание" (building), "в море" (sea), "без разрушений" (no damage). Must be written in UI language. Translate appropriately: "שטח פתוח" → "на открытой местности", "נפילה בשטח פתוח" → "на открытой местности". null if unknown or hitsConfirmed == 0.
155
+ - LANGUAGE: rocketDetail, hit_location, hit_detail MUST be written in the UI language (see context header). Translate from Hebrew/Arabic/English as needed. Do NOT output verbatim Hebrew if UI language is Russian, etc.
184
156
  - *_qual fields: use ONLY when NO exact count is given. If exact number present, set *_qual=null.
185
157
  - "none" qual is only valid if explicitly stated (e.g., "все перехвачены", "не упало в море").
186
- - For IDF (@idf_telegram) posts about ongoing operations (not this specific attack) → time_relevance=0.
158
+ - For IDF (@idf_telegram) posts about ongoing operations (not this specific attack) → timeRelevance=0.
187
159
  - CASUALTIES — HIGHEST THRESHOLD: Only set casualties > 0 if the source text EXPLICITLY uses words
188
160
  meaning "killed", "dead", "died", "fatality" (Hebrew: נהרג/מת/קטל; Russian: погиб/убит/смерть;
189
161
  English: killed/dead/died/fatality). NEVER infer deaths from "serious injury", "critical condition",
@@ -191,34 +163,36 @@ Rules:
191
163
  confidence for casualties MUST be >= 0.95 or set to null.
192
164
  - INJURY RETRACTIONS: If a source explicitly states "no injured", "false report of injury",
193
165
  "ложное сообщение о раненом", "אין פצועים", set injuries=0 with high confidence (>= 0.8).
194
- This overrides earlier injury reports.- INJURIES CAUSE: injuries_cause distinguishes:
166
+ This overrides earlier injury reports.
167
+ - INJURIES CAUSE: injuries_cause distinguishes:
195
168
  - "rocket" = injured by rocket fragment, blast, or structural damage from impact
196
169
  - "rushing_to_shelter" = injured while running to shelter (fell, stampede, heart attack, panic)
197
- - null = unknown or no injuries. ALWAYS set this when injuries > 0.- GEO-RELEVANCE FOR HITS: hits_confirmed, hit_location, hit_detail and hit_type must refer to
170
+ - null = unknown or no injuries. ALWAYS set this when injuries > 0.
171
+ - GEO-RELEVANCE FOR HITS: hitsConfirmed, hit_location, hit_detail and hit_type must refer to
198
172
  the CONFIGURED ALERT ZONE only. If the source describes damage/debris in a DIFFERENT city
199
173
  or area (e.g., Rishon LeZion when the zone is Tel Aviv South), set hit_location to that city
200
- name with a note, set region_relevance proportionally lower, and describe the actual location
174
+ name with a note, set regionRelevance proportionally lower, and describe the actual location
201
175
  in hit_detail. Do NOT report hits as "confirmed" in the alert zone if the source says a
202
176
  different city. If the damage is in a nearby but different city (~10-30km), report it in
203
177
  hit_detail as "<city> (~Xкм)".
204
178
  - LANGUAGE NEUTRALITY: Posts may be in Hebrew, Russian, Arabic, or English. The language of the post
205
- MUST NOT affect source_trust or confidence. Russian-language Israeli channels are equally reliable
179
+ MUST NOT affect sourceTrust or confidence. Russian-language Israeli channels are equally reliable
206
180
  and often break news faster than Hebrew ones. Judge ONLY by factual content and tone.
207
181
  - TRUST INTERCEPTION & IMPACT REPORTS: When a channel explicitly states interception results
208
182
  (e.g., "перехвачены", "intercepted", "יירוט", "упали в море", "fell in the sea", "נפלו בים",
209
- "open area impact", "שטח פתוח"), trust these claims with source_trust >= 0.7 and confidence >= 0.7.
183
+ "open area impact", "שטח פתוח"), trust these claims with sourceTrust >= 0.7 and confidence >= 0.7.
210
184
  Israeli Telegram channels often report interception results before official confirmation,
211
185
  and these reports are typically accurate. Do NOT downgrade these just because they lack official source.
212
186
  - EXISTING ENRICHMENT CROSS-REFERENCE: If the context includes "EXISTING ENRICHMENT", previous phases
213
187
  already established facts with high confidence. Cross-reference against them:
214
- - If this post discusses a DIFFERENT country_origin than what’s established, be skeptical.
215
- Security officials summarizing past operations or different events should get time_relevance=0.
188
+ - If this post discusses a DIFFERENT countryOrigin than what’s established, be skeptical.
189
+ Security officials summarizing past operations or different events should get timeRelevance=0.
216
190
  - Only override existing enrichment if this post has DIRECT, specific information about the current attack.
217
- - General security news that appeared right after a siren but doesn't mention THIS specific attack = time_relevance=0.
191
+ - General security news that appeared right after a siren but doesn't mention THIS specific attack = timeRelevance=0.
218
192
  - OFFICIAL PHASE ANNOUNCEMENTS ≠ INCIDENT DATA: Messages from IDF / Home Front Command (Pikud HaOref)
219
193
  that announce alert phases — "siren issued", "alert in effect", "can leave the shelter", "all clear" —
220
194
  are ADMINISTRATIVE NOTICES. They say nothing about rocket count, country of origin, interceptions,
221
- hits, casualties, or damage. Extract NO data fields from these messages. Set time_relevance=0 and
195
+ hits, casualties, or damage. Extract NO data fields from these messages. Set timeRelevance=0 and
222
196
  all data fields to null.`;
223
197
  /**
224
198
  * Extract structured data from posts using expensive LLM.
@@ -230,7 +204,7 @@ export async function extractPosts(posts, ctx) {
230
204
  // ── Post-level dedup ───────────────────────────────
231
205
  const postHashMap = new Map();
232
206
  for (const post of posts) {
233
- const hash = textHash(post.channel + "|" + post.text.slice(0, 800));
207
+ const hash = textHash(post.channelId + "|" + post.text.slice(0, 800));
234
208
  postHashMap.set(hash, post);
235
209
  }
236
210
  const allHashes = [...postHashMap.keys()];
@@ -294,7 +268,7 @@ export async function extractPosts(posts, ctx) {
294
268
  { role: "system", content: systemPrompt },
295
269
  {
296
270
  role: "user",
297
- content: `${contextHeader}Channel: ${post.channel}\n\nMessage:\n${post.text.slice(0, 800)}`,
271
+ content: `${contextHeader}Channel: ${post.channelId}\n\nMessage:\n${post.text.slice(0, 800)}`,
298
272
  },
299
273
  ]);
300
274
  const raw = typeof response.content === "string"
@@ -303,54 +277,37 @@ export async function extractPosts(posts, ctx) {
303
277
  const text = raw
304
278
  .replace(/^```(?:json)?\s*\n?/i, "")
305
279
  .replace(/\n?```\s*$/i, "");
306
- const parsed = JSON.parse(text.trim());
280
+ const rawParsed = JSON.parse(text.trim());
281
+ const parsed = Object.fromEntries(Object.entries(rawParsed).filter(([_, v]) => v !== null));
307
282
  return {
308
283
  ...parsed,
309
- channel: post.channel,
310
- messageUrl: post.url,
311
- time_relevance: parsed.time_relevance ?? 0.5,
284
+ channel: post.channelId,
285
+ messageUrl: post.sourceUrl,
286
+ timeRelevance: parsed.timeRelevance ?? 0.5,
312
287
  valid: true,
313
288
  };
314
289
  }
315
290
  catch (err) {
316
291
  logger.warn("Agent: extraction failed", {
317
- channel: post.channel,
292
+ channel: post.channelId,
318
293
  error: String(err),
319
294
  });
320
295
  return {
321
- channel: post.channel,
322
- region_relevance: 0,
323
- source_trust: 0,
296
+ channel: post.channelId,
297
+ regionRelevance: 0,
298
+ sourceTrust: 0,
324
299
  tone: "neutral",
325
- time_relevance: 0,
326
- country_origin: null,
327
- rocket_count: null,
328
- is_cassette: null,
329
- intercepted: null,
330
- intercepted_qual: null,
331
- intercepted_qual_num: null,
332
- sea_impact: null,
333
- sea_impact_qual: null,
334
- sea_impact_qual_num: null,
335
- open_area_impact: null,
336
- open_area_impact_qual: null,
337
- open_area_impact_qual_num: null,
338
- hits_confirmed: null,
339
- casualties: null,
340
- injuries: null,
341
- injuries_cause: null,
342
- eta_refined_minutes: null,
343
- rocket_detail: null,
300
+ timeRelevance: 0,
344
301
  confidence: 0,
345
302
  valid: false,
346
- reject_reason: "extraction_error",
303
+ rejectReason: "extraction_error",
347
304
  };
348
305
  }
349
306
  }));
350
307
  // Cache new results
351
308
  const cacheEntries = {};
352
309
  newPosts.forEach((post, i) => {
353
- const hash = textHash(post.channel + "|" + post.text.slice(0, 800));
310
+ const hash = textHash(post.channelId + "|" + post.text.slice(0, 800));
354
311
  cacheEntries[hash] = JSON.stringify(newResults[i]);
355
312
  });
356
313
  await saveCachedExtractions(cacheEntries);
@@ -372,47 +329,47 @@ export async function extractPosts(posts, ctx) {
372
329
  export function postFilter(extractions, alertId) {
373
330
  const validated = extractions.map((ext) => {
374
331
  // V0: TIME RELEVANCE — most important check
375
- if (ext.time_relevance < 0.5) {
376
- return { ...ext, valid: false, reject_reason: "stale_post" };
332
+ if (ext.timeRelevance < 0.5) {
333
+ return { ...ext, valid: false, rejectReason: "stale_post" };
377
334
  }
378
- // V1: region relevance — relaxed for rocket_count-only posts (national totals are valid)
379
- const regionThreshold = ext.rocket_count !== null &&
380
- ext.intercepted === null &&
381
- ext.intercepted_qual === null &&
382
- ext.hits_confirmed === null &&
383
- ext.casualties === null &&
384
- ext.injuries === null
335
+ // V1: region relevance — relaxed for rocketCount-only posts (national totals are valid)
336
+ const regionThreshold = ext.rocketCount != undefined &&
337
+ ext.intercepted == undefined &&
338
+ ext.interceptedQual == undefined &&
339
+ ext.hitsConfirmed == undefined &&
340
+ ext.casualties == undefined &&
341
+ ext.injuries == undefined
385
342
  ? 0.3
386
343
  : 0.5;
387
- if (ext.region_relevance < regionThreshold) {
388
- return { ...ext, valid: false, reject_reason: "region_irrelevant" };
344
+ if (ext.regionRelevance < regionThreshold) {
345
+ return { ...ext, valid: false, rejectReason: "region_irrelevant" };
389
346
  }
390
347
  // V2: source trust
391
- if (ext.source_trust < 0.4) {
392
- return { ...ext, valid: false, reject_reason: "untrusted_source" };
348
+ if (ext.sourceTrust < 0.4) {
349
+ return { ...ext, valid: false, rejectReason: "untrusted_source" };
393
350
  }
394
351
  // V3: tone — reject alarmist
395
352
  if (ext.tone === "alarmist") {
396
- return { ...ext, valid: false, reject_reason: "alarmist_tone" };
353
+ return { ...ext, valid: false, rejectReason: "alarmist_tone" };
397
354
  }
398
- // V4: at least one data field must be non-null
399
- const hasData = ext.country_origin !== null ||
400
- ext.rocket_count !== null ||
401
- ext.is_cassette !== null ||
402
- ext.intercepted !== null ||
403
- ext.intercepted_qual !== null ||
404
- ext.hits_confirmed !== null ||
405
- ext.casualties !== null ||
406
- ext.injuries !== null ||
407
- ext.eta_refined_minutes !== null;
355
+ // V4: at least one data field must be non-undefined
356
+ const hasData = ext.countryOrigin != undefined ||
357
+ ext.rocketCount != undefined ||
358
+ ext.isCassette != undefined ||
359
+ ext.intercepted != undefined ||
360
+ ext.interceptedQual != undefined ||
361
+ ext.hitsConfirmed != undefined ||
362
+ ext.casualties != undefined ||
363
+ ext.injuries != undefined ||
364
+ ext.etaRefinedMinutes != undefined;
408
365
  if (!hasData) {
409
- return { ...ext, valid: false, reject_reason: "no_data" };
366
+ return { ...ext, valid: false, rejectReason: "no_data" };
410
367
  }
411
368
  // V5: overall confidence floor
412
369
  // Rocket count posts get a lower floor (0.2) — national totals are high-value even if uncertain
413
- const confidenceFloor = ext.rocket_count !== null ? 0.2 : 0.3;
370
+ const confidenceFloor = ext.rocketCount != undefined ? 0.2 : 0.3;
414
371
  if (ext.confidence < confidenceFloor) {
415
- return { ...ext, valid: false, reject_reason: "low_confidence" };
372
+ return { ...ext, valid: false, rejectReason: "low_confidence" };
416
373
  }
417
374
  return { ...ext, valid: true };
418
375
  });
@@ -422,7 +379,7 @@ export function postFilter(extractions, alertId) {
422
379
  alertId,
423
380
  passed: passed.length,
424
381
  rejected: rejected.length,
425
- reasons: rejected.map((r) => `${r.channel}:${r.reject_reason}`),
382
+ reasons: rejected.map((r) => `${r.channel}:${r.rejectReason}`),
426
383
  });
427
384
  return validated;
428
385
  }
@@ -1 +1 @@
1
- {"version":3,"file":"extract.js","sourceRoot":"","sources":["../../src/agent/extract.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"extract.js","sourceRoot":"","sources":["../../src/agent/extract.ts"],"names":[],"mappings":"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"}