|
1 | 1 | """agent_instructions block builder for the 402 body.""" |
2 | 2 |
|
| 3 | +from collections.abc import Iterable |
3 | 4 | from dataclasses import dataclass, field |
4 | | -from typing import Any |
| 5 | +from typing import Any, Literal |
5 | 6 |
|
6 | 7 | _TEMPO_WARNING = ( |
7 | 8 | "Do NOT use `tempo wallet transfer` to pay to the address above. That moves USDC on-chain but does not " |
@@ -46,28 +47,48 @@ def _default_warnings(how_to_pay: dict[str, Any]) -> list[str]: |
46 | 47 | return w |
47 | 48 |
|
48 | 49 |
|
| 50 | +RailKey = Literal["tempo_mpp", "x402_base", "x402_solana", "stripe"] |
| 51 | + |
| 52 | +_RAIL_CLIENTS: dict[str, list[str]] = { |
| 53 | + "tempo_mpp": ["agentscore-pay", "tempo request", "x402-proxy"], |
| 54 | + "x402_base": ["agentscore-pay", "x402-proxy", "purl (omit --network flag)"], |
| 55 | + "x402_solana": ["agentscore-pay"], |
| 56 | + "stripe": ["link-cli"], |
| 57 | +} |
| 58 | + |
| 59 | + |
| 60 | +def compatible_clients_by_rails(rails: Iterable[str]) -> dict[str, list[str]] | None: |
| 61 | + """Smoke-verified client list for a set of rail keys. |
| 62 | +
|
| 63 | + The single source of truth for "which CLIs we've verified end-to-end on each rail" — |
| 64 | + consumed both by the 402-body builder (``build_agent_instructions``) and by discovery |
| 65 | + surfaces (skill.md, llms.txt, etc.). Update here, every surface inherits. |
| 66 | + """ |
| 67 | + out: dict[str, list[str]] = {} |
| 68 | + for r in rails: |
| 69 | + clients = _RAIL_CLIENTS.get(r) |
| 70 | + if clients is not None: |
| 71 | + out[r] = list(clients) |
| 72 | + return out or None |
| 73 | + |
| 74 | + |
49 | 75 | def _default_compatible_clients(how_to_pay: dict[str, Any]) -> dict[str, list[str]] | None: |
50 | 76 | """Default ``compatible_clients`` derived from the rails declared in ``how_to_pay``. |
51 | 77 |
|
52 | | - Lists clients the AgentScore team has smoke-verified end-to-end against an |
53 | | - ``agentscore-commerce`` merchant; entries appear only for rails the vendor actually |
54 | | - offers. Vendors override this in ``BuildAgentInstructionsInput(compatible_clients=...)`` |
| 78 | + Vendors override this in ``BuildAgentInstructionsInput(compatible_clients=...)`` |
55 | 79 | to add their own tested clients or remove entries that don't fit their endpoint. |
56 | | -
|
57 | | - Verified state as of the SDK release. The same data is also published as a docs page |
58 | | - for humans (rationale, per-rail commands, why some clients don't fully work, last |
59 | | - verified date) — this default keeps the merchant-side surface in sync. |
| 80 | + Verified state as of the SDK release. |
60 | 81 | """ |
61 | | - out: dict[str, list[str]] = {} |
| 82 | + rails: list[str] = [] |
62 | 83 | if "tempo" in how_to_pay: |
63 | | - out["tempo_mpp"] = ["agentscore-pay", "tempo request", "x402-proxy"] |
| 84 | + rails.append("tempo_mpp") |
64 | 85 | if "x402_base" in how_to_pay: |
65 | | - out["x402_base"] = ["agentscore-pay", "x402-proxy", "purl (omit --network flag)"] |
| 86 | + rails.append("x402_base") |
66 | 87 | if "x402_solana" in how_to_pay: |
67 | | - out["x402_solana"] = ["agentscore-pay"] |
| 88 | + rails.append("x402_solana") |
68 | 89 | if "stripe" in how_to_pay: |
69 | | - out["stripe"] = ["link-cli"] |
70 | | - return out or None |
| 90 | + rails.append("stripe") |
| 91 | + return compatible_clients_by_rails(rails) |
71 | 92 |
|
72 | 93 |
|
73 | 94 | @dataclass |
|
0 commit comments