veroq 1.0.0__tar.gz

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.
veroq-1.0.0/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ dist/
2
+ build/
3
+ *.egg-info/
4
+ __pycache__/
5
+ *.pyc
6
+ *.pyo
7
+ .pytest_cache/
8
+ .env
9
+ .env.*
10
+ *.whl
11
+ *.tar.gz
veroq-1.0.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 VEROQ
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
veroq-1.0.0/PKG-INFO ADDED
@@ -0,0 +1,157 @@
1
+ Metadata-Version: 2.4
2
+ Name: veroq
3
+ Version: 1.0.0
4
+ Summary: VEROQ Python SDK — verified intelligence for AI agents. The truth protocol for agentic AI.
5
+ Project-URL: Homepage, https://veroq.ai
6
+ Project-URL: Documentation, https://veroq.ai/docs
7
+ Project-URL: Repository, https://github.com/veroq/veroq-python
8
+ Project-URL: Bug Tracker, https://github.com/veroq/veroq-python/issues
9
+ Project-URL: Changelog, https://veroq.ai/docs/changelog
10
+ Author-email: VEROQ <dev@veroq.ai>
11
+ License-Expression: MIT
12
+ License-File: LICENSE
13
+ Keywords: agents,ai,api,financial,intelligence,nlp,sdk,truth,verified,veroq
14
+ Classifier: Development Status :: 5 - Production/Stable
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.8
19
+ Classifier: Programming Language :: Python :: 3.9
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
25
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
26
+ Classifier: Typing :: Typed
27
+ Requires-Python: >=3.8
28
+ Requires-Dist: requests>=2.20
29
+ Provides-Extra: async
30
+ Requires-Dist: httpx>=0.24; extra == 'async'
31
+ Description-Content-Type: text/markdown
32
+
33
+ # veroq
34
+
35
+ VEROQ Python SDK -- verified intelligence for AI agents. The truth protocol for agentic AI.
36
+
37
+ > **Migrating from `polaris-news`?** This is the official successor. All class names and env vars are backwards compatible. Just change your import from `polaris_news` to `veroq`.
38
+
39
+ ## Installation
40
+
41
+ ```bash
42
+ pip install veroq
43
+ ```
44
+
45
+ ## Quick Start
46
+
47
+ ### Universal Agent Connector (recommended)
48
+
49
+ ```python
50
+ from veroq import Agent
51
+
52
+ agent = Agent() # reads VEROQ_API_KEY (or POLARIS_API_KEY) from env
53
+ result = agent.ask("What's happening with NVDA?")
54
+ print(result.summary)
55
+
56
+ # Full cross-reference -- everything about a ticker in one call
57
+ full = agent.full("AAPL")
58
+ print(full.price, full.technicals, full.earnings)
59
+
60
+ # Subscribe to real-time events
61
+ for event in agent.subscribe(tickers=["NVDA", "AAPL"], events=["brief"]):
62
+ print(event.type, event.ticker, event.data)
63
+ ```
64
+
65
+ ### Authenticate via CLI
66
+
67
+ ```bash
68
+ veroq login # opens GitHub in your browser -- API key saved automatically
69
+ veroq whoami # check your auth status
70
+ veroq logout # remove saved credentials
71
+ ```
72
+
73
+ ### Full Client
74
+
75
+ ```python
76
+ from veroq import VeroqClient
77
+
78
+ client = VeroqClient() # auto-reads saved credentials
79
+ feed = client.feed(category="technology", limit=10)
80
+ for brief in feed.briefs:
81
+ print(brief.headline)
82
+ ```
83
+
84
+ You can also pass a key explicitly or set the `VEROQ_API_KEY` environment variable. For backwards compatibility, `POLARIS_API_KEY` is also supported.
85
+
86
+ ## Backwards Compatibility
87
+
88
+ If you are migrating from `polaris-news`, the following aliases are available:
89
+
90
+ ```python
91
+ from veroq import PolarisClient # alias for VeroqClient
92
+ from veroq import PolarisError # alias for VeroqError
93
+ ```
94
+
95
+ Both `VEROQ_API_KEY` and `POLARIS_API_KEY` environment variables are supported. Credentials from both `~/.veroq/credentials` and `~/.polaris/credentials` are read.
96
+
97
+ ## Methods
98
+
99
+ | Method | Description |
100
+ |--------|-------------|
101
+ | `feed(category?, limit?, page?, per_page?, min_confidence?)` | Get the news feed |
102
+ | `brief(brief_id, include_full_text?)` | Get a single brief by ID |
103
+ | `search(query, category?, page?, per_page?, sort?, min_confidence?, from_date?, to_date?, entity?, sentiment?)` | Search briefs |
104
+ | `generate(topic, category?)` | Generate a brief on a topic |
105
+ | `entities(q?, type?, limit?)` | List entities |
106
+ | `entity_briefs(name, role?, limit?, offset?)` | Get briefs for an entity |
107
+ | `trending_entities(limit?)` | Get trending entities |
108
+ | `similar(brief_id, limit?)` | Get similar briefs |
109
+ | `clusters(period?, limit?)` | Get brief clusters |
110
+ | `data(entity?, type?, limit?)` | Get structured data points |
111
+ | `agent_feed(category?, tags?, limit?, min_confidence?)` | Get agent-optimized feed |
112
+ | `compare_sources(brief_id)` | Compare sources for a brief |
113
+ | `trending(period?, limit?)` | Get trending briefs |
114
+ | `verify(claim, context?)` | Fact-check a claim against briefs |
115
+ | `research(query, max_sources?, depth?, category?)` | Deep research on a topic |
116
+ | `stream(categories?)` | Stream briefs via SSE (generator) |
117
+ | `ticker(symbol)` | Get ticker overview |
118
+ | `ticker_prices(symbols)` | Get live prices |
119
+ | `ticker_sentiment(symbol, period?)` | Sentiment breakdown |
120
+ | `ticker_signals(symbol, days?, threshold?)` | Trading signals |
121
+ | `candles(symbol, interval?, range?)` | OHLCV candle data |
122
+ | `technicals(symbol, range?)` | Full technical analysis |
123
+ | `screener(filters)` | Screen stocks by filters |
124
+ | `screener_natural(query)` | Natural language stock screen |
125
+ | `crypto(symbol?)` | Crypto data |
126
+ | `forex(pair?)` | Forex data |
127
+ | `generate_report(ticker, tier?)` | Generate a report |
128
+
129
+ ## Error Handling
130
+
131
+ ```python
132
+ from veroq import VeroqClient, AuthenticationError, RateLimitError, NotFoundError
133
+
134
+ client = VeroqClient()
135
+
136
+ try:
137
+ brief = client.brief("abc123")
138
+ except AuthenticationError:
139
+ print("Invalid API key")
140
+ except NotFoundError:
141
+ print("Brief not found")
142
+ except RateLimitError as e:
143
+ print(f"Rate limited. Retry after: {e.retry_after}s")
144
+ ```
145
+
146
+ ## Streaming
147
+
148
+ ```python
149
+ client = VeroqClient()
150
+
151
+ for brief in client.stream(categories="technology,science"):
152
+ print(f"[{brief.category}] {brief.headline}")
153
+ ```
154
+
155
+ ## Documentation
156
+
157
+ Full API documentation: https://veroq.ai/docs
veroq-1.0.0/README.md ADDED
@@ -0,0 +1,125 @@
1
+ # veroq
2
+
3
+ VEROQ Python SDK -- verified intelligence for AI agents. The truth protocol for agentic AI.
4
+
5
+ > **Migrating from `polaris-news`?** This is the official successor. All class names and env vars are backwards compatible. Just change your import from `polaris_news` to `veroq`.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ pip install veroq
11
+ ```
12
+
13
+ ## Quick Start
14
+
15
+ ### Universal Agent Connector (recommended)
16
+
17
+ ```python
18
+ from veroq import Agent
19
+
20
+ agent = Agent() # reads VEROQ_API_KEY (or POLARIS_API_KEY) from env
21
+ result = agent.ask("What's happening with NVDA?")
22
+ print(result.summary)
23
+
24
+ # Full cross-reference -- everything about a ticker in one call
25
+ full = agent.full("AAPL")
26
+ print(full.price, full.technicals, full.earnings)
27
+
28
+ # Subscribe to real-time events
29
+ for event in agent.subscribe(tickers=["NVDA", "AAPL"], events=["brief"]):
30
+ print(event.type, event.ticker, event.data)
31
+ ```
32
+
33
+ ### Authenticate via CLI
34
+
35
+ ```bash
36
+ veroq login # opens GitHub in your browser -- API key saved automatically
37
+ veroq whoami # check your auth status
38
+ veroq logout # remove saved credentials
39
+ ```
40
+
41
+ ### Full Client
42
+
43
+ ```python
44
+ from veroq import VeroqClient
45
+
46
+ client = VeroqClient() # auto-reads saved credentials
47
+ feed = client.feed(category="technology", limit=10)
48
+ for brief in feed.briefs:
49
+ print(brief.headline)
50
+ ```
51
+
52
+ You can also pass a key explicitly or set the `VEROQ_API_KEY` environment variable. For backwards compatibility, `POLARIS_API_KEY` is also supported.
53
+
54
+ ## Backwards Compatibility
55
+
56
+ If you are migrating from `polaris-news`, the following aliases are available:
57
+
58
+ ```python
59
+ from veroq import PolarisClient # alias for VeroqClient
60
+ from veroq import PolarisError # alias for VeroqError
61
+ ```
62
+
63
+ Both `VEROQ_API_KEY` and `POLARIS_API_KEY` environment variables are supported. Credentials from both `~/.veroq/credentials` and `~/.polaris/credentials` are read.
64
+
65
+ ## Methods
66
+
67
+ | Method | Description |
68
+ |--------|-------------|
69
+ | `feed(category?, limit?, page?, per_page?, min_confidence?)` | Get the news feed |
70
+ | `brief(brief_id, include_full_text?)` | Get a single brief by ID |
71
+ | `search(query, category?, page?, per_page?, sort?, min_confidence?, from_date?, to_date?, entity?, sentiment?)` | Search briefs |
72
+ | `generate(topic, category?)` | Generate a brief on a topic |
73
+ | `entities(q?, type?, limit?)` | List entities |
74
+ | `entity_briefs(name, role?, limit?, offset?)` | Get briefs for an entity |
75
+ | `trending_entities(limit?)` | Get trending entities |
76
+ | `similar(brief_id, limit?)` | Get similar briefs |
77
+ | `clusters(period?, limit?)` | Get brief clusters |
78
+ | `data(entity?, type?, limit?)` | Get structured data points |
79
+ | `agent_feed(category?, tags?, limit?, min_confidence?)` | Get agent-optimized feed |
80
+ | `compare_sources(brief_id)` | Compare sources for a brief |
81
+ | `trending(period?, limit?)` | Get trending briefs |
82
+ | `verify(claim, context?)` | Fact-check a claim against briefs |
83
+ | `research(query, max_sources?, depth?, category?)` | Deep research on a topic |
84
+ | `stream(categories?)` | Stream briefs via SSE (generator) |
85
+ | `ticker(symbol)` | Get ticker overview |
86
+ | `ticker_prices(symbols)` | Get live prices |
87
+ | `ticker_sentiment(symbol, period?)` | Sentiment breakdown |
88
+ | `ticker_signals(symbol, days?, threshold?)` | Trading signals |
89
+ | `candles(symbol, interval?, range?)` | OHLCV candle data |
90
+ | `technicals(symbol, range?)` | Full technical analysis |
91
+ | `screener(filters)` | Screen stocks by filters |
92
+ | `screener_natural(query)` | Natural language stock screen |
93
+ | `crypto(symbol?)` | Crypto data |
94
+ | `forex(pair?)` | Forex data |
95
+ | `generate_report(ticker, tier?)` | Generate a report |
96
+
97
+ ## Error Handling
98
+
99
+ ```python
100
+ from veroq import VeroqClient, AuthenticationError, RateLimitError, NotFoundError
101
+
102
+ client = VeroqClient()
103
+
104
+ try:
105
+ brief = client.brief("abc123")
106
+ except AuthenticationError:
107
+ print("Invalid API key")
108
+ except NotFoundError:
109
+ print("Brief not found")
110
+ except RateLimitError as e:
111
+ print(f"Rate limited. Retry after: {e.retry_after}s")
112
+ ```
113
+
114
+ ## Streaming
115
+
116
+ ```python
117
+ client = VeroqClient()
118
+
119
+ for brief in client.stream(categories="technology,science"):
120
+ print(f"[{brief.category}] {brief.headline}")
121
+ ```
122
+
123
+ ## Documentation
124
+
125
+ Full API documentation: https://veroq.ai/docs
@@ -0,0 +1,56 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "veroq"
7
+ version = "1.0.0"
8
+ description = "VEROQ Python SDK — verified intelligence for AI agents. The truth protocol for agentic AI."
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.8"
12
+ authors = [
13
+ { name = "VEROQ", email = "dev@veroq.ai" },
14
+ ]
15
+ keywords = ["veroq", "verified", "intelligence", "api", "sdk", "ai", "agents", "nlp", "truth", "financial"]
16
+ classifiers = [
17
+ "Development Status :: 5 - Production/Stable",
18
+ "Intended Audience :: Developers",
19
+ "License :: OSI Approved :: MIT License",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.8",
22
+ "Programming Language :: Python :: 3.9",
23
+ "Programming Language :: Python :: 3.10",
24
+ "Programming Language :: Python :: 3.11",
25
+ "Programming Language :: Python :: 3.12",
26
+ "Programming Language :: Python :: 3.13",
27
+ "Topic :: Software Development :: Libraries :: Python Modules",
28
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
29
+ "Typing :: Typed",
30
+ ]
31
+ dependencies = [
32
+ "requests>=2.20",
33
+ ]
34
+
35
+ [project.scripts]
36
+ veroq = "veroq.cli:main"
37
+
38
+ [project.optional-dependencies]
39
+ async = ["httpx>=0.24"]
40
+
41
+ [project.urls]
42
+ Homepage = "https://veroq.ai"
43
+ Documentation = "https://veroq.ai/docs"
44
+ Repository = "https://github.com/veroq/veroq-python"
45
+ "Bug Tracker" = "https://github.com/veroq/veroq-python/issues"
46
+ Changelog = "https://veroq.ai/docs/changelog"
47
+
48
+ [tool.hatch.build.targets.sdist]
49
+ include = ["veroq/", "LICENSE", "README.md"]
50
+
51
+ [tool.hatch.build.targets.wheel]
52
+ packages = ["veroq"]
53
+
54
+ [tool.pytest.ini_options]
55
+ testpaths = ["tests"]
56
+ asyncio_mode = "auto"
@@ -0,0 +1,87 @@
1
+ __version__ = "1.0.0"
2
+
3
+ from .client import VeroqClient
4
+ from .agent import Agent, AskResult, FullResult, SubscribeEvent
5
+ from .exceptions import APIError, AuthenticationError, NotFoundError, VeroqError, RateLimitError
6
+ from .types import (
7
+ Brief,
8
+ Cluster,
9
+ ClustersResponse,
10
+ ComparisonResponse,
11
+ DataPoint,
12
+ DataPointValue,
13
+ DataResponse,
14
+ DepthMetadata,
15
+ EntitiesResponse,
16
+ Entity,
17
+ EntityCrossRef,
18
+ ExtractResponse,
19
+ ExtractResult,
20
+ FeedResponse,
21
+ Provenance,
22
+ ResearchEntity,
23
+ ResearchMetadata,
24
+ ResearchResponse,
25
+ ResearchSourceUsed,
26
+ SearchResponse,
27
+ VerifyBrief,
28
+ VerifyResponse,
29
+ Source,
30
+ SourceAnalysis,
31
+ SourceVerification,
32
+ )
33
+
34
+ try:
35
+ from .async_client import AsyncVeroqClient
36
+ except ImportError:
37
+ pass
38
+
39
+ # Backwards compatibility aliases
40
+ PolarisClient = VeroqClient
41
+ PolarisError = VeroqError
42
+ try:
43
+ AsyncPolarisClient = AsyncVeroqClient
44
+ except NameError:
45
+ pass
46
+
47
+ __all__ = [
48
+ "VeroqClient",
49
+ "AsyncVeroqClient",
50
+ "VeroqError",
51
+ "AuthenticationError",
52
+ "RateLimitError",
53
+ "NotFoundError",
54
+ "APIError",
55
+ # Backwards compatibility
56
+ "PolarisClient",
57
+ "PolarisError",
58
+ "Agent",
59
+ "AskResult",
60
+ "FullResult",
61
+ "SubscribeEvent",
62
+ "Brief",
63
+ "Source",
64
+ "Entity",
65
+ "Provenance",
66
+ "FeedResponse",
67
+ "SearchResponse",
68
+ "Cluster",
69
+ "ClustersResponse",
70
+ "DataPoint",
71
+ "DataPointValue",
72
+ "DataResponse",
73
+ "EntitiesResponse",
74
+ "ComparisonResponse",
75
+ "SourceAnalysis",
76
+ "ExtractResult",
77
+ "ExtractResponse",
78
+ "ResearchResponse",
79
+ "ResearchEntity",
80
+ "ResearchMetadata",
81
+ "ResearchSourceUsed",
82
+ "DepthMetadata",
83
+ "EntityCrossRef",
84
+ "SourceVerification",
85
+ "VerifyBrief",
86
+ "VerifyResponse",
87
+ ]
@@ -0,0 +1,240 @@
1
+ """
2
+ VEROQ Universal Agent Connector
3
+
4
+ The simplest way to give any AI agent verified financial intelligence.
5
+
6
+ from veroq import Agent
7
+
8
+ agent = Agent() # reads VEROQ_API_KEY or POLARIS_API_KEY from env
9
+ result = agent.ask("What's happening with NVDA?")
10
+ print(result.summary)
11
+
12
+ # Full cross-reference — everything about a ticker
13
+ full = agent.full("AAPL")
14
+ print(full.price, full.technicals, full.earnings)
15
+
16
+ # Subscribe to real-time events
17
+ for event in agent.subscribe(tickers=["NVDA", "AAPL"], events=["brief"]):
18
+ print(event)
19
+ """
20
+
21
+ import json
22
+ import os
23
+ from typing import Any, Dict, Iterator, List, Optional
24
+
25
+ import requests
26
+
27
+
28
+ class AskResult:
29
+ """Result from /ask — structured financial intelligence."""
30
+
31
+ def __init__(self, data: Dict[str, Any]):
32
+ self._data = data
33
+ self.question: str = data.get("question", "")
34
+ self.intents: List[str] = data.get("intents", [])
35
+ self.tickers: List[str] = data.get("tickers", [])
36
+ self.reasoning: List[str] = data.get("reasoning", [])
37
+ self.summary: str = data.get("summary", "")
38
+ self.data: Dict[str, Any] = data.get("data", {})
39
+ self.credits_used: int = data.get("credits_used", 0)
40
+
41
+ def __repr__(self) -> str:
42
+ return f"AskResult(tickers={self.tickers}, intents={self.intents}, credits={self.credits_used})"
43
+
44
+ def __str__(self) -> str:
45
+ return self.summary
46
+
47
+
48
+ class FullResult:
49
+ """Result from /ticker/:symbol/full — complete cross-reference."""
50
+
51
+ def __init__(self, data: Dict[str, Any]):
52
+ self._data = data
53
+ self.ticker: str = data.get("ticker", "")
54
+ self.entity_name: str = data.get("entity_name", "")
55
+ self.sector: str = data.get("sector", "")
56
+ self.price: Dict[str, Any] = data.get("price", {})
57
+ self.sentiment: Dict[str, Any] = data.get("sentiment", {})
58
+ self.technicals: Dict[str, Any] = data.get("technicals", {})
59
+ self.earnings: Dict[str, Any] = data.get("earnings", {})
60
+ self.news: Dict[str, Any] = data.get("news", {})
61
+ self.insider: Dict[str, Any] = data.get("insider", {})
62
+ self.filings: Dict[str, Any] = data.get("filings", {})
63
+ self.analysts: Dict[str, Any] = data.get("analysts", {})
64
+ self.institutions: Dict[str, Any] = data.get("institutions", {})
65
+
66
+ def __repr__(self) -> str:
67
+ return f"FullResult({self.ticker} ${self.price.get('current', '?')})"
68
+
69
+ def __str__(self) -> str:
70
+ lines = [f"{self.entity_name} ({self.ticker})"]
71
+ if self.price.get("current"):
72
+ lines.append(f"Price: ${self.price['current']} ({self.price.get('change_pct', '?')}%)")
73
+ if self.technicals.get("signal"):
74
+ lines.append(f"Signal: {self.technicals['signal']} | RSI: {self.technicals.get('rsi_14', '?')}")
75
+ if self.earnings.get("next_date"):
76
+ lines.append(f"Next Earnings: {self.earnings['next_date']}")
77
+ return "\n".join(lines)
78
+
79
+
80
+ class SubscribeEvent:
81
+ """A real-time event from /subscribe."""
82
+
83
+ def __init__(self, event_type: str, data: Dict[str, Any]):
84
+ self.type: str = event_type
85
+ self.ticker: Optional[str] = data.get("ticker")
86
+ self.data: Dict[str, Any] = data.get("data", data)
87
+ self.timestamp: str = data.get("timestamp", "")
88
+
89
+ def __repr__(self) -> str:
90
+ return f"SubscribeEvent({self.type}, ticker={self.ticker})"
91
+
92
+
93
+ class Agent:
94
+ """
95
+ VEROQ Universal Agent Connector.
96
+
97
+ The simplest way to add verified financial intelligence to any AI agent.
98
+
99
+ agent = Agent(api_key="vq_live_...")
100
+ result = agent.ask("What's happening with NVDA?")
101
+ print(result.summary)
102
+ """
103
+
104
+ def __init__(
105
+ self,
106
+ api_key: Optional[str] = None,
107
+ base_url: str = "https://api.thepolarisreport.com",
108
+ timeout: int = 30,
109
+ ):
110
+ # Support both VEROQ_API_KEY and POLARIS_API_KEY for backwards compatibility
111
+ self.api_key = api_key or os.environ.get("VEROQ_API_KEY") or os.environ.get("POLARIS_API_KEY", "")
112
+ self.base_url = base_url.rstrip("/")
113
+ self.timeout = timeout
114
+ self._session = requests.Session()
115
+ self._session.headers.update({
116
+ "Authorization": f"Bearer {self.api_key}" if self.api_key else "",
117
+ "Content-Type": "application/json",
118
+ "User-Agent": "veroq-agent/1.0",
119
+ })
120
+
121
+ def ask(self, question: str) -> AskResult:
122
+ """
123
+ Ask any financial question. Returns structured data + markdown summary.
124
+
125
+ result = agent.ask("What's happening with NVDA?")
126
+ print(result.summary)
127
+ print(result.tickers) # ['NVDA']
128
+ print(result.reasoning) # ['Identified ticker: NVDA', ...]
129
+ print(result.data) # Raw data from all sources
130
+ """
131
+ resp = self._session.post(
132
+ f"{self.base_url}/api/v1/ask",
133
+ json={"question": question},
134
+ timeout=self.timeout,
135
+ )
136
+ resp.raise_for_status()
137
+ return AskResult(resp.json())
138
+
139
+ def full(self, ticker: str) -> FullResult:
140
+ """
141
+ Get EVERYTHING about a ticker in one call.
142
+
143
+ result = agent.full("NVDA")
144
+ print(result.price) # {'current': 178.68, 'change_pct': -0.95}
145
+ print(result.technicals) # {'signal': 'neutral', 'rsi_14': 46.4}
146
+ print(result.earnings) # {'next_date': '2026-05-20', ...}
147
+ print(result.insider) # {'transactions': [...], 'total': 20}
148
+ """
149
+ resp = self._session.get(
150
+ f"{self.base_url}/api/v1/ticker/{ticker.upper()}/full",
151
+ timeout=self.timeout,
152
+ )
153
+ resp.raise_for_status()
154
+ return FullResult(resp.json())
155
+
156
+ def subscribe(
157
+ self,
158
+ tickers: Optional[List[str]] = None,
159
+ events: Optional[List[str]] = None,
160
+ ) -> Iterator[SubscribeEvent]:
161
+ """
162
+ Subscribe to real-time financial events via SSE.
163
+
164
+ for event in agent.subscribe(tickers=["NVDA", "AAPL"], events=["brief"]):
165
+ print(event.type, event.ticker, event.data)
166
+ """
167
+ params = {}
168
+ if tickers:
169
+ params["tickers"] = ",".join(t.upper() for t in tickers)
170
+ else:
171
+ params["tickers"] = "*"
172
+ if events:
173
+ params["events"] = ",".join(events)
174
+
175
+ resp = self._session.get(
176
+ f"{self.base_url}/api/v1/subscribe",
177
+ params=params,
178
+ stream=True,
179
+ timeout=None, # SSE is long-lived
180
+ headers={**self._session.headers, "Accept": "text/event-stream"},
181
+ )
182
+ resp.raise_for_status()
183
+
184
+ event_type = ""
185
+ data_lines: List[str] = []
186
+
187
+ for line in resp.iter_lines(decode_unicode=True):
188
+ if line is None:
189
+ continue
190
+ line = line.strip()
191
+ if line.startswith("event:"):
192
+ event_type = line[6:].strip()
193
+ elif line.startswith("data:"):
194
+ data_lines.append(line[5:].strip())
195
+ elif line == "" and event_type and data_lines:
196
+ # Complete event
197
+ try:
198
+ data = json.loads("".join(data_lines))
199
+ yield SubscribeEvent(event_type, data)
200
+ except json.JSONDecodeError:
201
+ pass
202
+ event_type = ""
203
+ data_lines = []
204
+ elif line.startswith(":"):
205
+ pass # heartbeat, ignore
206
+
207
+ def run_agent(self, slug: str, **inputs) -> Dict[str, Any]:
208
+ """
209
+ Run a marketplace agent.
210
+
211
+ result = agent.run_agent("sector-pulse", sector="Technology")
212
+ print(result["summary"])
213
+ """
214
+ resp = self._session.post(
215
+ f"{self.base_url}/api/v1/agents/run/{slug}",
216
+ json=inputs,
217
+ timeout=120,
218
+ )
219
+ resp.raise_for_status()
220
+ return resp.json()
221
+
222
+ def search(self, query: str, per_page: int = 10) -> Dict[str, Any]:
223
+ """Search intelligence briefs."""
224
+ resp = self._session.get(
225
+ f"{self.base_url}/api/v1/search",
226
+ params={"q": query, "per_page": per_page},
227
+ timeout=self.timeout,
228
+ )
229
+ resp.raise_for_status()
230
+ return resp.json()
231
+
232
+ def verify(self, claim: str) -> Dict[str, Any]:
233
+ """Fact-check a claim against the intelligence corpus."""
234
+ resp = self._session.post(
235
+ f"{self.base_url}/api/v1/verify",
236
+ json={"claim": claim},
237
+ timeout=self.timeout,
238
+ )
239
+ resp.raise_for_status()
240
+ return resp.json()