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
1 change: 0 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ jobs:
- internal/telemetry
- internal/certauth
- internal/ap2
- internal/testutil
- internal/toolgate
# Services
- aex-gateway
Expand Down
4 changes: 2 additions & 2 deletions DEPLOYMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -603,8 +603,8 @@ git push origin v1.0.0
| `aex-gateway` | `WORK_PUBLISHER_URL`, `BID_GATEWAY_URL`, `PROVIDER_REGISTRY_URL`, `SETTLEMENT_URL`, `IDENTITY_URL` |
| `aex-work-publisher` | `STORE_TYPE`, `PROVIDER_REGISTRY_URL` |
| `aex-bid-gateway` | `PROVIDER_REGISTRY_URL` |
| `aex-bid-evaluator` | `BID_GATEWAY_URL`, `TRUST_BROKER_URL` |
| `aex-contract-engine` | `BID_GATEWAY_URL`, `SETTLEMENT_URL` |
| `aex-bid-evaluator` | `BID_GATEWAY_URL`, `TRUST_BROKER_URL`, `WORK_PUBLISHER_URL` |
| `aex-contract-engine` | `BID_GATEWAY_URL`, `WORK_PUBLISHER_URL`, `SETTLEMENT_URL` |

---

Expand Down
1 change: 0 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ clean:
# Run go mod tidy on all services
tidy:
@echo "Running go mod tidy..."
@cd src/internal && go mod tidy
@for service in $(SERVICES); do \
if [ -f "src/$$service/go.mod" ]; then \
echo "Tidying $$service..."; \
Expand Down
3 changes: 3 additions & 0 deletions demo/aex/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ services:
PORT: "8080"
BID_GATEWAY_URL: "http://aex-bid-gateway:8080"
TRUST_BROKER_URL: "http://aex-trust-broker:8080"
WORK_PUBLISHER_URL: "http://aex-work-publisher:8080"
MONGO_URI: "mongodb://root:root@mongo:27017/?authSource=admin"
MONGO_DB: "aex"
ports:
Expand All @@ -121,6 +122,8 @@ services:
environment:
PORT: "8080"
BID_GATEWAY_URL: "http://aex-bid-gateway:8080"
WORK_PUBLISHER_URL: "http://aex-work-publisher:8080"
SETTLEMENT_URL: "http://aex-settlement:8080"
MONGO_URI: "mongodb://root:root@mongo:27017/?authSource=admin"
MONGO_DB: "aex"
ports:
Expand Down
80 changes: 19 additions & 61 deletions demo/aex/ui/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
AEX_SETTLEMENT_URL = os.environ.get("AEX_SETTLEMENT_URL", "http://localhost:8088")
AEX_PROVIDER_REGISTRY_URL = os.environ.get("AEX_PROVIDER_REGISTRY_URL", "http://localhost:8085")
AEX_WORK_PUBLISHER_URL = os.environ.get("AEX_WORK_PUBLISHER_URL", "http://localhost:8081")
# The demo consumer. Work-publisher takes the consumer identity from the
# X-Consumer-ID header on direct (non-gateway) calls.
DEMO_CONSUMER_ID = "consumer-demo-001"
AEX_BID_GATEWAY_URL = os.environ.get("AEX_BID_GATEWAY_URL", "http://localhost:8082")
AEX_CONTRACT_ENGINE_URL = os.environ.get("AEX_CONTRACT_ENGINE_URL", "http://localhost:8084")
LEGAL_AGENT_A_URL = os.environ.get("LEGAL_AGENT_A_URL", "http://localhost:8100")
Expand Down Expand Up @@ -228,7 +231,7 @@ def publish_work_to_aex(description: str, document_pages: int, max_budget: float
"""Publish work request to AEX Work Publisher service."""
try:
payload = {
"consumer_id": "consumer-demo-001",
"consumer_id": DEMO_CONSUMER_ID,
"category": "legal/contract_review",
"description": description,
"constraints": {
Expand All @@ -248,7 +251,11 @@ def publish_work_to_aex(description: str, document_pages: int, max_budget: float
},
}
with httpx.Client(timeout=10.0) as client:
resp = client.post(f"{AEX_WORK_PUBLISHER_URL}/v1/work", json=payload)
resp = client.post(
f"{AEX_WORK_PUBLISHER_URL}/v1/work",
json=payload,
headers={"X-Consumer-ID": DEMO_CONSUMER_ID},
)
if resp.status_code in [200, 201]:
return resp.json()
print(f"Work Publisher returned {resp.status_code}: {resp.text}")
Expand Down Expand Up @@ -440,37 +447,6 @@ def select_best_payment_provider(bids: list[dict]) -> dict:
return min(bids, key=lambda b: b.get("net_fee_percent", 100))


def process_settlement_via_aex(contract_id: str, consumer_id: str, provider_id: str,
agreed_price: float, use_ap2: bool = True) -> dict:
"""Process settlement through AEX Settlement service with AP2."""
try:
payload = {
"contract_id": contract_id,
"work_id": f"work-{contract_id}",
"agent_id": provider_id,
"consumer_id": consumer_id,
"provider_id": provider_id,
"domain": "legal",
"started_at": datetime.utcnow().isoformat() + "Z",
"completed_at": datetime.utcnow().isoformat() + "Z",
"success": True,
"agreed_price": str(agreed_price),
"currency": "USD",
"use_ap2": use_ap2,
"payment_method": "card" if use_ap2 else "",
}
with httpx.Client(timeout=30.0) as client:
resp = client.post(
f"{AEX_SETTLEMENT_URL}/v1/contracts/complete",
json=payload
)
if resp.status_code in [200, 201]:
return resp.json()
except Exception as e:
print(f"Error processing settlement: {e}")
return {}


def fetch_real_bids(pages: int) -> list[dict]:
"""Fetch real bids from the three legal agents via A2A protocol."""
import sys
Expand Down Expand Up @@ -1090,34 +1066,16 @@ def on_fetch_payment_bids(e: me.ClickEvent):
def on_settle(e: me.ClickEvent):
state = me.state(State)

# Try to process settlement via AEX with AP2
settlement_result = process_settlement_via_aex(
contract_id=state.contract_id,
consumer_id="consumer-demo-001",
provider_id=state.winner_provider_id,
agreed_price=state.agreed_price,
use_ap2=True,
)

if settlement_result:
# Use real settlement data
state.platform_fee = float(settlement_result.get("platform_fee", state.agreed_price * 0.15))
state.provider_payout = float(settlement_result.get("provider_payout", state.agreed_price * 0.85))
state.ap2_enabled = settlement_result.get("ap2_enabled", False)
state.payment_mandate_id = settlement_result.get("payment_mandate_id", "")
state.payment_receipt_id = settlement_result.get("payment_receipt_id", "")
state.payment_transaction_id = settlement_result.get("payment_transaction_id", "")
state.payment_method = settlement_result.get("payment_method", "")
else:
# Fallback to local calculation
state.platform_fee = round(state.agreed_price * 0.15, 2)
state.provider_payout = round(state.agreed_price - state.platform_fee, 2)
# Simulate AP2 for demo purposes
state.ap2_enabled = True
state.payment_mandate_id = f"pm_{state.contract_id}"
state.payment_receipt_id = f"rcpt_{int(time.time())}"
state.payment_transaction_id = f"txn_{int(time.time())}"
state.payment_method = "Demo Visa ****1234"
# Contract Engine settles the contract with AEX Settlement when it is
# completed, so this step only presents the breakdown.
state.platform_fee = round(state.agreed_price * 0.15, 2)
state.provider_payout = round(state.agreed_price - state.platform_fee, 2)
# Simulate AP2 for demo purposes
state.ap2_enabled = True
state.payment_mandate_id = f"pm_{state.contract_id}"
state.payment_receipt_id = f"rcpt_{int(time.time())}"
state.payment_transaction_id = f"txn_{int(time.time())}"
state.payment_method = "Demo Visa ****1234"

state.settlement_timestamp = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC")

Expand Down
3 changes: 3 additions & 0 deletions demo/code_review/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ services:
PORT: "8080"
BID_GATEWAY_URL: "http://aex-bid-gateway:8080"
TRUST_BROKER_URL: "http://aex-trust-broker:8080"
WORK_PUBLISHER_URL: "http://aex-work-publisher:8080"
MONGO_URI: "mongodb://root:root@mongo:27017/?authSource=admin"
MONGO_DB: "aex"
ports:
Expand All @@ -121,6 +122,8 @@ services:
environment:
PORT: "8080"
BID_GATEWAY_URL: "http://aex-bid-gateway:8080"
WORK_PUBLISHER_URL: "http://aex-work-publisher:8080"
SETTLEMENT_URL: "http://aex-settlement:8080"
MONGO_URI: "mongodb://root:root@mongo:27017/?authSource=admin"
MONGO_DB: "aex"
ports:
Expand Down
4 changes: 2 additions & 2 deletions deploy/aws/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -229,8 +229,8 @@ Builds can be triggered:
| aex-provider-registry | 8085 | MONGO_URI |
| aex-work-publisher | 8081 | PROVIDER_REGISTRY_URL |
| aex-bid-gateway | 8082 | PROVIDER_REGISTRY_URL |
| aex-bid-evaluator | 8083 | BID_GATEWAY_URL, TRUST_BROKER_URL |
| aex-contract-engine | 8084 | BID_GATEWAY_URL, WORK_PUBLISHER_URL |
| aex-bid-evaluator | 8083 | BID_GATEWAY_URL, TRUST_BROKER_URL, WORK_PUBLISHER_URL |
| aex-contract-engine | 8084 | BID_GATEWAY_URL, WORK_PUBLISHER_URL, SETTLEMENT_URL |
| aex-settlement | 8086 | CONTRACT_ENGINE_URL, TRUST_BROKER_URL |
| aex-trust-broker | 8088 | - |
| aex-identity | 8089 | - |
Expand Down
2 changes: 2 additions & 0 deletions deploy/aws/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,8 @@ Resources:
Value: !Sub http://bid-gateway.${EnvironmentName}.local:8082
- Name: WORK_PUBLISHER_URL
Value: !Sub http://work-publisher.${EnvironmentName}.local:8081
- Name: SETTLEMENT_URL
Value: !Sub http://settlement.${EnvironmentName}.local:8086
- Name: MONGO_URI
Value: !Sub mongodb://root:root@mongodb.${EnvironmentName}.local:27017/?authSource=admin
- Name: MONGO_DB
Expand Down
1 change: 1 addition & 0 deletions deploy/deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,7 @@ services:
- PORT=8084
- BID_GATEWAY_URL=http://aex-bid-gateway:8082
- WORK_PUBLISHER_URL=http://aex-work-publisher:8081
- SETTLEMENT_URL=http://aex-settlement:8086
depends_on:
- aex-bid-gateway
- aex-work-publisher
Expand Down
4 changes: 2 additions & 2 deletions deploy/gcp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -261,8 +261,8 @@ kubectl apply -k deploy/k8s/overlays/staging/
| aex-provider-registry | MONGO_URI (optional) |
| aex-work-publisher | PROVIDER_REGISTRY_URL |
| aex-bid-gateway | PROVIDER_REGISTRY_URL |
| aex-bid-evaluator | BID_GATEWAY_URL, TRUST_BROKER_URL |
| aex-contract-engine | BID_GATEWAY_URL, WORK_PUBLISHER_URL |
| aex-bid-evaluator | BID_GATEWAY_URL, TRUST_BROKER_URL, WORK_PUBLISHER_URL |
| aex-contract-engine | BID_GATEWAY_URL, WORK_PUBLISHER_URL, SETTLEMENT_URL |
| aex-settlement | CONTRACT_ENGINE_URL, TRUST_BROKER_URL |

### Demo Agents
Expand Down
7 changes: 7 additions & 0 deletions deploy/gcp/deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,13 @@ gcloud run deploy aex-settlement \

SETTLEMENT_URL=$(gcloud run services describe aex-settlement --region "$REGION" --format 'value(status.url)')

# Contract engine notifies settlement on completion; settlement is deployed
# after it (it needs CONTRACT_ENGINE_URL), so set the URL now.
gcloud run services update aex-contract-engine \
--region "$REGION" \
--update-env-vars "SETTLEMENT_URL=$SETTLEMENT_URL" \
--quiet

# Identity
gcloud run deploy aex-identity \
--image "gcr.io/$PROJECT_ID/aex-identity:$COMMIT_SHA" \
Expand Down
5 changes: 5 additions & 0 deletions deploy/k8s/services/aex-bid-evaluator/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ spec:
configMapKeyRef:
name: aex-config
key: TRUST_BROKER_URL
- name: WORK_PUBLISHER_URL
valueFrom:
configMapKeyRef:
name: aex-config
key: WORK_PUBLISHER_URL
- name: MONGO_URI
valueFrom:
secretKeyRef:
Expand Down
10 changes: 10 additions & 0 deletions deploy/k8s/services/aex-contract-engine/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@ spec:
configMapKeyRef:
name: aex-config
key: BID_GATEWAY_URL
- name: WORK_PUBLISHER_URL
valueFrom:
configMapKeyRef:
name: aex-config
key: WORK_PUBLISHER_URL
- name: SETTLEMENT_URL
valueFrom:
configMapKeyRef:
name: aex-config
key: SETTLEMENT_URL
- name: MONGO_URI
valueFrom:
secretKeyRef:
Expand Down
4 changes: 4 additions & 0 deletions deploy/k8s/services/aex-gateway/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ spec:
configMapKeyRef:
name: aex-config
key: ENVIRONMENT
# Comma-separated browser origins allowed by CORS; "*" allows any.
# Set the real UI origins in production.
- name: ALLOWED_ORIGINS
value: "*"
resources:
requests:
cpu: 100m
Expand Down
3 changes: 2 additions & 1 deletion docs/AUTHENTICATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@ Every request passes through these middleware layers in order:
→ Prevents service crashes from propagating

4. CORS Cross-origin resource sharing headers
→ Configurable allowed origins for production
→ Allowed origins from ALLOWED_ORIGINS (default "*")
→ Allows preflight OPTIONS without auth

5. Timeout 30-second max request duration
Expand Down Expand Up @@ -492,6 +492,7 @@ For CA private key:
| `RATE_LIMIT_PER_MINUTE` | Default per-tenant request limit | `1000` | No |
| `RATE_LIMIT_BURST_SIZE` | Burst allowance above limit | `50` | No |
| `REQUEST_TIMEOUT_SECONDS` | Max request duration | `30` | No |
| `ALLOWED_ORIGINS` | Comma-separated CORS origins. `*` sends `Access-Control-Allow-Origin: *`; otherwise a listed origin is echoed with credentials and `Vary: Origin`, and any other origin gets no CORS headers. Each origin must be an exact `scheme://host[:port]` (no path; a trailing `/` is ignored). Set explicit origins in production | `*` | No |
| `WORK_PUBLISHER_URL` | Work publisher service URL | `http://localhost:8081` | Yes |
| `PROVIDER_REGISTRY_URL` | Provider registry service URL | `http://localhost:8085` | Yes |
| `BID_GATEWAY_URL` | Bid gateway service URL | `http://localhost:8082` | Yes |
Expand Down
3 changes: 1 addition & 2 deletions docs/PROJECT.md
Original file line number Diff line number Diff line change
Expand Up @@ -673,8 +673,7 @@ agent-exchange/
│ ├── httpclient/ # HTTP client + circuit breakers
│ ├── telemetry/ # OpenTelemetry tracing + Prometheus
│ ├── certauth/ # Certificate verification (shared)
│ ├── ap2/ # Agent Payments Protocol v2
│ └── agentcard/ # Agent card resolution (A2A protocol)
│ └── ap2/ # Agent Payments Protocol v2
├── deploy/
│ └── k8s/ # Kubernetes manifests
│ ├── base/ # Kustomize base configuration
Expand Down
2 changes: 2 additions & 0 deletions docs/a2a-integration/FINAL_IMPLEMENTATION_PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

**Version:** 1.0 | **Date:** January 2, 2026 | **Status:** APPROVED

> **Superseded (Oct 2026):** the planned `src/internal/agentcard` and `src/internal/token` packages were never adopted. Provider-registry accepts pushed agent cards with its own types, and the unused `internal/agentcard` package was removed. This plan is kept as history.

---

## 1. Project Overview
Expand Down
2 changes: 2 additions & 0 deletions docs/a2a-integration/IMPLEMENTATION_TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
**Created:** January 2, 2026
**Status:** PLANNING

> **Superseded (Oct 2026):** the planned `src/internal/agentcard` and `src/internal/token` packages were never adopted. Provider-registry accepts pushed agent cards with its own types, and the unused `internal/agentcard` package was removed. This plan is kept as history.

---

## Implementation Phases Overview
Expand Down
4 changes: 2 additions & 2 deletions docs/deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -603,8 +603,8 @@ git push origin v1.0.0
| `aex-gateway` | `WORK_PUBLISHER_URL`, `BID_GATEWAY_URL`, `PROVIDER_REGISTRY_URL`, `SETTLEMENT_URL`, `IDENTITY_URL` |
| `aex-work-publisher` | `STORE_TYPE`, `PROVIDER_REGISTRY_URL` |
| `aex-bid-gateway` | `PROVIDER_REGISTRY_URL` |
| `aex-bid-evaluator` | `BID_GATEWAY_URL`, `TRUST_BROKER_URL` |
| `aex-contract-engine` | `BID_GATEWAY_URL`, `SETTLEMENT_URL` |
| `aex-bid-evaluator` | `BID_GATEWAY_URL`, `TRUST_BROKER_URL`, `WORK_PUBLISHER_URL` |
| `aex-contract-engine` | `BID_GATEWAY_URL`, `WORK_PUBLISHER_URL`, `SETTLEMENT_URL` |

---

Expand Down
2 changes: 2 additions & 0 deletions hack/deploy/deploy-cloudrun.sh
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,11 @@ deploy_service() {
aex-bid-evaluator)
env_vars+=",BID_GATEWAY_URL=https://aex-bid-gateway-$PROJECT.run.app"
env_vars+=",TRUST_BROKER_URL=https://aex-trust-broker-$PROJECT.run.app"
env_vars+=",WORK_PUBLISHER_URL=https://aex-work-publisher-$PROJECT.run.app"
;;
aex-contract-engine)
env_vars+=",BID_GATEWAY_URL=https://aex-bid-gateway-$PROJECT.run.app"
env_vars+=",WORK_PUBLISHER_URL=https://aex-work-publisher-$PROJECT.run.app"
env_vars+=",SETTLEMENT_URL=https://aex-settlement-$PROJECT.run.app"
;;
esac
Expand Down
2 changes: 2 additions & 0 deletions hack/deploy/deploy-ecs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -187,9 +187,11 @@ create_or_update_service() {
aex-bid-evaluator)
env_vars+=",{\"name\":\"BID_GATEWAY_URL\",\"value\":\"http://aex-bid-gateway.$service_name.local:8080\"}"
env_vars+=",{\"name\":\"TRUST_BROKER_URL\",\"value\":\"http://aex-trust-broker.$service_name.local:8080\"}"
env_vars+=",{\"name\":\"WORK_PUBLISHER_URL\",\"value\":\"http://aex-work-publisher.$service_name.local:8080\"}"
;;
aex-contract-engine)
env_vars+=",{\"name\":\"BID_GATEWAY_URL\",\"value\":\"http://aex-bid-gateway.$service_name.local:8080\"}"
env_vars+=",{\"name\":\"WORK_PUBLISHER_URL\",\"value\":\"http://aex-work-publisher.$service_name.local:8080\"}"
env_vars+=",{\"name\":\"SETTLEMENT_URL\",\"value\":\"http://aex-settlement.$service_name.local:8080\"}"
;;
esac
Expand Down
4 changes: 4 additions & 0 deletions hack/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ services:
WORK_PUBLISHER_URL: "http://aex-work-publisher:8080"
SETTLEMENT_URL: "http://aex-settlement:8080"
BID_EVALUATOR_URL: "http://aex-bid-evaluator:8080"
ALLOWED_ORIGINS: "*"
ports:
- "8080:8080"
depends_on:
Expand Down Expand Up @@ -104,6 +105,7 @@ services:
PORT: "8080"
BID_GATEWAY_URL: "http://aex-bid-gateway:8080"
TRUST_BROKER_URL: "http://aex-trust-broker:8080"
WORK_PUBLISHER_URL: "http://aex-work-publisher:8080"
CERTAUTH_URL: "http://aex-certauth:8091"
MONGO_URI: "mongodb://root:root@mongo:27017/?authSource=admin"
MONGO_DB: "aex"
Expand All @@ -123,6 +125,8 @@ services:
environment:
PORT: "8080"
BID_GATEWAY_URL: "http://aex-bid-gateway:8080"
WORK_PUBLISHER_URL: "http://aex-work-publisher:8080"
SETTLEMENT_URL: "http://aex-settlement:8080"
MONGO_URI: "mongodb://root:root@mongo:27017/?authSource=admin"
MONGO_DB: "aex"
ports:
Expand Down
Loading
Loading