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
2 changes: 2 additions & 0 deletions docs/INTERFACE.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- Host: https://agent-guild-5d5r.onrender.com
- MCP (streamable HTTP): https://agent-guild-5d5r.onrender.com/mcp/
- MCP x402 payment safety: https://agent-guild-5d5r.onrender.com/mcp/payment-safety/
- AID v2 discovery: https://agent-guild-5d5r.onrender.com/.well-known/agent
- ARD catalogue: https://agent-guild-5d5r.onrender.com/.well-known/ai-catalog.json
- A2A JSON-RPC: https://agent-guild-5d5r.onrender.com/a2a · agent card: https://agent-guild-5d5r.onrender.com/.well-known/agent-card.json
- Issuer DID: https://agent-guild-5d5r.onrender.com/.well-known/agent-guild-did.json
Expand All @@ -24,6 +25,7 @@ guild_mediated requires two-party cryptographic participation, a Guild-observed

- `GET /`
- `GET /.well-known/402index-verify.txt`
- `GET /.well-known/agent`
- `GET /.well-known/agent-guild-did.json`
- `GET /.well-known/agent-guild.json`
- `GET /.well-known/agent-skills/agent-guild/SKILL.md`
Expand Down
25 changes: 25 additions & 0 deletions live/guild/app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ async def _lifespan(app: "FastAPI"):
# exactly ONE row per fetch here; downstream measurement deduplicates the
# privacy-safe actor and excludes our traffic, generic tools and crawlers.
_DISCOVERY_RESOURCE_SURFACES = {
"/.well-known/agent": "aid_v2",
"/.well-known/ai-catalog.json": "ard_catalog",
"/.well-known/agent-guild.json": "guild_manifest",
"/.well-known/integrations.json": "integrations_owner_declaration",
Expand Down Expand Up @@ -3897,6 +3898,7 @@ def _manifest() -> dict:
},
"discovery": {
"capabilities": "/capabilities",
"aid_v2": "/.well-known/agent",
"ard_catalog": "/.well-known/ai-catalog.json",
"ard_agentmap": "/robots.txt",
"discovery_census": {
Expand Down Expand Up @@ -4601,6 +4603,29 @@ def wellknown_integrations():
)


@app.get("/.well-known/agent")
def wellknown_aid_v2():
"""AID v2 HTTPS fallback for domain-first agent discovery.

Agent Identity & Discovery clients query ``_agent.<host>`` first and may
fall back to this exact path when no DNS TXT record exists. Keep the
record deliberately minimal: TLS already binds it to this host, and
omitting ``k`` avoids claiming the separate RFC 9421 PKA profile.
"""
base = x402.public_host().rstrip("/")
return JSONResponse(
content={
"v": "aid2",
"u": f"{base}/mcp",
"p": "mcp",
"a": "none",
"s": "Agent Guild trust and settlement",
"d": f"{base}/for-agents",
},
headers={"Cache-Control": "public, max-age=300, s-maxage=300"},
)


@app.get("/.well-known/mcp/payment-safety-server-card.json")
async def wellknown_payment_safety_mcp_server_card():
"""Static discovery for the focused, one-tool payment-safety server."""
Expand Down
7 changes: 7 additions & 0 deletions live/guild/contract/contract.json
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,12 @@
],
"path": "/.well-known/402index-verify.txt"
},
{
"methods": [
"GET"
],
"path": "/.well-known/agent"
},
{
"methods": [
"GET"
Expand Down Expand Up @@ -1109,6 +1115,7 @@
"service": {
"a2a_endpoint": "https://agent-guild-5d5r.onrender.com/a2a",
"agent_card": "https://agent-guild-5d5r.onrender.com/.well-known/agent-card.json",
"aid_well_known": "https://agent-guild-5d5r.onrender.com/.well-known/agent",
"ard_catalog": "https://agent-guild-5d5r.onrender.com/.well-known/ai-catalog.json",
"did_web_document": "https://agent-guild-5d5r.onrender.com/.well-known/did.json",
"host": "https://agent-guild-5d5r.onrender.com",
Expand Down
2 changes: 2 additions & 0 deletions live/guild/contract/generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ def build_contract() -> dict:
f"{HOST}/.well-known/mcp/"
"payment-safety-server-card.json"
),
"aid_well_known": f"{HOST}/.well-known/agent",
"ard_catalog": f"{HOST}/.well-known/ai-catalog.json",
"a2a_endpoint": f"{HOST}/a2a",
"agent_card": f"{HOST}/.well-known/agent-card.json",
Expand Down Expand Up @@ -409,6 +410,7 @@ def derived_interface_md(contract: dict) -> str:
f"- Host: {s['host']}",
f"- MCP (streamable HTTP): {s['mcp_url']}",
f"- MCP x402 payment safety: {s['payment_safety_mcp_url']}",
f"- AID v2 discovery: {s['aid_well_known']}",
f"- ARD catalogue: {s['ard_catalog']}",
f"- A2A JSON-RPC: {s['a2a_endpoint']} · agent card: {s['agent_card']}",
f"- Issuer DID: {s['issuer_did_document']}",
Expand Down
1 change: 1 addition & 0 deletions live/guild/tests/test_agent_native.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ def test_discovery_manifest_describes_service():
assert m["economics"]["pricing_credits"]["best_agent"] == PRICING["best_agent"]
# an agent can learn how to acquire credits with no human
assert m["economics"]["acquire_credits"]["trial"]["human_free"] is True
assert m["discovery"]["aid_v2"] == "/.well-known/agent"
assert "measured_lift" in m["evaluation_signals"]


Expand Down
54 changes: 54 additions & 0 deletions live/guild/tests/test_aid_discovery.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
"""Agent Identity & Discovery (AID) v2 HTTPS fallback."""
from urllib.parse import urlparse

from fastapi.testclient import TestClient

from app import main, x402


def test_aid_v2_well_known_fallback_is_valid_and_cacheable():
client = TestClient(main.app)
response = client.get(
"/.well-known/agent",
headers={"user-agent": "aid-python/2.1"},
follow_redirects=False,
)

assert response.status_code == 200
assert response.headers["content-type"].startswith("application/json")
assert response.headers["cache-control"] == (
"public, max-age=300, s-maxage=300")
assert len(response.content) < 64 * 1024

base = x402.public_host().rstrip("/")
assert response.json() == {
"v": "aid2",
"u": f"{base}/mcp",
"p": "mcp",
"a": "none",
"s": "Agent Guild trust and settlement",
"d": f"{base}/for-agents",
}
assert urlparse(response.json()["u"]).scheme == "https"
assert len(response.json()["s"].encode("utf-8")) <= 60


def test_aid_fetch_is_one_noncommercial_discovery_observation():
client = TestClient(main.app)
before = len(main.store.events)

response = client.get(
"/.well-known/agent",
headers={"user-agent": "aid-python/2.1"},
)

assert response.status_code == 200
new = main.store.events[before:]
observations = [event for event in new
if event["type"] == "discovery_resource_fetched"]
assert len(observations) == 1
assert observations[0]["discovery_surface"] == "aid_v2"
assert not any(event["type"] in {
"capability_demand", "offer_served", "paid_offer_served",
"paid_offer_shown",
} for event in new)
Loading