diff --git a/integrations/simplefunctions-world-model/README.md b/integrations/simplefunctions-world-model/README.md new file mode 100644 index 00000000..25e8c529 --- /dev/null +++ b/integrations/simplefunctions-world-model/README.md @@ -0,0 +1,54 @@ +# World-Aware CrewAI Crew + +A multi-agent crew where every agent shares the same real-time world context. The research analyst, risk officer, and briefing writer all see the same calibrated probabilities — no contradictions. + +## The Problem + +In a multi-agent crew, each agent hallucinates different numbers. The researcher says "recession probability is low." The risk officer says "recession probability is elevated." They're not disagreeing — they just have different training data cutoffs. + +## The Solution + +Fetch real-time world state from prediction markets once, share it across all agents. Data comes from [SimpleFunctions](https://simplefunctions.dev/world) — 9,706 contracts on Kalshi (CFTC-regulated) and Polymarket. No API key needed. + +## Setup + +```bash +pip install -r requirements.txt +export OPENAI_API_KEY=sk-... +``` + +## Run + +```bash +python main.py +``` + +## Architecture + +``` +SimpleFunctions World API (one call, ~800 tokens) + ↓ +Shared Context (all agents see same probabilities) + ↓ +┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ +│ Researcher │ → │ Risk Officer │ → │ Briefing Writer │ +│ - world_state │ │ - world_state │ │ (context from │ +│ - search_markets│ │ - market_detail │ │ both agents) │ +└─────────────────┘ └─────────────────┘ └─────────────────┘ +``` + +## Output Example + +Instead of vague hedging: +> "Geopolitical tensions remain elevated. We recommend monitoring the situation." + +You get data-driven briefings: +> "Iran invasion probability: 53% (+5c). Hormuz disruption: 95%. Oil at $127 (+3.2%). Geopolitical Risk: 85/100. Recession: 33%. Primary risk: unhedged energy exposure. Action: review commodity hedges by EOD." + +## Tools + +| Tool | Description | +|------|-------------| +| `get_focused_world_state` | Deeper coverage of specific topics | +| `search_prediction_markets` | Find specific contracts by keyword | +| `get_market_detail` | Orderbook depth and thesis edges for a contract | diff --git a/integrations/simplefunctions-world-model/main.py b/integrations/simplefunctions-world-model/main.py new file mode 100644 index 00000000..5e90ae41 --- /dev/null +++ b/integrations/simplefunctions-world-model/main.py @@ -0,0 +1,170 @@ +""" +World-Aware CrewAI Crew — Multi-agent system with shared real-time world context. + +Problem: In a multi-agent crew, each agent hallucinates different numbers. +The researcher says "recession probability is low," the risk officer says +"recession probability is elevated." They're not disagreeing — they just +have different training data cutoffs. + +Solution: Fetch real-time world state from prediction markets once, share +it across all agents. Everyone cites the same calibrated probabilities. + +Data source: SimpleFunctions (https://simplefunctions.dev/world) + - 9,706 prediction markets from Kalshi + Polymarket + - No API key needed — free and public + - ~800 tokens, updated every 15 minutes +""" + +import requests +from crewai import Agent, Task, Crew +from crewai.tools import tool + + +# ── Shared world context ─────────────────────────────────────────────────────── + +world = requests.get("https://simplefunctions.dev/api/agent/world").text + +SHARED_CONTEXT = f"""You have access to real-time world data from prediction markets. +Use the numbers below as ground truth. Do NOT hallucinate probabilities. +Cite specific contract prices and probabilities directly. +When citing data, mention the source: SimpleFunctions World Model. + +{world}""" + + +# ── Tools ────────────────────────────────────────────────────────────────────── + +@tool("get_focused_world_state") +def get_focused_world_state(topics: str) -> str: + """Get world state focused on specific topics for deeper coverage. + + Same token budget, concentrated on fewer topics — more contracts per topic. + + Args: + topics: Comma-separated topics, e.g. 'geopolitics,energy'. + Options: geopolitics, economy, energy, elections, crypto, tech. + """ + return requests.get( + f"https://simplefunctions.dev/api/agent/world?focus={topics}" + ).text + + +@tool("search_prediction_markets") +def search_prediction_markets(query: str) -> str: + """Search for specific prediction market contracts across Kalshi and Polymarket. + + Args: + query: Natural language query, e.g. 'iran oil', 'fed rate cut', 'bitcoin'. + """ + import json + resp = requests.get( + f"https://simplefunctions.dev/api/public/scan?q={query}&limit=10" + ) + return json.dumps(resp.json().get("markets", [])[:10], indent=2) + + +@tool("get_market_detail") +def get_market_detail(ticker: str) -> str: + """Get detailed data for a specific prediction market contract. + + Includes price, spread, volume, orderbook depth, and related thesis edges. + + Args: + ticker: Kalshi ticker (e.g. KXIRANINVASION) or Polymarket condition ID. + """ + import json + resp = requests.get( + f"https://simplefunctions.dev/api/public/market/{ticker}?depth=true" + ) + return json.dumps(resp.json(), indent=2) + + +# ── Agents ───────────────────────────────────────────────────────────────────── + +researcher = Agent( + role="Macro Research Analyst", + goal="Analyze geopolitical and economic developments using real-time probability data", + backstory=SHARED_CONTEXT + + "\nYou are a senior macro analyst at a global macro fund. You cite specific " + "probabilities and prices from prediction markets. You never say 'approximately' " + "when you have exact numbers. You identify the most important risks and opportunities.", + verbose=True, +) + +risk_officer = Agent( + role="Risk Officer", + goal="Identify portfolio risks based on current world conditions", + backstory=SHARED_CONTEXT + + "\nYou are a risk officer. You flag when probabilities cross thresholds that " + "matter for portfolio exposure. You reference specific contract prices. You never " + "say 'could' when you have a specific probability.", + verbose=True, +) + +writer = Agent( + role="Morning Briefing Writer", + goal="Produce a concise morning briefing for the investment committee", + backstory=SHARED_CONTEXT + + "\nYou write crisp, data-driven briefings for busy portfolio managers. Every " + "claim has a number attached. No hedging language. No filler. 200 words max.", + verbose=True, +) + + +# ── Tasks ────────────────────────────────────────────────────────────────────── + +research_task = Task( + description=( + "Analyze the current geopolitical and economic situation. Focus on: " + "1) The top geopolitical risk and its probability, " + "2) Recession and Fed rate expectations, " + "3) Energy market conditions. " + "Use the world state data and search for specific contracts if needed. " + "Cite every number with its source contract." + ), + expected_output="Structured analysis with specific probability citations from prediction markets", + agent=researcher, + tools=[get_focused_world_state, search_prediction_markets], +) + +risk_task = Task( + description=( + "Based on the research analysis, identify the top 3 portfolio risks right now. " + "For each risk: state the specific prediction market probability, explain why " + "it matters for portfolio exposure, and recommend one action." + ), + expected_output="3 risks with probability levels, portfolio implications, and actions", + agent=risk_officer, + tools=[get_focused_world_state, get_market_detail], + context=[research_task], +) + +briefing_task = Task( + description=( + "Write a 200-word morning briefing combining the research and risk analysis. " + "Rules: every sentence must contain a number. No hedging. No filler. " + "End with the single most important thing the PM should do today." + ), + expected_output="200-word morning briefing with data citations", + agent=writer, + context=[research_task, risk_task], +) + + +# ── Crew ─────────────────────────────────────────────────────────────────────── + +crew = Crew( + agents=[researcher, risk_officer, writer], + tasks=[research_task, risk_task, briefing_task], + verbose=True, +) + + +if __name__ == "__main__": + print("Starting world-aware macro crew...") + print(f"World state loaded: {len(world)} characters\n") + result = crew.kickoff() + print("\n" + "=" * 60) + print("MORNING BRIEFING") + print("=" * 60) + print(result) diff --git a/integrations/simplefunctions-world-model/requirements.txt b/integrations/simplefunctions-world-model/requirements.txt new file mode 100644 index 00000000..e1ef326d --- /dev/null +++ b/integrations/simplefunctions-world-model/requirements.txt @@ -0,0 +1,3 @@ +crewai>=0.152.0 +crewai-tools>=0.38.0 +requests>=2.31.0