@paybond/kit 0.12.3 → 0.12.5
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/dist/cli/command-spec.js +14 -4
- package/dist/cli/commands/workflows.d.ts +2 -0
- package/dist/cli/commands/workflows.js +117 -0
- package/dist/cli/help.d.ts +1 -1
- package/dist/cli/help.js +3 -1
- package/dist/cli/router.js +9 -1
- package/dist/dev/offline-gateway.js +11 -0
- package/dist/mcp-server.js +560 -62
- package/glama.json +6 -0
- package/package.json +3 -2
- package/templates/openai-shopping-agent/package-lock.json +7 -7
- package/templates/paybond-aws-operator/package-lock.json +4 -4
- package/templates/paybond-claude-agents-demo/package-lock.json +7 -7
- package/templates/paybond-mastra-travel-agent/package-lock.json +23 -23
- package/templates/paybond-mcp-coding-agent/package-lock.json +4 -4
- package/templates/paybond-openai-agents-demo/package-lock.json +7 -7
- package/templates/paybond-procurement-agent/package-lock.json +4 -4
- package/templates/paybond-shopify-shopping-agent/package-lock.json +4 -4
- package/templates/paybond-stripe-agent-demo/package-lock.json +4 -4
- package/templates/paybond-travel-agent/package-lock.json +4 -4
- package/templates/paybond-vercel-shopping-agent/package-lock.json +4 -4
package/dist/mcp-server.js
CHANGED
|
@@ -15,23 +15,79 @@ import { verifyAgentReceiptV1FromJSON } from "./agent-receipt.js";
|
|
|
15
15
|
import { agentReceiptResourceTemplateDefinition, agentReceiptResourceUri, MCP_AGENT_RECEIPT_RESOURCE_MIME_TYPE, parseAgentReceiptResourceUri, } from "./mcp-receipt-resource.js";
|
|
16
16
|
import { DEFAULT_PAYBOND_GATEWAY_BASE_URL, GatewayFraudClient, GatewaySignalClient, } from "./index.js";
|
|
17
17
|
const SERVER_NAME = "Paybond MCP";
|
|
18
|
-
const SERVER_VERSION = "0.12.
|
|
18
|
+
const SERVER_VERSION = "0.12.5";
|
|
19
19
|
const MCP_PROTOCOL_VERSION = "2025-11-25";
|
|
20
20
|
const DEFAULT_PRINCIPAL_PATH = "/v1/auth/principal";
|
|
21
21
|
const DEFAULT_RECOGNITION_VERIFIER_ID = "paybond-gateway";
|
|
22
22
|
const agentRecognitionProofHeader = "x-paybond-agent-recognition-proof";
|
|
23
23
|
const DEFAULT_ENV_FILE = ".env.local";
|
|
24
|
+
const AUTHORIZE_SPEND_OUTPUT_PROPERTIES = {
|
|
25
|
+
allow: {
|
|
26
|
+
type: "boolean",
|
|
27
|
+
description: "Whether the requested operation is allowed.",
|
|
28
|
+
},
|
|
29
|
+
tenant: {
|
|
30
|
+
type: "string",
|
|
31
|
+
description: "Tenant echoed by the gateway.",
|
|
32
|
+
},
|
|
33
|
+
intent_id: {
|
|
34
|
+
type: "string",
|
|
35
|
+
description: "Verified Harbor intent UUID.",
|
|
36
|
+
},
|
|
37
|
+
audit_id: {
|
|
38
|
+
type: "string",
|
|
39
|
+
description: "Gateway audit identifier when available.",
|
|
40
|
+
},
|
|
41
|
+
remaining_cents: {
|
|
42
|
+
type: "integer",
|
|
43
|
+
description: "Remaining spend budget in cents for the evaluated scope, when available.",
|
|
44
|
+
},
|
|
45
|
+
reason_codes: {
|
|
46
|
+
type: "array",
|
|
47
|
+
items: { type: "string" },
|
|
48
|
+
description: "Stable spend-policy reason codes from the authorization decision.",
|
|
49
|
+
},
|
|
50
|
+
message: {
|
|
51
|
+
type: "string",
|
|
52
|
+
description: "Human-readable decision message when present.",
|
|
53
|
+
},
|
|
54
|
+
decision_id: {
|
|
55
|
+
type: "string",
|
|
56
|
+
description: "Persisted spend decision identifier when authorization creates one.",
|
|
57
|
+
},
|
|
58
|
+
approval_request_id: {
|
|
59
|
+
type: "string",
|
|
60
|
+
description: "Approval request identifier when human approval is required.",
|
|
61
|
+
},
|
|
62
|
+
};
|
|
24
63
|
const TOOL_SELECTION_METADATA = {
|
|
25
64
|
paybond_get_principal: {
|
|
26
65
|
title: "Get Paybond Principal",
|
|
66
|
+
description: "Use this when you need to confirm which tenant-bound service-account principal the configured PAYBOND_API_KEY authenticates as " +
|
|
67
|
+
"(tenant_id, subject, and roles). Call early as a prerequisite before Harbor escrow, Signal reads, or other tenant-scoped tools when " +
|
|
68
|
+
"tenant identity is unknown. Not required before every later call once tenant_id is already known from a prior principal response or host config. " +
|
|
69
|
+
"Do not use this when you need Harbor intent escrow detail; use paybond_get_intent instead when you have an intent_id. " +
|
|
70
|
+
"Do not use this for A2A discovery; use paybond_get_a2a_agent_card instead. " +
|
|
71
|
+
"Makes one read-only external GET to the gateway principal endpoint; idempotent identity lookup with no side effects " +
|
|
72
|
+
"(no mutations, spend reservations, escrow changes, or ledger writes); auth or gateway failures surface as tool errors.",
|
|
27
73
|
annotations: readOnlyToolAnnotations("Get Paybond Principal"),
|
|
28
74
|
outputSchema: outputObjectSchema({
|
|
29
75
|
tenant_id: {
|
|
30
76
|
type: "string",
|
|
31
77
|
description: "Tenant bound to the configured Paybond API key.",
|
|
78
|
+
examples: ["tenant-a"],
|
|
79
|
+
},
|
|
80
|
+
subject: {
|
|
81
|
+
type: "string",
|
|
82
|
+
description: "Service-account subject identifier echoed by the gateway for the authenticated API key (example: service-account-1).",
|
|
83
|
+
examples: ["service-account-1"],
|
|
84
|
+
},
|
|
85
|
+
roles: {
|
|
86
|
+
type: "array",
|
|
87
|
+
items: { type: "string" },
|
|
88
|
+
description: "RBAC roles granted to this principal for the authenticated tenant (example: [\"operator\"]).",
|
|
89
|
+
examples: [["operator"]],
|
|
32
90
|
},
|
|
33
|
-
subject: { type: "string" },
|
|
34
|
-
roles: { type: "array", items: { type: "string" } },
|
|
35
91
|
}),
|
|
36
92
|
},
|
|
37
93
|
paybond_verify_capability: {
|
|
@@ -40,22 +96,7 @@ const TOOL_SELECTION_METADATA = {
|
|
|
40
96
|
"Do not use this to create, fund, or modify intents; use paybond_authorize_agent_spend as the clearer gate before side-effecting agent tools.",
|
|
41
97
|
annotations: additiveMutationToolAnnotations("Verify Paybond Capability"),
|
|
42
98
|
outputSchema: outputObjectSchema({
|
|
43
|
-
|
|
44
|
-
type: "boolean",
|
|
45
|
-
description: "Whether the requested operation is allowed.",
|
|
46
|
-
},
|
|
47
|
-
tenant: {
|
|
48
|
-
type: "string",
|
|
49
|
-
description: "Tenant echoed by the gateway.",
|
|
50
|
-
},
|
|
51
|
-
intent_id: {
|
|
52
|
-
type: "string",
|
|
53
|
-
description: "Verified Harbor intent UUID.",
|
|
54
|
-
},
|
|
55
|
-
audit_id: {
|
|
56
|
-
type: "string",
|
|
57
|
-
description: "Gateway audit identifier when available.",
|
|
58
|
-
},
|
|
99
|
+
...AUTHORIZE_SPEND_OUTPUT_PROPERTIES,
|
|
59
100
|
}, ["tenant", "intent_id"]),
|
|
60
101
|
},
|
|
61
102
|
paybond_authorize_agent_spend: {
|
|
@@ -64,23 +105,58 @@ const TOOL_SELECTION_METADATA = {
|
|
|
64
105
|
"Do not use this for creating, funding, or changing intents; call paybond_create_spend_intent or paybond_fund_intent first when no funded capability token exists.",
|
|
65
106
|
annotations: additiveMutationToolAnnotations("Authorize Agent Spend"),
|
|
66
107
|
outputSchema: outputObjectSchema({
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
108
|
+
...AUTHORIZE_SPEND_OUTPUT_PROPERTIES,
|
|
109
|
+
}, ["tenant", "intent_id"]),
|
|
110
|
+
},
|
|
111
|
+
paybond_get_budget_remaining: {
|
|
112
|
+
title: "Get Budget Remaining",
|
|
113
|
+
description: "Use this when you need a read-only dry-run of remaining spend budget for a tenant-bound intent before authorizing a paid tool. " +
|
|
114
|
+
"Do not use this to authorize spend or create decisions; call paybond_authorize_agent_spend when you are ready to gate a side-effecting tool.",
|
|
115
|
+
annotations: readOnlyToolAnnotations("Get Budget Remaining"),
|
|
116
|
+
outputSchema: outputObjectSchema({
|
|
117
|
+
remaining_cents: {
|
|
118
|
+
type: "integer",
|
|
119
|
+
description: "Remaining spend budget in cents for the evaluated scope, when available.",
|
|
70
120
|
},
|
|
71
|
-
|
|
72
|
-
type: "
|
|
73
|
-
description: "
|
|
121
|
+
spend_scope: {
|
|
122
|
+
type: "object",
|
|
123
|
+
description: "Spend scope used for the budget evaluation (scope_type and scope_key).",
|
|
124
|
+
additionalProperties: true,
|
|
74
125
|
},
|
|
75
|
-
|
|
126
|
+
policy_version: {
|
|
127
|
+
type: "integer",
|
|
128
|
+
description: "Active spend-control policy version when a policy is configured.",
|
|
129
|
+
},
|
|
130
|
+
}, []),
|
|
131
|
+
},
|
|
132
|
+
paybond_explain_policy: {
|
|
133
|
+
title: "Explain Spend Policy",
|
|
134
|
+
description: "Use this when you need a read-only explanation of whether a proposed spend would allow, require approval, or deny under the tenant spend-control policy. " +
|
|
135
|
+
"Do not use this to authorize spend or create approval requests; call paybond_authorize_agent_spend to persist a decision.",
|
|
136
|
+
annotations: readOnlyToolAnnotations("Explain Spend Policy"),
|
|
137
|
+
outputSchema: outputObjectSchema({
|
|
138
|
+
outcome: {
|
|
76
139
|
type: "string",
|
|
77
|
-
description: "
|
|
140
|
+
description: "Normalized policy outcome: allow, approval_required, or deny.",
|
|
78
141
|
},
|
|
79
|
-
|
|
142
|
+
reason_codes: {
|
|
143
|
+
type: "array",
|
|
144
|
+
items: { type: "string" },
|
|
145
|
+
description: "Stable policy reason codes from the dry-run evaluation.",
|
|
146
|
+
},
|
|
147
|
+
explanation: {
|
|
80
148
|
type: "string",
|
|
81
|
-
description: "
|
|
149
|
+
description: "Human-readable explanation derived from reason codes.",
|
|
82
150
|
},
|
|
83
|
-
|
|
151
|
+
remaining_cents: {
|
|
152
|
+
type: "integer",
|
|
153
|
+
description: "Remaining spend budget in cents for the evaluated scope, when available.",
|
|
154
|
+
},
|
|
155
|
+
approval_threshold_exceeded: {
|
|
156
|
+
type: "boolean",
|
|
157
|
+
description: "True when the dry-run indicates the request is at or above the approval threshold.",
|
|
158
|
+
},
|
|
159
|
+
}, ["outcome", "explanation"]),
|
|
84
160
|
},
|
|
85
161
|
paybond_bootstrap_sandbox_guardrail: {
|
|
86
162
|
title: "Bootstrap Sandbox Guardrail",
|
|
@@ -183,52 +259,229 @@ const TOOL_SELECTION_METADATA = {
|
|
|
183
259
|
},
|
|
184
260
|
paybond_get_reputation_receipt: {
|
|
185
261
|
title: "Get Reputation Receipt",
|
|
262
|
+
description: "Use this when you need the signed Signal reputation receipt for one known tenant-scoped operator DID " +
|
|
263
|
+
"(score, metrics, reason codes, and Ed25519 signing material under receipt). " +
|
|
264
|
+
"Requires PAYBOND_API_KEY with Signal analytics read access. " +
|
|
265
|
+
"Do not use this for tenant-wide aggregates—call paybond_get_portfolio_summary—or a portable signed operator list—call " +
|
|
266
|
+
"paybond_get_signed_portfolio_artifact—or one operator's fraud review posture—call paybond_get_fraud_assessment. " +
|
|
267
|
+
"Idempotent read with no side effects; returns null when no receipt exists for that operator and score_version.",
|
|
186
268
|
annotations: readOnlyToolAnnotations("Get Reputation Receipt"),
|
|
187
269
|
outputSchema: outputObjectSchema({
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
270
|
+
schema_version: {
|
|
271
|
+
type: "integer",
|
|
272
|
+
description: "Reputation receipt envelope schema version.",
|
|
273
|
+
},
|
|
274
|
+
updated_at: {
|
|
275
|
+
type: "string",
|
|
276
|
+
description: "RFC3339 timestamp when the stored receipt row was last updated.",
|
|
277
|
+
},
|
|
278
|
+
receipt: {
|
|
279
|
+
type: "object",
|
|
280
|
+
additionalProperties: true,
|
|
281
|
+
description: "Signed Signal receipt for the operator (tenant_id, operator_did, score_version, score, metrics, reason_codes, signing_algorithm, message_digest_hex, signing_public_key_hex, signature_hex).",
|
|
282
|
+
examples: [
|
|
283
|
+
{
|
|
284
|
+
tenant_id: "tenant-a",
|
|
285
|
+
operator_did: "did:web:vendor.example#booker-agent",
|
|
286
|
+
score_version: "1.0",
|
|
287
|
+
score: 812,
|
|
288
|
+
signature_hex: "ab".repeat(32),
|
|
289
|
+
},
|
|
290
|
+
],
|
|
291
|
+
},
|
|
191
292
|
}),
|
|
192
293
|
},
|
|
193
294
|
paybond_get_portfolio_summary: {
|
|
194
295
|
title: "Get Portfolio Summary",
|
|
296
|
+
description: "Use this when you need a read-only, tenant-scoped Signal portfolio aggregate for the authenticated API key " +
|
|
297
|
+
"(operator_count, average_score, total_terminal_intents, total_receipted_volume_cents, operators_under_review, " +
|
|
298
|
+
"and checkpoint_last_ledger_seq). Requires PAYBOND_API_KEY with Signal analytics read access and the private-dashboards feature. " +
|
|
299
|
+
"Do not use this when you need a portable signed operator list for partner or verifier sharing—call " +
|
|
300
|
+
"paybond_get_signed_portfolio_artifact instead—or for one operator's signed receipt—call paybond_get_reputation_receipt. " +
|
|
301
|
+
"Idempotent read with no side effects; auth, RBAC, feature, or gateway failures surface as tool errors.",
|
|
195
302
|
annotations: readOnlyToolAnnotations("Get Portfolio Summary"),
|
|
196
303
|
outputSchema: outputObjectSchema({
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
304
|
+
schema_version: {
|
|
305
|
+
type: "integer",
|
|
306
|
+
description: "Portfolio summary schema version (currently 1).",
|
|
307
|
+
},
|
|
308
|
+
tenant_id: {
|
|
309
|
+
type: "string",
|
|
310
|
+
description: "Tenant echoed by the gateway for the authenticated API key (example: tenant-a).",
|
|
311
|
+
examples: ["tenant-a"],
|
|
312
|
+
},
|
|
313
|
+
score_model_version: {
|
|
314
|
+
type: "string",
|
|
315
|
+
description: "Score model version used for the aggregate (echoes the requested score_version or the gateway default 1.0).",
|
|
316
|
+
examples: ["1.0"],
|
|
317
|
+
},
|
|
318
|
+
scoring_model: {
|
|
319
|
+
type: "string",
|
|
320
|
+
description: "Scoring model identifier used by Signal for this summary.",
|
|
321
|
+
},
|
|
322
|
+
checkpoint_last_ledger_seq: {
|
|
323
|
+
type: "integer",
|
|
324
|
+
description: "Last ledger sequence included in the tenant Signal checkpoint.",
|
|
325
|
+
},
|
|
326
|
+
operator_count: {
|
|
327
|
+
type: "integer",
|
|
328
|
+
description: "Number of operators with reputation data for this score model version.",
|
|
329
|
+
},
|
|
330
|
+
average_score: {
|
|
331
|
+
type: "number",
|
|
332
|
+
description: "Average operator score across the tenant portfolio for this score model version.",
|
|
333
|
+
},
|
|
334
|
+
total_terminal_intents: {
|
|
335
|
+
type: "integer",
|
|
336
|
+
description: "Aggregate terminal Harbor intents across operators in the portfolio.",
|
|
337
|
+
},
|
|
338
|
+
total_receipted_volume_cents: {
|
|
339
|
+
type: "integer",
|
|
340
|
+
description: "Aggregate receipted settlement volume in cents across the portfolio.",
|
|
341
|
+
},
|
|
342
|
+
operators_under_review: {
|
|
343
|
+
type: "integer",
|
|
344
|
+
description: "Count of operators currently under Signal review for this score model version.",
|
|
202
345
|
},
|
|
203
346
|
}),
|
|
204
347
|
},
|
|
205
348
|
paybond_get_signed_portfolio_artifact: {
|
|
206
349
|
title: "Get Signed Portfolio Artifact",
|
|
350
|
+
description: "Use this when you need a portable, tenant-scoped signed Signal portfolio snapshot (operator list plus Ed25519 signing material) " +
|
|
351
|
+
"for offline verifier checks or partner sharing—not a public leaderboard. " +
|
|
352
|
+
"Requires PAYBOND_API_KEY with Signal analytics read access. Omit score_version to use the gateway default current model (1.0). " +
|
|
353
|
+
"Do not use this for tenant-wide aggregates without signatures—call paybond_get_portfolio_summary—or for one operator's signed receipt—call " +
|
|
354
|
+
"paybond_get_reputation_receipt—or for one operator's fraud review posture—call paybond_get_fraud_assessment. " +
|
|
355
|
+
"Idempotent read with no side effects; auth, RBAC, feature, or gateway failures surface as tool errors.",
|
|
207
356
|
annotations: readOnlyToolAnnotations("Get Signed Portfolio Artifact"),
|
|
208
357
|
outputSchema: outputObjectSchema({
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
358
|
+
kind: {
|
|
359
|
+
type: "string",
|
|
360
|
+
description: "Artifact kind identifier (currently paybond.signal.portfolio_snapshot).",
|
|
361
|
+
examples: ["paybond.signal.portfolio_snapshot"],
|
|
362
|
+
},
|
|
363
|
+
tenant_id: {
|
|
364
|
+
type: "string",
|
|
365
|
+
description: "Tenant echoed by the gateway for the authenticated API key (example: tenant-a). Never invent tenant identifiers.",
|
|
366
|
+
examples: ["tenant-a"],
|
|
367
|
+
},
|
|
368
|
+
score_model_version: {
|
|
369
|
+
type: "string",
|
|
370
|
+
description: "Score model version used for the artifact (echoes the requested score_version or the gateway default 1.0).",
|
|
371
|
+
examples: ["1.0"],
|
|
372
|
+
},
|
|
373
|
+
checkpoint_last_ledger_seq: {
|
|
374
|
+
type: "integer",
|
|
375
|
+
description: "Last ledger sequence included in the tenant Signal checkpoint for this artifact.",
|
|
376
|
+
},
|
|
377
|
+
signature_hex: {
|
|
378
|
+
type: "string",
|
|
379
|
+
description: "Ed25519 signature hex over the canonical portfolio artifact payload.",
|
|
380
|
+
},
|
|
213
381
|
}),
|
|
214
382
|
},
|
|
215
383
|
paybond_get_fraud_assessment: {
|
|
216
384
|
title: "Get Fraud Assessment",
|
|
385
|
+
description: "Use this when you need the read-only fraud assessment and review posture for one known tenant-scoped operator DID (review state, fraud signals, and compact fraud_assessment). " +
|
|
386
|
+
"Example: look up operator_did=did:web:vendor.example#booker-agent (optionally score_version=1.0) before deciding whether to continue a spend workflow for that operator. " +
|
|
387
|
+
"Do not use this for tenant-wide fraud backtesting metrics—call paybond_get_fraud_metrics instead—or for Harbor intent escrow detail—call paybond_get_intent. " +
|
|
388
|
+
"Idempotent read; returns null when no assessment exists for that operator.",
|
|
217
389
|
annotations: readOnlyToolAnnotations("Get Fraud Assessment"),
|
|
218
390
|
outputSchema: outputObjectSchema({
|
|
219
|
-
tenant_id: {
|
|
220
|
-
|
|
221
|
-
|
|
391
|
+
tenant_id: {
|
|
392
|
+
type: "string",
|
|
393
|
+
description: "Tenant echoed by the gateway for the authenticated API key (example: tenant-a).",
|
|
394
|
+
examples: ["tenant-a"],
|
|
395
|
+
},
|
|
396
|
+
operator_did: {
|
|
397
|
+
type: "string",
|
|
398
|
+
description: "Operator DID echoed from the assessment response (example: did:web:vendor.example#booker-agent).",
|
|
399
|
+
examples: ["did:web:vendor.example#booker-agent"],
|
|
400
|
+
},
|
|
401
|
+
fraud_assessment: {
|
|
402
|
+
type: "object",
|
|
403
|
+
additionalProperties: true,
|
|
404
|
+
description: "Compact fraud assessment for the operator (level, severity, signal counts, summary). Example shape: {\"level\":\"high\",\"highest_severity\":\"high\",\"signal_count\":1,\"summary\":\"level=high\"}.",
|
|
405
|
+
examples: [
|
|
406
|
+
{
|
|
407
|
+
level: "high",
|
|
408
|
+
highest_severity: "high",
|
|
409
|
+
signal_count: 1,
|
|
410
|
+
summary: "level=high",
|
|
411
|
+
},
|
|
412
|
+
],
|
|
413
|
+
},
|
|
222
414
|
}),
|
|
223
415
|
},
|
|
224
416
|
paybond_get_fraud_metrics: {
|
|
225
417
|
title: "Get Fraud Metrics",
|
|
418
|
+
description: "Use this when you need tenant-wide Signal fraud backtesting and monitoring metrics over a rolling window " +
|
|
419
|
+
"(flagged operators, severity counts, review outcomes, precision/false-positive rates, and backtest_summary). " +
|
|
420
|
+
"Requires PAYBOND_API_KEY with Signal analytics read access and the private-dashboards feature. " +
|
|
421
|
+
"Do not use this for one operator's fraud posture—call paybond_get_fraud_assessment instead—or for Harbor intent escrow detail—call paybond_get_intent. " +
|
|
422
|
+
"Idempotent read with no side effects; omit window to default to 24h; unsupported windows fail with HTTP 400 " +
|
|
423
|
+
"(\"window must be one of 24h, 7d, or 30d\").",
|
|
226
424
|
annotations: readOnlyToolAnnotations("Get Fraud Metrics"),
|
|
227
425
|
outputSchema: outputObjectSchema({
|
|
228
|
-
tenant_id: {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
426
|
+
tenant_id: {
|
|
427
|
+
type: "string",
|
|
428
|
+
description: "Tenant echoed by the gateway for the authenticated API key (example: tenant-a).",
|
|
429
|
+
examples: ["tenant-a"],
|
|
430
|
+
},
|
|
431
|
+
score_model_version: {
|
|
432
|
+
type: "string",
|
|
433
|
+
description: "Score model version used for the metrics (echoes the requested score_version or the gateway default 1.0).",
|
|
434
|
+
examples: ["1.0"],
|
|
435
|
+
},
|
|
436
|
+
window: {
|
|
437
|
+
type: "string",
|
|
438
|
+
description: "Active metrics window label: 24h, 7d, or 30d.",
|
|
439
|
+
examples: ["24h", "7d", "30d"],
|
|
440
|
+
},
|
|
441
|
+
window_started_at: {
|
|
442
|
+
type: "string",
|
|
443
|
+
description: "RFC3339 start of the evaluated rolling window.",
|
|
444
|
+
},
|
|
445
|
+
window_ended_at: {
|
|
446
|
+
type: "string",
|
|
447
|
+
description: "RFC3339 end of the evaluated rolling window.",
|
|
448
|
+
},
|
|
449
|
+
flagged_operator_count: {
|
|
450
|
+
type: "integer",
|
|
451
|
+
description: "Operators with at least one fraud signal in the window.",
|
|
452
|
+
},
|
|
453
|
+
critical_signal_count: {
|
|
454
|
+
type: "integer",
|
|
455
|
+
description: "Count of critical-severity fraud signals in the window.",
|
|
456
|
+
},
|
|
457
|
+
high_signal_count: {
|
|
458
|
+
type: "integer",
|
|
459
|
+
description: "Count of high-severity fraud signals in the window.",
|
|
460
|
+
},
|
|
461
|
+
elevated_signal_count: {
|
|
462
|
+
type: "integer",
|
|
463
|
+
description: "Count of elevated-severity fraud signals in the window.",
|
|
464
|
+
},
|
|
465
|
+
review_open_count: {
|
|
466
|
+
type: "integer",
|
|
467
|
+
description: "Operators currently in an open review state.",
|
|
468
|
+
},
|
|
469
|
+
labeled_outcome_count: {
|
|
470
|
+
type: "integer",
|
|
471
|
+
description: "Review outcomes labeled in the window (confirmed risk, false positive, or needs more evidence).",
|
|
472
|
+
},
|
|
473
|
+
confirmed_risk_count: {
|
|
474
|
+
type: "integer",
|
|
475
|
+
description: "Labeled confirmed-risk outcomes in the window.",
|
|
476
|
+
},
|
|
477
|
+
false_positive_count: {
|
|
478
|
+
type: "integer",
|
|
479
|
+
description: "Labeled false-positive outcomes in the window.",
|
|
480
|
+
},
|
|
481
|
+
backtest_summary: {
|
|
482
|
+
type: "string",
|
|
483
|
+
description: "Human-readable backtest summary derived from the window metrics.",
|
|
484
|
+
},
|
|
232
485
|
}),
|
|
233
486
|
},
|
|
234
487
|
paybond_get_a2a_agent_card: {
|
|
@@ -299,10 +552,40 @@ const TOOL_SELECTION_METADATA = {
|
|
|
299
552
|
},
|
|
300
553
|
paybond_verify_protocol_receipt_v1: {
|
|
301
554
|
title: "Verify Protocol Receipt",
|
|
555
|
+
description: "Use this when you already have a signed protocol-v2 authorization or settlement receipt JSON object and need offline Ed25519 verification (structure, message digest, and signature) through the gateway. " +
|
|
556
|
+
"Do not use this to verify AgentMandateV1 envelopes—call paybond_verify_agent_mandate_v1—or to check a Harbor capability token before spend—call paybond_verify_capability or paybond_authorize_agent_spend. " +
|
|
557
|
+
"To load a settlement receipt by intent UUID first, call paybond_get_settlement_receipt_v1 then pass its body here. " +
|
|
558
|
+
"Read-only and side-effect free: success returns valid=true with kind, receipt_id, tenant_id, and the normalized receipt; unsupported kind, malformed JSON, digest mismatch, or bad signature fail with a gateway error (typically HTTP 400).",
|
|
302
559
|
annotations: readOnlyToolAnnotations("Verify Protocol Receipt"),
|
|
303
560
|
outputSchema: outputObjectSchema({
|
|
304
|
-
valid: {
|
|
305
|
-
|
|
561
|
+
valid: {
|
|
562
|
+
type: "boolean",
|
|
563
|
+
description: "True when the gateway accepted the receipt structure and Ed25519 signature. Example: true.",
|
|
564
|
+
examples: [true],
|
|
565
|
+
},
|
|
566
|
+
kind: {
|
|
567
|
+
type: "string",
|
|
568
|
+
description: "Verified receipt kind echoed from the normalized receipt. One of paybond.protocol_authorization_receipt_v1 or paybond.protocol_settlement_receipt_v1.",
|
|
569
|
+
examples: [
|
|
570
|
+
"paybond.protocol_authorization_receipt_v1",
|
|
571
|
+
"paybond.protocol_settlement_receipt_v1",
|
|
572
|
+
],
|
|
573
|
+
},
|
|
574
|
+
receipt_id: {
|
|
575
|
+
type: "string",
|
|
576
|
+
description: "Canonical receipt identifier from the verified receipt.",
|
|
577
|
+
examples: ["550e8400-e29b-41d4-a716-446655440000"],
|
|
578
|
+
},
|
|
579
|
+
tenant_id: {
|
|
580
|
+
type: "string",
|
|
581
|
+
description: "Tenant id embedded in the verified receipt (not invented by the caller).",
|
|
582
|
+
examples: ["acme-pilot"],
|
|
583
|
+
},
|
|
584
|
+
receipt: {
|
|
585
|
+
type: "object",
|
|
586
|
+
additionalProperties: true,
|
|
587
|
+
description: "Normalized verified receipt object matching the input kind (authorization or settlement fields plus signing material).",
|
|
588
|
+
},
|
|
306
589
|
}),
|
|
307
590
|
},
|
|
308
591
|
paybond_create_intent: {
|
|
@@ -732,6 +1015,70 @@ class PaybondMCPRuntime {
|
|
|
732
1015
|
}
|
|
733
1016
|
return body;
|
|
734
1017
|
}
|
|
1018
|
+
/**
|
|
1019
|
+
* Side-effect-free spend policy dry-run via `POST /v1/spend/preflight`.
|
|
1020
|
+
* Tenant scope comes from the authenticated API key only.
|
|
1021
|
+
*/
|
|
1022
|
+
async spendPreflight(init) {
|
|
1023
|
+
const payload = {
|
|
1024
|
+
intent_id: init.intentId,
|
|
1025
|
+
operation: init.operation?.trim() || "*",
|
|
1026
|
+
requested_spend_cents: init.requestedSpendCents ?? 0,
|
|
1027
|
+
};
|
|
1028
|
+
if (init.vendorId?.trim()) {
|
|
1029
|
+
payload.vendor_id = init.vendorId.trim();
|
|
1030
|
+
}
|
|
1031
|
+
if (init.toolName?.trim()) {
|
|
1032
|
+
payload.tool_name = init.toolName.trim();
|
|
1033
|
+
}
|
|
1034
|
+
if (init.taskId?.trim()) {
|
|
1035
|
+
payload.task_id = init.taskId.trim();
|
|
1036
|
+
}
|
|
1037
|
+
if (init.workflowId?.trim()) {
|
|
1038
|
+
payload.workflow_id = init.workflowId.trim();
|
|
1039
|
+
}
|
|
1040
|
+
if (init.toolCallId?.trim()) {
|
|
1041
|
+
payload.tool_call_id = init.toolCallId.trim();
|
|
1042
|
+
}
|
|
1043
|
+
if (init.currency?.trim()) {
|
|
1044
|
+
payload.currency = init.currency.trim();
|
|
1045
|
+
}
|
|
1046
|
+
if (init.agentSubject?.trim()) {
|
|
1047
|
+
payload.agent_subject = init.agentSubject.trim();
|
|
1048
|
+
}
|
|
1049
|
+
if (init.approvalToken?.trim()) {
|
|
1050
|
+
payload.approval_token = init.approvalToken.trim();
|
|
1051
|
+
}
|
|
1052
|
+
return this.gateway.postJSON("/v1/spend/preflight", payload, {
|
|
1053
|
+
"x-tenant-id": await this.tenantId(),
|
|
1054
|
+
});
|
|
1055
|
+
}
|
|
1056
|
+
async getBudgetRemaining(init) {
|
|
1057
|
+
const body = await this.spendPreflight(init);
|
|
1058
|
+
return {
|
|
1059
|
+
remaining_cents: body.remaining_cents ?? null,
|
|
1060
|
+
spend_scope: body.spend_scope ?? null,
|
|
1061
|
+
policy_version: body.policy_version ?? null,
|
|
1062
|
+
};
|
|
1063
|
+
}
|
|
1064
|
+
async explainPolicy(init) {
|
|
1065
|
+
const body = await this.spendPreflight(init);
|
|
1066
|
+
const reasonCodes = Array.isArray(body.reason_codes)
|
|
1067
|
+
? body.reason_codes.map((code) => String(code))
|
|
1068
|
+
: [];
|
|
1069
|
+
const outcome = normalizeExplainPolicyOutcome(String(body.outcome ?? ""), String(body.classification ?? ""));
|
|
1070
|
+
const result = {
|
|
1071
|
+
outcome,
|
|
1072
|
+
reason_codes: reasonCodes,
|
|
1073
|
+
explanation: String(body.explanation ?? ""),
|
|
1074
|
+
remaining_cents: body.remaining_cents ?? null,
|
|
1075
|
+
};
|
|
1076
|
+
if (reasonCodes.includes("approval_threshold_exceeded") ||
|
|
1077
|
+
outcome === "approval_required") {
|
|
1078
|
+
result.approval_threshold_exceeded = reasonCodes.includes("approval_threshold_exceeded");
|
|
1079
|
+
}
|
|
1080
|
+
return result;
|
|
1081
|
+
}
|
|
735
1082
|
async bootstrapSandboxGuardrail(init) {
|
|
736
1083
|
const expectedTenant = await this.tenantId();
|
|
737
1084
|
const payload = {
|
|
@@ -1203,7 +1550,13 @@ export class PaybondMCPServer {
|
|
|
1203
1550
|
const tools = [
|
|
1204
1551
|
{
|
|
1205
1552
|
name: "paybond_get_principal",
|
|
1206
|
-
description: "
|
|
1553
|
+
description: "Use this when you need to confirm which tenant-bound service-account principal the configured PAYBOND_API_KEY authenticates as " +
|
|
1554
|
+
"(tenant_id, subject, and roles). Call early as a prerequisite before Harbor escrow, Signal reads, or other tenant-scoped tools when " +
|
|
1555
|
+
"tenant identity is unknown. Not required before every later call once tenant_id is already known from a prior principal response or host config. " +
|
|
1556
|
+
"Do not use this when you need Harbor intent escrow detail; use paybond_get_intent instead when you have an intent_id. " +
|
|
1557
|
+
"Do not use this for A2A discovery; use paybond_get_a2a_agent_card instead. " +
|
|
1558
|
+
"Makes one read-only external GET to the gateway principal endpoint; idempotent identity lookup with no side effects " +
|
|
1559
|
+
"(no mutations, spend reservations, escrow changes, or ledger writes); auth or gateway failures surface as tool errors.",
|
|
1207
1560
|
inputSchema: emptyObjectSchema(),
|
|
1208
1561
|
call: async () => this.runtime.principal(),
|
|
1209
1562
|
},
|
|
@@ -1275,6 +1628,18 @@ export class PaybondMCPServer {
|
|
|
1275
1628
|
});
|
|
1276
1629
|
},
|
|
1277
1630
|
},
|
|
1631
|
+
{
|
|
1632
|
+
name: "paybond_get_budget_remaining",
|
|
1633
|
+
description: "Read-only dry-run of remaining spend budget for a tenant-bound intent via gateway spend preflight.",
|
|
1634
|
+
inputSchema: spendPreflightInputSchema(),
|
|
1635
|
+
call: async (args) => this.runtime.getBudgetRemaining(parseSpendPreflightArgs(args)),
|
|
1636
|
+
},
|
|
1637
|
+
{
|
|
1638
|
+
name: "paybond_explain_policy",
|
|
1639
|
+
description: "Read-only dry-run explanation of whether proposed spend would allow, require approval, or deny under tenant spend policy.",
|
|
1640
|
+
inputSchema: spendPreflightInputSchema(),
|
|
1641
|
+
call: async (args) => this.runtime.explainPolicy(parseSpendPreflightArgs(args)),
|
|
1642
|
+
},
|
|
1278
1643
|
{
|
|
1279
1644
|
name: "paybond_bootstrap_sandbox_guardrail",
|
|
1280
1645
|
description: "Bootstrap a sandbox-only Paybond guardrail intent for a first paid-tool integration. Tenant scope is derived from the configured service-account API key and the route never touches live settlement rails.",
|
|
@@ -1433,8 +1798,19 @@ export class PaybondMCPServer {
|
|
|
1433
1798
|
name: "paybond_get_reputation_receipt",
|
|
1434
1799
|
description: "Fetch the signed Signal receipt for one operator DID.",
|
|
1435
1800
|
inputSchema: objectSchema({
|
|
1436
|
-
operator_did: {
|
|
1437
|
-
|
|
1801
|
+
operator_did: {
|
|
1802
|
+
type: "string",
|
|
1803
|
+
description: "Tenant-scoped operator DID whose signed Signal reputation receipt to fetch. Must belong to the authenticated tenant; do not invent tenant identifiers. Examples: did:web:vendor.example#booker-agent, did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK.",
|
|
1804
|
+
examples: [
|
|
1805
|
+
"did:web:vendor.example#booker-agent",
|
|
1806
|
+
"did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK",
|
|
1807
|
+
],
|
|
1808
|
+
},
|
|
1809
|
+
score_version: {
|
|
1810
|
+
type: "string",
|
|
1811
|
+
description: "Optional Signal score model version to query. Omit to use the gateway default current model (1.0). Example: 1.0.",
|
|
1812
|
+
examples: ["1.0"],
|
|
1813
|
+
},
|
|
1438
1814
|
}, ["operator_did"]),
|
|
1439
1815
|
call: async (args) => (await this.runtime.signal()).getReputationReceipt(stringArg(args.operator_did, "operator_did"), optionalString(args.score_version)),
|
|
1440
1816
|
},
|
|
@@ -1442,7 +1818,11 @@ export class PaybondMCPServer {
|
|
|
1442
1818
|
name: "paybond_get_portfolio_summary",
|
|
1443
1819
|
description: "Fetch the tenant-scoped Signal portfolio summary.",
|
|
1444
1820
|
inputSchema: objectSchema({
|
|
1445
|
-
score_version: {
|
|
1821
|
+
score_version: {
|
|
1822
|
+
type: "string",
|
|
1823
|
+
description: "Optional Signal score model version to query. Omit to use the gateway default current model (1.0). Example: 1.0.",
|
|
1824
|
+
examples: ["1.0"],
|
|
1825
|
+
},
|
|
1446
1826
|
}),
|
|
1447
1827
|
call: async (args) => (await this.runtime.signal()).getPortfolioSummary(optionalString(args.score_version)),
|
|
1448
1828
|
},
|
|
@@ -1450,7 +1830,11 @@ export class PaybondMCPServer {
|
|
|
1450
1830
|
name: "paybond_get_signed_portfolio_artifact",
|
|
1451
1831
|
description: "Fetch the tenant-scoped signed Signal portfolio artifact for portable verifier and partner sharing.",
|
|
1452
1832
|
inputSchema: objectSchema({
|
|
1453
|
-
score_version: {
|
|
1833
|
+
score_version: {
|
|
1834
|
+
type: "string",
|
|
1835
|
+
description: "Optional Signal score model version to query. Omit to use the gateway default current model (1.0). Example: 1.0.",
|
|
1836
|
+
examples: ["1.0"],
|
|
1837
|
+
},
|
|
1454
1838
|
}),
|
|
1455
1839
|
call: async (args) => (await this.runtime.signal()).getSignedPortfolioArtifact(optionalString(args.score_version)),
|
|
1456
1840
|
},
|
|
@@ -1458,8 +1842,19 @@ export class PaybondMCPServer {
|
|
|
1458
1842
|
name: "paybond_get_fraud_assessment",
|
|
1459
1843
|
description: "Fetch the read-only fraud assessment for one tenant-scoped operator DID.",
|
|
1460
1844
|
inputSchema: objectSchema({
|
|
1461
|
-
operator_did: {
|
|
1462
|
-
|
|
1845
|
+
operator_did: {
|
|
1846
|
+
type: "string",
|
|
1847
|
+
description: "Tenant-scoped operator DID to assess. Must belong to the authenticated tenant; do not invent tenant identifiers. Examples: did:web:vendor.example#booker-agent, did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK.",
|
|
1848
|
+
examples: [
|
|
1849
|
+
"did:web:vendor.example#booker-agent",
|
|
1850
|
+
"did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK",
|
|
1851
|
+
],
|
|
1852
|
+
},
|
|
1853
|
+
score_version: {
|
|
1854
|
+
type: "string",
|
|
1855
|
+
description: "Optional Signal score model version to query. Omit to use the gateway default current model. Example: 1.0.",
|
|
1856
|
+
examples: ["1.0"],
|
|
1857
|
+
},
|
|
1463
1858
|
}, ["operator_did"]),
|
|
1464
1859
|
call: async (args) => (await this.runtime.fraud()).getFraudAssessment(stringArg(args.operator_did, "operator_did"), optionalString(args.score_version)),
|
|
1465
1860
|
},
|
|
@@ -1467,8 +1862,17 @@ export class PaybondMCPServer {
|
|
|
1467
1862
|
name: "paybond_get_fraud_metrics",
|
|
1468
1863
|
description: "Fetch tenant-scoped read-only fraud backtesting and monitoring metrics for a supported active window.",
|
|
1469
1864
|
inputSchema: objectSchema({
|
|
1470
|
-
window: {
|
|
1471
|
-
|
|
1865
|
+
window: {
|
|
1866
|
+
type: "string",
|
|
1867
|
+
enum: ["24h", "7d", "30d"],
|
|
1868
|
+
description: "Rolling metrics window. Allowed values: 24h, 7d, 30d. Omit to use the gateway default 24h. Unsupported values fail with HTTP 400.",
|
|
1869
|
+
examples: ["24h", "7d", "30d"],
|
|
1870
|
+
},
|
|
1871
|
+
score_version: {
|
|
1872
|
+
type: "string",
|
|
1873
|
+
description: "Optional Signal score model version to query. Omit to use the gateway default current model (1.0). Example: 1.0.",
|
|
1874
|
+
examples: ["1.0"],
|
|
1875
|
+
},
|
|
1472
1876
|
}),
|
|
1473
1877
|
call: async (args) => (await this.runtime.fraud()).getFraudMetrics({
|
|
1474
1878
|
window: optionalString(args.window),
|
|
@@ -1546,9 +1950,16 @@ export class PaybondMCPServer {
|
|
|
1546
1950
|
},
|
|
1547
1951
|
{
|
|
1548
1952
|
name: "paybond_verify_protocol_receipt_v1",
|
|
1549
|
-
description: "Verify a protocol-v2 authorization or settlement receipt through the gateway.",
|
|
1953
|
+
description: "Verify a signed protocol-v2 authorization or settlement receipt through the gateway.",
|
|
1550
1954
|
inputSchema: objectSchema({
|
|
1551
|
-
receipt: {
|
|
1955
|
+
receipt: {
|
|
1956
|
+
type: "object",
|
|
1957
|
+
additionalProperties: true,
|
|
1958
|
+
description: "Complete signed protocol receipt object posted as the verify request body (not a receipt_id string). " +
|
|
1959
|
+
"Discriminate on kind: paybond.protocol_authorization_receipt_v1 requires schema_version=1, receipt_version=\"1\", receipt_id, issued_at, status (authorized), intent_id, tenant_id, verifier_id, transport_binding, mandate_digest_sha256_hex, imported_mandate_signing_public_key_ed25519_hex, authorization, agent, allowed_actions, allowed_tools, spend_ceiling, settlement, constraint, expires_at, nonce, human_presence_mode, plus signing_algorithm=ed25519-sha256-json-v1, message_digest_sha256_hex, signing_public_key_ed25519_hex, and ed25519_signature_hex. " +
|
|
1960
|
+
"paybond.protocol_settlement_receipt_v1 requires schema_version=1, receipt_version=\"1\", receipt_id, issued_at, intent_id, tenant_id, verifier_id, transport_binding, authorization_receipt_id, mandate_digest_sha256_hex, harbor_state, settlement_rail, settlement_mode, principal_did, payee_did, currency, amount_cents, terminal_observed_at, optional predicate_passed, and the same Ed25519 signing fields. " +
|
|
1961
|
+
"Obtain receipts from mandate import, paybond_get_settlement_receipt_v1, audit export, or partner handoff—do not invent digests or signatures.",
|
|
1962
|
+
},
|
|
1552
1963
|
}, ["receipt"]),
|
|
1553
1964
|
call: async (args) => this.runtime.verifyProtocolReceiptV1(ensureObject(args.receipt, "receipt")),
|
|
1554
1965
|
},
|
|
@@ -1722,6 +2133,93 @@ function stringArg(value, field) {
|
|
|
1722
2133
|
function optionalString(value) {
|
|
1723
2134
|
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
1724
2135
|
}
|
|
2136
|
+
function spendPreflightInputSchema() {
|
|
2137
|
+
return objectSchema({
|
|
2138
|
+
intent_id: {
|
|
2139
|
+
type: "string",
|
|
2140
|
+
description: "Canonical Harbor intent UUID.",
|
|
2141
|
+
},
|
|
2142
|
+
operation: {
|
|
2143
|
+
type: "string",
|
|
2144
|
+
description: "Optional delegated operation or tool name. Defaults to * when omitted.",
|
|
2145
|
+
},
|
|
2146
|
+
requested_spend_cents: {
|
|
2147
|
+
type: "integer",
|
|
2148
|
+
description: "Optional proposed spend in cents for the dry-run evaluation.",
|
|
2149
|
+
},
|
|
2150
|
+
vendor_id: {
|
|
2151
|
+
type: "string",
|
|
2152
|
+
description: "Optional vendor scope hint for policy evaluation.",
|
|
2153
|
+
},
|
|
2154
|
+
tool_name: {
|
|
2155
|
+
type: "string",
|
|
2156
|
+
description: "Optional tool name scope hint for policy evaluation.",
|
|
2157
|
+
},
|
|
2158
|
+
task_id: {
|
|
2159
|
+
type: "string",
|
|
2160
|
+
description: "Optional task scope hint for policy evaluation.",
|
|
2161
|
+
},
|
|
2162
|
+
workflow_id: {
|
|
2163
|
+
type: "string",
|
|
2164
|
+
description: "Optional workflow scope hint for policy evaluation.",
|
|
2165
|
+
},
|
|
2166
|
+
tool_call_id: {
|
|
2167
|
+
type: "string",
|
|
2168
|
+
description: "Optional tool-call correlation id for policy evaluation.",
|
|
2169
|
+
},
|
|
2170
|
+
currency: {
|
|
2171
|
+
type: "string",
|
|
2172
|
+
description: "Optional ISO currency code for the proposed spend.",
|
|
2173
|
+
},
|
|
2174
|
+
agent_subject: {
|
|
2175
|
+
type: "string",
|
|
2176
|
+
description: "Optional agent subject for agent-scoped caps.",
|
|
2177
|
+
},
|
|
2178
|
+
approval_token: {
|
|
2179
|
+
type: "string",
|
|
2180
|
+
description: "Optional approval token to evaluate against pending approval state (not consumed).",
|
|
2181
|
+
},
|
|
2182
|
+
}, ["intent_id"]);
|
|
2183
|
+
}
|
|
2184
|
+
function parseSpendPreflightArgs(args) {
|
|
2185
|
+
return {
|
|
2186
|
+
intentId: uuidArg(args.intent_id, "intent_id"),
|
|
2187
|
+
operation: optionalString(args.operation),
|
|
2188
|
+
requestedSpendCents: args.requested_spend_cents === undefined
|
|
2189
|
+
? undefined
|
|
2190
|
+
: intArg(args.requested_spend_cents, "requested_spend_cents"),
|
|
2191
|
+
vendorId: optionalString(args.vendor_id),
|
|
2192
|
+
toolName: optionalString(args.tool_name),
|
|
2193
|
+
taskId: optionalString(args.task_id),
|
|
2194
|
+
workflowId: optionalString(args.workflow_id),
|
|
2195
|
+
toolCallId: optionalString(args.tool_call_id),
|
|
2196
|
+
currency: optionalString(args.currency),
|
|
2197
|
+
agentSubject: optionalString(args.agent_subject),
|
|
2198
|
+
approvalToken: optionalString(args.approval_token),
|
|
2199
|
+
};
|
|
2200
|
+
}
|
|
2201
|
+
/** Normalize gateway preflight outcomes to the agent-facing explain-policy set. */
|
|
2202
|
+
function normalizeExplainPolicyOutcome(outcome, classification) {
|
|
2203
|
+
const normalized = outcome.trim().toLowerCase();
|
|
2204
|
+
if (normalized === "allow" || normalized === "anomaly_observe") {
|
|
2205
|
+
return "allow";
|
|
2206
|
+
}
|
|
2207
|
+
if (normalized === "approval_required" ||
|
|
2208
|
+
normalized === "anomaly_escalate") {
|
|
2209
|
+
return "approval_required";
|
|
2210
|
+
}
|
|
2211
|
+
if (normalized === "deny") {
|
|
2212
|
+
return "deny";
|
|
2213
|
+
}
|
|
2214
|
+
const classNorm = classification.trim().toLowerCase();
|
|
2215
|
+
if (classNorm === "allow") {
|
|
2216
|
+
return "allow";
|
|
2217
|
+
}
|
|
2218
|
+
if (classNorm === "hold") {
|
|
2219
|
+
return "approval_required";
|
|
2220
|
+
}
|
|
2221
|
+
return "deny";
|
|
2222
|
+
}
|
|
1725
2223
|
function intArg(value, field) {
|
|
1726
2224
|
const parsed = typeof value === "number"
|
|
1727
2225
|
? value
|