Skip to main content

Evidence System Guide

The Aragora Evidence system provides connectors for grounding debates in real-world data. Each connector integrates with the provenance system for full traceability and reliability scoring.

Overview​

Evidence connectors fetch data from external sources and return Evidence objects that include:

  • Content and metadata
  • Confidence and authority scores
  • Provenance tracking for debate traceability

Available Connectors​

ConnectorSourceAPI Key RequiredUse Case
LocalDocsConnectorLocal filesNoDocumentation, code, markdown
GitHubConnectorGitHub APIOptionalIssues, PRs, discussions
WebConnectorWeb searchNoLive web content
ArXivConnectorarXiv.orgNoAcademic papers
HackerNewsConnectorHacker NewsNoTech community discussions
WikipediaConnectorWikipediaNoEncyclopedia articles
RedditConnectorReddit APIOptionalCommunity discussions
TwitterConnectorTwitter/X APIYesReal-time discourse
SQLConnectorSQL databasesNoPostgreSQL, MySQL, SQLite
NewsAPIConnectorNewsAPIYesNews articles
SECConnectorSEC EDGARNoFinancial filings

Quick Start​

from aragora.connectors import ArXivConnector, Evidence

# Create connector
connector = ArXivConnector()

# Search for evidence
results = connector.search("large language model safety", max_results=5)

for evidence in results:
print(f"Title: {evidence.title}")
print(f"Score: {evidence.reliability_score:.2f}")
print(f"URL: {evidence.url}")
print("---")

Evidence Object​

Every connector returns Evidence objects with standardized fields:

@dataclass
class Evidence:
id: str # Unique identifier
source_type: SourceType # Type of source (paper, article, etc.)
source_id: str # URL, file path, or identifier
content: str # Main text content
title: str # Title or headline

# Metadata
created_at: str | None # Publication/creation date
author: str | None # Author or source
url: str | None # Link to original

# Reliability scores (0.0 to 1.0)
confidence: float # Base confidence in source
freshness: float # How recent (decays over time)
authority: float # Source authority rating

metadata: dict # Additional connector-specific data

Reliability Score​

The combined reliability score is computed as:

reliability = 0.4 * confidence + 0.3 * freshness + 0.3 * authority

Connector Details​

LocalDocsConnector​

Search local documentation, markdown files, and code.

from aragora.connectors import LocalDocsConnector

connector = LocalDocsConnector(
root_paths=["./docs", "./src"],
extensions=[".md", ".py", ".txt"],
)

results = connector.search("authentication flow")

ArXivConnector​

Search academic papers on arXiv.org.

from aragora.connectors import ArXivConnector, ARXIV_CATEGORIES

connector = ArXivConnector(
categories=["cs.AI", "cs.LG"], # Filter by category
max_age_days=365, # Only recent papers
)

results = connector.search("transformer architecture")

# Available categories
print(ARXIV_CATEGORIES) # {'cs.AI': 'Artificial Intelligence', ...}

NewsAPIConnector​

Fetch news articles from multiple sources with credibility scoring.

from aragora.connectors import (
NewsAPIConnector,
HIGH_CREDIBILITY_SOURCES,
MEDIUM_CREDIBILITY_SOURCES,
)

connector = NewsAPIConnector(
api_key="your-newsapi-key",
preferred_sources=HIGH_CREDIBILITY_SOURCES, # Reuters, AP, etc.
)

results = connector.search("artificial intelligence regulation")

Credibility tiers:

  • HIGH_CREDIBILITY_SOURCES: Major news agencies (Reuters, AP, BBC, etc.)
  • MEDIUM_CREDIBILITY_SOURCES: Quality publications with editorial standards

SECConnector​

Access SEC EDGAR financial filings.

from aragora.connectors import SECConnector, FORM_TYPES

connector = SECConnector()

# Search by company
results = connector.search("Apple Inc", form_types=["10-K", "10-Q"])

# Fetch specific filing
filing = connector.fetch("0000320193-24-000123")

# Available form types
print(FORM_TYPES) # {'10-K': 'Annual report', '10-Q': 'Quarterly report', ...}

GitHubConnector​

Fetch issues, pull requests, and discussions.

from aragora.connectors import GitHubConnector

connector = GitHubConnector(
token="ghp_...", # Optional, increases rate limits
repos=["anthropics/claude-code", "langchain-ai/langchain"],
)

# Search issues
issues = connector.search("memory leak", content_type="issues")

# Fetch specific issue
issue = connector.fetch("anthropics/claude-code/issues/123")

WebConnector​

Search and fetch live web content.

from aragora.connectors import WebConnector

connector = WebConnector(
user_agent="AragonaBot/1.0",
timeout=30,
)

results = connector.search("AI safety research 2024")

SQLConnector​

Query SQL databases directly.

from aragora.connectors import SQLConnector, SQLQueryResult

connector = SQLConnector(
connection_string="postgresql://user:pass@localhost/db"
)

# Execute query
result: SQLQueryResult = connector.query(
"SELECT * FROM debates WHERE topic LIKE %s",
params=["%AI%"],
)

print(f"Found {result.row_count} rows")
for row in result.rows:
print(row)

WikipediaConnector​

Search Wikipedia articles.

from aragora.connectors import WikipediaConnector

connector = WikipediaConnector(
language="en",
max_section_depth=2, # Include subsections
)

results = connector.search("artificial general intelligence")

HackerNewsConnector​

Search Hacker News stories and comments.

from aragora.connectors import HackerNewsConnector

connector = HackerNewsConnector(
include_comments=True,
min_score=50, # Filter by points
)

results = connector.search("Claude AI")

RedditConnector​

Search Reddit posts and comments.

from aragora.connectors import RedditConnector

connector = RedditConnector(
client_id="...",
client_secret="...",
subreddits=["MachineLearning", "LocalLLaMA"],
)

results = connector.search("fine-tuning techniques")

TwitterConnector​

Search Twitter/X posts.

from aragora.connectors import TwitterConnector

connector = TwitterConnector(
bearer_token="...",
max_results=100,
)

results = connector.search("AI safety debate")

Error Handling​

All connectors use a standardized exception hierarchy:

from aragora.connectors import (
ConnectorError, # Base exception
ConnectorAuthError, # Authentication failed
ConnectorRateLimitError, # Rate limit exceeded
ConnectorTimeoutError, # Request timed out
ConnectorNetworkError, # Network connectivity issue
ConnectorAPIError, # API returned error
ConnectorValidationError, # Invalid input
ConnectorNotFoundError, # Resource not found
ConnectorQuotaError, # Quota exceeded
ConnectorParseError, # Failed to parse response
is_retryable_error, # Check if error is retryable
get_retry_delay, # Get recommended retry delay
)

try:
results = connector.search("query")
except ConnectorRateLimitError as e:
delay = get_retry_delay(e)
print(f"Rate limited. Retry after \{delay\}s")
except ConnectorAuthError:
print("Check your API credentials")
except ConnectorError as e:
if is_retryable_error(e):
# Retry with backoff
pass

Provenance Integration​

Evidence automatically integrates with the provenance system:

from aragora.connectors import ArXivConnector
from aragora.reasoning.provenance import ProvenanceManager

manager = ProvenanceManager()
connector = ArXivConnector(provenance_manager=manager)

# Evidence is automatically recorded
results = connector.search("reinforcement learning")

# View provenance chain
for evidence in results:
record = manager.get_record(evidence.id)
print(f"Source: {record.source_type}")
print(f"Confidence: {record.confidence}")

Custom Connectors​

Create custom connectors by extending BaseConnector:

from aragora.connectors import BaseConnector, Evidence
from aragora.reasoning.provenance import SourceType

class MyCustomConnector(BaseConnector):
"""Custom connector for my data source."""

source_type = SourceType.CUSTOM
default_confidence = 0.7

def search(self, query: str, max_results: int = 10) -> list[Evidence]:
# Implement search logic
results = self._fetch_from_api(query, max_results)
return [self._to_evidence(r) for r in results]

def fetch(self, evidence_id: str) -> Evidence | None:
# Implement fetch by ID
data = self._fetch_by_id(evidence_id)
return self._to_evidence(data) if data else None

def _to_evidence(self, data: dict) -> Evidence:
return Evidence(
id=data["id"],
source_type=self.source_type,
source_id=data["url"],
content=data["text"],
title=data["title"],
confidence=self.default_confidence,
authority=data.get("authority", 0.5),
url=data["url"],
)

Environment Variables​

Configure connectors via environment variables:

VariableConnectorDescription
NEWSAPI_KEYNewsAPIConnectorNewsAPI API key
GITHUB_TOKENGitHubConnectorGitHub personal access token
TWITTER_BEARER_TOKENTwitterConnectorTwitter API bearer token
REDDIT_CLIENT_IDRedditConnectorReddit OAuth client ID
REDDIT_CLIENT_SECRETRedditConnectorReddit OAuth client secret

Best Practices​

  1. Rate Limiting: Respect API rate limits. Use get_retry_delay() for backoff.

  2. Caching: Enable caching for repeated queries:

    connector = ArXivConnector(cache_ttl=3600)  # 1 hour cache
  3. Filtering: Use source-specific filters to improve relevance:

    connector = NewsAPIConnector(
    preferred_sources=HIGH_CREDIBILITY_SOURCES,
    language="en",
    )
  4. Error Recovery: Always handle errors gracefully:

    try:
    results = connector.search(query)
    except ConnectorError:
    results = [] # Fallback to empty results
  5. Provenance: Always use provenance tracking in production:

    connector = ArXivConnector(provenance_manager=manager)

Testing​

Mock connectors for testing:

from unittest.mock import Mock
from aragora.connectors import Evidence
from aragora.reasoning.provenance import SourceType

def test_with_mock_connector():
mock_connector = Mock()
mock_connector.search.return_value = [
Evidence(
id="test-1",
source_type=SourceType.PAPER,
source_id="https://example.com",
content="Test content",
title="Test Paper",
confidence=0.9,
)
]

results = mock_connector.search("test query")
assert len(results) == 1
assert results[0].confidence == 0.9

REST API Reference​

The Evidence API provides HTTP endpoints for managing evidence collection and storage.

Authentication​

All endpoints require authentication via Authorization: Bearer <token> header when ARAGORA_API_TOKEN is set.

Rate Limits​

OperationLimit
Read operations (GET)60 requests/minute
Write operations (POST, DELETE)10 requests/minute

Endpoints​

List Evidence​

GET /api/evidence

Query Parameters:

ParameterTypeDefaultDescription
limitint20Maximum results to return
offsetint0Pagination offset
sourcestring-Filter by source name
min_reliabilityfloat0.0Minimum reliability score (0.0-1.0)

Response:

{
"evidence": [...],
"total": 150,
"limit": 20,
"offset": 0
}

Get Evidence by ID​

GET /api/evidence/:id

Response:

{
"evidence": {
"id": "evid-abc123",
"source": "arxiv",
"title": "Large Language Model Safety",
"snippet": "...",
"url": "https://arxiv.org/abs/...",
"reliability_score": 0.85,
"metadata": {...}
}
}

Errors:

  • 404 - Evidence not found

Search Evidence​

POST /api/evidence/search

Request Body:

{
"query": "AI safety techniques",
"limit": 20,
"source": "arxiv",
"min_reliability": 0.5,
"context": {
"topic": "AI alignment",
"keywords": ["safety", "alignment"],
"preferred_sources": ["arxiv", "nature"],
"max_age_days": 365
}
}

Response:

{
"query": "AI safety techniques",
"results": [...],
"count": 15
}

Collect Evidence​

Collect new evidence from configured connectors.

POST /api/evidence/collect

Request Body:

{
"task": "What are the best practices for AI safety?",
"connectors": ["arxiv", "hackernews"],
"debate_id": "debate-123",
"round": 2
}

Response:

{
"task": "What are the best practices for AI safety?",
"keywords": ["AI", "safety", "best practices"],
"snippets": [...],
"count": 12,
"total_searched": 45,
"average_reliability": 0.78,
"average_freshness": 0.65,
"saved_ids": ["evid-1", "evid-2"],
"debate_id": "debate-123"
}

Get Debate Evidence​

GET /api/evidence/debate/:debate_id

Query Parameters:

ParameterTypeDescription
roundintFilter by debate round (optional)

Response:

{
"debate_id": "debate-123",
"round": 2,
"evidence": [...],
"count": 8
}

Associate Evidence with Debate​

POST /api/evidence/debate/:debate_id

Request Body:

{
"evidence_ids": ["evid-1", "evid-2", "evid-3"],
"round": 2
}

Response:

{
"debate_id": "debate-123",
"associated": ["evid-1", "evid-2", "evid-3"],
"count": 3
}

Delete Evidence​

DELETE /api/evidence/:id

Response:

{
"deleted": true,
"evidence_id": "evid-abc123"
}

Errors:

  • 404 - Evidence not found

Get Statistics​

GET /api/evidence/statistics

Response:

{
"statistics": {
"total_evidence": 1250,
"sources": {
"arxiv": 450,
"hackernews": 320,
"wikipedia": 280,
"newsapi": 200
},
"average_reliability": 0.72,
"debates_with_evidence": 45
}
}

Error Responses​

All errors return JSON in this format:

{
"error": "Evidence not found: evid-invalid",
"code": "NOT_FOUND"
}
StatusCodeDescription
400VALIDATION_ERRORInvalid request parameters
401UNAUTHORIZEDMissing or invalid authentication
404NOT_FOUNDResource not found
429RATE_LIMITEDRate limit exceeded
500INTERNAL_ERRORServer error

Python SDK Usage​

from aragora.client import AragoraClient

client = AragoraClient(base_url="http://localhost:8080")

# Search evidence
results = client._request("POST", "/api/evidence/search", json={
"query": "transformer architecture",
"limit": 10
})

# Collect evidence for a debate
evidence = client._request("POST", "/api/evidence/collect", json={
"task": "Compare GPT-4 vs Claude 3.5",
"debate_id": "debate-123",
"connectors": ["arxiv", "hackernews"]
})

Attribution & Reputation System​

The attribution module tracks source reputation across debates and provides cross-debate evidence tracking.

ReputationTier​

Source reputation classification:

TierScore RangeDescription
AUTHORITATIVE>= 0.85Highly trusted source
RELIABLE>= 0.70Generally trustworthy
STANDARD>= 0.50Default/neutral reputation
UNCERTAIN>= 0.30Questionable reliability
UNRELIABLE< 0.30Poor track record

VerificationOutcome​

Track verification results for evidence:

from aragora.evidence import VerificationOutcome

VerificationOutcome.VERIFIED # Confirmed accurate
VerificationOutcome.PARTIALLY_VERIFIED # Some claims verified
VerificationOutcome.UNVERIFIED # Could not verify (neutral)
VerificationOutcome.CONTESTED # Disputed by other evidence
VerificationOutcome.REFUTED # Shown to be incorrect

SourceReputationManager​

Track source reputation across debates:

from aragora.evidence import SourceReputationManager, VerificationOutcome

manager = SourceReputationManager()

# Record a verification
manager.record_verification(
record_id="v-001",
source_id="arxiv.org",
debate_id="debate-123",
outcome=VerificationOutcome.VERIFIED,
confidence=0.9,
)

# Get reputation
rep = manager.get_reputation("arxiv.org")
print(rep.reputation_score) # 0-1 score
print(rep.tier) # ReputationTier.RELIABLE
print(rep.verification_rate) # Fraction verified
print(rep.trend) # Recent vs overall trend

# Query sources
top_sources = manager.get_top_sources(limit=10)
unreliable = manager.get_unreliable_sources(threshold=0.3)

# Export/import state
state = manager.export_state()
new_manager.import_state(state)

ReputationScorer​

Algorithms for computing reputation with time decay:

from aragora.evidence import ReputationScorer

scorer = ReputationScorer(
decay_half_life=30.0, # Days for time decay
recent_window=7.0, # Days for "recent" window
)

# Compute from history
overall, recent, trend = scorer.compute_score(verifications, current_score=0.5)

Outcome Impact Weights:

OutcomeImpact
VERIFIED+0.15
PARTIALLY_VERIFIED+0.05
UNVERIFIED0.00
CONTESTED-0.05
REFUTED-0.20

AttributionChain​

Track evidence usage across debates:

from aragora.evidence import AttributionChain

chain = AttributionChain()

# Track evidence usage
entry = chain.add_entry(
evidence_id="ev-001",
source_id="arxiv.org",
debate_id="debate-123",
content="Evidence content...",
)

# Record verification
chain.record_verification(
evidence_id="ev-001",
outcome=VerificationOutcome.VERIFIED,
)

# Query chain
evidence_history = chain.get_evidence_chain("ev-001")
source_usage = chain.get_source_chain("arxiv.org")
debate_attributions = chain.get_debate_attributions("debate-123")

# Find reused evidence
reused = chain.find_reused_evidence(min_uses=2)

# Compute debate reliability
metrics = chain.compute_debate_reliability("debate-123")
# {
# "evidence_count": 5,
# "avg_reputation": 0.75,
# "min_reputation": 0.60,
# "verified_count": 3,
# "reliability_score": 0.72,
# }

Evidence Metadata Enrichment​

MetadataEnricher​

Enriches evidence with source classification and provenance:

from aragora.evidence import MetadataEnricher

enricher = MetadataEnricher()

metadata = enricher.enrich(
content="Research paper content...",
url="https://arxiv.org/abs/2024.12345",
existing_metadata={"author": "John Smith", "doi": "10.1234/example"},
)

print(metadata.source_type) # SourceType.ACADEMIC
print(metadata.confidence) # 0.75
print(metadata.has_citations) # True
print(metadata.topics) # ["Machine Learning", ...]

Source Types​

TypeDomains/Patterns
ACADEMICarxiv.org, doi.org, scholar.google.com
DOCUMENTATIONdocs.python.org, readthedocs.io
NEWSreuters.com, bbc.com, nytimes.com
SOCIALstackoverflow.com, reddit.com, twitter.com
CODEgithub.com, gitlab.com

Confidence Scoring​

Confidence is computed from multiple factors:

FactorImpact
Academic source+0.20
Has DOI+0.10
Peer reviewed+0.15
Has citations+0.10
Recent (<30 days)+0.10
Short content (<50 words)-0.10

See Also​