@stellar-agent-services/protocol 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +14 -2
- package/dist/canonical-json.d.ts +18 -0
- package/dist/canonical-json.d.ts.map +1 -0
- package/dist/canonical-json.js +86 -0
- package/dist/canonical-json.js.map +1 -0
- package/dist/errors.d.ts +85 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +46 -0
- package/dist/errors.js.map +1 -0
- package/dist/headers.d.ts +15 -0
- package/dist/headers.d.ts.map +1 -0
- package/dist/headers.js +29 -0
- package/dist/headers.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/jobs.d.ts +62 -0
- package/dist/jobs.d.ts.map +1 -0
- package/dist/jobs.js +66 -0
- package/dist/jobs.js.map +1 -0
- package/dist/manifest.d.ts +95 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +144 -0
- package/dist/manifest.js.map +1 -0
- package/dist/networks.d.ts +19 -0
- package/dist/networks.d.ts.map +1 -0
- package/dist/networks.js +33 -0
- package/dist/networks.js.map +1 -0
- package/dist/receipts.d.ts +112 -0
- package/dist/receipts.d.ts.map +1 -0
- package/dist/receipts.js +35 -0
- package/dist/receipts.js.map +1 -0
- package/dist/standard.d.ts +25 -0
- package/dist/standard.d.ts.map +1 -0
- package/dist/standard.js +29 -0
- package/dist/standard.js.map +1 -0
- package/dist/strkey.d.ts +7 -0
- package/dist/strkey.d.ts.map +1 -0
- package/dist/strkey.js +56 -0
- package/dist/strkey.js.map +1 -0
- package/dist/validation-request.d.ts +32 -0
- package/dist/validation-request.d.ts.map +1 -0
- package/dist/validation-request.js +29 -0
- package/dist/validation-request.js.map +1 -0
- package/package.json +37 -4
- package/schemas/manifest.schema.json +272 -0
- package/schemas/validation-request.schema.json +43 -0
- package/schemas/verification-receipt.schema.json +149 -0
- package/test-vectors/README.md +45 -0
- package/test-vectors/binding-hash.json +64 -0
- package/test-vectors/canonical-json.json +94 -0
- package/test-vectors/challenges.json +245 -0
- package/test-vectors/headers.json +37 -0
- package/test-vectors/job-states.json +39 -0
- package/test-vectors/manifests.json +1322 -0
- package/test-vectors/problems.json +15 -0
- package/test-vectors/validation-requests.json +98 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "RFC 8785 (JCS) canonical JSON. For each case, parse `json`, canonicalize it, and compare the result with `canonical` character for character; `sha256` is the lowercase hex SHA-256 of its UTF-8 bytes. For each number, the IEEE 754 double with bits `ieee754` canonicalizes to `canonical`. Every `invalid` entry must be rejected.",
|
|
3
|
+
"source": "RFC 8785 §3.2.2, §3.2.3 and Appendix B, plus cases for Provider Standard v1. Cross-checked with the canonicalize package by an RFC 8785 author.",
|
|
4
|
+
"cases": [
|
|
5
|
+
{
|
|
6
|
+
"name": "RFC 8785 §3.2.2 example",
|
|
7
|
+
"json": "{\n \"numbers\": [333333333.33333329, 1E30, 4.50,\n 2e-3, 0.000000000000000000000000001],\n \"string\": \"\\u20ac$\\u000F\\u000aA'\\u0042\\u0022\\u005c\\\\\\\"\\/\",\n \"literals\": [null, true, false]\n}",
|
|
8
|
+
"canonical": "{\"literals\":[null,true,false],\"numbers\":[333333333.3333333,1e+30,4.5,0.002,1e-27],\"string\":\"€$\\u000f\\nA'B\\\"\\\\\\\\\\\"/\"}",
|
|
9
|
+
"sha256": "2d5e01a318d0f0879ab568c4be289c8b1f64ef8921a53c6277d5e069978baacb"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"name": "RFC 8785 §3.2.3 sorting example: keys are compared as UTF-16 code units",
|
|
13
|
+
"json": "{\n \"\\u20ac\": \"Euro Sign\",\n \"\\r\": \"Carriage Return\",\n \"\\ufb33\": \"Hebrew Letter Dalet With Dagesh\",\n \"1\": \"One\",\n \"\\ud83d\\ude00\": \"Emoji: Grinning Face\",\n \"\\u0080\": \"Control\",\n \"\\u00f6\": \"Latin Small Letter O With Diaeresis\"\n}",
|
|
14
|
+
"canonical": "{\"\\r\":\"Carriage Return\",\"1\":\"One\",\"\u0080\":\"Control\",\"ö\":\"Latin Small Letter O With Diaeresis\",\"€\":\"Euro Sign\",\"😀\":\"Emoji: Grinning Face\",\"דּ\":\"Hebrew Letter Dalet With Dagesh\"}",
|
|
15
|
+
"sha256": "5e321556d22018a9656991a9e94f77ec175fa193e52a2429d312f8419ec8b08c"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"name": "whitespace and key order do not matter",
|
|
19
|
+
"json": "{ \"b\" : 2 , \"a\" : [ 1 , 2 ] , \"c\" : { \"z\" : null , \"y\" : true } }",
|
|
20
|
+
"canonical": "{\"a\":[1,2],\"b\":2,\"c\":{\"y\":true,\"z\":null}}",
|
|
21
|
+
"sha256": "a64f58f8aa2f3aba0ede6531306d8094ec11b12b1051b2929285a0f803b42c53"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"name": "empty containers",
|
|
25
|
+
"json": "{\"object\":{},\"array\":[],\"string\":\"\"}",
|
|
26
|
+
"canonical": "{\"array\":[],\"object\":{},\"string\":\"\"}",
|
|
27
|
+
"sha256": "160df1cb7c08864a4d113733fe02cfbc06a3e39c4ce0e0273ca7f2bb42e0facc"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"name": "objects are sorted at every depth; arrays keep their order",
|
|
31
|
+
"json": "{\"z\":{\"b\":{\"d\":1,\"c\":2},\"a\":[{\"y\":1,\"x\":2},3]},\"a\":0}",
|
|
32
|
+
"canonical": "{\"a\":0,\"z\":{\"a\":[{\"x\":2,\"y\":1},3],\"b\":{\"c\":2,\"d\":1}}}",
|
|
33
|
+
"sha256": "c90dff4558815659aa438ae7de17fa587e7b155aae5a4edb0bd73993176e1792"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"name": "number formatting",
|
|
37
|
+
"json": "[0, -0, 1, -1, 1.5, 0.1, 100.000, 1E+2, 123e-2, 1e20, 1e21, 0.000001, 1e-7]",
|
|
38
|
+
"canonical": "[0,0,1,-1,1.5,0.1,100,100,1.23,100000000000000000000,1e+21,0.000001,1e-7]",
|
|
39
|
+
"sha256": "95dad194c18706dc426c66239fc41371eba794d7e66476dd443379a4840bc2a3"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"name": "integers up to 2^53 - 1 stay exact",
|
|
43
|
+
"json": "[9007199254740991, -9007199254740991]",
|
|
44
|
+
"canonical": "[9007199254740991,-9007199254740991]",
|
|
45
|
+
"sha256": "84bad60c1793654a7cdca854230af90af531ecc8f7656e2c7b2bd91890017b37"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"name": "string escaping: only quote, backslash and C0 controls are escaped",
|
|
49
|
+
"json": "\"\\u0000\\u0001\\b\\t\\n\\u000b\\f\\r\\u001f\\u007f\\u2028\\/\\\\\\\"\"",
|
|
50
|
+
"canonical": "\"\\u0000\\u0001\\b\\t\\n\\u000b\\f\\r\\u001f\u007f\u2028/\\\\\\\"\"",
|
|
51
|
+
"sha256": "a5392ec3bf42164c717677e307656ec0bbe1d66acd6c71e03332208bb3785563"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"name": "escaped non-ASCII text is written as UTF-8",
|
|
55
|
+
"json": "{\"text\":\"Merhaba d\\u00fcnya \\ud83c\\udf0d \\u4e2d\\u6587\"}",
|
|
56
|
+
"canonical": "{\"text\":\"Merhaba dünya 🌍 中文\"}",
|
|
57
|
+
"sha256": "5c6d767ebe9d1b2c2ff28ee7294a682270405ea0a6d8bd89522c6b3593c0ec64"
|
|
58
|
+
}
|
|
59
|
+
],
|
|
60
|
+
"numbers": [
|
|
61
|
+
{ "ieee754": "0000000000000000", "canonical": "0" },
|
|
62
|
+
{ "ieee754": "8000000000000000", "canonical": "0" },
|
|
63
|
+
{ "ieee754": "0000000000000001", "canonical": "5e-324" },
|
|
64
|
+
{ "ieee754": "8000000000000001", "canonical": "-5e-324" },
|
|
65
|
+
{ "ieee754": "7fefffffffffffff", "canonical": "1.7976931348623157e+308" },
|
|
66
|
+
{ "ieee754": "ffefffffffffffff", "canonical": "-1.7976931348623157e+308" },
|
|
67
|
+
{ "ieee754": "4340000000000000", "canonical": "9007199254740992" },
|
|
68
|
+
{ "ieee754": "c340000000000000", "canonical": "-9007199254740992" },
|
|
69
|
+
{ "ieee754": "4430000000000000", "canonical": "295147905179352830000" },
|
|
70
|
+
{ "ieee754": "44b52d02c7e14af5", "canonical": "9.999999999999997e+22" },
|
|
71
|
+
{ "ieee754": "44b52d02c7e14af6", "canonical": "1e+23" },
|
|
72
|
+
{ "ieee754": "44b52d02c7e14af7", "canonical": "1.0000000000000001e+23" },
|
|
73
|
+
{ "ieee754": "444b1ae4d6e2ef4e", "canonical": "999999999999999700000" },
|
|
74
|
+
{ "ieee754": "444b1ae4d6e2ef4f", "canonical": "999999999999999900000" },
|
|
75
|
+
{ "ieee754": "444b1ae4d6e2ef50", "canonical": "1e+21" },
|
|
76
|
+
{ "ieee754": "3eb0c6f7a0b5ed8c", "canonical": "9.999999999999997e-7" },
|
|
77
|
+
{ "ieee754": "3eb0c6f7a0b5ed8d", "canonical": "0.000001" },
|
|
78
|
+
{ "ieee754": "41b3de4355555553", "canonical": "333333333.3333332" },
|
|
79
|
+
{ "ieee754": "41b3de4355555554", "canonical": "333333333.33333325" },
|
|
80
|
+
{ "ieee754": "41b3de4355555555", "canonical": "333333333.3333333" },
|
|
81
|
+
{ "ieee754": "41b3de4355555556", "canonical": "333333333.3333334" },
|
|
82
|
+
{ "ieee754": "41b3de4355555557", "canonical": "333333333.33333343" },
|
|
83
|
+
{ "ieee754": "becbf647612f3696", "canonical": "-0.0000033333333333333333" },
|
|
84
|
+
{ "ieee754": "43143ff3c1cb0959", "canonical": "1424953923781206.2" }
|
|
85
|
+
],
|
|
86
|
+
"invalid": [
|
|
87
|
+
{ "name": "NaN", "ieee754": "7fffffffffffffff" },
|
|
88
|
+
{ "name": "Infinity", "ieee754": "7ff0000000000000" },
|
|
89
|
+
{ "name": "-Infinity", "ieee754": "fff0000000000000" },
|
|
90
|
+
{ "name": "lone high surrogate", "json": "\"\\ud800\"" },
|
|
91
|
+
{ "name": "lone low surrogate in a key", "json": "{\"\\udc00\":1}" },
|
|
92
|
+
{ "name": "high surrogate followed by a letter", "json": "[\"\\ud83dA\"]" }
|
|
93
|
+
]
|
|
94
|
+
}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "Checking a decoded x402 PAYMENT-REQUIRED challenge against the approved manifest (provider-standard.md [P3], [P4], [P5]). Apply each case's `patch` (RFC 6902 add, replace and remove) to `challenge`, check it for `service` against `manifest`, and expect exactly `violations` (in any order). A client signs only when there are none [P7].",
|
|
3
|
+
"manifest": {
|
|
4
|
+
"standard": "stellar-agent-services/provider@1",
|
|
5
|
+
"provider": {
|
|
6
|
+
"name": "Example Text Tools",
|
|
7
|
+
"description": "Small, deterministic text utilities for agents.",
|
|
8
|
+
"homepage": "https://example.com",
|
|
9
|
+
"agentId": 42,
|
|
10
|
+
"termsUrl": "https://example.com/terms",
|
|
11
|
+
"dataUse": { "storesInputs": false, "trainsOnInputs": false }
|
|
12
|
+
},
|
|
13
|
+
"baseUrl": "https://api.example.com/agent",
|
|
14
|
+
"payment": {
|
|
15
|
+
"protocol": "x402",
|
|
16
|
+
"x402Version": 2,
|
|
17
|
+
"accepts": [
|
|
18
|
+
{
|
|
19
|
+
"scheme": "exact",
|
|
20
|
+
"network": "stellar:testnet",
|
|
21
|
+
"asset": "CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA",
|
|
22
|
+
"payTo": "GBZSBASBFMV5RGKPRIPCB5QQVAJ35IXKMTF2A2766MOA4ZHQ7MLSIPXU",
|
|
23
|
+
"maxTimeoutSeconds": 60,
|
|
24
|
+
"extra": { "areFeesSponsored": true }
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
},
|
|
28
|
+
"jobs": { "retentionSeconds": 604800 },
|
|
29
|
+
"services": [
|
|
30
|
+
{
|
|
31
|
+
"name": "text-stats",
|
|
32
|
+
"title": "Text statistics",
|
|
33
|
+
"description": "Counts words, sentences and characters in English text. Use it to check length limits before publishing. Accepts up to 20,000 characters.",
|
|
34
|
+
"price": { "amount": "100000" },
|
|
35
|
+
"charge": "on-success",
|
|
36
|
+
"expectedDurationSeconds": 2,
|
|
37
|
+
"inputSchema": {
|
|
38
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
39
|
+
"type": "object",
|
|
40
|
+
"properties": { "text": { "type": "string", "maxLength": 20000 } },
|
|
41
|
+
"required": ["text"],
|
|
42
|
+
"additionalProperties": false
|
|
43
|
+
},
|
|
44
|
+
"outputSchema": {
|
|
45
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
46
|
+
"type": "object",
|
|
47
|
+
"properties": {
|
|
48
|
+
"words": { "type": "integer" },
|
|
49
|
+
"sentences": { "type": "integer" },
|
|
50
|
+
"characters": { "type": "integer" }
|
|
51
|
+
},
|
|
52
|
+
"required": ["words", "sentences", "characters"]
|
|
53
|
+
},
|
|
54
|
+
"examples": [{ "input": { "text": "Hello world." }, "output": { "words": 2, "sentences": 1, "characters": 12 } }],
|
|
55
|
+
"tags": ["text", "analysis"]
|
|
56
|
+
}
|
|
57
|
+
]
|
|
58
|
+
},
|
|
59
|
+
"service": "text-stats",
|
|
60
|
+
"challenge": {
|
|
61
|
+
"x402Version": 2,
|
|
62
|
+
"resource": {
|
|
63
|
+
"url": "https://api.example.com/agent/services/text-stats/jobs",
|
|
64
|
+
"description": "Text statistics",
|
|
65
|
+
"mimeType": "application/json"
|
|
66
|
+
},
|
|
67
|
+
"accepts": [
|
|
68
|
+
{
|
|
69
|
+
"scheme": "exact",
|
|
70
|
+
"network": "stellar:testnet",
|
|
71
|
+
"asset": "CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA",
|
|
72
|
+
"amount": "100000",
|
|
73
|
+
"payTo": "GBZSBASBFMV5RGKPRIPCB5QQVAJ35IXKMTF2A2766MOA4ZHQ7MLSIPXU",
|
|
74
|
+
"maxTimeoutSeconds": 60,
|
|
75
|
+
"extra": { "areFeesSponsored": true }
|
|
76
|
+
}
|
|
77
|
+
]
|
|
78
|
+
},
|
|
79
|
+
"cases": [
|
|
80
|
+
{ "name": "equals the manifest option plus the price", "patch": [], "valid": true, "violations": [] },
|
|
81
|
+
{
|
|
82
|
+
"name": "unknown fields are ignored",
|
|
83
|
+
"patch": [
|
|
84
|
+
{ "op": "add", "path": "/accepts/0/extra/version", "value": "1" },
|
|
85
|
+
{ "op": "add", "path": "/extensions", "value": { "com.example.trace": "abc" } },
|
|
86
|
+
{ "op": "add", "path": "/resource/serviceName", "value": "Example Text Tools" }
|
|
87
|
+
],
|
|
88
|
+
"valid": true,
|
|
89
|
+
"violations": []
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"name": "an error message is allowed",
|
|
93
|
+
"patch": [{ "op": "add", "path": "/error", "value": "Payment required" }],
|
|
94
|
+
"valid": true,
|
|
95
|
+
"violations": []
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"name": "amount differs from the price",
|
|
99
|
+
"patch": [{ "op": "replace", "path": "/accepts/0/amount", "value": "200000" }],
|
|
100
|
+
"valid": false,
|
|
101
|
+
"violations": [{ "rule": "P4", "pointer": "/accepts/0/amount" }]
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"name": "amount is a number, not a string",
|
|
105
|
+
"patch": [{ "op": "replace", "path": "/accepts/0/amount", "value": 100000 }],
|
|
106
|
+
"valid": false,
|
|
107
|
+
"violations": [{ "rule": "P4", "pointer": "/accepts/0/amount" }]
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"name": "payTo differs",
|
|
111
|
+
"patch": [
|
|
112
|
+
{
|
|
113
|
+
"op": "replace",
|
|
114
|
+
"path": "/accepts/0/payTo",
|
|
115
|
+
"value": "GCMM7PUD2GTN7EJ4EAUQB2BF7B3LWL2UYSULRQE3WEYJ4EF6Y5665GP5"
|
|
116
|
+
}
|
|
117
|
+
],
|
|
118
|
+
"valid": false,
|
|
119
|
+
"violations": [{ "rule": "P4", "pointer": "/accepts/0/payTo" }]
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"name": "asset differs",
|
|
123
|
+
"patch": [
|
|
124
|
+
{
|
|
125
|
+
"op": "replace",
|
|
126
|
+
"path": "/accepts/0/asset",
|
|
127
|
+
"value": "CCW67TSZV3SSS2HXMBQ5JFGCKJNXKZM7UQUWUZPUTHXSTZLEO7SJMI75"
|
|
128
|
+
}
|
|
129
|
+
],
|
|
130
|
+
"valid": false,
|
|
131
|
+
"violations": [{ "rule": "P4", "pointer": "/accepts/0/asset" }]
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"name": "network differs",
|
|
135
|
+
"patch": [{ "op": "replace", "path": "/accepts/0/network", "value": "stellar:pubnet" }],
|
|
136
|
+
"valid": false,
|
|
137
|
+
"violations": [{ "rule": "P4", "pointer": "/accepts/0/network" }]
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
"name": "scheme differs",
|
|
141
|
+
"patch": [{ "op": "replace", "path": "/accepts/0/scheme", "value": "upto" }],
|
|
142
|
+
"valid": false,
|
|
143
|
+
"violations": [{ "rule": "P4", "pointer": "/accepts/0/scheme" }]
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
"name": "maxTimeoutSeconds differs",
|
|
147
|
+
"patch": [{ "op": "replace", "path": "/accepts/0/maxTimeoutSeconds", "value": 120 }],
|
|
148
|
+
"valid": false,
|
|
149
|
+
"violations": [{ "rule": "P4", "pointer": "/accepts/0/maxTimeoutSeconds" }]
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
"name": "fees are not sponsored",
|
|
153
|
+
"patch": [{ "op": "replace", "path": "/accepts/0/extra/areFeesSponsored", "value": false }],
|
|
154
|
+
"valid": false,
|
|
155
|
+
"violations": [{ "rule": "P4", "pointer": "/accepts/0/extra/areFeesSponsored" }]
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
"name": "extra is missing",
|
|
159
|
+
"patch": [{ "op": "remove", "path": "/accepts/0/extra" }],
|
|
160
|
+
"valid": false,
|
|
161
|
+
"violations": [{ "rule": "P4", "pointer": "/accepts/0/extra/areFeesSponsored" }]
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
"name": "two payment options",
|
|
165
|
+
"patch": [
|
|
166
|
+
{
|
|
167
|
+
"op": "add",
|
|
168
|
+
"path": "/accepts/-",
|
|
169
|
+
"value": {
|
|
170
|
+
"scheme": "exact",
|
|
171
|
+
"network": "stellar:testnet",
|
|
172
|
+
"asset": "CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA",
|
|
173
|
+
"amount": "100000",
|
|
174
|
+
"payTo": "GBZSBASBFMV5RGKPRIPCB5QQVAJ35IXKMTF2A2766MOA4ZHQ7MLSIPXU",
|
|
175
|
+
"maxTimeoutSeconds": 60,
|
|
176
|
+
"extra": { "areFeesSponsored": true }
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
],
|
|
180
|
+
"valid": false,
|
|
181
|
+
"violations": [{ "rule": "P4", "pointer": "/accepts" }]
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
"name": "no payment option",
|
|
185
|
+
"patch": [{ "op": "replace", "path": "/accepts", "value": [] }],
|
|
186
|
+
"valid": false,
|
|
187
|
+
"violations": [{ "rule": "P4", "pointer": "/accepts" }]
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
"name": "accepts is missing",
|
|
191
|
+
"patch": [{ "op": "remove", "path": "/accepts" }],
|
|
192
|
+
"valid": false,
|
|
193
|
+
"violations": [{ "rule": "P4", "pointer": "/accepts" }]
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
"name": "x402 version 1",
|
|
197
|
+
"patch": [{ "op": "replace", "path": "/x402Version", "value": 1 }],
|
|
198
|
+
"valid": false,
|
|
199
|
+
"violations": [{ "rule": "P3", "pointer": "/x402Version" }]
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
"name": "resource.url uses http",
|
|
203
|
+
"patch": [
|
|
204
|
+
{
|
|
205
|
+
"op": "replace",
|
|
206
|
+
"path": "/resource/url",
|
|
207
|
+
"value": "http://api.example.com/agent/services/text-stats/jobs"
|
|
208
|
+
}
|
|
209
|
+
],
|
|
210
|
+
"valid": false,
|
|
211
|
+
"violations": [{ "rule": "P5", "pointer": "/resource/url" }]
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
"name": "resource.url is another service's URL",
|
|
215
|
+
"patch": [
|
|
216
|
+
{
|
|
217
|
+
"op": "replace",
|
|
218
|
+
"path": "/resource/url",
|
|
219
|
+
"value": "https://api.example.com/agent/services/summarize/jobs"
|
|
220
|
+
}
|
|
221
|
+
],
|
|
222
|
+
"valid": false,
|
|
223
|
+
"violations": [{ "rule": "P5", "pointer": "/resource/url" }]
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
"name": "resource is missing",
|
|
227
|
+
"patch": [{ "op": "remove", "path": "/resource" }],
|
|
228
|
+
"valid": false,
|
|
229
|
+
"violations": [{ "rule": "P5", "pointer": "/resource/url" }]
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
"name": "several differences are all reported",
|
|
233
|
+
"patch": [
|
|
234
|
+
{ "op": "replace", "path": "/accepts/0/amount", "value": "1" },
|
|
235
|
+
{
|
|
236
|
+
"op": "replace",
|
|
237
|
+
"path": "/accepts/0/payTo",
|
|
238
|
+
"value": "GCMM7PUD2GTN7EJ4EAUQB2BF7B3LWL2UYSULRQE3WEYJ4EF6Y5665GP5"
|
|
239
|
+
}
|
|
240
|
+
],
|
|
241
|
+
"valid": false,
|
|
242
|
+
"violations": [{ "rule": "P4", "pointer": "/accepts/0/amount" }, { "rule": "P4", "pointer": "/accepts/0/payTo" }]
|
|
243
|
+
}
|
|
244
|
+
]
|
|
245
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "Header formats from provider-standard.md §5.2. A provider answers 400 invalid_request to a create-job request whose header doesn't match `pattern` (an ECMA-262 regular expression). `retryAfter` (§5.8) gives the whole seconds to wait for each Retry-After value, read at `now`; `invalid` values are ignored.",
|
|
3
|
+
"idempotencyKey": {
|
|
4
|
+
"pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$",
|
|
5
|
+
"valid": ["0192d3a4-7c1e-7b2a-9f00-3c5e8a1b2c3d", "f47ac10b-58cc-4372-a567-0e02b2c3d479"],
|
|
6
|
+
"invalid": [
|
|
7
|
+
"F47AC10B-58CC-4372-A567-0E02B2C3D479",
|
|
8
|
+
"{f47ac10b-58cc-4372-a567-0e02b2c3d479}",
|
|
9
|
+
"urn:uuid:f47ac10b-58cc-4372-a567-0e02b2c3d479",
|
|
10
|
+
"f47ac10b58cc4372a5670e02b2c3d479",
|
|
11
|
+
"f47ac10b-58cc-4372-a567-0e02b2c3d47",
|
|
12
|
+
""
|
|
13
|
+
]
|
|
14
|
+
},
|
|
15
|
+
"jobToken": {
|
|
16
|
+
"pattern": "^[A-Za-z0-9_-]{43}$",
|
|
17
|
+
"valid": ["q7Zt3m0bX0s8b6f5JmS2kQ9xg3Y1rZcV4nL8pW2eA0c", "lDgabH0XuZH0QvUHoZygLnzlIj45A193SL-aZNcnIiE"],
|
|
18
|
+
"invalid": [
|
|
19
|
+
"lDgabH0XuZH0QvUHoZygLnzlIj45A193SL-aZNcnIiE=",
|
|
20
|
+
"q7Zt3m0bX0s8b6f5JmS2kQ9xg3Y1rZcV4nL8pW2eA0+",
|
|
21
|
+
"lDgabH0XuZH0QvUHoZygLnzlIj45A193SL-aZNcnIi",
|
|
22
|
+
"lDgabH0XuZH0QvUHoZygLnzlIj45A193SL-aZNcnIiEA",
|
|
23
|
+
""
|
|
24
|
+
]
|
|
25
|
+
},
|
|
26
|
+
"retryAfter": {
|
|
27
|
+
"now": "2026-10-20T10:00:00Z",
|
|
28
|
+
"valid": [
|
|
29
|
+
{ "value": "0", "seconds": 0 },
|
|
30
|
+
{ "value": "5", "seconds": 5 },
|
|
31
|
+
{ "value": " 30 ", "seconds": 30 },
|
|
32
|
+
{ "value": "Tue, 20 Oct 2026 10:00:12 GMT", "seconds": 12 },
|
|
33
|
+
{ "value": "Tue, 20 Oct 2026 09:59:00 GMT", "seconds": 0 }
|
|
34
|
+
],
|
|
35
|
+
"invalid": ["", "-1", "1.5", "5s", "soon", "2026-10-20T10:00:12Z"]
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "Job states from provider-standard.md §5.6. `transitions` lists, per charge policy, every state a job may move to from each state, \"(new)\" being a job that does not exist yet. Every pair not listed is forbidden. `charged` gives the job view's `charged` value for each status, charge and failure code.",
|
|
3
|
+
"transitions": {
|
|
4
|
+
"upfront": {
|
|
5
|
+
"(new)": ["queued", "running", "payment_uncertain", "failed"],
|
|
6
|
+
"queued": ["running"],
|
|
7
|
+
"running": ["succeeded", "failed"],
|
|
8
|
+
"payment_uncertain": ["queued", "succeeded", "failed"],
|
|
9
|
+
"succeeded": [],
|
|
10
|
+
"failed": []
|
|
11
|
+
},
|
|
12
|
+
"on-success": {
|
|
13
|
+
"(new)": ["queued", "running", "payment_uncertain", "failed"],
|
|
14
|
+
"queued": ["running"],
|
|
15
|
+
"running": ["succeeded", "failed", "payment_uncertain"],
|
|
16
|
+
"payment_uncertain": ["queued", "succeeded", "failed"],
|
|
17
|
+
"succeeded": [],
|
|
18
|
+
"failed": []
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"charged": [
|
|
22
|
+
{ "status": "queued", "charge": "upfront", "charged": true },
|
|
23
|
+
{ "status": "queued", "charge": "on-success", "charged": false },
|
|
24
|
+
{ "status": "running", "charge": "upfront", "charged": true },
|
|
25
|
+
{ "status": "running", "charge": "on-success", "charged": false },
|
|
26
|
+
{ "status": "succeeded", "charge": "upfront", "charged": true },
|
|
27
|
+
{ "status": "succeeded", "charge": "on-success", "charged": true },
|
|
28
|
+
{ "status": "payment_uncertain", "charge": "upfront", "charged": "unknown" },
|
|
29
|
+
{ "status": "payment_uncertain", "charge": "on-success", "charged": "unknown" },
|
|
30
|
+
{ "status": "failed", "charge": "upfront", "failureCode": "service_failed", "charged": true },
|
|
31
|
+
{ "status": "failed", "charge": "upfront", "failureCode": "output_invalid", "charged": true },
|
|
32
|
+
{ "status": "failed", "charge": "upfront", "failureCode": "timeout", "charged": true },
|
|
33
|
+
{ "status": "failed", "charge": "upfront", "failureCode": "payment_failed", "charged": false },
|
|
34
|
+
{ "status": "failed", "charge": "on-success", "failureCode": "service_failed", "charged": false },
|
|
35
|
+
{ "status": "failed", "charge": "on-success", "failureCode": "output_invalid", "charged": false },
|
|
36
|
+
{ "status": "failed", "charge": "on-success", "failureCode": "timeout", "charged": false },
|
|
37
|
+
{ "status": "failed", "charge": "on-success", "failureCode": "payment_failed", "charged": false }
|
|
38
|
+
]
|
|
39
|
+
}
|