fetchkit-agents 0.3.0__tar.gz → 0.4.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.
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/PKG-INFO +174 -12
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/README.md +173 -11
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/pyproject.toml +1 -1
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit/__init__.py +13 -1
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit/cli.py +95 -9
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit/collector.py +16 -10
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit/config_loader.py +22 -11
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit/discovery/__init__.py +2 -1
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit/discovery/core.py +27 -1
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit/discovery/data/catalog.json +241 -1
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit/fetchers/__init__.py +6 -0
- fetchkit_agents-0.4.0/src/fetchkit/fetchers/edgar.py +287 -0
- fetchkit_agents-0.4.0/src/fetchkit/fetchers/gdelt.py +150 -0
- fetchkit_agents-0.4.0/src/fetchkit/fetchers/googlenews.py +145 -0
- fetchkit_agents-0.4.0/src/fetchkit/fetchers/manifold.py +110 -0
- fetchkit_agents-0.4.0/src/fetchkit/fetchers/polymarket.py +145 -0
- fetchkit_agents-0.4.0/src/fetchkit/fetchers/reddit.py +132 -0
- fetchkit_agents-0.4.0/src/fetchkit/schemas/collector.py +54 -0
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit/schemas/describe.py +6 -0
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit/schemas/fetcher.py +218 -2
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit/schemas/post.py +6 -0
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit_agents.egg-info/PKG-INFO +174 -12
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit_agents.egg-info/SOURCES.txt +6 -0
- fetchkit_agents-0.3.0/src/fetchkit/schemas/collector.py +0 -21
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/LICENSE +0 -0
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/setup.cfg +0 -0
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit/__main__.py +0 -0
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit/discovery/autodiscover.py +0 -0
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit/discovery/catalog.py +0 -0
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit/discovery/data/CATALOG.md +0 -0
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit/discovery/embedding.py +0 -0
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit/discovery/errors.py +0 -0
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit/discovery/external.py +0 -0
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit/discovery/ranking.py +0 -0
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit/discovery/schemas.py +0 -0
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit/fetchers/arxiv.py +0 -0
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit/fetchers/base.py +0 -0
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit/fetchers/bluesky.py +0 -0
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit/fetchers/github.py +0 -0
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit/fetchers/hackernews.py +0 -0
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit/fetchers/lobsters.py +0 -0
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit/fetchers/mastodon.py +0 -0
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit/fetchers/registry.py +0 -0
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit/fetchers/rss.py +0 -0
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit/fetchers/stackexchange.py +0 -0
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit/fetchers/suggest_registry.py +0 -0
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit/http/__init__.py +0 -0
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit/http/client.py +0 -0
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit/http/rate_limit.py +0 -0
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit/http/ssrf.py +0 -0
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit/py.typed +0 -0
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit/schemas/__init__.py +0 -0
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit/schemas/base.py +0 -0
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit/schemas/config.py +0 -0
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit/utils/__init__.py +0 -0
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit/utils/time.py +0 -0
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit_agents.egg-info/dependency_links.txt +0 -0
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit_agents.egg-info/entry_points.txt +0 -0
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit_agents.egg-info/requires.txt +0 -0
- {fetchkit_agents-0.3.0 → fetchkit_agents-0.4.0}/src/fetchkit_agents.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fetchkit-agents
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: A YAML-configured data fetching library for agentic applications.
|
|
5
5
|
Author-email: mete morris <morrismete@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -50,7 +50,8 @@ Dynamic: license-file
|
|
|
50
50
|
A YAML-configured data-fetching library for agentic applications.
|
|
51
51
|
|
|
52
52
|
`fetchkit` collects posts and comments from sources (Hacker News, RSS/Atom, arXiv,
|
|
53
|
-
GitHub, Lobsters, Stack Exchange, Bluesky, Mastodon
|
|
53
|
+
GitHub, Lobsters, Stack Exchange, Bluesky, Mastodon, Reddit, Google News, GDELT,
|
|
54
|
+
SEC EDGAR, Polymarket, Manifold) into a single canonical `Post`
|
|
54
55
|
model, with de-duplication,
|
|
55
56
|
deterministic sorting, and a shared HTTP client with retries and rate limiting. It is
|
|
56
57
|
designed as the data-collection layer for LLM/agent pipelines — feed it configs, get
|
|
@@ -59,7 +60,8 @@ back clean typed data.
|
|
|
59
60
|
- **YAML-first** configuration with strict validation: unknown or misspelled keys
|
|
60
61
|
are rejected up front, so a bad config fails loudly instead of silently.
|
|
61
62
|
- **Builtin fetchers**: Hacker News, RSS/Atom, arXiv, GitHub, Lobsters, Stack Exchange,
|
|
62
|
-
Bluesky,
|
|
63
|
+
Bluesky, Mastodon, Reddit, Google News, GDELT (global news firehose), SEC EDGAR
|
|
64
|
+
(securities filings), and Polymarket/Manifold (prediction markets) — all zero-auth.
|
|
63
65
|
- **Relative time windows**: say `window: "last 6 hours"` instead of computing
|
|
64
66
|
timestamps.
|
|
65
67
|
- **Open `metadata`**: each `Post` carries a `metadata` dict for source-specific
|
|
@@ -120,6 +122,20 @@ fetchers:
|
|
|
120
122
|
- type: mastodon
|
|
121
123
|
instance: mastodon.social
|
|
122
124
|
tag: ai
|
|
125
|
+
- type: edgar
|
|
126
|
+
companies: ["AAPL", "MSFT"]
|
|
127
|
+
forms: ["8-K", "10-Q"]
|
|
128
|
+
- type: reddit
|
|
129
|
+
subreddits: ["news", "wallstreetbets"]
|
|
130
|
+
listing: new
|
|
131
|
+
- type: googlenews
|
|
132
|
+
resource: search
|
|
133
|
+
query: "nvidia earnings when:6h"
|
|
134
|
+
- type: gdelt
|
|
135
|
+
query: '"interest rates"'
|
|
136
|
+
languages: ["english"]
|
|
137
|
+
- type: polymarket
|
|
138
|
+
query: "fed"
|
|
123
139
|
- type: rss
|
|
124
140
|
feeds:
|
|
125
141
|
- url: "https://feeds.bbci.co.uk/news/rss.xml"
|
|
@@ -156,33 +172,49 @@ Python. `run` prints **only** JSON to stdout (diagnostics go to stderr), so it p
|
|
|
156
172
|
cleanly into `jq`:
|
|
157
173
|
|
|
158
174
|
```bash
|
|
159
|
-
fetchkit run config.yaml # pretty JSON: {"count", "posts", "errors"}
|
|
175
|
+
fetchkit run config.yaml # pretty JSON: {"count", "posts", "sources", "errors"}
|
|
160
176
|
fetchkit run config.yaml -o out.json # write JSON to a file (stdout stays empty)
|
|
161
177
|
fetchkit run config.yaml --window "6h" # override the time window at runtime
|
|
162
178
|
fetchkit run config.yaml --compact # single-line JSON
|
|
163
179
|
fetchkit run config.yaml --fail-on-error # exit 1 if any source failed
|
|
164
|
-
fetchkit
|
|
180
|
+
echo "$CONFIG_YAML" | fetchkit run - # read the config from stdin
|
|
181
|
+
fetchkit validate config.yaml # validate a config without fetching (also accepts -)
|
|
165
182
|
fetchkit schema # JSON Schema for every config/output model
|
|
166
183
|
python -m fetchkit run config.yaml # module form, identical behavior
|
|
167
184
|
```
|
|
168
185
|
|
|
186
|
+
`fetchkit run --help` and `fetchkit validate --help` print the YAML config format
|
|
187
|
+
inline (top-level keys, a minimal example, and the fetcher type list), so simple
|
|
188
|
+
configs need no schema round-trip.
|
|
189
|
+
|
|
169
190
|
`fetchkit schema` lets an agent discover what it can fetch — it prints the JSON
|
|
170
191
|
Schema (with field descriptions) for the top-level config, the shared HTTP
|
|
171
192
|
settings, every builtin fetcher's typed config, and the canonical `Post` output —
|
|
172
|
-
so a config can be written without knowing the YAML format out of band
|
|
193
|
+
so a config can be written without knowing the YAML format out of band. Pass a
|
|
194
|
+
section name to print just that part instead of the full ~50 KB document:
|
|
173
195
|
|
|
174
196
|
```bash
|
|
175
|
-
fetchkit schema | jq '.fetchers | keys' # ["arxiv","bluesky","github","hackernews","lobsters","mastodon","rss","stackexchange"]
|
|
197
|
+
fetchkit schema | jq '.fetchers | keys' # ["arxiv","bluesky","edgar","gdelt","github","googlenews","hackernews","lobsters","manifold","mastodon","polymarket","reddit","rss","stackexchange"]
|
|
198
|
+
fetchkit schema config # just the top-level config schema
|
|
199
|
+
fetchkit schema rss # just one fetcher's config schema
|
|
200
|
+
fetchkit schema post # just the output Post model
|
|
176
201
|
fetchkit schema -o schema.json # write to a file; supports --compact too
|
|
177
202
|
```
|
|
178
203
|
|
|
179
|
-
Output shape
|
|
204
|
+
Output shape — `sources` reports per-fetcher success/failure (one entry per
|
|
205
|
+
enabled fetcher, in config order), so partial failures are visible without
|
|
206
|
+
diffing domains against `posts`. A source can partially fail, e.g. one dead
|
|
207
|
+
feed among many: it keeps its posts, records the error, and reports `ok: false`.
|
|
180
208
|
|
|
181
209
|
```json
|
|
182
210
|
{
|
|
183
211
|
"count": 2,
|
|
184
212
|
"posts": [ { "id": "...", "source": "rss", "title": "...", "url": "...", "created_at": "..." } ],
|
|
185
|
-
"
|
|
213
|
+
"sources": [
|
|
214
|
+
{ "source": "rss", "name": null, "ok": false, "posts": 2,
|
|
215
|
+
"errors": ["Failed to fetch feed https://dead.example/feed.xml: ..."] }
|
|
216
|
+
],
|
|
217
|
+
"errors": [ { "source": "rss", "error": "Failed to fetch feed https://dead.example/feed.xml: ..." } ]
|
|
186
218
|
}
|
|
187
219
|
```
|
|
188
220
|
|
|
@@ -269,6 +301,14 @@ not the live article stream — for the latter, fetch the feed with the `rss`
|
|
|
269
301
|
fetcher and match individual posts. Catalog quality is the main lever on result
|
|
270
302
|
quality; see `src/fetchkit/discovery/data/CATALOG.md` to extend it.
|
|
271
303
|
|
|
304
|
+
Because discovery only *ranks* candidates it already holds, a niche query (a
|
|
305
|
+
specific region, product, or community) can come back filled with generic feeds
|
|
306
|
+
that matched only the query's broad terms. The CLI flags this instead of letting
|
|
307
|
+
it pass: the JSON payload carries `unmatched_terms` (query terms no returned
|
|
308
|
+
feed mentions) plus a `hint`, and the same hint is printed to stderr. When you
|
|
309
|
+
see it, feed discovery better candidates — `--from-urls` with sites from your
|
|
310
|
+
own web search, `fetchkit find-feeds <site-url>`, or `--external`.
|
|
311
|
+
|
|
272
312
|
## Discoverability for every source
|
|
273
313
|
|
|
274
314
|
`discover` solves RSS's "which feed URL?" problem. The other sources have a
|
|
@@ -285,6 +325,12 @@ fetchkit suggest github --query "language:rust stars:>5000" # popular repos to
|
|
|
285
325
|
fetchkit suggest mastodon --instance fosstodon.org # trending hashtags
|
|
286
326
|
fetchkit suggest bluesky # popular custom feeds
|
|
287
327
|
fetchkit suggest bluesky --what actors --query "ai" # accounts for an author_feed
|
|
328
|
+
fetchkit suggest edgar --query apple # tickers/CIKs for an edgar config
|
|
329
|
+
fetchkit suggest reddit --query finance # subreddits for a topic
|
|
330
|
+
fetchkit suggest gdelt --query country # GDELT languages/countries/operators
|
|
331
|
+
fetchkit suggest googlenews # Google News topics + query operators
|
|
332
|
+
fetchkit suggest polymarket --query fed # most active prediction markets
|
|
333
|
+
fetchkit suggest manifold --query "rate cut" # Manifold markets for a topic
|
|
288
334
|
fetchkit suggest rss --query "AI safety news" # delegates to discover()
|
|
289
335
|
```
|
|
290
336
|
|
|
@@ -298,6 +344,12 @@ fetchkit suggest rss --query "AI safety news" # delegates to discov
|
|
|
298
344
|
| `stackexchange` | popular tags, or sites (`--what sites`) | `tagged` / `site` |
|
|
299
345
|
| `bluesky` | popular feeds, or actors (`--what actors`) | `actor` |
|
|
300
346
|
| `mastodon` | trending hashtags on an instance | `tag` / `instance` |
|
|
347
|
+
| `edgar` | company tickers/CIKs matching a query | `companies` |
|
|
348
|
+
| `reddit` | subreddits matching a query | `subreddits` |
|
|
349
|
+
| `gdelt` | languages, country codes, query operators (static) | `languages` / `countries` / `query` |
|
|
350
|
+
| `googlenews` | topic sections + query operators (static) | `topic` / `query` |
|
|
351
|
+
| `polymarket` | most active live markets (by 24h volume) | `query` |
|
|
352
|
+
| `manifold` | live markets matching a query | `query` |
|
|
301
353
|
|
|
302
354
|
> Most suggesters call the source's live API (all no-auth); `hackernews`/`arxiv`
|
|
303
355
|
> are static, and `rss` reuses the offline catalog ranker. Network suggesters fail
|
|
@@ -319,7 +371,9 @@ Set the time window with **either** a relative `window` **or** both
|
|
|
319
371
|
`start_time`/`end_time` — the two are mutually exclusive. **If you specify none of
|
|
320
372
|
them, the window defaults to the last 24 hours.** `start_time <= end_time` is
|
|
321
373
|
enforced, and unknown top-level keys are rejected. Per-fetcher
|
|
322
|
-
`start_time`/`end_time` default to `None` and **inherit** the
|
|
374
|
+
`start_time`/`end_time` default to `None` and **inherit** the run window from these
|
|
375
|
+
top-level keys at runtime (there is no `global:` key — the top level *is* the
|
|
376
|
+
global scope).
|
|
323
377
|
|
|
324
378
|
#### Relative windows
|
|
325
379
|
|
|
@@ -441,6 +495,111 @@ plain text; tags, instance, and visibility are kept in `post.metadata`.
|
|
|
441
495
|
| `local` | false | Restrict to statuses originating on this instance |
|
|
442
496
|
| `max_items`| 50 | 1–200 (paginated, 40/page) |
|
|
443
497
|
|
|
498
|
+
### SEC EDGAR (`type: edgar`)
|
|
499
|
+
|
|
500
|
+
Securities filings from the SEC's free, keyless EDGAR APIs. `resource: filings`
|
|
501
|
+
pulls recent filings per company from `data.sec.gov/submissions` (acceptance
|
|
502
|
+
timestamps are near-real-time — new 8-Ks appear within minutes); `resource: search`
|
|
503
|
+
runs EDGAR full-text search across all filers (date granularity only; the run
|
|
504
|
+
window is passed to the API as a date range). Form type, CIK, accession number,
|
|
505
|
+
and 8-K item codes are kept in `post.metadata`.
|
|
506
|
+
|
|
507
|
+
The SEC's [fair-access policy](https://www.sec.gov/os/accessing-edgar-data) asks
|
|
508
|
+
clients to identify themselves with contact info and stay under 10 req/s — set
|
|
509
|
+
`user_agent` and consider `http.rate_limit_per_host`.
|
|
510
|
+
|
|
511
|
+
| Field | Default | Notes |
|
|
512
|
+
|--------------|----------|--------------------------------------------------------------|
|
|
513
|
+
| `resource` | filings | `filings` (per-company recent) or `search` (full-text) |
|
|
514
|
+
| `companies` | `[]` | Tickers or CIKs — required for `resource: filings` |
|
|
515
|
+
| `forms` | `[]` | Form types to include, e.g. `["8-K", "10-Q"]` (empty = all) |
|
|
516
|
+
| `query` | null | Full-text query — required for `resource: search` |
|
|
517
|
+
| `user_agent` | null | Descriptive UA with contact info, e.g. `myapp me@example.com`|
|
|
518
|
+
| `max_items` | 50 | 1–500 |
|
|
519
|
+
|
|
520
|
+
### Reddit (`type: reddit`)
|
|
521
|
+
|
|
522
|
+
Reddit's public `.json` endpoints with a descriptive User-Agent. `listing: new`
|
|
523
|
+
surfaces posts seconds after submission (engagement is near zero at that point by
|
|
524
|
+
definition); `hot`/`top` carry engagement at the cost of recency. Score,
|
|
525
|
+
comment count, and upvote ratio are captured as of fetch time. Subreddit, flair,
|
|
526
|
+
and upvote ratio are kept in `post.metadata`.
|
|
527
|
+
|
|
528
|
+
> **Terms note:** unauthenticated access is tolerated by Reddit at low volume
|
|
529
|
+
> (~10 requests/minute per IP) but sits in a gray area of Reddit's Data API
|
|
530
|
+
> terms, which formally expect registered OAuth clients. fetchkit issues one
|
|
531
|
+
> request per fetch; keep polling rates low (`http.rate_limit_per_host`).
|
|
532
|
+
> Reddit also blocks many datacenter/cloud IPs outright (403 regardless of
|
|
533
|
+
> User-Agent), so this fetcher may work from a residential connection but not
|
|
534
|
+
> from CI or a cloud host.
|
|
535
|
+
|
|
536
|
+
| Field | Default | Notes |
|
|
537
|
+
|---------------|---------|-------------------------------------------------------------|
|
|
538
|
+
| `subreddits` | `[]` | Without `r/` prefix; combined into one listing request |
|
|
539
|
+
| `listing` | new | `new`, `hot`, `top`, or `rising` (when `query` unset) |
|
|
540
|
+
| `query` | null | Search; restricted to `subreddits` when both are set |
|
|
541
|
+
| `time_filter` | day | For `listing: top` and searches: `hour`…`all` |
|
|
542
|
+
| `max_items` | 50 | 1–100 (single request) |
|
|
543
|
+
|
|
544
|
+
### GDELT (`type: gdelt`)
|
|
545
|
+
|
|
546
|
+
The GDELT Project's DOC 2.0 API — machine-reads worldwide news media in 65
|
|
547
|
+
languages, re-indexed every 15 minutes. A zero-auth global news firehose. Hits
|
|
548
|
+
carry URL, title, timestamp, source domain/country/language (kept in
|
|
549
|
+
`post.metadata`); there is no author, body text, or engagement, so those fields
|
|
550
|
+
are `None`. The run window maps to the API's `startdatetime`/`enddatetime`.
|
|
551
|
+
|
|
552
|
+
| Field | Default | Notes |
|
|
553
|
+
|-------------|---------|----------------------------------------------------------------|
|
|
554
|
+
| `query` | — | Required; keywords/"phrases" plus operators (`domain:`, `tone<-5`) |
|
|
555
|
+
| `languages` | `[]` | Source languages, e.g. `["english", "spanish"]` |
|
|
556
|
+
| `countries` | `[]` | Source countries (GDELT/FIPS codes), e.g. `["US", "UK"]` |
|
|
557
|
+
| `max_items` | 75 | 1–250 |
|
|
558
|
+
|
|
559
|
+
### Google News (`type: googlenews`)
|
|
560
|
+
|
|
561
|
+
Google News' public RSS endpoints: top stories, search, or a topic section.
|
|
562
|
+
Minutes-fresh headlines aggregated from thousands of publishers. The query
|
|
563
|
+
language supports `when:2h` (recency), `site:`, quoted phrases, `-exclusions`,
|
|
564
|
+
and `intitle:`. Links are Google News redirect URLs (they resolve to the
|
|
565
|
+
publisher); the publisher name maps to `author`.
|
|
566
|
+
|
|
567
|
+
| Field | Default | Notes |
|
|
568
|
+
|-------------|---------|----------------------------------------------------------------|
|
|
569
|
+
| `resource` | top | `top`, `search` (needs `query`), or `topic` (needs `topic`) |
|
|
570
|
+
| `query` | null | e.g. `'nvidia earnings when:2h'` |
|
|
571
|
+
| `topic` | null | `WORLD`, `NATION`, `BUSINESS`, `TECHNOLOGY`, `ENTERTAINMENT`, `SPORTS`, `SCIENCE`, `HEALTH` |
|
|
572
|
+
| `language` | en-US | UI language (`hl=`) |
|
|
573
|
+
| `country` | US | Edition (`gl=`/`ceid=`) |
|
|
574
|
+
| `max_items` | 50 | 1–100 |
|
|
575
|
+
|
|
576
|
+
### Polymarket (`type: polymarket`) and Manifold (`type: manifold`)
|
|
577
|
+
|
|
578
|
+
Prediction markets as posts: the market question is the `title`, and live odds,
|
|
579
|
+
volume, and close date land in `post.metadata` (`odds`/`probability`,
|
|
580
|
+
`volume_24h`, …). Odds moving is often a signal about breaking news before
|
|
581
|
+
articles are written. Both APIs are public read-only, no auth.
|
|
582
|
+
|
|
583
|
+
> **Snapshot semantics:** markets are live state, not timestamped events, so
|
|
584
|
+
> these two fetchers deliberately ignore the run window — an active market
|
|
585
|
+
> created months ago is still current. `created_at` is the market's creation
|
|
586
|
+
> time, which also means snapshot posts sort below newer article-shaped posts
|
|
587
|
+
> in a mixed feed.
|
|
588
|
+
|
|
589
|
+
| Field (`polymarket`) | Default | Notes |
|
|
590
|
+
|----------------------|---------|--------------------------------------------------|
|
|
591
|
+
| `query` | null | Substring filter on the question, applied client-side over the top ~100 markets for the chosen `order` (not a full search) |
|
|
592
|
+
| `order` | volume | `volume` (24h), `liquidity`, or `new` |
|
|
593
|
+
| `closed` | false | Include closed/resolved markets |
|
|
594
|
+
| `max_items` | 50 | 1–100 |
|
|
595
|
+
|
|
596
|
+
| Field (`manifold`) | Default | Notes |
|
|
597
|
+
|--------------------|---------|----------------------------------------------------|
|
|
598
|
+
| `query` | null | Full-text search; omit for most recent markets |
|
|
599
|
+
| `market_filter` | open | `open`, `closed`, `resolved`, `all` (searches) |
|
|
600
|
+
| `sort` | score | `score`, `newest`, `liquidity`, `24-hour-vol` |
|
|
601
|
+
| `max_items` | 50 | 1–100 |
|
|
602
|
+
|
|
444
603
|
### HTTP (`http:`)
|
|
445
604
|
|
|
446
605
|
| Field | Default | Notes |
|
|
@@ -492,7 +651,8 @@ columns.
|
|
|
492
651
|
class Post(BaseModel):
|
|
493
652
|
id: str # unique within source
|
|
494
653
|
source: str # "hackernews" | "rss" | "arxiv" | "github" | "lobsters"
|
|
495
|
-
# | "stackexchange" | "bluesky" | "mastodon"
|
|
654
|
+
# | "stackexchange" | "bluesky" | "mastodon" | "edgar"
|
|
655
|
+
# | "reddit" | "gdelt" | "googlenews" | "polymarket" | "manifold"
|
|
496
656
|
title: str | None
|
|
497
657
|
text: str | None # body / content
|
|
498
658
|
url: str | None # external link
|
|
@@ -510,7 +670,9 @@ sorted descending by `(created_at, id)` for deterministic output.
|
|
|
510
670
|
|
|
511
671
|
> **`score` is source-relative.** Each source defines it differently — Hacker News
|
|
512
672
|
> points, Lobsters score, GitHub stars (for `search_repos`), Stack Exchange question
|
|
513
|
-
> score, Bluesky likes, Mastodon favourites,
|
|
673
|
+
> score, Bluesky likes, Mastodon favourites, Reddit score (fuzzed by Reddit, and
|
|
674
|
+
> near zero on brand-new posts), and `None` for arXiv, RSS, Google News, GDELT,
|
|
675
|
+
> EDGAR, and the prediction-market sources. The values
|
|
514
676
|
> are **not comparable across sources**, so don't rank a mixed
|
|
515
677
|
> feed by `score` directly. Compare within a single `source`, or use a source-aware
|
|
516
678
|
> ranking of your own. Output is ordered by recency (`created_at`), not by `score`.
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
A YAML-configured data-fetching library for agentic applications.
|
|
9
9
|
|
|
10
10
|
`fetchkit` collects posts and comments from sources (Hacker News, RSS/Atom, arXiv,
|
|
11
|
-
GitHub, Lobsters, Stack Exchange, Bluesky, Mastodon
|
|
11
|
+
GitHub, Lobsters, Stack Exchange, Bluesky, Mastodon, Reddit, Google News, GDELT,
|
|
12
|
+
SEC EDGAR, Polymarket, Manifold) into a single canonical `Post`
|
|
12
13
|
model, with de-duplication,
|
|
13
14
|
deterministic sorting, and a shared HTTP client with retries and rate limiting. It is
|
|
14
15
|
designed as the data-collection layer for LLM/agent pipelines — feed it configs, get
|
|
@@ -17,7 +18,8 @@ back clean typed data.
|
|
|
17
18
|
- **YAML-first** configuration with strict validation: unknown or misspelled keys
|
|
18
19
|
are rejected up front, so a bad config fails loudly instead of silently.
|
|
19
20
|
- **Builtin fetchers**: Hacker News, RSS/Atom, arXiv, GitHub, Lobsters, Stack Exchange,
|
|
20
|
-
Bluesky,
|
|
21
|
+
Bluesky, Mastodon, Reddit, Google News, GDELT (global news firehose), SEC EDGAR
|
|
22
|
+
(securities filings), and Polymarket/Manifold (prediction markets) — all zero-auth.
|
|
21
23
|
- **Relative time windows**: say `window: "last 6 hours"` instead of computing
|
|
22
24
|
timestamps.
|
|
23
25
|
- **Open `metadata`**: each `Post` carries a `metadata` dict for source-specific
|
|
@@ -78,6 +80,20 @@ fetchers:
|
|
|
78
80
|
- type: mastodon
|
|
79
81
|
instance: mastodon.social
|
|
80
82
|
tag: ai
|
|
83
|
+
- type: edgar
|
|
84
|
+
companies: ["AAPL", "MSFT"]
|
|
85
|
+
forms: ["8-K", "10-Q"]
|
|
86
|
+
- type: reddit
|
|
87
|
+
subreddits: ["news", "wallstreetbets"]
|
|
88
|
+
listing: new
|
|
89
|
+
- type: googlenews
|
|
90
|
+
resource: search
|
|
91
|
+
query: "nvidia earnings when:6h"
|
|
92
|
+
- type: gdelt
|
|
93
|
+
query: '"interest rates"'
|
|
94
|
+
languages: ["english"]
|
|
95
|
+
- type: polymarket
|
|
96
|
+
query: "fed"
|
|
81
97
|
- type: rss
|
|
82
98
|
feeds:
|
|
83
99
|
- url: "https://feeds.bbci.co.uk/news/rss.xml"
|
|
@@ -114,33 +130,49 @@ Python. `run` prints **only** JSON to stdout (diagnostics go to stderr), so it p
|
|
|
114
130
|
cleanly into `jq`:
|
|
115
131
|
|
|
116
132
|
```bash
|
|
117
|
-
fetchkit run config.yaml # pretty JSON: {"count", "posts", "errors"}
|
|
133
|
+
fetchkit run config.yaml # pretty JSON: {"count", "posts", "sources", "errors"}
|
|
118
134
|
fetchkit run config.yaml -o out.json # write JSON to a file (stdout stays empty)
|
|
119
135
|
fetchkit run config.yaml --window "6h" # override the time window at runtime
|
|
120
136
|
fetchkit run config.yaml --compact # single-line JSON
|
|
121
137
|
fetchkit run config.yaml --fail-on-error # exit 1 if any source failed
|
|
122
|
-
fetchkit
|
|
138
|
+
echo "$CONFIG_YAML" | fetchkit run - # read the config from stdin
|
|
139
|
+
fetchkit validate config.yaml # validate a config without fetching (also accepts -)
|
|
123
140
|
fetchkit schema # JSON Schema for every config/output model
|
|
124
141
|
python -m fetchkit run config.yaml # module form, identical behavior
|
|
125
142
|
```
|
|
126
143
|
|
|
144
|
+
`fetchkit run --help` and `fetchkit validate --help` print the YAML config format
|
|
145
|
+
inline (top-level keys, a minimal example, and the fetcher type list), so simple
|
|
146
|
+
configs need no schema round-trip.
|
|
147
|
+
|
|
127
148
|
`fetchkit schema` lets an agent discover what it can fetch — it prints the JSON
|
|
128
149
|
Schema (with field descriptions) for the top-level config, the shared HTTP
|
|
129
150
|
settings, every builtin fetcher's typed config, and the canonical `Post` output —
|
|
130
|
-
so a config can be written without knowing the YAML format out of band
|
|
151
|
+
so a config can be written without knowing the YAML format out of band. Pass a
|
|
152
|
+
section name to print just that part instead of the full ~50 KB document:
|
|
131
153
|
|
|
132
154
|
```bash
|
|
133
|
-
fetchkit schema | jq '.fetchers | keys' # ["arxiv","bluesky","github","hackernews","lobsters","mastodon","rss","stackexchange"]
|
|
155
|
+
fetchkit schema | jq '.fetchers | keys' # ["arxiv","bluesky","edgar","gdelt","github","googlenews","hackernews","lobsters","manifold","mastodon","polymarket","reddit","rss","stackexchange"]
|
|
156
|
+
fetchkit schema config # just the top-level config schema
|
|
157
|
+
fetchkit schema rss # just one fetcher's config schema
|
|
158
|
+
fetchkit schema post # just the output Post model
|
|
134
159
|
fetchkit schema -o schema.json # write to a file; supports --compact too
|
|
135
160
|
```
|
|
136
161
|
|
|
137
|
-
Output shape
|
|
162
|
+
Output shape — `sources` reports per-fetcher success/failure (one entry per
|
|
163
|
+
enabled fetcher, in config order), so partial failures are visible without
|
|
164
|
+
diffing domains against `posts`. A source can partially fail, e.g. one dead
|
|
165
|
+
feed among many: it keeps its posts, records the error, and reports `ok: false`.
|
|
138
166
|
|
|
139
167
|
```json
|
|
140
168
|
{
|
|
141
169
|
"count": 2,
|
|
142
170
|
"posts": [ { "id": "...", "source": "rss", "title": "...", "url": "...", "created_at": "..." } ],
|
|
143
|
-
"
|
|
171
|
+
"sources": [
|
|
172
|
+
{ "source": "rss", "name": null, "ok": false, "posts": 2,
|
|
173
|
+
"errors": ["Failed to fetch feed https://dead.example/feed.xml: ..."] }
|
|
174
|
+
],
|
|
175
|
+
"errors": [ { "source": "rss", "error": "Failed to fetch feed https://dead.example/feed.xml: ..." } ]
|
|
144
176
|
}
|
|
145
177
|
```
|
|
146
178
|
|
|
@@ -227,6 +259,14 @@ not the live article stream — for the latter, fetch the feed with the `rss`
|
|
|
227
259
|
fetcher and match individual posts. Catalog quality is the main lever on result
|
|
228
260
|
quality; see `src/fetchkit/discovery/data/CATALOG.md` to extend it.
|
|
229
261
|
|
|
262
|
+
Because discovery only *ranks* candidates it already holds, a niche query (a
|
|
263
|
+
specific region, product, or community) can come back filled with generic feeds
|
|
264
|
+
that matched only the query's broad terms. The CLI flags this instead of letting
|
|
265
|
+
it pass: the JSON payload carries `unmatched_terms` (query terms no returned
|
|
266
|
+
feed mentions) plus a `hint`, and the same hint is printed to stderr. When you
|
|
267
|
+
see it, feed discovery better candidates — `--from-urls` with sites from your
|
|
268
|
+
own web search, `fetchkit find-feeds <site-url>`, or `--external`.
|
|
269
|
+
|
|
230
270
|
## Discoverability for every source
|
|
231
271
|
|
|
232
272
|
`discover` solves RSS's "which feed URL?" problem. The other sources have a
|
|
@@ -243,6 +283,12 @@ fetchkit suggest github --query "language:rust stars:>5000" # popular repos to
|
|
|
243
283
|
fetchkit suggest mastodon --instance fosstodon.org # trending hashtags
|
|
244
284
|
fetchkit suggest bluesky # popular custom feeds
|
|
245
285
|
fetchkit suggest bluesky --what actors --query "ai" # accounts for an author_feed
|
|
286
|
+
fetchkit suggest edgar --query apple # tickers/CIKs for an edgar config
|
|
287
|
+
fetchkit suggest reddit --query finance # subreddits for a topic
|
|
288
|
+
fetchkit suggest gdelt --query country # GDELT languages/countries/operators
|
|
289
|
+
fetchkit suggest googlenews # Google News topics + query operators
|
|
290
|
+
fetchkit suggest polymarket --query fed # most active prediction markets
|
|
291
|
+
fetchkit suggest manifold --query "rate cut" # Manifold markets for a topic
|
|
246
292
|
fetchkit suggest rss --query "AI safety news" # delegates to discover()
|
|
247
293
|
```
|
|
248
294
|
|
|
@@ -256,6 +302,12 @@ fetchkit suggest rss --query "AI safety news" # delegates to discov
|
|
|
256
302
|
| `stackexchange` | popular tags, or sites (`--what sites`) | `tagged` / `site` |
|
|
257
303
|
| `bluesky` | popular feeds, or actors (`--what actors`) | `actor` |
|
|
258
304
|
| `mastodon` | trending hashtags on an instance | `tag` / `instance` |
|
|
305
|
+
| `edgar` | company tickers/CIKs matching a query | `companies` |
|
|
306
|
+
| `reddit` | subreddits matching a query | `subreddits` |
|
|
307
|
+
| `gdelt` | languages, country codes, query operators (static) | `languages` / `countries` / `query` |
|
|
308
|
+
| `googlenews` | topic sections + query operators (static) | `topic` / `query` |
|
|
309
|
+
| `polymarket` | most active live markets (by 24h volume) | `query` |
|
|
310
|
+
| `manifold` | live markets matching a query | `query` |
|
|
259
311
|
|
|
260
312
|
> Most suggesters call the source's live API (all no-auth); `hackernews`/`arxiv`
|
|
261
313
|
> are static, and `rss` reuses the offline catalog ranker. Network suggesters fail
|
|
@@ -277,7 +329,9 @@ Set the time window with **either** a relative `window` **or** both
|
|
|
277
329
|
`start_time`/`end_time` — the two are mutually exclusive. **If you specify none of
|
|
278
330
|
them, the window defaults to the last 24 hours.** `start_time <= end_time` is
|
|
279
331
|
enforced, and unknown top-level keys are rejected. Per-fetcher
|
|
280
|
-
`start_time`/`end_time` default to `None` and **inherit** the
|
|
332
|
+
`start_time`/`end_time` default to `None` and **inherit** the run window from these
|
|
333
|
+
top-level keys at runtime (there is no `global:` key — the top level *is* the
|
|
334
|
+
global scope).
|
|
281
335
|
|
|
282
336
|
#### Relative windows
|
|
283
337
|
|
|
@@ -399,6 +453,111 @@ plain text; tags, instance, and visibility are kept in `post.metadata`.
|
|
|
399
453
|
| `local` | false | Restrict to statuses originating on this instance |
|
|
400
454
|
| `max_items`| 50 | 1–200 (paginated, 40/page) |
|
|
401
455
|
|
|
456
|
+
### SEC EDGAR (`type: edgar`)
|
|
457
|
+
|
|
458
|
+
Securities filings from the SEC's free, keyless EDGAR APIs. `resource: filings`
|
|
459
|
+
pulls recent filings per company from `data.sec.gov/submissions` (acceptance
|
|
460
|
+
timestamps are near-real-time — new 8-Ks appear within minutes); `resource: search`
|
|
461
|
+
runs EDGAR full-text search across all filers (date granularity only; the run
|
|
462
|
+
window is passed to the API as a date range). Form type, CIK, accession number,
|
|
463
|
+
and 8-K item codes are kept in `post.metadata`.
|
|
464
|
+
|
|
465
|
+
The SEC's [fair-access policy](https://www.sec.gov/os/accessing-edgar-data) asks
|
|
466
|
+
clients to identify themselves with contact info and stay under 10 req/s — set
|
|
467
|
+
`user_agent` and consider `http.rate_limit_per_host`.
|
|
468
|
+
|
|
469
|
+
| Field | Default | Notes |
|
|
470
|
+
|--------------|----------|--------------------------------------------------------------|
|
|
471
|
+
| `resource` | filings | `filings` (per-company recent) or `search` (full-text) |
|
|
472
|
+
| `companies` | `[]` | Tickers or CIKs — required for `resource: filings` |
|
|
473
|
+
| `forms` | `[]` | Form types to include, e.g. `["8-K", "10-Q"]` (empty = all) |
|
|
474
|
+
| `query` | null | Full-text query — required for `resource: search` |
|
|
475
|
+
| `user_agent` | null | Descriptive UA with contact info, e.g. `myapp me@example.com`|
|
|
476
|
+
| `max_items` | 50 | 1–500 |
|
|
477
|
+
|
|
478
|
+
### Reddit (`type: reddit`)
|
|
479
|
+
|
|
480
|
+
Reddit's public `.json` endpoints with a descriptive User-Agent. `listing: new`
|
|
481
|
+
surfaces posts seconds after submission (engagement is near zero at that point by
|
|
482
|
+
definition); `hot`/`top` carry engagement at the cost of recency. Score,
|
|
483
|
+
comment count, and upvote ratio are captured as of fetch time. Subreddit, flair,
|
|
484
|
+
and upvote ratio are kept in `post.metadata`.
|
|
485
|
+
|
|
486
|
+
> **Terms note:** unauthenticated access is tolerated by Reddit at low volume
|
|
487
|
+
> (~10 requests/minute per IP) but sits in a gray area of Reddit's Data API
|
|
488
|
+
> terms, which formally expect registered OAuth clients. fetchkit issues one
|
|
489
|
+
> request per fetch; keep polling rates low (`http.rate_limit_per_host`).
|
|
490
|
+
> Reddit also blocks many datacenter/cloud IPs outright (403 regardless of
|
|
491
|
+
> User-Agent), so this fetcher may work from a residential connection but not
|
|
492
|
+
> from CI or a cloud host.
|
|
493
|
+
|
|
494
|
+
| Field | Default | Notes |
|
|
495
|
+
|---------------|---------|-------------------------------------------------------------|
|
|
496
|
+
| `subreddits` | `[]` | Without `r/` prefix; combined into one listing request |
|
|
497
|
+
| `listing` | new | `new`, `hot`, `top`, or `rising` (when `query` unset) |
|
|
498
|
+
| `query` | null | Search; restricted to `subreddits` when both are set |
|
|
499
|
+
| `time_filter` | day | For `listing: top` and searches: `hour`…`all` |
|
|
500
|
+
| `max_items` | 50 | 1–100 (single request) |
|
|
501
|
+
|
|
502
|
+
### GDELT (`type: gdelt`)
|
|
503
|
+
|
|
504
|
+
The GDELT Project's DOC 2.0 API — machine-reads worldwide news media in 65
|
|
505
|
+
languages, re-indexed every 15 minutes. A zero-auth global news firehose. Hits
|
|
506
|
+
carry URL, title, timestamp, source domain/country/language (kept in
|
|
507
|
+
`post.metadata`); there is no author, body text, or engagement, so those fields
|
|
508
|
+
are `None`. The run window maps to the API's `startdatetime`/`enddatetime`.
|
|
509
|
+
|
|
510
|
+
| Field | Default | Notes |
|
|
511
|
+
|-------------|---------|----------------------------------------------------------------|
|
|
512
|
+
| `query` | — | Required; keywords/"phrases" plus operators (`domain:`, `tone<-5`) |
|
|
513
|
+
| `languages` | `[]` | Source languages, e.g. `["english", "spanish"]` |
|
|
514
|
+
| `countries` | `[]` | Source countries (GDELT/FIPS codes), e.g. `["US", "UK"]` |
|
|
515
|
+
| `max_items` | 75 | 1–250 |
|
|
516
|
+
|
|
517
|
+
### Google News (`type: googlenews`)
|
|
518
|
+
|
|
519
|
+
Google News' public RSS endpoints: top stories, search, or a topic section.
|
|
520
|
+
Minutes-fresh headlines aggregated from thousands of publishers. The query
|
|
521
|
+
language supports `when:2h` (recency), `site:`, quoted phrases, `-exclusions`,
|
|
522
|
+
and `intitle:`. Links are Google News redirect URLs (they resolve to the
|
|
523
|
+
publisher); the publisher name maps to `author`.
|
|
524
|
+
|
|
525
|
+
| Field | Default | Notes |
|
|
526
|
+
|-------------|---------|----------------------------------------------------------------|
|
|
527
|
+
| `resource` | top | `top`, `search` (needs `query`), or `topic` (needs `topic`) |
|
|
528
|
+
| `query` | null | e.g. `'nvidia earnings when:2h'` |
|
|
529
|
+
| `topic` | null | `WORLD`, `NATION`, `BUSINESS`, `TECHNOLOGY`, `ENTERTAINMENT`, `SPORTS`, `SCIENCE`, `HEALTH` |
|
|
530
|
+
| `language` | en-US | UI language (`hl=`) |
|
|
531
|
+
| `country` | US | Edition (`gl=`/`ceid=`) |
|
|
532
|
+
| `max_items` | 50 | 1–100 |
|
|
533
|
+
|
|
534
|
+
### Polymarket (`type: polymarket`) and Manifold (`type: manifold`)
|
|
535
|
+
|
|
536
|
+
Prediction markets as posts: the market question is the `title`, and live odds,
|
|
537
|
+
volume, and close date land in `post.metadata` (`odds`/`probability`,
|
|
538
|
+
`volume_24h`, …). Odds moving is often a signal about breaking news before
|
|
539
|
+
articles are written. Both APIs are public read-only, no auth.
|
|
540
|
+
|
|
541
|
+
> **Snapshot semantics:** markets are live state, not timestamped events, so
|
|
542
|
+
> these two fetchers deliberately ignore the run window — an active market
|
|
543
|
+
> created months ago is still current. `created_at` is the market's creation
|
|
544
|
+
> time, which also means snapshot posts sort below newer article-shaped posts
|
|
545
|
+
> in a mixed feed.
|
|
546
|
+
|
|
547
|
+
| Field (`polymarket`) | Default | Notes |
|
|
548
|
+
|----------------------|---------|--------------------------------------------------|
|
|
549
|
+
| `query` | null | Substring filter on the question, applied client-side over the top ~100 markets for the chosen `order` (not a full search) |
|
|
550
|
+
| `order` | volume | `volume` (24h), `liquidity`, or `new` |
|
|
551
|
+
| `closed` | false | Include closed/resolved markets |
|
|
552
|
+
| `max_items` | 50 | 1–100 |
|
|
553
|
+
|
|
554
|
+
| Field (`manifold`) | Default | Notes |
|
|
555
|
+
|--------------------|---------|----------------------------------------------------|
|
|
556
|
+
| `query` | null | Full-text search; omit for most recent markets |
|
|
557
|
+
| `market_filter` | open | `open`, `closed`, `resolved`, `all` (searches) |
|
|
558
|
+
| `sort` | score | `score`, `newest`, `liquidity`, `24-hour-vol` |
|
|
559
|
+
| `max_items` | 50 | 1–100 |
|
|
560
|
+
|
|
402
561
|
### HTTP (`http:`)
|
|
403
562
|
|
|
404
563
|
| Field | Default | Notes |
|
|
@@ -450,7 +609,8 @@ columns.
|
|
|
450
609
|
class Post(BaseModel):
|
|
451
610
|
id: str # unique within source
|
|
452
611
|
source: str # "hackernews" | "rss" | "arxiv" | "github" | "lobsters"
|
|
453
|
-
# | "stackexchange" | "bluesky" | "mastodon"
|
|
612
|
+
# | "stackexchange" | "bluesky" | "mastodon" | "edgar"
|
|
613
|
+
# | "reddit" | "gdelt" | "googlenews" | "polymarket" | "manifold"
|
|
454
614
|
title: str | None
|
|
455
615
|
text: str | None # body / content
|
|
456
616
|
url: str | None # external link
|
|
@@ -468,7 +628,9 @@ sorted descending by `(created_at, id)` for deterministic output.
|
|
|
468
628
|
|
|
469
629
|
> **`score` is source-relative.** Each source defines it differently — Hacker News
|
|
470
630
|
> points, Lobsters score, GitHub stars (for `search_repos`), Stack Exchange question
|
|
471
|
-
> score, Bluesky likes, Mastodon favourites,
|
|
631
|
+
> score, Bluesky likes, Mastodon favourites, Reddit score (fuzzed by Reddit, and
|
|
632
|
+
> near zero on brand-new posts), and `None` for arXiv, RSS, Google News, GDELT,
|
|
633
|
+
> EDGAR, and the prediction-market sources. The values
|
|
472
634
|
> are **not comparable across sources**, so don't rank a mixed
|
|
473
635
|
> feed by `score` directly. Compare within a single `source`, or use a source-aware
|
|
474
636
|
> ranking of your own. Output is ordered by recency (`created_at`), not by `score`.
|
|
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
|
|
|
6
6
|
# Distribution name on PyPI. The importable package and CLI are still `fetchkit`;
|
|
7
7
|
# the `fetchkit` PyPI name was already taken by an unrelated project.
|
|
8
8
|
name = "fetchkit-agents"
|
|
9
|
-
version = "0.
|
|
9
|
+
version = "0.4.0"
|
|
10
10
|
description = "A YAML-configured data fetching library for agentic applications."
|
|
11
11
|
readme = "README.md"
|
|
12
12
|
requires-python = ">=3.10"
|
|
@@ -19,7 +19,7 @@ See the README for the full configuration reference and the guide to adding
|
|
|
19
19
|
fetchers.
|
|
20
20
|
"""
|
|
21
21
|
|
|
22
|
-
__version__ = "0.
|
|
22
|
+
__version__ = "0.4.0"
|
|
23
23
|
|
|
24
24
|
from typing import TYPE_CHECKING, Any
|
|
25
25
|
|
|
@@ -55,6 +55,12 @@ from fetchkit.schemas.fetcher import (
|
|
|
55
55
|
StackExchangeFetchConfig,
|
|
56
56
|
BlueskyFetchConfig,
|
|
57
57
|
MastodonFetchConfig,
|
|
58
|
+
EdgarFetchConfig,
|
|
59
|
+
RedditFetchConfig,
|
|
60
|
+
GdeltFetchConfig,
|
|
61
|
+
GoogleNewsFetchConfig,
|
|
62
|
+
PolymarketFetchConfig,
|
|
63
|
+
ManifoldFetchConfig,
|
|
58
64
|
FetcherConfig,
|
|
59
65
|
)
|
|
60
66
|
from fetchkit.schemas.collector import CollectorResult
|
|
@@ -121,6 +127,12 @@ __all__ = [
|
|
|
121
127
|
"StackExchangeFetchConfig",
|
|
122
128
|
"BlueskyFetchConfig",
|
|
123
129
|
"MastodonFetchConfig",
|
|
130
|
+
"EdgarFetchConfig",
|
|
131
|
+
"RedditFetchConfig",
|
|
132
|
+
"GdeltFetchConfig",
|
|
133
|
+
"GoogleNewsFetchConfig",
|
|
134
|
+
"PolymarketFetchConfig",
|
|
135
|
+
"ManifoldFetchConfig",
|
|
124
136
|
"FetcherConfig",
|
|
125
137
|
"CollectorResult",
|
|
126
138
|
"FetchKitConfig",
|