Skip to main content

Technical Design Document (TDD): Gemini URL Context Integration

Document ID: TDD-2026-0204-004
Date: February 4, 2026
Version: 1.0
Status: Draft


1. Implementation Architecture

1.1 Technology Stack

LayerTechnologyRationale
API ClientRaw HTTP (httpx/aiohttp)REST API over SDK per presenter recommendation
CachingFoundationDBExisting Coditect state backbone
Audit StorageFoundationDB (immutable keyspace)Compliance requirement; 7-year retention
Agent FrameworkCoditect Multi-Agent OrchestratorExisting orchestration infrastructure
Model RoutingCoditect Model RouterCost optimization via Haiku/Sonnet/Opus equivalent
MonitoringOpenTelemetry → Coditect ObservabilityUnified platform metrics

1.2 Module Structure

coditect/
├── web_intelligence/
│ ├── __init__.py
│ ├── adapter.py # URLContextAdapter - Gemini API wrapper
│ ├── cache.py # ContentCache - FoundationDB caching
│ ├── audit.py # AuditTrail - compliance audit records
│ ├── models.py # Data models (requests, responses, metadata)
│ ├── router.py # ModelRouter - intelligent model selection
│ ├── sanitizer.py # ContentSanitizer - input/output sanitization
│ ├── validator.py # URLValidator - allowlisting, format checks
│ ├── circuit_breaker.py # CircuitBreaker - failure protection
│ └── tools/
│ ├── __init__.py
│ ├── url_context.py # Coditect tool interface for URL Context
│ ├── web_research.py # Combined Search + URL Context tool
│ └── compliance_research.py # Compliance-specific research tool
├── agents/
│ ├── researcher.py # Enhanced with web intelligence tools
│ └── compliance.py # Enhanced with compliance research tools
└── tests/
├── test_adapter.py
├── test_cache.py
├── test_audit.py
├── test_integration.py
└── test_compliance.py

2. Core Implementation

2.1 URL Context Adapter (REST API)

import httpx
import hashlib
from dataclasses import dataclass, field
from typing import List, Optional, Dict, Any
from datetime import datetime
import asyncio

@dataclass
class GeminiURLContextAdapter:
"""Direct REST API adapter for Gemini URL Context.

Uses REST API over SDK to:
- Reduce dependency complexity
- Avoid SDK version churn
- Maintain direct control over request/response handling
"""

api_key: str
base_url: str = "https://generativelanguage.googleapis.com/v1beta"
default_model: str = "gemini-2.5-flash"
timeout: float = 30.0
max_retries: int = 3

_client: httpx.AsyncClient = field(init=False, repr=False)

def __post_init__(self):
self._client = httpx.AsyncClient(
timeout=httpx.Timeout(self.timeout),
headers={"Content-Type": "application/json"}
)

async def fetch_and_analyze(
self,
urls: List[str],
prompt: str,
model: Optional[str] = None,
include_search: bool = False,
) -> Dict[str, Any]:
"""Fetch URL content and analyze with Gemini."""

model = model or self.default_model
endpoint = f"{self.base_url}/models/{model}:generateContent"

# Build tool configuration
tools = [{"url_context": {}}]
if include_search:
tools.append({"google_search": {}})

# Build URL references into prompt
url_refs = "\n".join(f"- {url}" for url in urls)
full_prompt = f"{prompt}\n\nSource URLs:\n{url_refs}"

payload = {
"contents": [{"parts": [{"text": full_prompt}]}],
"tools": tools
}

# Execute with retry
for attempt in range(self.max_retries):
try:
response = await self._client.post(
endpoint,
json=payload,
params={"key": self.api_key}
)

if response.status_code == 429:
wait = 2 ** attempt
await asyncio.sleep(wait)
continue

response.raise_for_status()
return self._parse_response(response.json())

except httpx.TimeoutException:
if attempt == self.max_retries - 1:
raise
await asyncio.sleep(2 ** attempt)

raise RuntimeError(f"Failed after {self.max_retries} retries")

def _parse_response(self, data: Dict) -> Dict[str, Any]:
"""Extract content and metadata from Gemini response."""
candidate = data["candidates"][0]

# Extract text content
text_parts = [
part["text"] for part in candidate["content"]["parts"]
if "text" in part
]

# Extract URL metadata
url_metadata = []
if "urlContextMetadata" in candidate:
for meta in candidate["urlContextMetadata"].get("urlMetadata", []):
url_metadata.append({
"url": meta.get("retrievedUrl", ""),
"status": meta.get("urlRetrievalStatus", "UNKNOWN")
})

# Extract token usage
usage = data.get("usageMetadata", {})

return {
"content": "\n".join(text_parts),
"url_metadata": url_metadata,
"tokens": {
"input": usage.get("promptTokenCount", 0),
"output": usage.get("candidatesTokenCount", 0),
"total": usage.get("totalTokenCount", 0)
},
"timestamp": datetime.utcnow().isoformat()
}

2.2 Model Routing for URL Context Tasks

class URLContextModelRouter:
"""Route URL Context requests to optimal Gemini model."""

ROUTING_RULES = {
# Task type → (model, rationale)
"research": ("gemini-2.5-flash", "Cost-efficient for general research"),
"compliance": ("gemini-2.5-pro", "Higher accuracy for regulatory docs"),
"pdf_analysis": ("gemini-2.5-pro", "Better visual document understanding"),
"api_docs": ("gemini-2.5-flash", "Structured content; Flash sufficient"),
"news": ("gemini-2.5-flash", "Simple extraction; cost priority"),
"code_review": ("gemini-2.5-flash", "Code is structured; Flash handles well"),
"architecture": ("gemini-2.5-pro", "Complex reasoning required"),
}

def select_model(
self,
task_type: str,
regulatory: bool = False,
content_types: List[str] = None
) -> str:
if regulatory:
return "gemini-2.5-pro"

if content_types and "pdf" in content_types:
return "gemini-2.5-pro"

model, _ = self.ROUTING_RULES.get(
task_type,
("gemini-2.5-flash", "default")
)
return model

2.3 FoundationDB Cache Implementation

import fdb
import json
import time
from enum import Enum

fdb.api_version(710)

class ContentCategory(Enum):
REGULATORY = "regulatory"
DOCUMENTATION = "documentation"
NEWS = "news"
STATIC = "static"
VOLATILE = "volatile"

class URLContentCache:
"""FoundationDB-backed cache for URL Context responses."""

TTL_SECONDS = {
ContentCategory.REGULATORY: 86400, # 24 hours
ContentCategory.DOCUMENTATION: 21600, # 6 hours
ContentCategory.NEWS: 3600, # 1 hour
ContentCategory.STATIC: 604800, # 7 days
ContentCategory.VOLATILE: 1800, # 30 minutes
}

def __init__(self, db: fdb.Database):
self.db = db
self.cache_space = fdb.directory.create_or_open(
db, ('coditect', 'web_intelligence', 'cache')
)

@fdb.transactional
def get(self, tr, url_hash: str) -> Optional[Dict]:
"""Get cached content if not expired."""
key = self.cache_space.pack((url_hash,))
value = tr[key]

if value is None:
return None

entry = json.loads(value)
if time.time() > entry.get("expires_at", 0):
del tr[key] # Clean up expired entry
return None

return entry

@fdb.transactional
def put(self, tr, url_hash: str, content: Dict, category: ContentCategory):
"""Store content with category-based TTL."""
ttl = self.TTL_SECONDS[category]
entry = {
**content,
"cached_at": time.time(),
"expires_at": time.time() + ttl,
"category": category.value
}
key = self.cache_space.pack((url_hash,))
tr[key] = json.dumps(entry).encode()

@staticmethod
def hash_url(url: str) -> str:
return hashlib.sha256(url.encode()).hexdigest()[:32]

2.4 Compliance Audit Trail

import uuid
from dataclasses import dataclass, asdict

@dataclass(frozen=True)
class ComplianceAuditRecord:
"""Immutable audit record for regulatory compliance.

Satisfies:
- FDA 21 CFR Part 11.10(e): Audit trail
- HIPAA §164.312(b): Audit controls
- SOC2 CC8.1: Change management
"""

record_id: str
timestamp: str
agent_id: str
agent_role: str
task_description: str
urls_requested: List[str]
urls_retrieved: List[str]
retrieval_statuses: Dict[str, str]
model_used: str
tokens_input: int
tokens_output: int
prompt_hash: str
response_hash: str
cache_hit: bool
regulatory_context: str
content_hashes: Dict[str, str] # URL → SHA-256 of content

@classmethod
def create(
cls,
agent_id: str,
agent_role: str,
task_description: str,
request: Dict,
response: Dict,
regulatory_context: str = ""
) -> "ComplianceAuditRecord":
return cls(
record_id=str(uuid.uuid4()),
timestamp=datetime.utcnow().isoformat() + "Z",
agent_id=agent_id,
agent_role=agent_role,
task_description=task_description,
urls_requested=request.get("urls", []),
urls_retrieved=[m["url"] for m in response.get("url_metadata", [])],
retrieval_statuses={
m["url"]: m["status"]
for m in response.get("url_metadata", [])
},
model_used=request.get("model", "unknown"),
tokens_input=response.get("tokens", {}).get("input", 0),
tokens_output=response.get("tokens", {}).get("output", 0),
prompt_hash=hashlib.sha256(
request.get("prompt", "").encode()
).hexdigest(),
response_hash=hashlib.sha256(
response.get("content", "").encode()
).hexdigest(),
cache_hit=response.get("cached", False),
regulatory_context=regulatory_context,
content_hashes={}
)

class AuditTrailStore:
"""FoundationDB-backed immutable audit trail."""

def __init__(self, db: fdb.Database):
self.db = db
self.audit_space = fdb.directory.create_or_open(
db, ('coditect', 'web_intelligence', 'audit')
)

@fdb.transactional
def record(self, tr, audit: ComplianceAuditRecord):
"""Write immutable audit record."""
key = self.audit_space.pack((
audit.timestamp,
audit.record_id
))
tr[key] = json.dumps(asdict(audit)).encode()

@fdb.transactional
def query_by_timerange(
self, tr, start: str, end: str
) -> List[ComplianceAuditRecord]:
"""Query audit records within time range."""
start_key = self.audit_space.pack((start,))
end_key = self.audit_space.pack((end,))

records = []
for kv in tr.get_range(start_key, end_key):
data = json.loads(kv.value)
records.append(ComplianceAuditRecord(**data))
return records

3. Coditect Tool Interface

3.1 URL Context Tool for Agent Framework

from coditect.tools import BaseTool, ToolResult

class URLContextTool(BaseTool):
"""Coditect tool interface for Gemini URL Context.

Enables agents to fetch and analyze web content autonomously
with built-in caching, audit trails, and compliance support.
"""

name = "url_context"
description = """Fetch and analyze content from web URLs.
Supports HTML, PDF, images, JSON, XML, CSV.
Use for: documentation research, compliance checks, API analysis.
Limits: 20 URLs/request, 34MB/URL, public URLs only."""

def __init__(
self,
adapter: GeminiURLContextAdapter,
cache: URLContentCache,
audit: AuditTrailStore,
model_router: URLContextModelRouter
):
self.adapter = adapter
self.cache = cache
self.audit = audit
self.router = model_router

async def execute(
self,
urls: List[str],
analysis_prompt: str,
task_type: str = "research",
compliance_mode: bool = False,
regulatory_context: str = "",
force_refresh: bool = False
) -> ToolResult:
# Validate URLs
validated = [u for u in urls if await self._validate_url(u, compliance_mode)]
if not validated:
return ToolResult(
success=False,
error="No valid URLs provided"
)

# Check cache (unless force refresh)
if not force_refresh:
cached = await self._check_cache(validated, analysis_prompt)
if cached:
return ToolResult(success=True, data=cached)

# Route to optimal model
model = self.router.select_model(
task_type=task_type,
regulatory=compliance_mode
)

# Execute API call
response = await self.adapter.fetch_and_analyze(
urls=validated,
prompt=analysis_prompt,
model=model,
include_search=(task_type == "research")
)

# Verify retrieval success
failed_urls = [
m["url"] for m in response["url_metadata"]
if m["status"] != "URL_RETRIEVAL_STATUS_SUCCESS"
]
if failed_urls:
response["warnings"] = f"Failed to retrieve: {failed_urls}"

# Cache response
await self._update_cache(validated, analysis_prompt, response, task_type)

# Record audit trail
if compliance_mode:
audit_record = ComplianceAuditRecord.create(
agent_id=self.current_agent_id,
agent_role=self.current_agent_role,
task_description=analysis_prompt,
request={"urls": validated, "model": model, "prompt": analysis_prompt},
response=response,
regulatory_context=regulatory_context
)
self.audit.record(self.db, audit_record)

return ToolResult(success=True, data=response)

3.2 Compliance Research Tool

class ComplianceResearchTool(BaseTool):
"""Specialized tool for regulatory document research.

Combines URL Context with domain-specific validation
for FDA, HIPAA, and SOC2 compliance workflows.
"""

name = "compliance_research"
description = """Research regulatory requirements from authoritative sources.
Automatically enforces URL allowlisting, audit trails, and content verification.
Supported frameworks: FDA 21 CFR Part 11, HIPAA, SOC2."""

AUTHORITATIVE_SOURCES = {
"fda_21cfr11": [
"https://www.fda.gov/regulatory-information/search-fda-guidance-documents",
"https://www.ecfr.gov/current/title-21/chapter-I/subchapter-A/part-11",
],
"hipaa": [
"https://www.hhs.gov/hipaa/index.html",
"https://www.hhs.gov/hipaa/for-professionals/security/index.html",
],
"soc2": [
"https://www.aicpa-cima.com/topic/audit-assurance/audit-and-assurance-greater-than-soc-2",
],
}

async def research_requirement(
self,
framework: str,
requirement_query: str,
additional_urls: List[str] = None
) -> ToolResult:
"""Research specific compliance requirement with full audit trail."""

urls = self.AUTHORITATIVE_SOURCES.get(framework, [])
if additional_urls:
urls.extend(additional_urls)

return await self.url_context_tool.execute(
urls=urls,
analysis_prompt=f"""
Framework: {framework}
Query: {requirement_query}

Extract specific requirements, control objectives, and implementation
guidance. Cite the exact section/paragraph for each requirement.
Flag any areas of ambiguity requiring human review.
""",
task_type="compliance",
compliance_mode=True,
regulatory_context=framework
)

4. Performance Specifications

MetricTargetMeasurement
Cache hit ratio> 50% (steady state)FoundationDB metrics
API response latency (P50)< 5sEnd-to-end timer
API response latency (P99)< 15sEnd-to-end timer
URL retrieval success rate> 95%Metadata parsing
Audit record write latency< 10msFoundationDB timer
Token cost per research task< $0.05 (Flash) / < $0.20 (Pro)Token counter

5. Migration Path

Phase 1: Adapter + Cache (Week 1-2)

  • Implement GeminiURLContextAdapter
  • Implement FoundationDB ContentCache
  • Unit tests and integration tests

Phase 2: Agent Integration (Week 3-4)

  • Build URLContextTool and ComplianceResearchTool
  • Integrate into Researcher and Compliance agents
  • Integration testing with real URLs

Phase 3: Audit Trail + Compliance (Week 5-6)

  • Implement AuditTrailStore
  • Compliance testing with regulatory documents
  • Human checkpoint integration

Phase 4: Production Hardening (Week 7-8)

  • Circuit breaker implementation
  • Monitoring and alerting setup
  • Performance benchmarking
  • Documentation and training

Document maintained by Coditect Engineering
Review cycle: Bi-weekly during implementation