Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 10 additions & 9 deletions alembic/versions/e38f2f6f395a_add_mock_manual_approval_required.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,33 @@
Create Date: 2025-10-23 20:06:20.766732

"""
from typing import Sequence, Union

from alembic import op
from collections.abc import Sequence

import sqlalchemy as sa

from alembic import op

# revision identifiers, used by Alembic.
revision: str = 'e38f2f6f395a'
down_revision: Union[str, Sequence[str], None] = 'faaed3b71428'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
revision: str = "e38f2f6f395a"
down_revision: str | Sequence[str] | None = "faaed3b71428"
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None


def upgrade() -> None:
"""Upgrade schema."""
# Add mock_manual_approval_required column to adapter_config table
op.add_column('adapter_config', sa.Column('mock_manual_approval_required', sa.Boolean(), nullable=True))
op.add_column("adapter_config", sa.Column("mock_manual_approval_required", sa.Boolean(), nullable=True))

# Set default value to False for ALL existing rows (not just mock adapters)
op.execute("UPDATE adapter_config SET mock_manual_approval_required = false")

# Make the column non-nullable after setting defaults
op.alter_column('adapter_config', 'mock_manual_approval_required', nullable=False, server_default=sa.false())
op.alter_column("adapter_config", "mock_manual_approval_required", nullable=False, server_default=sa.false())


def downgrade() -> None:
"""Downgrade schema."""
# Remove mock_manual_approval_required column
op.drop_column('adapter_config', 'mock_manual_approval_required')
op.drop_column("adapter_config", "mock_manual_approval_required")
26 changes: 17 additions & 9 deletions examples/upstream_product_catalog_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,15 +164,23 @@ async def match_products(self, brief: str, all_products: list[dict[str, Any]]) -
prompt = f"""Given this advertising brief: "{brief}"

And these available products:
{json.dumps([{
'id': p['product_id'],
'name': p['name'],
'description': p['description'],
'formats': [f['type'] for f in p['formats']],
'targeting': p.get('targeting_template', {}),
'price': p.get('cpm') or p.get('price_guidance', {}).get('p50', 'variable'),
'special_features': p.get('availability', {})
} for p in all_products], indent=2)}
{
json.dumps(
[
{
"id": p["product_id"],
"name": p["name"],
"description": p["description"],
"formats": [f["type"] for f in p["formats"]],
"targeting": p.get("targeting_template", {}),
"price": p.get("cpm") or p.get("price_guidance", {}).get("p50", "variable"),
"special_features": p.get("availability", {}),
}
for p in all_products
],
indent=2,
)
}

Select the most relevant products (up to 3) and return as JSON:
{{
Expand Down
1 change: 1 addition & 0 deletions scripts/audit_e2e_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
3. Redundant tests
4. Tests with excessive tool calls
"""

import re
import sys
from collections import defaultdict
Expand Down
1 change: 1 addition & 0 deletions scripts/deploy/fly-proxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"""
Simple HTTP proxy for Fly.io deployment to route between MCP server and Admin UI
"""

import asyncio
import logging

Expand Down
12 changes: 6 additions & 6 deletions scripts/maintenance/audit_all_production_products.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,18 +45,18 @@ def audit_all_products():
if not data["pricing_options"]:
missing_pricing.append(data["product"])

print(f"\n{'='*80}")
print(f"\n{'=' * 80}")
print("PRODUCTION PRODUCT PRICING AUDIT")
print(f"{'='*80}\n")
print(f"{'=' * 80}\n")

print(f"Total products in database: {len(products_by_id)}")
print(f"Products WITH pricing_options: {len(products_by_id) - len(missing_pricing)}")
print(f"Products MISSING pricing_options: {len(missing_pricing)}")

if missing_pricing:
print(f"\n{'='*80}")
print(f"\n{'=' * 80}")
print("⚠️ PRODUCTS MISSING PRICING_OPTIONS (BLOCKING MIGRATION)")
print(f"{'='*80}\n")
print(f"{'=' * 80}\n")

for product in missing_pricing:
print(f"❌ {product.product_id}")
Expand All @@ -65,9 +65,9 @@ def audit_all_products():
print(f" Delivery Type: {product.delivery_type}")
print()

print(f"{'='*80}")
print(f"{'=' * 80}")
print("⚠️ ACTION REQUIRED")
print(f"{'='*80}\n")
print(f"{'=' * 80}\n")
print("These products MUST have pricing_options added before migration can proceed.")
print("\nRecommended fix (run in Fly.io SSH console):")
print("\n```python")
Expand Down
2 changes: 1 addition & 1 deletion scripts/ops/aggregate_format_metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def main():
args = parser.parse_args()

logger.info(
f"Starting format metrics aggregation (period_days={args.period_days}, " f"tenant_id={args.tenant_id or 'all'})"
f"Starting format metrics aggregation (period_days={args.period_days}, tenant_id={args.tenant_id or 'all'})"
)

try:
Expand Down
2 changes: 1 addition & 1 deletion scripts/ops/gam_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ def test_gam_connection(tenant_id: str) -> dict:

return {
"success": True,
"message": f'Successfully connected to GAM network: {network["displayName"]} (ID: {network["id"]})',
"message": f"Successfully connected to GAM network: {network['displayName']} (ID: {network['id']})",
}

except Exception as e:
Expand Down
1 change: 0 additions & 1 deletion scripts/ops/get_tokens.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#!/usr/bin/env python3
"""Quick script to get tokens from the database."""


from src.core.database.database_session import get_db_session
from src.core.database.models import Principal, Tenant

Expand Down
3 changes: 2 additions & 1 deletion scripts/ops/show_principal_mappings.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#!/usr/bin/env python3
"""Show detailed platform mappings for all principals in a tenant."""

import json
import sys

Expand All @@ -19,7 +20,7 @@ def show_mappings(tenant_name=None):
principals = session.query(Principal).all()

for principal in principals:
print(f"\n{'='*80}")
print(f"\n{'=' * 80}")
print(f"Name: {principal.name}")
print(f"Principal ID: {principal.principal_id}")
print(f"Tenant ID: {principal.tenant_id}")
Expand Down
2 changes: 1 addition & 1 deletion scripts/ops/sync_all_tenants.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def sync_all_gam_tenants():
try:
# Call sync API
response = requests.post(
f'http://localhost:{os.environ.get("ADMIN_UI_PORT", 8001)}/api/v1/sync/trigger/{tenant_id}',
f"http://localhost:{os.environ.get('ADMIN_UI_PORT', 8001)}/api/v1/sync/trigger/{tenant_id}",
headers={"X-API-Key": api_key},
json={"sync_type": "full"},
timeout=300, # 5 minute timeout per tenant
Expand Down
4 changes: 2 additions & 2 deletions scripts/run_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ def run_tests(categories, verbose=False, failfast=False, coverage=False, specifi
print(f"Available categories: {', '.join(TEST_CATEGORIES.keys())}")
continue

print(f"\n{'='*60}")
print(f"\n{'=' * 60}")
print(f"Running {category} tests: {TEST_CATEGORIES[category]['description']}")
print("=" * 60)

Expand Down Expand Up @@ -155,7 +155,7 @@ def run_tests(categories, verbose=False, failfast=False, coverage=False, specifi
break

# Summary
print(f"\n{'='*60}")
print(f"\n{'=' * 60}")
print("TEST SUMMARY")
print("=" * 60)
print(f"✅ Passed: {len(passed_categories)} categories")
Expand Down
2 changes: 1 addition & 1 deletion scripts/setup/setup_tenant.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ def create_tenant(args):
{f"Login as {admin_email} to manage this publisher" if admin_email else "Login with your Google account to manage this publisher"}

📝 Next Steps:
1. {'Access the Admin UI with your admin account' if admin_email else 'Access the Admin UI to complete setup'}
1. {"Access the Admin UI with your admin account" if admin_email else "Access the Admin UI to complete setup"}
2. Configure your ad server integration (if not done)
3. Add more authorized domains/emails in the Users & Access section
4. Create principals for each advertiser who will buy inventory
Expand Down
2 changes: 1 addition & 1 deletion scripts/test_gam_automation_dry_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ def main():
total = len(results)
failed = total - passed

print(f"\n{'='*40}")
print(f"\n{'=' * 40}")
print(f"📊 RESULTS: {passed}/{total} tests passed")

if failed == 0:
Expand Down
12 changes: 6 additions & 6 deletions scripts/test_mcp_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@

async def test_mcp_endpoint(url: str, auth_token: str = None):
"""Test MCP endpoint with actual MCP client."""
print(f"\n{'='*80}")
print(f"\n{'=' * 80}")
print(f"Testing MCP endpoint: {url}")
print(f"{'='*80}")
print(f"{'=' * 80}")

headers = {}
if auth_token:
Expand Down Expand Up @@ -79,16 +79,16 @@ async def main():
results = []

for name, url, _needs_auth in test_cases:
print(f"\n{'='*80}")
print(f"\n{'=' * 80}")
print(f"TEST: {name}")
print(f"{'='*80}")
print(f"{'=' * 80}")
success = await test_mcp_endpoint(url)
results.append((name, success))

# Print summary
print(f"\n{'='*80}")
print(f"\n{'=' * 80}")
print("SUMMARY")
print(f"{'='*80}")
print(f"{'=' * 80}")

for name, success in results:
status = "✅ PASS" if success else "❌ FAIL"
Expand Down
16 changes: 8 additions & 8 deletions scripts/test_nginx_routing.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,12 @@ def simulate_approximated_request(self, domain: str, path: str, extra_headers: d

def run_test(self, test: TestCase) -> bool:
"""Run a single test case."""
print(f"\n{'='*80}")
print(f"\n{'=' * 80}")
print(f"TEST: {test.name}")
print(f"Domain: {test.domain}{test.path}")
if test.description:
print(f"Description: {test.description}")
print(f"{'='*80}")
print(f"{'=' * 80}")

# Set headers based on routing path
if test.via_approximated:
Expand Down Expand Up @@ -150,26 +150,26 @@ def _error(self, test: TestCase, error: str):

def print_summary(self):
"""Print test summary."""
print(f"\n{'='*80}")
print(f"\n{'=' * 80}")
print("TEST SUMMARY")
print(f"{'='*80}")
print(f"{'=' * 80}")
print(f"Passed: {self.passed}")
print(f"Failed: {self.failed}")
print(f"Total: {self.passed + self.failed}")

if self.errors:
print(f"\n{'='*80}")
print(f"\n{'=' * 80}")
print("FAILURES")
print(f"{'='*80}")
print(f"{'=' * 80}")
for error in self.errors:
print(error)

print(f"\n{'='*80}")
print(f"\n{'=' * 80}")
if self.failed == 0:
print("✅ ALL TESTS PASSED")
else:
print(f"❌ {self.failed} TESTS FAILED")
print(f"{'='*80}")
print(f"{'=' * 80}")


def get_test_cases() -> list[TestCase]:
Expand Down
7 changes: 5 additions & 2 deletions scripts/test_service_account_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@
sys.path.insert(0, str(project_root))

from sqlalchemy import select

from src.adapters.gam import build_gam_config_from_adapter
from src.adapters.google_ad_manager import GoogleAdManager
from src.core.database.database_session import get_db_session
from src.core.database.models import Tenant
from src.adapters.google_ad_manager import GoogleAdManager
from src.adapters.gam import build_gam_config_from_adapter
from src.core.schemas import Principal


Expand Down Expand Up @@ -132,6 +133,7 @@ def test_service_account_auth(tenant_name: str):
except Exception as e:
print(f"❌ Failed to create adapter: {e}")
import traceback

traceback.print_exc()
return False

Expand All @@ -153,6 +155,7 @@ def test_service_account_auth(tenant_name: str):
except Exception as e:
print(f"❌ Failed to fetch advertisers: {e}")
import traceback

traceback.print_exc()
return False

Expand Down
4 changes: 2 additions & 2 deletions scripts/validate_pydantic_against_adcp_schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,9 +243,9 @@ def validate_all(self) -> bool:
print() # Blank line between validations

# Summary
print(f"\n{Colors.BOLD}{'='*60}{Colors.RESET}")
print(f"\n{Colors.BOLD}{'=' * 60}{Colors.RESET}")
print(f"{Colors.BOLD}Validation Summary{Colors.RESET}")
print(f"{'='*60}")
print(f"{'=' * 60}")
print(f"Models validated: {validated_count}")
print(f"{Colors.RED}Errors: {len(self.errors)}{Colors.RESET}")
print(f"{Colors.YELLOW}Warnings: {len(self.warnings)}{Colors.RESET}")
Expand Down
6 changes: 4 additions & 2 deletions src/a2a_server/adcp_a2a_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -529,7 +529,7 @@ async def on_message_send(
task.artifacts = task.artifacts or []
task.artifacts.append(
Artifact(
artifactId=f"skill_result_{i+1}",
artifactId=f"skill_result_{i + 1}",
name=f"{'error' if not res['success'] else res['skill']}_result",
description=description, # Human-readable message
parts=[Part(type="data", data=artifact_data)],
Expand Down Expand Up @@ -2274,7 +2274,9 @@ async def dynamic_agent_card_endpoint(request):
logger.info("Replaced /.well-known/agent.json with dynamic version")
elif route.path == "/.well-known/agent-card.json":
# Replace with our dynamic endpoint (primary A2A discovery)
new_routes.append(Route("/.well-known/agent-card.json", dynamic_agent_discovery, methods=["GET", "OPTIONS"]))
new_routes.append(
Route("/.well-known/agent-card.json", dynamic_agent_discovery, methods=["GET", "OPTIONS"])
)
logger.info("Replaced /.well-known/agent-card.json with dynamic version")
elif route.path == "/agent.json":
# Replace with our dynamic endpoint
Expand Down
3 changes: 1 addition & 2 deletions src/adapters/gam/managers/inventory.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,7 @@ def sync_all_inventory(self, custom_targeting_limit: int = 1000, fetch_values: b

discovery = self._get_discovery()
return discovery.sync_all(
fetch_custom_targeting_values=fetch_values,
max_custom_targeting_values_per_key=custom_targeting_limit
fetch_custom_targeting_values=fetch_values, max_custom_targeting_values_per_key=custom_targeting_limit
)

def build_ad_unit_tree(self) -> dict[str, Any]:
Expand Down
2 changes: 1 addition & 1 deletion src/adapters/gam/managers/reporting.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def start_delivery_reporting(
self._active_reports[media_buy_id] = thread
thread.start()

logger.info(f"✅ Started delivery reporting for {media_buy_id} " f"(interval: {reporting_interval_hours}h)")
logger.info(f"✅ Started delivery reporting for {media_buy_id} (interval: {reporting_interval_hours}h)")

def stop_delivery_reporting(self, media_buy_id: str):
"""Stop delivery reporting for a media buy.
Expand Down
Loading