@agirails/sdk 3.3.0 → 3.5.3
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/api/agirailsApp.d.ts +21 -1
- package/dist/api/agirailsApp.d.ts.map +1 -1
- package/dist/api/agirailsApp.js.map +1 -1
- package/dist/builders/CounterAcceptBuilder.d.ts +96 -0
- package/dist/builders/CounterAcceptBuilder.d.ts.map +1 -0
- package/dist/builders/CounterAcceptBuilder.js +226 -0
- package/dist/builders/CounterAcceptBuilder.js.map +1 -0
- package/dist/builders/CounterOfferBuilder.d.ts +143 -0
- package/dist/builders/CounterOfferBuilder.d.ts.map +1 -0
- package/dist/builders/CounterOfferBuilder.js +329 -0
- package/dist/builders/CounterOfferBuilder.js.map +1 -0
- package/dist/builders/QuoteBuilder.d.ts +9 -3
- package/dist/builders/QuoteBuilder.d.ts.map +1 -1
- package/dist/builders/QuoteBuilder.js +22 -6
- package/dist/builders/QuoteBuilder.js.map +1 -1
- package/dist/builders/index.d.ts +2 -0
- package/dist/builders/index.d.ts.map +1 -1
- package/dist/builders/index.js +7 -1
- package/dist/builders/index.js.map +1 -1
- package/dist/cli/agirails.js +22 -2
- package/dist/cli/agirails.js.map +1 -1
- package/dist/cli/commands/agent.d.ts +22 -0
- package/dist/cli/commands/agent.d.ts.map +1 -0
- package/dist/cli/commands/agent.js +209 -0
- package/dist/cli/commands/agent.js.map +1 -0
- package/dist/cli/commands/health.js +21 -5
- package/dist/cli/commands/health.js.map +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +25 -5
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/publish.d.ts +34 -0
- package/dist/cli/commands/publish.d.ts.map +1 -1
- package/dist/cli/commands/publish.js +256 -80
- package/dist/cli/commands/publish.js.map +1 -1
- package/dist/cli/commands/repair.d.ts +23 -0
- package/dist/cli/commands/repair.d.ts.map +1 -0
- package/dist/cli/commands/repair.js +210 -0
- package/dist/cli/commands/repair.js.map +1 -0
- package/dist/cli/commands/serve.d.ts +38 -0
- package/dist/cli/commands/serve.d.ts.map +1 -0
- package/dist/cli/commands/serve.js +308 -0
- package/dist/cli/commands/serve.js.map +1 -0
- package/dist/cli/commands/test.js +2 -2
- package/dist/cli/commands/test.js.map +1 -1
- package/dist/cli/index.js +10 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/config/agirailsmdV4.d.ts +46 -1
- package/dist/config/agirailsmdV4.d.ts.map +1 -1
- package/dist/config/agirailsmdV4.js +65 -8
- package/dist/config/agirailsmdV4.js.map +1 -1
- package/dist/config/defaults.d.ts +10 -0
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +10 -0
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/networks.d.ts.map +1 -1
- package/dist/config/networks.js +7 -1
- package/dist/config/networks.js.map +1 -1
- package/dist/config/publishPipeline.d.ts +23 -1
- package/dist/config/publishPipeline.d.ts.map +1 -1
- package/dist/config/publishPipeline.js +70 -15
- package/dist/config/publishPipeline.js.map +1 -1
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +39 -3
- package/dist/index.js.map +1 -1
- package/dist/level1/Agent.d.ts +27 -0
- package/dist/level1/Agent.d.ts.map +1 -1
- package/dist/level1/Agent.js +77 -6
- package/dist/level1/Agent.js.map +1 -1
- package/dist/negotiation/BuyerOrchestrator.d.ts +115 -1
- package/dist/negotiation/BuyerOrchestrator.d.ts.map +1 -1
- package/dist/negotiation/BuyerOrchestrator.js +530 -4
- package/dist/negotiation/BuyerOrchestrator.js.map +1 -1
- package/dist/negotiation/DecisionEngine.d.ts +69 -1
- package/dist/negotiation/DecisionEngine.d.ts.map +1 -1
- package/dist/negotiation/DecisionEngine.js +140 -1
- package/dist/negotiation/DecisionEngine.js.map +1 -1
- package/dist/negotiation/MockChannel.d.ts +63 -0
- package/dist/negotiation/MockChannel.d.ts.map +1 -0
- package/dist/negotiation/MockChannel.js +175 -0
- package/dist/negotiation/MockChannel.js.map +1 -0
- package/dist/negotiation/NegotiationChannel.d.ts +142 -0
- package/dist/negotiation/NegotiationChannel.d.ts.map +1 -0
- package/dist/negotiation/NegotiationChannel.js +59 -0
- package/dist/negotiation/NegotiationChannel.js.map +1 -0
- package/dist/negotiation/PolicyEngine.d.ts +32 -0
- package/dist/negotiation/PolicyEngine.d.ts.map +1 -1
- package/dist/negotiation/PolicyEngine.js.map +1 -1
- package/dist/negotiation/ProviderOrchestrator.d.ts +158 -0
- package/dist/negotiation/ProviderOrchestrator.d.ts.map +1 -0
- package/dist/negotiation/ProviderOrchestrator.js +286 -0
- package/dist/negotiation/ProviderOrchestrator.js.map +1 -0
- package/dist/negotiation/ProviderPolicy.d.ts +188 -0
- package/dist/negotiation/ProviderPolicy.d.ts.map +1 -0
- package/dist/negotiation/ProviderPolicy.js +259 -0
- package/dist/negotiation/ProviderPolicy.js.map +1 -0
- package/dist/negotiation/RelayChannel.d.ts +59 -0
- package/dist/negotiation/RelayChannel.d.ts.map +1 -0
- package/dist/negotiation/RelayChannel.js +208 -0
- package/dist/negotiation/RelayChannel.js.map +1 -0
- package/dist/negotiation/index.d.ts +8 -1
- package/dist/negotiation/index.d.ts.map +1 -1
- package/dist/negotiation/index.js +8 -1
- package/dist/negotiation/index.js.map +1 -1
- package/dist/negotiation/verifyQuoteOnChain.d.ts +58 -0
- package/dist/negotiation/verifyQuoteOnChain.d.ts.map +1 -0
- package/dist/negotiation/verifyQuoteOnChain.js +83 -0
- package/dist/negotiation/verifyQuoteOnChain.js.map +1 -0
- package/dist/protocol/ACTPKernel.d.ts.map +1 -1
- package/dist/protocol/ACTPKernel.js +51 -1
- package/dist/protocol/ACTPKernel.js.map +1 -1
- package/dist/runtime/BlockchainRuntime.d.ts +13 -0
- package/dist/runtime/BlockchainRuntime.d.ts.map +1 -1
- package/dist/runtime/BlockchainRuntime.js +33 -2
- package/dist/runtime/BlockchainRuntime.js.map +1 -1
- package/dist/runtime/IACTPRuntime.d.ts +35 -0
- package/dist/runtime/IACTPRuntime.d.ts.map +1 -1
- package/dist/runtime/MockRuntime.d.ts +11 -0
- package/dist/runtime/MockRuntime.d.ts.map +1 -1
- package/dist/runtime/MockRuntime.js +39 -0
- package/dist/runtime/MockRuntime.js.map +1 -1
- package/dist/runtime/types/MockState.d.ts +10 -0
- package/dist/runtime/types/MockState.d.ts.map +1 -1
- package/dist/runtime/types/MockState.js.map +1 -1
- package/dist/transport/QuoteChannel.d.ts +201 -0
- package/dist/transport/QuoteChannel.d.ts.map +1 -0
- package/dist/transport/QuoteChannel.js +358 -0
- package/dist/transport/QuoteChannel.js.map +1 -0
- package/dist/types/adapter.d.ts +24 -24
- package/package.json +16 -1
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* ProviderOrchestrator — autonomous provider-side negotiation flow.
|
|
4
|
+
*
|
|
5
|
+
* Two responsibilities:
|
|
6
|
+
*
|
|
7
|
+
* 1. Accept an incoming request → decide whether to quote → if yes,
|
|
8
|
+
* build + sign a QuoteMessage, anchor on-chain via submitQuote,
|
|
9
|
+
* post it on the NegotiationChannel for the buyer.
|
|
10
|
+
*
|
|
11
|
+
* 2. (3.5.0) Run a long-lived `start()` listener on the channel:
|
|
12
|
+
* every counter that arrives is evaluated against ProviderPolicy;
|
|
13
|
+
* based on `counter_strategy` we either auto-accept (build + post
|
|
14
|
+
* CounterAcceptMessage), auto-requote (build + post a new
|
|
15
|
+
* QuoteMessage with the conceded amount), or walk (log + drop).
|
|
16
|
+
*
|
|
17
|
+
* Symmetric to BuyerOrchestrator's channel-driven multi-round loop —
|
|
18
|
+
* together they implement the full AIP-2.1 §6 negotiation protocol
|
|
19
|
+
* without either party needing to host an HTTP endpoint.
|
|
20
|
+
*
|
|
21
|
+
* @module negotiation/ProviderOrchestrator
|
|
22
|
+
* @see Protocol/aips/AIP-2.1.md §5.2 (provider quote flow)
|
|
23
|
+
* @see Protocol/aips/AIP-2.1.md §6 (NegotiationChannel)
|
|
24
|
+
*/
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.ProviderOrchestrator = void 0;
|
|
27
|
+
const QuoteBuilder_1 = require("../builders/QuoteBuilder");
|
|
28
|
+
const CounterOfferBuilder_1 = require("../builders/CounterOfferBuilder");
|
|
29
|
+
const CounterAcceptBuilder_1 = require("../builders/CounterAcceptBuilder");
|
|
30
|
+
const NonceManager_1 = require("../utils/NonceManager");
|
|
31
|
+
const NegotiationChannel_1 = require("./NegotiationChannel");
|
|
32
|
+
const ProviderPolicy_1 = require("./ProviderPolicy");
|
|
33
|
+
// ============================================================================
|
|
34
|
+
// Orchestrator
|
|
35
|
+
// ============================================================================
|
|
36
|
+
class ProviderOrchestrator {
|
|
37
|
+
constructor(cfg) {
|
|
38
|
+
/** Per-tx state for the multi-round counter listener. */
|
|
39
|
+
this.txStates = new Map();
|
|
40
|
+
this.policy = cfg.policy;
|
|
41
|
+
this.policyEngine = new ProviderPolicy_1.ProviderPolicyEngine(cfg.policy);
|
|
42
|
+
this.runtime = cfg.runtime;
|
|
43
|
+
this.signer = cfg.signer;
|
|
44
|
+
this.kernelAddress = cfg.kernelAddress;
|
|
45
|
+
this.chainId = cfg.chainId;
|
|
46
|
+
this.providerDID = cfg.providerDID;
|
|
47
|
+
this.nonceManager = cfg.nonceManager ?? new NonceManager_1.InMemoryNonceManager();
|
|
48
|
+
this.negotiationChannel = cfg.negotiationChannel;
|
|
49
|
+
this.log = cfg.log ?? (() => undefined);
|
|
50
|
+
this.quoteBuilder = new QuoteBuilder_1.QuoteBuilder(this.signer, this.nonceManager);
|
|
51
|
+
this.counterVerifier = new CounterOfferBuilder_1.CounterOfferBuilder(); // verify-only
|
|
52
|
+
this.counterAcceptBuilder = new CounterAcceptBuilder_1.CounterAcceptBuilder(this.signer, this.nonceManager);
|
|
53
|
+
}
|
|
54
|
+
// --------------------------------------------------------------------------
|
|
55
|
+
// One-shot quote (caller-driven)
|
|
56
|
+
// --------------------------------------------------------------------------
|
|
57
|
+
/**
|
|
58
|
+
* Decide whether to quote. Pure policy — no chain, no channel.
|
|
59
|
+
*/
|
|
60
|
+
evaluateRequest(req) {
|
|
61
|
+
const result = this.policyEngine.evaluate(req);
|
|
62
|
+
if (!result.allowed) {
|
|
63
|
+
return {
|
|
64
|
+
action: 'skip',
|
|
65
|
+
reason: result.violations.map((v) => `${v.rule}: ${v.detail}`).join('; '),
|
|
66
|
+
violations: result.violations,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
action: 'quote',
|
|
71
|
+
amountBaseUnits: result.recommended_quote_amount_base_units,
|
|
72
|
+
reason: `Policy passed; recommended quote ${result.recommended_quote_amount_base_units} base units`,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Full quote flow: evaluate → build signed QuoteMessage → submit
|
|
77
|
+
* on-chain → post on negotiationChannel.
|
|
78
|
+
*
|
|
79
|
+
* Channel post failure is non-fatal: on-chain anchor succeeded so
|
|
80
|
+
* buyer can still observe the quote, just won't see the off-chain
|
|
81
|
+
* signed body. Caller can retry channel post separately.
|
|
82
|
+
*/
|
|
83
|
+
async quote(req, providerDID) {
|
|
84
|
+
const decision = this.evaluateRequest(req);
|
|
85
|
+
if (decision.action === 'skip')
|
|
86
|
+
return { decision };
|
|
87
|
+
const now = Math.floor(Date.now() / 1000);
|
|
88
|
+
const currency = this.policyEngine.policyCurrency;
|
|
89
|
+
const decimals = currency.toUpperCase() === 'USDC' ? 6 : 6;
|
|
90
|
+
const quote = await this.quoteBuilder.build({
|
|
91
|
+
txId: req.txId,
|
|
92
|
+
provider: providerDID,
|
|
93
|
+
consumer: req.consumer,
|
|
94
|
+
quotedAmount: decision.amountBaseUnits,
|
|
95
|
+
originalAmount: req.offeredAmount,
|
|
96
|
+
maxPrice: req.maxPrice,
|
|
97
|
+
currency,
|
|
98
|
+
decimals,
|
|
99
|
+
expiresAt: now + this.policyEngine.quoteTtlSeconds,
|
|
100
|
+
chainId: this.chainId,
|
|
101
|
+
kernelAddress: this.kernelAddress,
|
|
102
|
+
});
|
|
103
|
+
await this.runtime.submitQuote(req.txId, quote);
|
|
104
|
+
if (this.negotiationChannel) {
|
|
105
|
+
try {
|
|
106
|
+
await this.negotiationChannel.post(req.txId, { type: 'agirails.quote.v1', message: quote });
|
|
107
|
+
}
|
|
108
|
+
catch (err) {
|
|
109
|
+
return { decision, quote, channelError: err instanceof Error ? err.message : String(err) };
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// Seed per-tx state so a follow-up counter is evaluated with the
|
|
113
|
+
// right `lastQuote` baseline if the listener is running.
|
|
114
|
+
this.txStates.set(req.txId, {
|
|
115
|
+
lastQuote: quote,
|
|
116
|
+
requotesUsed: 0,
|
|
117
|
+
consumerDID: req.consumer,
|
|
118
|
+
});
|
|
119
|
+
return { decision, quote };
|
|
120
|
+
}
|
|
121
|
+
// --------------------------------------------------------------------------
|
|
122
|
+
// Long-running listener (channel-driven, multi-round)
|
|
123
|
+
// --------------------------------------------------------------------------
|
|
124
|
+
/**
|
|
125
|
+
* Subscribe to the negotiation channel and auto-respond to incoming
|
|
126
|
+
* counter-offers per `counter_strategy`. Idempotent — calling start()
|
|
127
|
+
* twice replaces the previous subscription.
|
|
128
|
+
*
|
|
129
|
+
* Returns a Subscription so the caller can stop the daemon cleanly.
|
|
130
|
+
*
|
|
131
|
+
* @throws if `negotiationChannel` or `providerDID` was not set in config.
|
|
132
|
+
*/
|
|
133
|
+
async start() {
|
|
134
|
+
if (!this.negotiationChannel) {
|
|
135
|
+
throw new Error('ProviderOrchestrator.start() requires negotiationChannel in config');
|
|
136
|
+
}
|
|
137
|
+
if (!this.providerDID) {
|
|
138
|
+
throw new Error('ProviderOrchestrator.start() requires providerDID in config');
|
|
139
|
+
}
|
|
140
|
+
// Replace any prior subscription.
|
|
141
|
+
if (this.channelSubscription) {
|
|
142
|
+
this.channelSubscription.unsubscribe();
|
|
143
|
+
}
|
|
144
|
+
const sub = this.negotiationChannel.subscribeAgent(this.providerDID, async (txId, delivered) => {
|
|
145
|
+
if (!(0, NegotiationChannel_1.isCounterOfferEnvelope)(delivered.envelope))
|
|
146
|
+
return;
|
|
147
|
+
try {
|
|
148
|
+
await this._handleIncomingCounter(txId, delivered.envelope.message);
|
|
149
|
+
}
|
|
150
|
+
catch (err) {
|
|
151
|
+
this.log('error', `Counter handler crashed for tx ${txId.slice(0, 12)}…: ${err instanceof Error ? err.message : String(err)}`);
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
this.channelSubscription = sub;
|
|
155
|
+
this.log('info', `ProviderOrchestrator listening on channel for ${this.providerDID}`);
|
|
156
|
+
return {
|
|
157
|
+
unsubscribe: () => {
|
|
158
|
+
sub.unsubscribe();
|
|
159
|
+
this.channelSubscription = undefined;
|
|
160
|
+
this.log('info', 'ProviderOrchestrator stopped');
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Stop the active channel subscription if any. Idempotent.
|
|
166
|
+
*/
|
|
167
|
+
stop() {
|
|
168
|
+
if (this.channelSubscription) {
|
|
169
|
+
this.channelSubscription.unsubscribe();
|
|
170
|
+
this.channelSubscription = undefined;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
// --------------------------------------------------------------------------
|
|
174
|
+
// Single-shot counter evaluation (tests + callers that want manual control)
|
|
175
|
+
// --------------------------------------------------------------------------
|
|
176
|
+
/**
|
|
177
|
+
* Verify + evaluate a buyer counter-offer. Returns the decision
|
|
178
|
+
* (accept / reject / requote with concession amount). Does NOT send
|
|
179
|
+
* any response — caller drives the next step. Use `start()` for
|
|
180
|
+
* autonomous operation.
|
|
181
|
+
*
|
|
182
|
+
* `lastQuoteAmountBaseUnits` — provider's most recent quote amount
|
|
183
|
+
* for this tx. On the first counter pass `counter.quoteAmount`.
|
|
184
|
+
*
|
|
185
|
+
* `requotesUsed` — defaults to 0; pass the real count for multi-round.
|
|
186
|
+
*
|
|
187
|
+
* @throws if the counter signature / band / expiry fails verify.
|
|
188
|
+
*/
|
|
189
|
+
async evaluateCounter(counter, lastQuoteAmountBaseUnits, requotesUsed = 0) {
|
|
190
|
+
await this.counterVerifier.verify(counter, this.kernelAddress);
|
|
191
|
+
const lastAmount = lastQuoteAmountBaseUnits ?? counter.quoteAmount;
|
|
192
|
+
const verdict = this.policyEngine.evaluateCounter(counter.counterAmount, lastAmount, requotesUsed);
|
|
193
|
+
if (verdict.decision === 'requote') {
|
|
194
|
+
return { action: 'requote', amountBaseUnits: verdict.amountBaseUnits, reason: verdict.reason };
|
|
195
|
+
}
|
|
196
|
+
return { action: verdict.decision, reason: verdict.reason };
|
|
197
|
+
}
|
|
198
|
+
/** Read-only policy accessor for UIs and tests. */
|
|
199
|
+
getPolicy() {
|
|
200
|
+
return this.policy;
|
|
201
|
+
}
|
|
202
|
+
// --------------------------------------------------------------------------
|
|
203
|
+
// Internals
|
|
204
|
+
// --------------------------------------------------------------------------
|
|
205
|
+
async _handleIncomingCounter(txId, counter) {
|
|
206
|
+
if (!this.providerDID || !this.negotiationChannel)
|
|
207
|
+
return;
|
|
208
|
+
// Look up per-tx state. If we never quoted (counter arrived without
|
|
209
|
+
// prior `quote()` call), we still process — `counter.quoteAmount`
|
|
210
|
+
// is the provider's quote per buyer's view, so we use it as baseline.
|
|
211
|
+
const state = this.txStates.get(txId) ?? {
|
|
212
|
+
lastQuote: null,
|
|
213
|
+
requotesUsed: 0,
|
|
214
|
+
consumerDID: counter.consumer,
|
|
215
|
+
};
|
|
216
|
+
const lastAmount = state.lastQuote?.quotedAmount ?? counter.quoteAmount;
|
|
217
|
+
let decision;
|
|
218
|
+
try {
|
|
219
|
+
decision = await this.evaluateCounter(counter, lastAmount, state.requotesUsed);
|
|
220
|
+
}
|
|
221
|
+
catch (err) {
|
|
222
|
+
this.log('warn', `[counter] tx=${txId.slice(0, 12)}… verify failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
this.log('info', `[counter] tx=${txId.slice(0, 12)}… counter=${counter.counterAmount} → ${decision.action}: ${decision.reason}`);
|
|
226
|
+
if (decision.action === 'accept') {
|
|
227
|
+
const accept = await this.counterAcceptBuilder.build({
|
|
228
|
+
txId,
|
|
229
|
+
provider: this.providerDID,
|
|
230
|
+
consumer: counter.consumer,
|
|
231
|
+
acceptedAmount: counter.counterAmount,
|
|
232
|
+
inReplyTo: new CounterOfferBuilder_1.CounterOfferBuilder().computeHash(counter),
|
|
233
|
+
chainId: this.chainId,
|
|
234
|
+
kernelAddress: this.kernelAddress,
|
|
235
|
+
});
|
|
236
|
+
await this.negotiationChannel.post(txId, { type: 'agirails.counteraccept.v1', message: accept });
|
|
237
|
+
this.txStates.delete(txId); // terminal
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
if (decision.action === 'requote') {
|
|
241
|
+
const now = Math.floor(Date.now() / 1000);
|
|
242
|
+
const currency = this.policyEngine.policyCurrency;
|
|
243
|
+
const decimals = currency.toUpperCase() === 'USDC' ? 6 : 6;
|
|
244
|
+
// QuoteBuilder enforces `quotedAmount >= originalAmount` (AIP-2
|
|
245
|
+
// invariant: provider can't quote below buyer's offered amount).
|
|
246
|
+
// For re-quotes the buyer's original amount lives on-chain
|
|
247
|
+
// as tx.amount (set at createTransaction, immutable until
|
|
248
|
+
// acceptQuote). Fall back to counter.counterAmount if read
|
|
249
|
+
// fails (matches what buyer is willing to pay anyway).
|
|
250
|
+
let originalAmount = counter.counterAmount;
|
|
251
|
+
try {
|
|
252
|
+
const onChainTx = await this.runtime.getTransaction(txId);
|
|
253
|
+
if (onChainTx?.amount)
|
|
254
|
+
originalAmount = String(onChainTx.amount);
|
|
255
|
+
}
|
|
256
|
+
catch {
|
|
257
|
+
/* fall back to counter.counterAmount */
|
|
258
|
+
}
|
|
259
|
+
const newQuote = await this.quoteBuilder.build({
|
|
260
|
+
txId,
|
|
261
|
+
provider: this.providerDID,
|
|
262
|
+
consumer: counter.consumer,
|
|
263
|
+
quotedAmount: decision.amountBaseUnits,
|
|
264
|
+
originalAmount,
|
|
265
|
+
maxPrice: counter.maxPrice,
|
|
266
|
+
currency,
|
|
267
|
+
decimals,
|
|
268
|
+
expiresAt: now + this.policyEngine.quoteTtlSeconds,
|
|
269
|
+
chainId: this.chainId,
|
|
270
|
+
kernelAddress: this.kernelAddress,
|
|
271
|
+
});
|
|
272
|
+
// Re-quotes are off-chain only — kernel forbids QUOTED → QUOTED.
|
|
273
|
+
await this.negotiationChannel.post(txId, { type: 'agirails.quote.v1', message: newQuote });
|
|
274
|
+
this.txStates.set(txId, {
|
|
275
|
+
lastQuote: newQuote,
|
|
276
|
+
requotesUsed: state.requotesUsed + 1,
|
|
277
|
+
consumerDID: counter.consumer,
|
|
278
|
+
});
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
// reject — let buyer's TTL expire to CANCELLED. Drop state.
|
|
282
|
+
this.txStates.delete(txId);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
exports.ProviderOrchestrator = ProviderOrchestrator;
|
|
286
|
+
//# sourceMappingURL=ProviderOrchestrator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProviderOrchestrator.js","sourceRoot":"","sources":["../../src/negotiation/ProviderOrchestrator.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;;;AAIH,2DAAsE;AACtE,yEAGyC;AACzC,2EAE0C;AAC1C,wDAA2E;AAC3E,6DAI8B;AAC9B,qDAI0B;AAuE1B,+EAA+E;AAC/E,eAAe;AACf,+EAA+E;AAE/E,MAAa,oBAAoB;IAoB/B,YAAY,GAA+B;QAL3C,yDAAyD;QACxC,aAAQ,GAAG,IAAI,GAAG,EAAmB,CAAC;QAKrD,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;QACzB,IAAI,CAAC,YAAY,GAAG,IAAI,qCAAoB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACzD,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC;QAC3B,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;QACzB,IAAI,CAAC,aAAa,GAAG,GAAG,CAAC,aAAa,CAAC;QACvC,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC;QAC3B,IAAI,CAAC,WAAW,GAAG,GAAG,CAAC,WAAW,CAAC;QACnC,IAAI,CAAC,YAAY,GAAG,GAAG,CAAC,YAAY,IAAI,IAAI,mCAAoB,EAAE,CAAC;QACnE,IAAI,CAAC,kBAAkB,GAAG,GAAG,CAAC,kBAAkB,CAAC;QACjD,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QACxC,IAAI,CAAC,YAAY,GAAG,IAAI,2BAAY,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;QACrE,IAAI,CAAC,eAAe,GAAG,IAAI,yCAAmB,EAAE,CAAC,CAAC,cAAc;QAChE,IAAI,CAAC,oBAAoB,GAAG,IAAI,2CAAoB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;IACvF,CAAC;IAED,6EAA6E;IAC7E,iCAAiC;IACjC,6EAA6E;IAE7E;;OAEG;IACH,eAAe,CAAC,GAAoB;QAClC,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QAC/C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO;gBACL,MAAM,EAAE,MAAM;gBACd,MAAM,EAAE,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;gBACzE,UAAU,EAAE,MAAM,CAAC,UAAU;aAC9B,CAAC;QACJ,CAAC;QACD,OAAO;YACL,MAAM,EAAE,OAAO;YACf,eAAe,EAAE,MAAM,CAAC,mCAAoC;YAC5D,MAAM,EAAE,oCAAoC,MAAM,CAAC,mCAAmC,aAAa;SACpG,CAAC;IACJ,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,KAAK,CAAC,GAAoB,EAAE,WAAmB;QACnD,MAAM,QAAQ,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;QAC3C,IAAI,QAAQ,CAAC,MAAM,KAAK,MAAM;YAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;QAEpD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;QAC1C,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,cAAc,CAAC;QAClD,MAAM,QAAQ,GAAG,QAAQ,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3D,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC;YAC1C,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,QAAQ,EAAE,WAAW;YACrB,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,YAAY,EAAE,QAAQ,CAAC,eAAe;YACtC,cAAc,EAAE,GAAG,CAAC,aAAa;YACjC,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,QAAQ;YACR,QAAQ;YACR,SAAS,EAAE,GAAG,GAAG,IAAI,CAAC,YAAY,CAAC,eAAe;YAClD,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,aAAa,EAAE,IAAI,CAAC,aAAa;SAClC,CAAC,CAAC;QAEH,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAEhD,IAAI,IAAI,CAAC,kBAAkB,EAAE,CAAC;YAC5B,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;YAC9F,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;YAC7F,CAAC;QACH,CAAC;QAED,iEAAiE;QACjE,yDAAyD;QACzD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE;YAC1B,SAAS,EAAE,KAAK;YAChB,YAAY,EAAE,CAAC;YACf,WAAW,EAAE,GAAG,CAAC,QAAQ;SAC1B,CAAC,CAAC;QAEH,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IAC7B,CAAC;IAED,6EAA6E;IAC7E,sDAAsD;IACtD,6EAA6E;IAE7E;;;;;;;;OAQG;IACH,KAAK,CAAC,KAAK;QACT,IAAI,CAAC,IAAI,CAAC,kBAAkB,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CAAC,oEAAoE,CAAC,CAAC;QACxF,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACtB,MAAM,IAAI,KAAK,CAAC,6DAA6D,CAAC,CAAC;QACjF,CAAC;QAED,kCAAkC;QAClC,IAAI,IAAI,CAAC,mBAAmB,EAAE,CAAC;YAC7B,IAAI,CAAC,mBAAmB,CAAC,WAAW,EAAE,CAAC;QACzC,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,CAAC,kBAAkB,CAAC,cAAc,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE;YAC7F,IAAI,CAAC,IAAA,2CAAsB,EAAC,SAAS,CAAC,QAAQ,CAAC;gBAAE,OAAO;YACxD,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,sBAAsB,CAAC,IAAI,EAAE,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YACtE,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,kCAAkC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACjI,CAAC;QACH,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,mBAAmB,GAAG,GAAG,CAAC;QAC/B,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,iDAAiD,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;QACtF,OAAO;YACL,WAAW,EAAE,GAAG,EAAE;gBAChB,GAAG,CAAC,WAAW,EAAE,CAAC;gBAClB,IAAI,CAAC,mBAAmB,GAAG,SAAS,CAAC;gBACrC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,8BAA8B,CAAC,CAAC;YACnD,CAAC;SACF,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,IAAI;QACF,IAAI,IAAI,CAAC,mBAAmB,EAAE,CAAC;YAC7B,IAAI,CAAC,mBAAmB,CAAC,WAAW,EAAE,CAAC;YACvC,IAAI,CAAC,mBAAmB,GAAG,SAAS,CAAC;QACvC,CAAC;IACH,CAAC;IAED,6EAA6E;IAC7E,4EAA4E;IAC5E,6EAA6E;IAE7E;;;;;;;;;;;;OAYG;IACH,KAAK,CAAC,eAAe,CACnB,OAA4B,EAC5B,wBAAiC,EACjC,YAAY,GAAG,CAAC;QAEhB,MAAM,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;QAC/D,MAAM,UAAU,GAAG,wBAAwB,IAAI,OAAO,CAAC,WAAW,CAAC;QACnE,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,eAAe,CAAC,OAAO,CAAC,aAAa,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC;QACnG,IAAI,OAAO,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YACnC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,eAAe,EAAE,OAAO,CAAC,eAAgB,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;QAClG,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;IAC9D,CAAC;IAED,mDAAmD;IACnD,SAAS;QACP,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED,6EAA6E;IAC7E,YAAY;IACZ,6EAA6E;IAErE,KAAK,CAAC,sBAAsB,CAAC,IAAY,EAAE,OAA4B;QAC7E,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,kBAAkB;YAAE,OAAO;QAE1D,oEAAoE;QACpE,kEAAkE;QAClE,sEAAsE;QACtE,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI;YACvC,SAAS,EAAE,IAA+B;YAC1C,YAAY,EAAE,CAAC;YACf,WAAW,EAAE,OAAO,CAAC,QAAQ;SAC9B,CAAC;QACF,MAAM,UAAU,GAAG,KAAK,CAAC,SAAS,EAAE,YAAY,IAAI,OAAO,CAAC,WAAW,CAAC;QAExE,IAAI,QAAyB,CAAC;QAC9B,IAAI,CAAC;YACH,QAAQ,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,OAAO,EAAE,UAAU,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;QACjF,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,gBAAgB,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,oBAAoB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC1H,OAAO;QACT,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,gBAAgB,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,OAAO,CAAC,aAAa,MAAM,QAAQ,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QAEjI,IAAI,QAAQ,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YACjC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,oBAAoB,CAAC,KAAK,CAAC;gBACnD,IAAI;gBACJ,QAAQ,EAAE,IAAI,CAAC,WAAW;gBAC1B,QAAQ,EAAE,OAAO,CAAC,QAAQ;gBAC1B,cAAc,EAAE,OAAO,CAAC,aAAa;gBACrC,SAAS,EAAE,IAAI,yCAAmB,EAAE,CAAC,WAAW,CAAC,OAAO,CAAC;gBACzD,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,aAAa,EAAE,IAAI,CAAC,aAAa;aAClC,CAAC,CAAC;YACH,MAAM,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,2BAA2B,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;YACjG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW;YACvC,OAAO;QACT,CAAC;QAED,IAAI,QAAQ,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAClC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;YAC1C,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,cAAc,CAAC;YAClD,MAAM,QAAQ,GAAG,QAAQ,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC3D,gEAAgE;YAChE,iEAAiE;YACjE,2DAA2D;YAC3D,0DAA0D;YAC1D,2DAA2D;YAC3D,uDAAuD;YACvD,IAAI,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;YAC3C,IAAI,CAAC;gBACH,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;gBAC1D,IAAI,SAAS,EAAE,MAAM;oBAAE,cAAc,GAAG,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YACnE,CAAC;YAAC,MAAM,CAAC;gBACP,wCAAwC;YAC1C,CAAC;YACD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC;gBAC7C,IAAI;gBACJ,QAAQ,EAAE,IAAI,CAAC,WAAW;gBAC1B,QAAQ,EAAE,OAAO,CAAC,QAAQ;gBAC1B,YAAY,EAAE,QAAQ,CAAC,eAAe;gBACtC,cAAc;gBACd,QAAQ,EAAE,OAAO,CAAC,QAAQ;gBAC1B,QAAQ;gBACR,QAAQ;gBACR,SAAS,EAAE,GAAG,GAAG,IAAI,CAAC,YAAY,CAAC,eAAe;gBAClD,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,aAAa,EAAE,IAAI,CAAC,aAAa;aAClC,CAAC,CAAC;YACH,iEAAiE;YACjE,MAAM,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;YAC3F,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE;gBACtB,SAAS,EAAE,QAAQ;gBACnB,YAAY,EAAE,KAAK,CAAC,YAAY,GAAG,CAAC;gBACpC,WAAW,EAAE,OAAO,CAAC,QAAQ;aAC9B,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,4DAA4D;QAC5D,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;CACF;AA7RD,oDA6RC"}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ProviderPolicy — hard guardrails for autonomous provider quoting.
|
|
3
|
+
*
|
|
4
|
+
* Symmetric to BuyerPolicy. Provider configures what they'll deliver,
|
|
5
|
+
* their price floor, and their lifecycle preferences; ProviderPolicyEngine
|
|
6
|
+
* enforces those invariants on every incoming request so the provider
|
|
7
|
+
* never quotes below floor, outside their service menu, or for a
|
|
8
|
+
* transaction they can't realistically complete before the deadline.
|
|
9
|
+
*
|
|
10
|
+
* @module negotiation/ProviderPolicy
|
|
11
|
+
* @see Protocol/aips/AIP-2.1-DRAFT.md §5.2 (ProviderPolicy.ts creation)
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* What this agent provides + at what terms.
|
|
15
|
+
*
|
|
16
|
+
* Pricing invariant (enforced at construction):
|
|
17
|
+
* ideal_price.amount ≥ min_acceptable.amount ≥ PLATFORM_MIN_USDC
|
|
18
|
+
*
|
|
19
|
+
* `currency`/`unit` must be identical across min_acceptable and
|
|
20
|
+
* ideal_price — we compare amounts directly, there's no FX in v1.
|
|
21
|
+
*/
|
|
22
|
+
export interface ProviderPolicy {
|
|
23
|
+
/**
|
|
24
|
+
* Services this provider offers. Incoming requests for service types
|
|
25
|
+
* NOT in this list get a 'skip' decision (let the tx timeout to
|
|
26
|
+
* CANCELLED; we don't quote for work we don't do).
|
|
27
|
+
*/
|
|
28
|
+
services: string[];
|
|
29
|
+
pricing: {
|
|
30
|
+
/** Absolute floor. Any buyer maxPrice below this → skip. */
|
|
31
|
+
min_acceptable: {
|
|
32
|
+
amount: number;
|
|
33
|
+
currency: string;
|
|
34
|
+
unit: string;
|
|
35
|
+
};
|
|
36
|
+
/** Preferred quote amount when buyer's maxPrice ≥ ideal. */
|
|
37
|
+
ideal_price: {
|
|
38
|
+
amount: number;
|
|
39
|
+
currency: string;
|
|
40
|
+
unit: string;
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
/** Quote validity window (e.g. "15m"). Governs our QuoteMessage expiresAt. */
|
|
44
|
+
quote_ttl: string;
|
|
45
|
+
/**
|
|
46
|
+
* Minimum time (seconds) we need between now and tx.deadline to
|
|
47
|
+
* realistically deliver. Requests with a tighter deadline get 'skip'.
|
|
48
|
+
* Defaults to 60s if omitted.
|
|
49
|
+
*/
|
|
50
|
+
min_deadline_seconds?: number;
|
|
51
|
+
/**
|
|
52
|
+
* Multi-round counter strategy (3.5.0). Controls what the orchestrator
|
|
53
|
+
* does when a buyer's counter is below our floor:
|
|
54
|
+
*
|
|
55
|
+
* 'walk' — reject and log; buyer's TTL expires → CANCELLED. Default.
|
|
56
|
+
* 'concede' — re-quote at a price between our previous quote and
|
|
57
|
+
* our floor (governed by `concede_pct`), up to
|
|
58
|
+
* `max_requotes` times before walking.
|
|
59
|
+
*
|
|
60
|
+
* The buyer side enforces its own `rounds_per_provider` cap; provider
|
|
61
|
+
* `max_requotes` is independent and provides defense-in-depth — if a
|
|
62
|
+
* misbehaving buyer keeps countering low, we stop responding after N
|
|
63
|
+
* concessions.
|
|
64
|
+
*/
|
|
65
|
+
counter_strategy?: 'walk' | 'concede';
|
|
66
|
+
/**
|
|
67
|
+
* Concede strategy: when re-quoting, our new amount =
|
|
68
|
+
* last_quote - (last_quote - floor) * concede_pct / 100
|
|
69
|
+
*
|
|
70
|
+
* Default 30 (we move 30% of the way from last quote toward floor
|
|
71
|
+
* each round). Bounded [1, 99]; 100 would give the buyer everything
|
|
72
|
+
* (just accept), 0 would be a no-op.
|
|
73
|
+
*/
|
|
74
|
+
concede_pct?: number;
|
|
75
|
+
/**
|
|
76
|
+
* Hard cap on re-quotes per (provider, txId). Default 2 — combined
|
|
77
|
+
* with the buyer's typical rounds_per_provider=3 this gives 1 initial
|
|
78
|
+
* quote + 2 re-quotes = 3 quote messages total per tx, matching the
|
|
79
|
+
* buyer's expected exchange depth.
|
|
80
|
+
*/
|
|
81
|
+
max_requotes?: number;
|
|
82
|
+
}
|
|
83
|
+
export type ProviderPolicyViolation = {
|
|
84
|
+
rule: 'service_not_offered';
|
|
85
|
+
detail: string;
|
|
86
|
+
} | {
|
|
87
|
+
rule: 'max_price_below_floor';
|
|
88
|
+
detail: string;
|
|
89
|
+
} | {
|
|
90
|
+
rule: 'deadline_too_tight';
|
|
91
|
+
detail: string;
|
|
92
|
+
} | {
|
|
93
|
+
rule: 'currency_mismatch';
|
|
94
|
+
detail: string;
|
|
95
|
+
} | {
|
|
96
|
+
rule: 'unit_mismatch';
|
|
97
|
+
detail: string;
|
|
98
|
+
};
|
|
99
|
+
export interface ProviderPolicyResult {
|
|
100
|
+
allowed: boolean;
|
|
101
|
+
violations: ProviderPolicyViolation[];
|
|
102
|
+
/**
|
|
103
|
+
* When `allowed`, the amount we SHOULD quote per this policy,
|
|
104
|
+
* expressed in USDC base units (1e6 per $1) as a decimal string.
|
|
105
|
+
* Using string-of-base-units throughout avoids Number/float drift
|
|
106
|
+
* on very large amounts and matches what the QuoteMessage carries.
|
|
107
|
+
*
|
|
108
|
+
* Rule: quote our ideal if buyer maxPrice ≥ ideal; otherwise quote
|
|
109
|
+
* at buyer maxPrice (still ≥ floor, validated above). Never below
|
|
110
|
+
* min_acceptable.
|
|
111
|
+
*/
|
|
112
|
+
recommended_quote_amount_base_units?: string;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Incoming request surface — the minimum the orchestrator needs to
|
|
116
|
+
* decide whether + at what price to quote. Extracted from the
|
|
117
|
+
* on-chain transaction plus any off-chain context the caller has
|
|
118
|
+
* (service type, consumer DID).
|
|
119
|
+
*/
|
|
120
|
+
export interface IncomingRequest {
|
|
121
|
+
txId: string;
|
|
122
|
+
consumer: string;
|
|
123
|
+
/** Buyer's offered amount in USDC base units (smallest unit, string). */
|
|
124
|
+
offeredAmount: string;
|
|
125
|
+
/** Buyer's ceiling in USDC base units. */
|
|
126
|
+
maxPrice: string;
|
|
127
|
+
/** Unix seconds — tx.deadline from on-chain. */
|
|
128
|
+
deadline: number;
|
|
129
|
+
/** Service identifier (e.g. "code-review"). */
|
|
130
|
+
serviceType: string;
|
|
131
|
+
currency: string;
|
|
132
|
+
unit: string;
|
|
133
|
+
}
|
|
134
|
+
export declare class ProviderPolicyEngine {
|
|
135
|
+
private readonly policy;
|
|
136
|
+
private readonly floorBaseUnits;
|
|
137
|
+
private readonly idealBaseUnits;
|
|
138
|
+
private readonly currency;
|
|
139
|
+
constructor(policy: ProviderPolicy);
|
|
140
|
+
/**
|
|
141
|
+
* Evaluate an incoming request against policy. Returns `allowed: true`
|
|
142
|
+
* with `recommended_quote_amount_base_units` (bigint-as-string) when
|
|
143
|
+
* we should quote, or `allowed: false` with the specific rule(s)
|
|
144
|
+
* violated.
|
|
145
|
+
*
|
|
146
|
+
* All numeric comparisons use BigInt on base units — no float drift,
|
|
147
|
+
* no precision loss for large amounts.
|
|
148
|
+
*/
|
|
149
|
+
evaluate(req: IncomingRequest): ProviderPolicyResult;
|
|
150
|
+
/**
|
|
151
|
+
* Decide what to do with a buyer's counter-offer (3.5.0 multi-round).
|
|
152
|
+
*
|
|
153
|
+
* accept — counter ≥ floor: take the deal
|
|
154
|
+
* requote — counter < floor AND counter_strategy === 'concede' AND
|
|
155
|
+
* requotesUsed < max_requotes: send a new quote at the
|
|
156
|
+
* concession price (between last quote and floor)
|
|
157
|
+
* reject — anything else (walk strategy, or requote budget spent)
|
|
158
|
+
*
|
|
159
|
+
* `lastQuoteAmountBaseUnits` is the amount we most recently quoted to
|
|
160
|
+
* this txId — the concession baseline. On the FIRST counter it equals
|
|
161
|
+
* the counter's `quoteAmount` field (provider's original quote);
|
|
162
|
+
* on subsequent rounds it equals the orchestrator's most recent
|
|
163
|
+
* re-quote.
|
|
164
|
+
*
|
|
165
|
+
* `requotesUsed` is how many re-quotes we've already sent for this
|
|
166
|
+
* txId. Pass 0 on first call.
|
|
167
|
+
*
|
|
168
|
+
* All arithmetic uses BigInt on base units — no float drift.
|
|
169
|
+
*/
|
|
170
|
+
evaluateCounter(counterAmountBaseUnits: string, lastQuoteAmountBaseUnits: string, requotesUsed: number): {
|
|
171
|
+
decision: 'accept' | 'reject' | 'requote';
|
|
172
|
+
reason: string;
|
|
173
|
+
amountBaseUnits?: string;
|
|
174
|
+
};
|
|
175
|
+
/** Expose ttl as seconds for callers building QuoteMessage.expiresAt. */
|
|
176
|
+
get quoteTtlSeconds(): number;
|
|
177
|
+
/** Expose the policy's currency for orchestrator wiring. */
|
|
178
|
+
get policyCurrency(): string;
|
|
179
|
+
/** Expose the policy's unit for orchestrator wiring + UI. */
|
|
180
|
+
get policyUnit(): string;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Parse a short duration string like "15m", "1h", "30s" into seconds.
|
|
184
|
+
* Mirror of PolicyEngine.parseTtl (buyer side) so both sides use the
|
|
185
|
+
* same format in their JSON policies.
|
|
186
|
+
*/
|
|
187
|
+
export declare function parseTtl(ttl: string): number;
|
|
188
|
+
//# sourceMappingURL=ProviderPolicy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProviderPolicy.d.ts","sourceRoot":"","sources":["../../src/negotiation/ProviderPolicy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH;;;;;;;;GAQG;AACH,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,QAAQ,EAAE,MAAM,EAAE,CAAC;IAEnB,OAAO,EAAE;QACP,4DAA4D;QAC5D,cAAc,EAAE;YAAE,MAAM,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,CAAC;QACnE,4DAA4D;QAC5D,WAAW,EAAE;YAAE,MAAM,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,CAAC;KACjE,CAAC;IAEF,8EAA8E;IAC9E,SAAS,EAAE,MAAM,CAAC;IAElB;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAE9B;;;;;;;;;;;;;OAaG;IACH,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAEtC;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,MAAM,uBAAuB,GAC/B;IAAE,IAAI,EAAE,qBAAqB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC/C;IAAE,IAAI,EAAE,uBAAuB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACjD;IAAE,IAAI,EAAE,oBAAoB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9C,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,uBAAuB,EAAE,CAAC;IACtC;;;;;;;;;OASG;IACH,mCAAmC,CAAC,EAAE,MAAM,CAAC;CAC9C;AAED;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,yEAAyE;IACzE,aAAa,EAAE,MAAM,CAAC;IACtB,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAC;IACjB,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB,+CAA+C;IAC/C,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAqCD,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiB;IACxC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAEtB,MAAM,EAAE,cAAc;IAmClC;;;;;;;;OAQG;IACH,QAAQ,CAAC,GAAG,EAAE,eAAe,GAAG,oBAAoB;IAsEpD;;;;;;;;;;;;;;;;;;;OAmBG;IACH,eAAe,CACb,sBAAsB,EAAE,MAAM,EAC9B,wBAAwB,EAAE,MAAM,EAChC,YAAY,EAAE,MAAM,GACnB;QAAE,QAAQ,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,CAAA;KAAE;IA0D1F,yEAAyE;IACzE,IAAI,eAAe,IAAI,MAAM,CAE5B;IAED,4DAA4D;IAC5D,IAAI,cAAc,IAAI,MAAM,CAE3B;IAED,6DAA6D;IAC7D,IAAI,UAAU,IAAI,MAAM,CAEvB;CACF;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAU5C"}
|