-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmpp.js
More file actions
84 lines (72 loc) · 2.99 KB
/
Copy pathmpp.js
File metadata and controls
84 lines (72 loc) · 2.99 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
/**
* MPP (Machine Payment Protocol) 402 Handler Middleware
*
* Enables agents to autonomously handle 'Payment Required' (HTTP 402) flows.
* If an agent hits a 402, it checks for a valid mandate, generates a cart mandate,
* and retries the request with the payment header.
*/
class MPP402Handler {
constructor(agentService, mandateService) {
this.agentService = agentService;
this.mandateService = mandateService;
}
/**
* Handle an autonomous request that might result in a 402
* @param {Object} agent - The acting agent
* @param {Function} requestFn - The function that executes the request
* @param {string} intentMandateToken - The agent's pre-authorized intent mandate
*/
async executeAutonomousRequest(agent, requestFn, intentMandateToken) {
try {
let response = await requestFn();
if (response.status === 402) {
return await this._handle402Response(agent, response, intentMandateToken, requestFn);
}
return response;
} catch (error) {
if (error.response?.status === 402) {
return await this._handle402Response(agent, error.response, intentMandateToken, requestFn);
}
throw error;
}
}
/**
* Handle 402 response and retry
* @private
*/
async _handle402Response(agent, response, intentMandateToken, requestFn) {
console.log(`MPP: Handling 402 Payment Required for agent ${agent.name}`);
// 1. Extract payment requirement details from headers or body
// MPP standard uses headers like 'X-MPP-Amount' and 'X-MPP-Merchant-DID'
const amount = parseFloat(response.headers?.['x-mpp-amount'] || response.data?.amount);
const currency = response.headers?.['x-mpp-currency'] || response.data?.currency || 'USD';
const merchantDid = response.headers?.['x-mpp-merchant-did'] || response.data?.merchant_did;
const cartItems = response.data?.cart_items || [{ item: 'API_CALL', quantity: 1 }];
if (!amount || !merchantDid) {
throw new Error('Incomplete payment requirements in 402 response');
}
// 2. Validate Intent Mandate
const decodedIntent = await this.mandateService.verifyMandate(intentMandateToken);
// Check if the 402 request is within the intent's budget
if (amount > decodedIntent.max_budget.value) {
throw new Error(`MPP: Payment amount ${amount} exceeds intent mandate budget of ${decodedIntent.max_budget.value}`);
}
// 3. Generate a Cart Mandate for the specific 402 request
console.log(`MPP: Issuing autonomous cart mandate for amount ${amount}`);
const cartMandateToken = await this.mandateService.issueCartMandate({
intentMandate: intentMandateToken,
cartItems,
totalPrice: amount,
merchantDid
});
// 4. Retry the request with the Payment Mandate header
console.log(`MPP: Retrying request with Cart Mandate...`);
return await requestFn({
headers: {
'X-OCP-Cart-Mandate': cartMandateToken,
'Authorization': `Bearer ${agent.id}`
}
});
}
}
module.exports = MPP402Handler;