|
|
@@ -38,7 +38,7 @@ def _cluster_entity_haystack(cluster: dict) -> list[str]:
|
|
|
|
|
|
|
|
|
@mcp.tool(description="What is happening right now? Return the latest deduplicated news clusters for a topic.")
|
|
|
-async def get_latest_events(topic: str = "crypto", limit: int = 5):
|
|
|
+async def get_latest_events(topic: str = "crypto", limit: int = 5, include_articles: bool = False):
|
|
|
limit = max(1, min(int(limit), 20))
|
|
|
# If the caller passes an entity-like value, resolve it and use the canonical
|
|
|
# entity as the query lens. Otherwise keep the original topic path.
|
|
|
@@ -80,24 +80,36 @@ async def get_latest_events(topic: str = "crypto", limit: int = 5):
|
|
|
|
|
|
out = []
|
|
|
for c in clusters_sorted:
|
|
|
- out.append(
|
|
|
- {
|
|
|
- "cluster_id": c.get("cluster_id"),
|
|
|
- "headline": c.get("headline"),
|
|
|
- "summary": c.get("summary"),
|
|
|
- "entities": c.get("entities", []),
|
|
|
- "sentiment": c.get("sentiment", "neutral"),
|
|
|
- "importance": c.get("importance", 0.0),
|
|
|
- "sources": c.get("sources", []),
|
|
|
- "timestamp": c.get("timestamp"),
|
|
|
- }
|
|
|
- )
|
|
|
+ item = {
|
|
|
+ "cluster_id": c.get("cluster_id"),
|
|
|
+ "headline": c.get("headline"),
|
|
|
+ "summary": c.get("summary"),
|
|
|
+ "entities": c.get("entities", []),
|
|
|
+ "sentiment": c.get("sentiment", "neutral"),
|
|
|
+ "importance": c.get("importance", 0.0),
|
|
|
+ "sources": c.get("sources", []),
|
|
|
+ "timestamp": c.get("timestamp"),
|
|
|
+ }
|
|
|
+ if include_articles:
|
|
|
+ # Return minimal article fields to keep responses compact.
|
|
|
+ arts = c.get("articles", []) or []
|
|
|
+ item["articles"] = [
|
|
|
+ {
|
|
|
+ "title": a.get("title"),
|
|
|
+ "url": a.get("url"),
|
|
|
+ "source": a.get("source"),
|
|
|
+ "timestamp": a.get("timestamp"),
|
|
|
+ }
|
|
|
+ for a in arts
|
|
|
+ if isinstance(a, dict)
|
|
|
+ ]
|
|
|
+ out.append(item)
|
|
|
|
|
|
return out
|
|
|
|
|
|
|
|
|
@mcp.tool(description="What's happening with X? Filter latest clusters by extracted entity substring (case-insensitive).")
|
|
|
-async def get_events_for_entity(entity: str, limit: int = 10):
|
|
|
+async def get_events_for_entity(entity: str, limit: int = 10, include_articles: bool = False):
|
|
|
limit = max(1, min(int(limit), 30))
|
|
|
query = normalize_query(entity).strip().lower()
|
|
|
if not query:
|
|
|
@@ -136,18 +148,29 @@ async def get_events_for_entity(entity: str, limit: int = 10):
|
|
|
# Compress to tool response shape.
|
|
|
out = []
|
|
|
for c in hits:
|
|
|
- out.append(
|
|
|
- {
|
|
|
- "cluster_id": c.get("cluster_id"),
|
|
|
- "headline": c.get("headline"),
|
|
|
- "summary": c.get("summary"),
|
|
|
- "entities": c.get("entities", []),
|
|
|
- "sentiment": c.get("sentiment", "neutral"),
|
|
|
- "importance": c.get("importance", 0.0),
|
|
|
- "sources": c.get("sources", []),
|
|
|
- "timestamp": c.get("timestamp"),
|
|
|
- }
|
|
|
- )
|
|
|
+ item = {
|
|
|
+ "cluster_id": c.get("cluster_id"),
|
|
|
+ "headline": c.get("headline"),
|
|
|
+ "summary": c.get("summary"),
|
|
|
+ "entities": c.get("entities", []),
|
|
|
+ "sentiment": c.get("sentiment", "neutral"),
|
|
|
+ "importance": c.get("importance", 0.0),
|
|
|
+ "sources": c.get("sources", []),
|
|
|
+ "timestamp": c.get("timestamp"),
|
|
|
+ }
|
|
|
+ if include_articles:
|
|
|
+ arts = c.get("articles", []) or []
|
|
|
+ item["articles"] = [
|
|
|
+ {
|
|
|
+ "title": a.get("title"),
|
|
|
+ "url": a.get("url"),
|
|
|
+ "source": a.get("source"),
|
|
|
+ "timestamp": a.get("timestamp"),
|
|
|
+ }
|
|
|
+ for a in arts
|
|
|
+ if isinstance(a, dict)
|
|
|
+ ]
|
|
|
+ out.append(item)
|
|
|
return out
|
|
|
|
|
|
|