Add AI topics, a sources discovery command, and intelligence-radar's pointer sources.
Topics ai.benchmarks, ai.pricing and ai.models; 'sources --repo' lists visible sources matching a repo's topics. Registers the five ir-* URL sources contributed by intelligence-radar (IR-WP-0010-T04). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 7780@bnt-lap001 Assistant-Session: 622cd705-cb31-4322-ba08-dd42e44fa583
This commit is contained in:
parent
ac8227eead
commit
c810fe6dfe
11 changed files with 117 additions and 2 deletions
|
|
@ -106,6 +106,7 @@ Python 3.11+ standard library only; no install step.
|
|||
| `python3 -m inbound_library run-due` | one timer wake; safe to repeat |
|
||||
| `python3 -m inbound_library new --repo <r> [--topic t] [--since iso]` | pull notices |
|
||||
| `python3 -m inbound_library show <item>` / `get <item>` | derived text / original bytes |
|
||||
| `python3 -m inbound_library sources --repo <r> [--topic t]` | registered sources a repo may see that match its topics (URL sources are pointers, never fetched) |
|
||||
| `python3 -m inbound_library health` | last scan, silence, quarantine, pending notices |
|
||||
|
||||
Retained mail lives in the gitignored `data/` (see `docs/data-contracts.md`).
|
||||
|
|
|
|||
|
|
@ -76,6 +76,10 @@ subscriptions may only use registered topics.
|
|||
| `cadence` | `daily`, `weekly` or `irregular`; daily and weekly email sources are watched for silence (36 h or 9 days) |
|
||||
| `visibility` | `shared` (any matching repo) or `restricted` (owner only) |
|
||||
|
||||
A `url` source is a pointer. The library does not fetch it, so it produces no
|
||||
items or notices. Repos find these sources with `sources --repo <r>`. Extra
|
||||
descriptive fields such as `publisher` and `notes` are allowed.
|
||||
|
||||
## Subscription
|
||||
|
||||
| Field | Meaning |
|
||||
|
|
|
|||
|
|
@ -81,6 +81,9 @@ def main(argv=None):
|
|||
get = sub.add_parser('get', help='write the original bytes of an item to stdout')
|
||||
get.add_argument('item')
|
||||
sub.add_parser('health', help='last scan, per-source counts, silence, quarantine')
|
||||
sources = sub.add_parser('sources', help='list registered sources a repo may see, by topic')
|
||||
sources.add_argument('--repo', required=True)
|
||||
sources.add_argument('--topic', help='limit to one topic (default: the repo subscription topics)')
|
||||
args = parser.parse_args(argv)
|
||||
root = Path(args.root)
|
||||
config = _config(root, args.config)
|
||||
|
|
@ -121,6 +124,9 @@ def main(argv=None):
|
|||
if args.command == 'get':
|
||||
sys.stdout.buffer.write(store.get_item(root, args.item))
|
||||
return 0
|
||||
if args.command == 'sources':
|
||||
_print(reg.sources_for(reg.load(root), args.repo, args.topic))
|
||||
return 0
|
||||
if args.command == 'health':
|
||||
report = notify.health(root)
|
||||
_print(report)
|
||||
|
|
|
|||
|
|
@ -120,3 +120,20 @@ def subscribers_for(registry, source_id):
|
|||
set(source.get('topics', [])) & set(subscription.get('topics', [])):
|
||||
matched.append(repo)
|
||||
return matched
|
||||
|
||||
|
||||
def sources_for(registry, repo, topic=None):
|
||||
"""Sources visible to a repo whose topics match its subscription (or one topic).
|
||||
|
||||
URL sources are pointers: the library lists them and does not fetch them.
|
||||
"""
|
||||
if topic:
|
||||
wanted = {topic}
|
||||
else:
|
||||
subscription = registry['subscriptions'].get(repo, {})
|
||||
wanted = set(subscription.get('topics', []))
|
||||
listed = []
|
||||
for ident, source in sorted(visible_sources(registry, repo).items()):
|
||||
if wanted & set(source.get('topics', [])):
|
||||
listed.append({key: value for key, value in source.items() if key != '_file'})
|
||||
return listed
|
||||
|
|
|
|||
13
registry/sources/ir-anthropic-pricing.json
Normal file
13
registry/sources/ir-anthropic-pricing.json
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"id": "ir-anthropic-pricing",
|
||||
"owner_repo": "intelligence-radar",
|
||||
"channel": "url",
|
||||
"url": "https://claude.com/pricing",
|
||||
"topics": [
|
||||
"ai.pricing"
|
||||
],
|
||||
"cadence": "irregular",
|
||||
"visibility": "shared",
|
||||
"publisher": "Anthropic",
|
||||
"notes": "Primary source captured by intelligence-radar (catalog/sources.json id anthropic-pricing). Pointer only; inbound-library does not fetch it."
|
||||
}
|
||||
13
registry/sources/ir-anthropic-sonnet-launch.json
Normal file
13
registry/sources/ir-anthropic-sonnet-launch.json
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"id": "ir-anthropic-sonnet-launch",
|
||||
"owner_repo": "intelligence-radar",
|
||||
"channel": "url",
|
||||
"url": "https://www.anthropic.com/news/claude-sonnet-5",
|
||||
"topics": [
|
||||
"ai.models"
|
||||
],
|
||||
"cadence": "irregular",
|
||||
"visibility": "shared",
|
||||
"publisher": "Anthropic",
|
||||
"notes": "Primary source captured by intelligence-radar (catalog/sources.json id anthropic-sonnet-launch). Pointer only; inbound-library does not fetch it."
|
||||
}
|
||||
13
registry/sources/ir-anthropic-sonnet.json
Normal file
13
registry/sources/ir-anthropic-sonnet.json
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"id": "ir-anthropic-sonnet",
|
||||
"owner_repo": "intelligence-radar",
|
||||
"channel": "url",
|
||||
"url": "https://www.anthropic.com/claude/sonnet",
|
||||
"topics": [
|
||||
"ai.models"
|
||||
],
|
||||
"cadence": "irregular",
|
||||
"visibility": "shared",
|
||||
"publisher": "Anthropic",
|
||||
"notes": "Primary source captured by intelligence-radar (catalog/sources.json id anthropic-sonnet). Pointer only; inbound-library does not fetch it."
|
||||
}
|
||||
14
registry/sources/ir-openrouter-models.json
Normal file
14
registry/sources/ir-openrouter-models.json
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"id": "ir-openrouter-models",
|
||||
"owner_repo": "intelligence-radar",
|
||||
"channel": "url",
|
||||
"url": "https://openrouter.ai/api/v1/models",
|
||||
"topics": [
|
||||
"ai.models",
|
||||
"ai.pricing"
|
||||
],
|
||||
"cadence": "irregular",
|
||||
"visibility": "shared",
|
||||
"publisher": "OpenRouter",
|
||||
"notes": "Primary source captured by intelligence-radar (catalog/sources.json id openrouter-models). Pointer only; inbound-library does not fetch it."
|
||||
}
|
||||
13
registry/sources/ir-swe-bench.json
Normal file
13
registry/sources/ir-swe-bench.json
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"id": "ir-swe-bench",
|
||||
"owner_repo": "intelligence-radar",
|
||||
"channel": "url",
|
||||
"url": "https://www.swebench.com/",
|
||||
"topics": [
|
||||
"ai.benchmarks"
|
||||
],
|
||||
"cadence": "irregular",
|
||||
"visibility": "shared",
|
||||
"publisher": "SWE-bench maintainers",
|
||||
"notes": "Primary source captured by intelligence-radar (catalog/sources.json id swe-bench). Pointer only; inbound-library does not fetch it."
|
||||
}
|
||||
|
|
@ -1,7 +1,10 @@
|
|||
{
|
||||
"version": 2,
|
||||
"version": 3,
|
||||
"topics": {
|
||||
"intelligence.daily-brief": "Daily editorial brief on intelligence and AI (automation-generated, unreviewed)",
|
||||
"intelligence.weekly-brief": "Weekly editorial brief on intelligence and AI (automation-generated, unreviewed)"
|
||||
"intelligence.weekly-brief": "Weekly editorial brief on intelligence and AI (automation-generated, unreviewed)",
|
||||
"ai.benchmarks": "Capability benchmarks and leaderboards for AI systems (primary maintainer pages)",
|
||||
"ai.pricing": "Published prices and availability of AI models and APIs",
|
||||
"ai.models": "Model releases, model cards and provider model catalogs"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -98,6 +98,24 @@ class Library(unittest.TestCase):
|
|||
self.assertEqual(reg.validate(registry), [])
|
||||
self.assertEqual(reg.subscribers_for(registry, 'arxiv-agents'), ['markitect'])
|
||||
|
||||
def test_sources_lists_visible_matches_only(self):
|
||||
write(self.root / 'registry' / 'sources' / 'arxiv-agents.json', {
|
||||
'id': 'arxiv-agents', 'owner_repo': 'intelligence-radar', 'channel': 'url',
|
||||
'url': 'https://arxiv.org/list/cs.MA/recent', 'topics': ['research.papers'],
|
||||
'cadence': 'irregular', 'visibility': 'shared'})
|
||||
write(self.root / 'registry' / 'sources' / 'private.json', {
|
||||
'id': 'private', 'owner_repo': 'intelligence-radar', 'channel': 'url',
|
||||
'url': 'https://example.org', 'topics': ['research.papers'],
|
||||
'cadence': 'irregular', 'visibility': 'restricted'})
|
||||
write(self.root / 'registry' / 'subscriptions' / 'markitect.json', {
|
||||
'repo': 'markitect', 'agent': 'markitect', 'topics': ['research.papers'],
|
||||
'channels': ['pull']})
|
||||
registry = reg.load(self.root)
|
||||
self.assertEqual([s['id'] for s in reg.sources_for(registry, 'markitect')], ['arxiv-agents'])
|
||||
self.assertEqual([s['id'] for s in reg.sources_for(registry, 'intelligence-radar',
|
||||
'research.papers')],
|
||||
['arxiv-agents', 'private'])
|
||||
|
||||
# Intake
|
||||
def test_scan_retains_message_attachment_and_provenance(self):
|
||||
self.drop('1.eml', mail('Grok <noreply@x.ai>', 'Daily brief', 'Body text', b'attached'))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue