@spendguard/sdk 0.5.0
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/CHANGELOG.md +190 -0
- package/LICENSE_NOTICES.md +127 -0
- package/README.md +151 -0
- package/dist/adapter-D9T3yEEw.d.ts +3441 -0
- package/dist/cache-DOnw8QtJ.d.ts +1164 -0
- package/dist/cache.d.ts +6 -0
- package/dist/cache.js +74 -0
- package/dist/client.d.ts +6 -0
- package/dist/client.js +4815 -0
- package/dist/errors.d.ts +269 -0
- package/dist/errors.js +148 -0
- package/dist/ids.d.ts +69 -0
- package/dist/ids.js +61 -0
- package/dist/index.d.ts +61 -0
- package/dist/index.js +5295 -0
- package/dist/otel.d.ts +118 -0
- package/dist/otel.js +84 -0
- package/dist/pricing/demo.d.ts +26 -0
- package/dist/pricing/demo.js +138 -0
- package/dist/pricing.d.ts +70 -0
- package/dist/pricing.js +92 -0
- package/dist/promptHash.d.ts +23 -0
- package/dist/promptHash.js +25 -0
- package/dist/proto.d.ts +609 -0
- package/dist/proto.js +3055 -0
- package/dist/retry.d.ts +121 -0
- package/dist/retry.js +92 -0
- package/dist/runPlan.d.ts +69 -0
- package/dist/runPlan.js +35 -0
- package/fixtures/cross-language/v1.json +327 -0
- package/package.json +123 -0
package/dist/client.js
ADDED
|
@@ -0,0 +1,4815 @@
|
|
|
1
|
+
import { createHash, createHmac } from 'crypto';
|
|
2
|
+
import { credentials } from '@grpc/grpc-js';
|
|
3
|
+
import { GrpcTransport } from '@protobuf-ts/grpc-transport';
|
|
4
|
+
import { ServiceType, RpcError, stackIntercept } from '@protobuf-ts/runtime-rpc';
|
|
5
|
+
import { MessageType, PbLong, typeofJsonValue, isJsonObject } from '@protobuf-ts/runtime';
|
|
6
|
+
import { AsyncLocalStorage } from 'async_hooks';
|
|
7
|
+
|
|
8
|
+
// src/client.ts
|
|
9
|
+
var Timestamp$Type = class extends MessageType {
|
|
10
|
+
constructor() {
|
|
11
|
+
super("google.protobuf.Timestamp", [
|
|
12
|
+
{
|
|
13
|
+
no: 1,
|
|
14
|
+
name: "seconds",
|
|
15
|
+
kind: "scalar",
|
|
16
|
+
T: 3
|
|
17
|
+
/*ScalarType.INT64*/
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
no: 2,
|
|
21
|
+
name: "nanos",
|
|
22
|
+
kind: "scalar",
|
|
23
|
+
T: 5
|
|
24
|
+
/*ScalarType.INT32*/
|
|
25
|
+
}
|
|
26
|
+
]);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Creates a new `Timestamp` for the current time.
|
|
30
|
+
*/
|
|
31
|
+
now() {
|
|
32
|
+
const msg = this.create();
|
|
33
|
+
const ms = Date.now();
|
|
34
|
+
msg.seconds = PbLong.from(Math.floor(ms / 1e3)).toString();
|
|
35
|
+
msg.nanos = ms % 1e3 * 1e6;
|
|
36
|
+
return msg;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Converts a `Timestamp` to a JavaScript Date.
|
|
40
|
+
*/
|
|
41
|
+
toDate(message) {
|
|
42
|
+
return new Date(PbLong.from(message.seconds).toNumber() * 1e3 + Math.ceil(message.nanos / 1e6));
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Converts a JavaScript Date to a `Timestamp`.
|
|
46
|
+
*/
|
|
47
|
+
fromDate(date) {
|
|
48
|
+
const msg = this.create();
|
|
49
|
+
const ms = date.getTime();
|
|
50
|
+
msg.seconds = PbLong.from(Math.floor(ms / 1e3)).toString();
|
|
51
|
+
msg.nanos = (ms % 1e3 + (ms < 0 && ms % 1e3 !== 0 ? 1e3 : 0)) * 1e6;
|
|
52
|
+
return msg;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* In JSON format, the `Timestamp` type is encoded as a string
|
|
56
|
+
* in the RFC 3339 format.
|
|
57
|
+
*/
|
|
58
|
+
internalJsonWrite(message, options) {
|
|
59
|
+
let ms = PbLong.from(message.seconds).toNumber() * 1e3;
|
|
60
|
+
if (ms < Date.parse("0001-01-01T00:00:00Z") || ms > Date.parse("9999-12-31T23:59:59Z"))
|
|
61
|
+
throw new Error("Unable to encode Timestamp to JSON. Must be from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z inclusive.");
|
|
62
|
+
if (message.nanos < 0)
|
|
63
|
+
throw new Error("Unable to encode invalid Timestamp to JSON. Nanos must not be negative.");
|
|
64
|
+
let z = "Z";
|
|
65
|
+
if (message.nanos > 0) {
|
|
66
|
+
let nanosStr = (message.nanos + 1e9).toString().substring(1);
|
|
67
|
+
if (nanosStr.substring(3) === "000000")
|
|
68
|
+
z = "." + nanosStr.substring(0, 3) + "Z";
|
|
69
|
+
else if (nanosStr.substring(6) === "000")
|
|
70
|
+
z = "." + nanosStr.substring(0, 6) + "Z";
|
|
71
|
+
else
|
|
72
|
+
z = "." + nanosStr + "Z";
|
|
73
|
+
}
|
|
74
|
+
return new Date(ms).toISOString().replace(".000Z", z);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* In JSON format, the `Timestamp` type is encoded as a string
|
|
78
|
+
* in the RFC 3339 format.
|
|
79
|
+
*/
|
|
80
|
+
internalJsonRead(json, options, target) {
|
|
81
|
+
if (typeof json !== "string")
|
|
82
|
+
throw new Error("Unable to parse Timestamp from JSON " + typeofJsonValue(json) + ".");
|
|
83
|
+
let matches = json.match(/^([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})(?:Z|\.([0-9]{3,9})Z|([+-][0-9][0-9]:[0-9][0-9]))$/);
|
|
84
|
+
if (!matches)
|
|
85
|
+
throw new Error("Unable to parse Timestamp from JSON. Invalid format.");
|
|
86
|
+
let ms = Date.parse(matches[1] + "-" + matches[2] + "-" + matches[3] + "T" + matches[4] + ":" + matches[5] + ":" + matches[6] + (matches[8] ? matches[8] : "Z"));
|
|
87
|
+
if (Number.isNaN(ms))
|
|
88
|
+
throw new Error("Unable to parse Timestamp from JSON. Invalid value.");
|
|
89
|
+
if (ms < Date.parse("0001-01-01T00:00:00Z") || ms > Date.parse("9999-12-31T23:59:59Z"))
|
|
90
|
+
throw new globalThis.Error("Unable to parse Timestamp from JSON. Must be from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z inclusive.");
|
|
91
|
+
if (!target)
|
|
92
|
+
target = this.create();
|
|
93
|
+
target.seconds = PbLong.from(ms / 1e3).toString();
|
|
94
|
+
target.nanos = 0;
|
|
95
|
+
if (matches[7])
|
|
96
|
+
target.nanos = parseInt("1" + matches[7] + "0".repeat(9 - matches[7].length)) - 1e9;
|
|
97
|
+
return target;
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
var Timestamp = new Timestamp$Type();
|
|
101
|
+
|
|
102
|
+
// src/_proto/spendguard/common/v1/common.ts
|
|
103
|
+
var UnitRef_Kind = /* @__PURE__ */ ((UnitRef_Kind2) => {
|
|
104
|
+
UnitRef_Kind2[UnitRef_Kind2["KIND_UNSPECIFIED"] = 0] = "KIND_UNSPECIFIED";
|
|
105
|
+
UnitRef_Kind2[UnitRef_Kind2["MONETARY"] = 1] = "MONETARY";
|
|
106
|
+
UnitRef_Kind2[UnitRef_Kind2["TOKEN"] = 2] = "TOKEN";
|
|
107
|
+
UnitRef_Kind2[UnitRef_Kind2["CREDIT"] = 3] = "CREDIT";
|
|
108
|
+
UnitRef_Kind2[UnitRef_Kind2["NON_MONETARY"] = 4] = "NON_MONETARY";
|
|
109
|
+
return UnitRef_Kind2;
|
|
110
|
+
})(UnitRef_Kind || {});
|
|
111
|
+
var Replay_StatusCode = /* @__PURE__ */ ((Replay_StatusCode2) => {
|
|
112
|
+
Replay_StatusCode2[Replay_StatusCode2["STATUS_CODE_UNSPECIFIED"] = 0] = "STATUS_CODE_UNSPECIFIED";
|
|
113
|
+
Replay_StatusCode2[Replay_StatusCode2["POSTED"] = 1] = "POSTED";
|
|
114
|
+
Replay_StatusCode2[Replay_StatusCode2["VOIDED"] = 2] = "VOIDED";
|
|
115
|
+
Replay_StatusCode2[Replay_StatusCode2["PENDING"] = 3] = "PENDING";
|
|
116
|
+
return Replay_StatusCode2;
|
|
117
|
+
})(Replay_StatusCode || {});
|
|
118
|
+
var Error_Code = /* @__PURE__ */ ((Error_Code2) => {
|
|
119
|
+
Error_Code2[Error_Code2["CODE_UNSPECIFIED"] = 0] = "CODE_UNSPECIFIED";
|
|
120
|
+
Error_Code2[Error_Code2["FENCING_EPOCH_STALE"] = 1] = "FENCING_EPOCH_STALE";
|
|
121
|
+
Error_Code2[Error_Code2["LOCK_ORDER_TOKEN_MISMATCH"] = 2] = "LOCK_ORDER_TOKEN_MISMATCH";
|
|
122
|
+
Error_Code2[Error_Code2["PRICING_VERSION_UNKNOWN"] = 3] = "PRICING_VERSION_UNKNOWN";
|
|
123
|
+
Error_Code2[Error_Code2["UNIT_NORMALIZATION_REQUIRED"] = 4] = "UNIT_NORMALIZATION_REQUIRED";
|
|
124
|
+
Error_Code2[Error_Code2["BUDGET_EXHAUSTED"] = 5] = "BUDGET_EXHAUSTED";
|
|
125
|
+
Error_Code2[Error_Code2["DEADLOCK_TIMEOUT"] = 6] = "DEADLOCK_TIMEOUT";
|
|
126
|
+
Error_Code2[Error_Code2["SYNC_REPLICA_UNAVAILABLE"] = 7] = "SYNC_REPLICA_UNAVAILABLE";
|
|
127
|
+
Error_Code2[Error_Code2["TENANT_DISABLED"] = 8] = "TENANT_DISABLED";
|
|
128
|
+
Error_Code2[Error_Code2["SCHEMA_BUNDLE_UNKNOWN"] = 9] = "SCHEMA_BUNDLE_UNKNOWN";
|
|
129
|
+
Error_Code2[Error_Code2["SIGNATURE_INVALID"] = 10] = "SIGNATURE_INVALID";
|
|
130
|
+
Error_Code2[Error_Code2["AUDIT_INVARIANT_VIOLATED"] = 11] = "AUDIT_INVARIANT_VIOLATED";
|
|
131
|
+
Error_Code2[Error_Code2["DUPLICATE_DECISION_EVENT"] = 12] = "DUPLICATE_DECISION_EVENT";
|
|
132
|
+
Error_Code2[Error_Code2["RESERVATION_STATE_CONFLICT"] = 13] = "RESERVATION_STATE_CONFLICT";
|
|
133
|
+
Error_Code2[Error_Code2["PRICING_FREEZE_MISMATCH"] = 14] = "PRICING_FREEZE_MISMATCH";
|
|
134
|
+
Error_Code2[Error_Code2["OVERRUN_RESERVATION"] = 15] = "OVERRUN_RESERVATION";
|
|
135
|
+
Error_Code2[Error_Code2["RESERVATION_TTL_EXPIRED"] = 16] = "RESERVATION_TTL_EXPIRED";
|
|
136
|
+
Error_Code2[Error_Code2["MULTI_RESERVATION_COMMIT_DEFERRED"] = 17] = "MULTI_RESERVATION_COMMIT_DEFERRED";
|
|
137
|
+
Error_Code2[Error_Code2["IDEMPOTENCY_CONFLICT"] = 18] = "IDEMPOTENCY_CONFLICT";
|
|
138
|
+
return Error_Code2;
|
|
139
|
+
})(Error_Code || {});
|
|
140
|
+
var BudgetClaim_Direction = /* @__PURE__ */ ((BudgetClaim_Direction2) => {
|
|
141
|
+
BudgetClaim_Direction2[BudgetClaim_Direction2["DIRECTION_UNSPECIFIED"] = 0] = "DIRECTION_UNSPECIFIED";
|
|
142
|
+
BudgetClaim_Direction2[BudgetClaim_Direction2["DEBIT"] = 1] = "DEBIT";
|
|
143
|
+
BudgetClaim_Direction2[BudgetClaim_Direction2["CREDIT"] = 2] = "CREDIT";
|
|
144
|
+
return BudgetClaim_Direction2;
|
|
145
|
+
})(BudgetClaim_Direction || {});
|
|
146
|
+
var SubscriptionMeter_CapDecision = /* @__PURE__ */ ((SubscriptionMeter_CapDecision2) => {
|
|
147
|
+
SubscriptionMeter_CapDecision2[SubscriptionMeter_CapDecision2["CAP_DECISION_UNSPECIFIED"] = 0] = "CAP_DECISION_UNSPECIFIED";
|
|
148
|
+
SubscriptionMeter_CapDecision2[SubscriptionMeter_CapDecision2["CAP_PASS"] = 1] = "CAP_PASS";
|
|
149
|
+
SubscriptionMeter_CapDecision2[SubscriptionMeter_CapDecision2["CAP_SOFT_ALERT"] = 2] = "CAP_SOFT_ALERT";
|
|
150
|
+
SubscriptionMeter_CapDecision2[SubscriptionMeter_CapDecision2["CAP_HARD_BLOCK"] = 3] = "CAP_HARD_BLOCK";
|
|
151
|
+
return SubscriptionMeter_CapDecision2;
|
|
152
|
+
})(SubscriptionMeter_CapDecision || {});
|
|
153
|
+
var ReservationSource = /* @__PURE__ */ ((ReservationSource2) => {
|
|
154
|
+
ReservationSource2[ReservationSource2["UNSPECIFIED"] = 0] = "UNSPECIFIED";
|
|
155
|
+
ReservationSource2[ReservationSource2["BYOK"] = 1] = "BYOK";
|
|
156
|
+
ReservationSource2[ReservationSource2["SUBSCRIPTION_METER"] = 2] = "SUBSCRIPTION_METER";
|
|
157
|
+
return ReservationSource2;
|
|
158
|
+
})(ReservationSource || {});
|
|
159
|
+
var TraceContext$Type = class extends MessageType {
|
|
160
|
+
constructor() {
|
|
161
|
+
super("spendguard.common.v1.TraceContext", [
|
|
162
|
+
{
|
|
163
|
+
no: 1,
|
|
164
|
+
name: "trace_id",
|
|
165
|
+
kind: "scalar",
|
|
166
|
+
T: 9
|
|
167
|
+
/*ScalarType.STRING*/
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
no: 2,
|
|
171
|
+
name: "span_id",
|
|
172
|
+
kind: "scalar",
|
|
173
|
+
T: 9
|
|
174
|
+
/*ScalarType.STRING*/
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
no: 3,
|
|
178
|
+
name: "parent_span_id",
|
|
179
|
+
kind: "scalar",
|
|
180
|
+
T: 9
|
|
181
|
+
/*ScalarType.STRING*/
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
no: 4,
|
|
185
|
+
name: "trace_state",
|
|
186
|
+
kind: "scalar",
|
|
187
|
+
T: 9
|
|
188
|
+
/*ScalarType.STRING*/
|
|
189
|
+
}
|
|
190
|
+
]);
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
var TraceContext = new TraceContext$Type();
|
|
194
|
+
var SpendGuardIds$Type = class extends MessageType {
|
|
195
|
+
constructor() {
|
|
196
|
+
super("spendguard.common.v1.SpendGuardIds", [
|
|
197
|
+
{
|
|
198
|
+
no: 1,
|
|
199
|
+
name: "run_id",
|
|
200
|
+
kind: "scalar",
|
|
201
|
+
T: 9
|
|
202
|
+
/*ScalarType.STRING*/
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
no: 2,
|
|
206
|
+
name: "step_id",
|
|
207
|
+
kind: "scalar",
|
|
208
|
+
T: 9
|
|
209
|
+
/*ScalarType.STRING*/
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
no: 3,
|
|
213
|
+
name: "llm_call_id",
|
|
214
|
+
kind: "scalar",
|
|
215
|
+
T: 9
|
|
216
|
+
/*ScalarType.STRING*/
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
no: 4,
|
|
220
|
+
name: "tool_call_id",
|
|
221
|
+
kind: "scalar",
|
|
222
|
+
T: 9
|
|
223
|
+
/*ScalarType.STRING*/
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
no: 5,
|
|
227
|
+
name: "decision_id",
|
|
228
|
+
kind: "scalar",
|
|
229
|
+
T: 9
|
|
230
|
+
/*ScalarType.STRING*/
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
no: 6,
|
|
234
|
+
name: "snapshot_id",
|
|
235
|
+
kind: "scalar",
|
|
236
|
+
T: 9
|
|
237
|
+
/*ScalarType.STRING*/
|
|
238
|
+
}
|
|
239
|
+
]);
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
var SpendGuardIds = new SpendGuardIds$Type();
|
|
243
|
+
var UnitRef$Type = class extends MessageType {
|
|
244
|
+
constructor() {
|
|
245
|
+
super("spendguard.common.v1.UnitRef", [
|
|
246
|
+
{
|
|
247
|
+
no: 1,
|
|
248
|
+
name: "unit_id",
|
|
249
|
+
kind: "scalar",
|
|
250
|
+
T: 9
|
|
251
|
+
/*ScalarType.STRING*/
|
|
252
|
+
},
|
|
253
|
+
{ no: 2, name: "kind", kind: "enum", T: () => ["spendguard.common.v1.UnitRef.Kind", UnitRef_Kind] },
|
|
254
|
+
{
|
|
255
|
+
no: 3,
|
|
256
|
+
name: "currency",
|
|
257
|
+
kind: "scalar",
|
|
258
|
+
T: 9
|
|
259
|
+
/*ScalarType.STRING*/
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
no: 4,
|
|
263
|
+
name: "unit_name",
|
|
264
|
+
kind: "scalar",
|
|
265
|
+
T: 9
|
|
266
|
+
/*ScalarType.STRING*/
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
no: 5,
|
|
270
|
+
name: "token_kind",
|
|
271
|
+
kind: "scalar",
|
|
272
|
+
T: 9
|
|
273
|
+
/*ScalarType.STRING*/
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
no: 6,
|
|
277
|
+
name: "model_family",
|
|
278
|
+
kind: "scalar",
|
|
279
|
+
T: 9
|
|
280
|
+
/*ScalarType.STRING*/
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
no: 7,
|
|
284
|
+
name: "credit_program",
|
|
285
|
+
kind: "scalar",
|
|
286
|
+
T: 9
|
|
287
|
+
/*ScalarType.STRING*/
|
|
288
|
+
}
|
|
289
|
+
]);
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
var UnitRef = new UnitRef$Type();
|
|
293
|
+
var Amount$Type = class extends MessageType {
|
|
294
|
+
constructor() {
|
|
295
|
+
super("spendguard.common.v1.Amount", [
|
|
296
|
+
{
|
|
297
|
+
no: 1,
|
|
298
|
+
name: "atomic",
|
|
299
|
+
kind: "scalar",
|
|
300
|
+
T: 9
|
|
301
|
+
/*ScalarType.STRING*/
|
|
302
|
+
},
|
|
303
|
+
{ no: 2, name: "unit", kind: "message", T: () => UnitRef }
|
|
304
|
+
]);
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
new Amount$Type();
|
|
308
|
+
var PricingFreeze$Type = class extends MessageType {
|
|
309
|
+
constructor() {
|
|
310
|
+
super("spendguard.common.v1.PricingFreeze", [
|
|
311
|
+
{
|
|
312
|
+
no: 1,
|
|
313
|
+
name: "pricing_version",
|
|
314
|
+
kind: "scalar",
|
|
315
|
+
T: 9
|
|
316
|
+
/*ScalarType.STRING*/
|
|
317
|
+
},
|
|
318
|
+
{
|
|
319
|
+
no: 2,
|
|
320
|
+
name: "price_snapshot_hash",
|
|
321
|
+
kind: "scalar",
|
|
322
|
+
T: 12
|
|
323
|
+
/*ScalarType.BYTES*/
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
no: 3,
|
|
327
|
+
name: "fx_rate_version",
|
|
328
|
+
kind: "scalar",
|
|
329
|
+
T: 9
|
|
330
|
+
/*ScalarType.STRING*/
|
|
331
|
+
},
|
|
332
|
+
{
|
|
333
|
+
no: 4,
|
|
334
|
+
name: "unit_conversion_version",
|
|
335
|
+
kind: "scalar",
|
|
336
|
+
T: 9
|
|
337
|
+
/*ScalarType.STRING*/
|
|
338
|
+
}
|
|
339
|
+
]);
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
var PricingFreeze = new PricingFreeze$Type();
|
|
343
|
+
var Fencing$Type = class extends MessageType {
|
|
344
|
+
constructor() {
|
|
345
|
+
super("spendguard.common.v1.Fencing", [
|
|
346
|
+
{
|
|
347
|
+
no: 1,
|
|
348
|
+
name: "epoch",
|
|
349
|
+
kind: "scalar",
|
|
350
|
+
T: 4
|
|
351
|
+
/*ScalarType.UINT64*/
|
|
352
|
+
},
|
|
353
|
+
{
|
|
354
|
+
no: 2,
|
|
355
|
+
name: "scope_id",
|
|
356
|
+
kind: "scalar",
|
|
357
|
+
T: 9
|
|
358
|
+
/*ScalarType.STRING*/
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
no: 3,
|
|
362
|
+
name: "workload_instance_id",
|
|
363
|
+
kind: "scalar",
|
|
364
|
+
T: 9
|
|
365
|
+
/*ScalarType.STRING*/
|
|
366
|
+
}
|
|
367
|
+
]);
|
|
368
|
+
}
|
|
369
|
+
};
|
|
370
|
+
new Fencing$Type();
|
|
371
|
+
var Replay$Type = class extends MessageType {
|
|
372
|
+
constructor() {
|
|
373
|
+
super("spendguard.common.v1.Replay", [
|
|
374
|
+
{
|
|
375
|
+
no: 1,
|
|
376
|
+
name: "ledger_transaction_id",
|
|
377
|
+
kind: "scalar",
|
|
378
|
+
T: 9
|
|
379
|
+
/*ScalarType.STRING*/
|
|
380
|
+
},
|
|
381
|
+
{
|
|
382
|
+
no: 2,
|
|
383
|
+
name: "operation_kind",
|
|
384
|
+
kind: "scalar",
|
|
385
|
+
T: 9
|
|
386
|
+
/*ScalarType.STRING*/
|
|
387
|
+
},
|
|
388
|
+
{
|
|
389
|
+
no: 3,
|
|
390
|
+
name: "audit_decision_event_id",
|
|
391
|
+
kind: "scalar",
|
|
392
|
+
T: 9
|
|
393
|
+
/*ScalarType.STRING*/
|
|
394
|
+
},
|
|
395
|
+
{ no: 4, name: "recorded_at", kind: "message", T: () => Timestamp },
|
|
396
|
+
{
|
|
397
|
+
no: 5,
|
|
398
|
+
name: "operation_id",
|
|
399
|
+
kind: "scalar",
|
|
400
|
+
T: 9
|
|
401
|
+
/*ScalarType.STRING*/
|
|
402
|
+
},
|
|
403
|
+
{ no: 6, name: "status_code", kind: "enum", T: () => ["spendguard.common.v1.Replay.StatusCode", Replay_StatusCode] },
|
|
404
|
+
{
|
|
405
|
+
no: 7,
|
|
406
|
+
name: "decision_id",
|
|
407
|
+
kind: "scalar",
|
|
408
|
+
T: 9
|
|
409
|
+
/*ScalarType.STRING*/
|
|
410
|
+
},
|
|
411
|
+
{
|
|
412
|
+
no: 8,
|
|
413
|
+
name: "projection_ids",
|
|
414
|
+
kind: "scalar",
|
|
415
|
+
repeat: 2,
|
|
416
|
+
T: 9
|
|
417
|
+
/*ScalarType.STRING*/
|
|
418
|
+
},
|
|
419
|
+
{ no: 9, name: "ttl_expires_at", kind: "message", T: () => Timestamp }
|
|
420
|
+
]);
|
|
421
|
+
}
|
|
422
|
+
};
|
|
423
|
+
new Replay$Type();
|
|
424
|
+
var FullResponsePayload$Type = class extends MessageType {
|
|
425
|
+
constructor() {
|
|
426
|
+
super("spendguard.common.v1.FullResponsePayload", [
|
|
427
|
+
{
|
|
428
|
+
no: 1,
|
|
429
|
+
name: "payload",
|
|
430
|
+
kind: "scalar",
|
|
431
|
+
T: 12
|
|
432
|
+
/*ScalarType.BYTES*/
|
|
433
|
+
},
|
|
434
|
+
{ no: 2, name: "expires_at", kind: "message", T: () => Timestamp }
|
|
435
|
+
]);
|
|
436
|
+
}
|
|
437
|
+
};
|
|
438
|
+
new FullResponsePayload$Type();
|
|
439
|
+
var Error$Type = class extends MessageType {
|
|
440
|
+
constructor() {
|
|
441
|
+
super("spendguard.common.v1.Error", [
|
|
442
|
+
{ no: 1, name: "code", kind: "enum", T: () => ["spendguard.common.v1.Error.Code", Error_Code] },
|
|
443
|
+
{
|
|
444
|
+
no: 2,
|
|
445
|
+
name: "message",
|
|
446
|
+
kind: "scalar",
|
|
447
|
+
T: 9
|
|
448
|
+
/*ScalarType.STRING*/
|
|
449
|
+
},
|
|
450
|
+
{ no: 3, name: "details", kind: "map", K: 9, V: {
|
|
451
|
+
kind: "scalar",
|
|
452
|
+
T: 9
|
|
453
|
+
/*ScalarType.STRING*/
|
|
454
|
+
} }
|
|
455
|
+
]);
|
|
456
|
+
}
|
|
457
|
+
};
|
|
458
|
+
var Error2 = new Error$Type();
|
|
459
|
+
var BudgetClaim$Type = class extends MessageType {
|
|
460
|
+
constructor() {
|
|
461
|
+
super("spendguard.common.v1.BudgetClaim", [
|
|
462
|
+
{
|
|
463
|
+
no: 1,
|
|
464
|
+
name: "budget_id",
|
|
465
|
+
kind: "scalar",
|
|
466
|
+
T: 9
|
|
467
|
+
/*ScalarType.STRING*/
|
|
468
|
+
},
|
|
469
|
+
{ no: 2, name: "unit", kind: "message", T: () => UnitRef },
|
|
470
|
+
{
|
|
471
|
+
no: 3,
|
|
472
|
+
name: "amount_atomic",
|
|
473
|
+
kind: "scalar",
|
|
474
|
+
T: 9
|
|
475
|
+
/*ScalarType.STRING*/
|
|
476
|
+
},
|
|
477
|
+
{ no: 4, name: "direction", kind: "enum", T: () => ["spendguard.common.v1.BudgetClaim.Direction", BudgetClaim_Direction] },
|
|
478
|
+
{
|
|
479
|
+
no: 5,
|
|
480
|
+
name: "window_instance_id",
|
|
481
|
+
kind: "scalar",
|
|
482
|
+
T: 9
|
|
483
|
+
/*ScalarType.STRING*/
|
|
484
|
+
}
|
|
485
|
+
]);
|
|
486
|
+
}
|
|
487
|
+
};
|
|
488
|
+
var BudgetClaim = new BudgetClaim$Type();
|
|
489
|
+
var LockOrderToken$Type = class extends MessageType {
|
|
490
|
+
constructor() {
|
|
491
|
+
super("spendguard.common.v1.LockOrderToken", [
|
|
492
|
+
{
|
|
493
|
+
no: 1,
|
|
494
|
+
name: "value",
|
|
495
|
+
kind: "scalar",
|
|
496
|
+
T: 9
|
|
497
|
+
/*ScalarType.STRING*/
|
|
498
|
+
}
|
|
499
|
+
]);
|
|
500
|
+
}
|
|
501
|
+
};
|
|
502
|
+
new LockOrderToken$Type();
|
|
503
|
+
var CloudEvent$Type = class extends MessageType {
|
|
504
|
+
constructor() {
|
|
505
|
+
super("spendguard.common.v1.CloudEvent", [
|
|
506
|
+
{
|
|
507
|
+
no: 1,
|
|
508
|
+
name: "specversion",
|
|
509
|
+
kind: "scalar",
|
|
510
|
+
T: 9
|
|
511
|
+
/*ScalarType.STRING*/
|
|
512
|
+
},
|
|
513
|
+
{
|
|
514
|
+
no: 2,
|
|
515
|
+
name: "type",
|
|
516
|
+
kind: "scalar",
|
|
517
|
+
T: 9
|
|
518
|
+
/*ScalarType.STRING*/
|
|
519
|
+
},
|
|
520
|
+
{
|
|
521
|
+
no: 3,
|
|
522
|
+
name: "source",
|
|
523
|
+
kind: "scalar",
|
|
524
|
+
T: 9
|
|
525
|
+
/*ScalarType.STRING*/
|
|
526
|
+
},
|
|
527
|
+
{
|
|
528
|
+
no: 4,
|
|
529
|
+
name: "id",
|
|
530
|
+
kind: "scalar",
|
|
531
|
+
T: 9
|
|
532
|
+
/*ScalarType.STRING*/
|
|
533
|
+
},
|
|
534
|
+
{ no: 5, name: "time", kind: "message", T: () => Timestamp },
|
|
535
|
+
{
|
|
536
|
+
no: 6,
|
|
537
|
+
name: "datacontenttype",
|
|
538
|
+
kind: "scalar",
|
|
539
|
+
T: 9
|
|
540
|
+
/*ScalarType.STRING*/
|
|
541
|
+
},
|
|
542
|
+
{
|
|
543
|
+
no: 7,
|
|
544
|
+
name: "data",
|
|
545
|
+
kind: "scalar",
|
|
546
|
+
T: 12
|
|
547
|
+
/*ScalarType.BYTES*/
|
|
548
|
+
},
|
|
549
|
+
{
|
|
550
|
+
no: 100,
|
|
551
|
+
name: "tenant_id",
|
|
552
|
+
kind: "scalar",
|
|
553
|
+
T: 9
|
|
554
|
+
/*ScalarType.STRING*/
|
|
555
|
+
},
|
|
556
|
+
{
|
|
557
|
+
no: 101,
|
|
558
|
+
name: "run_id",
|
|
559
|
+
kind: "scalar",
|
|
560
|
+
T: 9
|
|
561
|
+
/*ScalarType.STRING*/
|
|
562
|
+
},
|
|
563
|
+
{
|
|
564
|
+
no: 102,
|
|
565
|
+
name: "decision_id",
|
|
566
|
+
kind: "scalar",
|
|
567
|
+
T: 9
|
|
568
|
+
/*ScalarType.STRING*/
|
|
569
|
+
},
|
|
570
|
+
{
|
|
571
|
+
no: 103,
|
|
572
|
+
name: "schema_bundle_id",
|
|
573
|
+
kind: "scalar",
|
|
574
|
+
T: 9
|
|
575
|
+
/*ScalarType.STRING*/
|
|
576
|
+
},
|
|
577
|
+
{
|
|
578
|
+
no: 200,
|
|
579
|
+
name: "producer_id",
|
|
580
|
+
kind: "scalar",
|
|
581
|
+
T: 9
|
|
582
|
+
/*ScalarType.STRING*/
|
|
583
|
+
},
|
|
584
|
+
{
|
|
585
|
+
no: 201,
|
|
586
|
+
name: "producer_sequence",
|
|
587
|
+
kind: "scalar",
|
|
588
|
+
T: 4
|
|
589
|
+
/*ScalarType.UINT64*/
|
|
590
|
+
},
|
|
591
|
+
{
|
|
592
|
+
no: 202,
|
|
593
|
+
name: "producer_signature",
|
|
594
|
+
kind: "scalar",
|
|
595
|
+
T: 12
|
|
596
|
+
/*ScalarType.BYTES*/
|
|
597
|
+
},
|
|
598
|
+
{
|
|
599
|
+
no: 203,
|
|
600
|
+
name: "signing_key_id",
|
|
601
|
+
kind: "scalar",
|
|
602
|
+
T: 9
|
|
603
|
+
/*ScalarType.STRING*/
|
|
604
|
+
},
|
|
605
|
+
{
|
|
606
|
+
no: 300,
|
|
607
|
+
name: "predicted_a_tokens",
|
|
608
|
+
kind: "scalar",
|
|
609
|
+
T: 3
|
|
610
|
+
/*ScalarType.INT64*/
|
|
611
|
+
},
|
|
612
|
+
{
|
|
613
|
+
no: 301,
|
|
614
|
+
name: "predicted_b_tokens",
|
|
615
|
+
kind: "scalar",
|
|
616
|
+
T: 3
|
|
617
|
+
/*ScalarType.INT64*/
|
|
618
|
+
},
|
|
619
|
+
{
|
|
620
|
+
no: 302,
|
|
621
|
+
name: "predicted_c_tokens",
|
|
622
|
+
kind: "scalar",
|
|
623
|
+
T: 3
|
|
624
|
+
/*ScalarType.INT64*/
|
|
625
|
+
},
|
|
626
|
+
{
|
|
627
|
+
no: 303,
|
|
628
|
+
name: "reserved_strategy",
|
|
629
|
+
kind: "scalar",
|
|
630
|
+
T: 9
|
|
631
|
+
/*ScalarType.STRING*/
|
|
632
|
+
},
|
|
633
|
+
{
|
|
634
|
+
no: 304,
|
|
635
|
+
name: "prediction_strategy_used",
|
|
636
|
+
kind: "scalar",
|
|
637
|
+
T: 9
|
|
638
|
+
/*ScalarType.STRING*/
|
|
639
|
+
},
|
|
640
|
+
{
|
|
641
|
+
no: 305,
|
|
642
|
+
name: "prediction_policy_used",
|
|
643
|
+
kind: "scalar",
|
|
644
|
+
T: 9
|
|
645
|
+
/*ScalarType.STRING*/
|
|
646
|
+
},
|
|
647
|
+
{
|
|
648
|
+
no: 306,
|
|
649
|
+
name: "tokenizer_tier",
|
|
650
|
+
kind: "scalar",
|
|
651
|
+
T: 9
|
|
652
|
+
/*ScalarType.STRING*/
|
|
653
|
+
},
|
|
654
|
+
{
|
|
655
|
+
no: 307,
|
|
656
|
+
name: "tokenizer_version_id",
|
|
657
|
+
kind: "scalar",
|
|
658
|
+
T: 9
|
|
659
|
+
/*ScalarType.STRING*/
|
|
660
|
+
},
|
|
661
|
+
{
|
|
662
|
+
no: 308,
|
|
663
|
+
name: "prediction_confidence",
|
|
664
|
+
kind: "scalar",
|
|
665
|
+
T: 2
|
|
666
|
+
/*ScalarType.FLOAT*/
|
|
667
|
+
},
|
|
668
|
+
{
|
|
669
|
+
no: 309,
|
|
670
|
+
name: "prediction_sample_size",
|
|
671
|
+
kind: "scalar",
|
|
672
|
+
T: 3
|
|
673
|
+
/*ScalarType.INT64*/
|
|
674
|
+
},
|
|
675
|
+
{
|
|
676
|
+
no: 310,
|
|
677
|
+
name: "cold_start_layer_used",
|
|
678
|
+
kind: "scalar",
|
|
679
|
+
T: 9
|
|
680
|
+
/*ScalarType.STRING*/
|
|
681
|
+
},
|
|
682
|
+
{
|
|
683
|
+
no: 311,
|
|
684
|
+
name: "run_projection_at_decision_atomic",
|
|
685
|
+
kind: "scalar",
|
|
686
|
+
T: 3
|
|
687
|
+
/*ScalarType.INT64*/
|
|
688
|
+
},
|
|
689
|
+
{
|
|
690
|
+
no: 312,
|
|
691
|
+
name: "run_predicted_remaining_steps",
|
|
692
|
+
kind: "scalar",
|
|
693
|
+
T: 5
|
|
694
|
+
/*ScalarType.INT32*/
|
|
695
|
+
},
|
|
696
|
+
{
|
|
697
|
+
no: 313,
|
|
698
|
+
name: "run_steps_completed_so_far",
|
|
699
|
+
kind: "scalar",
|
|
700
|
+
T: 3
|
|
701
|
+
/*ScalarType.INT64*/
|
|
702
|
+
},
|
|
703
|
+
{
|
|
704
|
+
no: 314,
|
|
705
|
+
name: "actual_input_tokens",
|
|
706
|
+
kind: "scalar",
|
|
707
|
+
T: 3
|
|
708
|
+
/*ScalarType.INT64*/
|
|
709
|
+
},
|
|
710
|
+
{
|
|
711
|
+
no: 315,
|
|
712
|
+
name: "actual_output_tokens",
|
|
713
|
+
kind: "scalar",
|
|
714
|
+
T: 3
|
|
715
|
+
/*ScalarType.INT64*/
|
|
716
|
+
},
|
|
717
|
+
{
|
|
718
|
+
no: 316,
|
|
719
|
+
name: "delta_b_ratio",
|
|
720
|
+
kind: "scalar",
|
|
721
|
+
T: 2
|
|
722
|
+
/*ScalarType.FLOAT*/
|
|
723
|
+
},
|
|
724
|
+
{
|
|
725
|
+
no: 317,
|
|
726
|
+
name: "delta_c_ratio",
|
|
727
|
+
kind: "scalar",
|
|
728
|
+
T: 2
|
|
729
|
+
/*ScalarType.FLOAT*/
|
|
730
|
+
}
|
|
731
|
+
]);
|
|
732
|
+
}
|
|
733
|
+
};
|
|
734
|
+
new CloudEvent$Type();
|
|
735
|
+
var SchemaBundleRef$Type = class extends MessageType {
|
|
736
|
+
constructor() {
|
|
737
|
+
super("spendguard.common.v1.SchemaBundleRef", [
|
|
738
|
+
{
|
|
739
|
+
no: 1,
|
|
740
|
+
name: "schema_bundle_id",
|
|
741
|
+
kind: "scalar",
|
|
742
|
+
T: 9
|
|
743
|
+
/*ScalarType.STRING*/
|
|
744
|
+
},
|
|
745
|
+
{
|
|
746
|
+
no: 2,
|
|
747
|
+
name: "schema_bundle_hash",
|
|
748
|
+
kind: "scalar",
|
|
749
|
+
T: 12
|
|
750
|
+
/*ScalarType.BYTES*/
|
|
751
|
+
},
|
|
752
|
+
{
|
|
753
|
+
no: 3,
|
|
754
|
+
name: "canonical_schema_version",
|
|
755
|
+
kind: "scalar",
|
|
756
|
+
T: 9
|
|
757
|
+
/*ScalarType.STRING*/
|
|
758
|
+
}
|
|
759
|
+
]);
|
|
760
|
+
}
|
|
761
|
+
};
|
|
762
|
+
var SchemaBundleRef = new SchemaBundleRef$Type();
|
|
763
|
+
var ContractBundleRef$Type = class extends MessageType {
|
|
764
|
+
constructor() {
|
|
765
|
+
super("spendguard.common.v1.ContractBundleRef", [
|
|
766
|
+
{
|
|
767
|
+
no: 1,
|
|
768
|
+
name: "bundle_id",
|
|
769
|
+
kind: "scalar",
|
|
770
|
+
T: 9
|
|
771
|
+
/*ScalarType.STRING*/
|
|
772
|
+
},
|
|
773
|
+
{
|
|
774
|
+
no: 2,
|
|
775
|
+
name: "bundle_hash",
|
|
776
|
+
kind: "scalar",
|
|
777
|
+
T: 12
|
|
778
|
+
/*ScalarType.BYTES*/
|
|
779
|
+
},
|
|
780
|
+
{
|
|
781
|
+
no: 3,
|
|
782
|
+
name: "bundle_signature",
|
|
783
|
+
kind: "scalar",
|
|
784
|
+
T: 12
|
|
785
|
+
/*ScalarType.BYTES*/
|
|
786
|
+
},
|
|
787
|
+
{
|
|
788
|
+
no: 4,
|
|
789
|
+
name: "signing_key_id",
|
|
790
|
+
kind: "scalar",
|
|
791
|
+
T: 9
|
|
792
|
+
/*ScalarType.STRING*/
|
|
793
|
+
}
|
|
794
|
+
]);
|
|
795
|
+
}
|
|
796
|
+
};
|
|
797
|
+
var ContractBundleRef = new ContractBundleRef$Type();
|
|
798
|
+
var Idempotency$Type = class extends MessageType {
|
|
799
|
+
constructor() {
|
|
800
|
+
super("spendguard.common.v1.Idempotency", [
|
|
801
|
+
{
|
|
802
|
+
no: 1,
|
|
803
|
+
name: "key",
|
|
804
|
+
kind: "scalar",
|
|
805
|
+
T: 9
|
|
806
|
+
/*ScalarType.STRING*/
|
|
807
|
+
},
|
|
808
|
+
{
|
|
809
|
+
no: 2,
|
|
810
|
+
name: "request_hash",
|
|
811
|
+
kind: "scalar",
|
|
812
|
+
T: 12
|
|
813
|
+
/*ScalarType.BYTES*/
|
|
814
|
+
}
|
|
815
|
+
]);
|
|
816
|
+
}
|
|
817
|
+
};
|
|
818
|
+
var Idempotency = new Idempotency$Type();
|
|
819
|
+
var SubscriptionMeter$Type = class extends MessageType {
|
|
820
|
+
constructor() {
|
|
821
|
+
super("spendguard.common.v1.SubscriptionMeter", [
|
|
822
|
+
{
|
|
823
|
+
no: 1,
|
|
824
|
+
name: "plan",
|
|
825
|
+
kind: "scalar",
|
|
826
|
+
T: 9
|
|
827
|
+
/*ScalarType.STRING*/
|
|
828
|
+
},
|
|
829
|
+
{ no: 2, name: "period_start", kind: "message", T: () => Timestamp },
|
|
830
|
+
{ no: 3, name: "period_end", kind: "message", T: () => Timestamp },
|
|
831
|
+
{
|
|
832
|
+
no: 4,
|
|
833
|
+
name: "consumed_atomic",
|
|
834
|
+
kind: "scalar",
|
|
835
|
+
T: 3
|
|
836
|
+
/*ScalarType.INT64*/
|
|
837
|
+
},
|
|
838
|
+
{
|
|
839
|
+
no: 5,
|
|
840
|
+
name: "monthly_cap_atomic",
|
|
841
|
+
kind: "scalar",
|
|
842
|
+
T: 3
|
|
843
|
+
/*ScalarType.INT64*/
|
|
844
|
+
},
|
|
845
|
+
{
|
|
846
|
+
no: 6,
|
|
847
|
+
name: "alert_at_atomic",
|
|
848
|
+
kind: "scalar",
|
|
849
|
+
T: 3
|
|
850
|
+
/*ScalarType.INT64*/
|
|
851
|
+
},
|
|
852
|
+
{
|
|
853
|
+
no: 7,
|
|
854
|
+
name: "hard_cap_at_atomic",
|
|
855
|
+
kind: "scalar",
|
|
856
|
+
T: 3
|
|
857
|
+
/*ScalarType.INT64*/
|
|
858
|
+
},
|
|
859
|
+
{ no: 8, name: "cap_decision", kind: "enum", T: () => ["spendguard.common.v1.SubscriptionMeter.CapDecision", SubscriptionMeter_CapDecision] },
|
|
860
|
+
{
|
|
861
|
+
no: 9,
|
|
862
|
+
name: "retry_after_seconds",
|
|
863
|
+
kind: "scalar",
|
|
864
|
+
T: 3
|
|
865
|
+
/*ScalarType.INT64*/
|
|
866
|
+
}
|
|
867
|
+
]);
|
|
868
|
+
}
|
|
869
|
+
};
|
|
870
|
+
var SubscriptionMeter = new SubscriptionMeter$Type();
|
|
871
|
+
var NullValue = /* @__PURE__ */ ((NullValue2) => {
|
|
872
|
+
NullValue2[NullValue2["NULL_VALUE"] = 0] = "NULL_VALUE";
|
|
873
|
+
return NullValue2;
|
|
874
|
+
})(NullValue || {});
|
|
875
|
+
var Struct$Type = class extends MessageType {
|
|
876
|
+
constructor() {
|
|
877
|
+
super("google.protobuf.Struct", [
|
|
878
|
+
{ no: 1, name: "fields", kind: "map", K: 9, V: { kind: "message", T: () => Value } }
|
|
879
|
+
]);
|
|
880
|
+
}
|
|
881
|
+
/**
|
|
882
|
+
* Encode `Struct` to JSON object.
|
|
883
|
+
*/
|
|
884
|
+
internalJsonWrite(message, options) {
|
|
885
|
+
let json = {};
|
|
886
|
+
for (let [k, v] of Object.entries(message.fields)) {
|
|
887
|
+
json[k] = Value.toJson(v);
|
|
888
|
+
}
|
|
889
|
+
return json;
|
|
890
|
+
}
|
|
891
|
+
/**
|
|
892
|
+
* Decode `Struct` from JSON object.
|
|
893
|
+
*/
|
|
894
|
+
internalJsonRead(json, options, target) {
|
|
895
|
+
if (!isJsonObject(json))
|
|
896
|
+
throw new globalThis.Error("Unable to parse message " + this.typeName + " from JSON " + typeofJsonValue(json) + ".");
|
|
897
|
+
if (!target)
|
|
898
|
+
target = this.create();
|
|
899
|
+
for (let [k, v] of globalThis.Object.entries(json)) {
|
|
900
|
+
target.fields[k] = Value.fromJson(v);
|
|
901
|
+
}
|
|
902
|
+
return target;
|
|
903
|
+
}
|
|
904
|
+
};
|
|
905
|
+
var Struct = new Struct$Type();
|
|
906
|
+
var Value$Type = class extends MessageType {
|
|
907
|
+
constructor() {
|
|
908
|
+
super("google.protobuf.Value", [
|
|
909
|
+
{ no: 1, name: "null_value", kind: "enum", oneof: "kind", T: () => ["google.protobuf.NullValue", NullValue] },
|
|
910
|
+
{
|
|
911
|
+
no: 2,
|
|
912
|
+
name: "number_value",
|
|
913
|
+
kind: "scalar",
|
|
914
|
+
oneof: "kind",
|
|
915
|
+
T: 1
|
|
916
|
+
/*ScalarType.DOUBLE*/
|
|
917
|
+
},
|
|
918
|
+
{
|
|
919
|
+
no: 3,
|
|
920
|
+
name: "string_value",
|
|
921
|
+
kind: "scalar",
|
|
922
|
+
oneof: "kind",
|
|
923
|
+
T: 9
|
|
924
|
+
/*ScalarType.STRING*/
|
|
925
|
+
},
|
|
926
|
+
{
|
|
927
|
+
no: 4,
|
|
928
|
+
name: "bool_value",
|
|
929
|
+
kind: "scalar",
|
|
930
|
+
oneof: "kind",
|
|
931
|
+
T: 8
|
|
932
|
+
/*ScalarType.BOOL*/
|
|
933
|
+
},
|
|
934
|
+
{ no: 5, name: "struct_value", kind: "message", oneof: "kind", T: () => Struct },
|
|
935
|
+
{ no: 6, name: "list_value", kind: "message", oneof: "kind", T: () => ListValue }
|
|
936
|
+
]);
|
|
937
|
+
}
|
|
938
|
+
/**
|
|
939
|
+
* Encode `Value` to JSON value.
|
|
940
|
+
*/
|
|
941
|
+
internalJsonWrite(message, options) {
|
|
942
|
+
if (message.kind.oneofKind === void 0)
|
|
943
|
+
throw new globalThis.Error();
|
|
944
|
+
switch (message.kind.oneofKind) {
|
|
945
|
+
case void 0:
|
|
946
|
+
throw new globalThis.Error();
|
|
947
|
+
case "boolValue":
|
|
948
|
+
return message.kind.boolValue;
|
|
949
|
+
case "nullValue":
|
|
950
|
+
return null;
|
|
951
|
+
case "numberValue":
|
|
952
|
+
let numberValue = message.kind.numberValue;
|
|
953
|
+
if (typeof numberValue == "number" && !Number.isFinite(numberValue))
|
|
954
|
+
throw new globalThis.Error();
|
|
955
|
+
return numberValue;
|
|
956
|
+
case "stringValue":
|
|
957
|
+
return message.kind.stringValue;
|
|
958
|
+
case "listValue":
|
|
959
|
+
let listValueField = this.fields.find((f) => f.no === 6);
|
|
960
|
+
if (listValueField?.kind !== "message")
|
|
961
|
+
throw new globalThis.Error();
|
|
962
|
+
return listValueField.T().toJson(message.kind.listValue);
|
|
963
|
+
case "structValue":
|
|
964
|
+
let structValueField = this.fields.find((f) => f.no === 5);
|
|
965
|
+
if (structValueField?.kind !== "message")
|
|
966
|
+
throw new globalThis.Error();
|
|
967
|
+
return structValueField.T().toJson(message.kind.structValue);
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
/**
|
|
971
|
+
* Decode `Value` from JSON value.
|
|
972
|
+
*/
|
|
973
|
+
internalJsonRead(json, options, target) {
|
|
974
|
+
if (!target)
|
|
975
|
+
target = this.create();
|
|
976
|
+
switch (typeof json) {
|
|
977
|
+
case "number":
|
|
978
|
+
target.kind = { oneofKind: "numberValue", numberValue: json };
|
|
979
|
+
break;
|
|
980
|
+
case "string":
|
|
981
|
+
target.kind = { oneofKind: "stringValue", stringValue: json };
|
|
982
|
+
break;
|
|
983
|
+
case "boolean":
|
|
984
|
+
target.kind = { oneofKind: "boolValue", boolValue: json };
|
|
985
|
+
break;
|
|
986
|
+
case "object":
|
|
987
|
+
if (json === null) {
|
|
988
|
+
target.kind = { oneofKind: "nullValue", nullValue: 0 /* NULL_VALUE */ };
|
|
989
|
+
} else if (globalThis.Array.isArray(json)) {
|
|
990
|
+
target.kind = { oneofKind: "listValue", listValue: ListValue.fromJson(json) };
|
|
991
|
+
} else {
|
|
992
|
+
target.kind = { oneofKind: "structValue", structValue: Struct.fromJson(json) };
|
|
993
|
+
}
|
|
994
|
+
break;
|
|
995
|
+
default:
|
|
996
|
+
throw new globalThis.Error("Unable to parse " + this.typeName + " from JSON " + typeofJsonValue(json));
|
|
997
|
+
}
|
|
998
|
+
return target;
|
|
999
|
+
}
|
|
1000
|
+
};
|
|
1001
|
+
var Value = new Value$Type();
|
|
1002
|
+
var ListValue$Type = class extends MessageType {
|
|
1003
|
+
constructor() {
|
|
1004
|
+
super("google.protobuf.ListValue", [
|
|
1005
|
+
{ no: 1, name: "values", kind: "message", repeat: 2, T: () => Value }
|
|
1006
|
+
]);
|
|
1007
|
+
}
|
|
1008
|
+
/**
|
|
1009
|
+
* Encode `ListValue` to JSON array.
|
|
1010
|
+
*/
|
|
1011
|
+
internalJsonWrite(message, options) {
|
|
1012
|
+
return message.values.map((v) => Value.toJson(v));
|
|
1013
|
+
}
|
|
1014
|
+
/**
|
|
1015
|
+
* Decode `ListValue` from JSON array.
|
|
1016
|
+
*/
|
|
1017
|
+
internalJsonRead(json, options, target) {
|
|
1018
|
+
if (!globalThis.Array.isArray(json))
|
|
1019
|
+
throw new globalThis.Error("Unable to parse " + this.typeName + " from JSON " + typeofJsonValue(json));
|
|
1020
|
+
if (!target)
|
|
1021
|
+
target = this.create();
|
|
1022
|
+
let values = json.map((v) => Value.fromJson(v));
|
|
1023
|
+
target.values.push(...values);
|
|
1024
|
+
return target;
|
|
1025
|
+
}
|
|
1026
|
+
};
|
|
1027
|
+
var ListValue = new ListValue$Type();
|
|
1028
|
+
|
|
1029
|
+
// src/_proto/spendguard/sidecar_adapter/v1/adapter.ts
|
|
1030
|
+
var HandshakeRequest_CapabilityLevel = /* @__PURE__ */ ((HandshakeRequest_CapabilityLevel2) => {
|
|
1031
|
+
HandshakeRequest_CapabilityLevel2[HandshakeRequest_CapabilityLevel2["CAPABILITY_LEVEL_UNSPECIFIED"] = 0] = "CAPABILITY_LEVEL_UNSPECIFIED";
|
|
1032
|
+
HandshakeRequest_CapabilityLevel2[HandshakeRequest_CapabilityLevel2["L0_INGEST"] = 16] = "L0_INGEST";
|
|
1033
|
+
HandshakeRequest_CapabilityLevel2[HandshakeRequest_CapabilityLevel2["L1_LLM_CALL"] = 32] = "L1_LLM_CALL";
|
|
1034
|
+
HandshakeRequest_CapabilityLevel2[HandshakeRequest_CapabilityLevel2["L2_STEP"] = 48] = "L2_STEP";
|
|
1035
|
+
HandshakeRequest_CapabilityLevel2[HandshakeRequest_CapabilityLevel2["L3_POLICY_HOOK"] = 64] = "L3_POLICY_HOOK";
|
|
1036
|
+
HandshakeRequest_CapabilityLevel2[HandshakeRequest_CapabilityLevel2["L4_RUNTIME_NATIVE"] = 80] = "L4_RUNTIME_NATIVE";
|
|
1037
|
+
return HandshakeRequest_CapabilityLevel2;
|
|
1038
|
+
})(HandshakeRequest_CapabilityLevel || {});
|
|
1039
|
+
var DecisionRequest_Trigger = /* @__PURE__ */ ((DecisionRequest_Trigger2) => {
|
|
1040
|
+
DecisionRequest_Trigger2[DecisionRequest_Trigger2["TRIGGER_UNSPECIFIED"] = 0] = "TRIGGER_UNSPECIFIED";
|
|
1041
|
+
DecisionRequest_Trigger2[DecisionRequest_Trigger2["RUN_PRE"] = 1] = "RUN_PRE";
|
|
1042
|
+
DecisionRequest_Trigger2[DecisionRequest_Trigger2["AGENT_STEP_PRE"] = 2] = "AGENT_STEP_PRE";
|
|
1043
|
+
DecisionRequest_Trigger2[DecisionRequest_Trigger2["LLM_CALL_PRE"] = 3] = "LLM_CALL_PRE";
|
|
1044
|
+
DecisionRequest_Trigger2[DecisionRequest_Trigger2["TOOL_CALL_PRE"] = 4] = "TOOL_CALL_PRE";
|
|
1045
|
+
return DecisionRequest_Trigger2;
|
|
1046
|
+
})(DecisionRequest_Trigger || {});
|
|
1047
|
+
var DecisionResponse_Decision = /* @__PURE__ */ ((DecisionResponse_Decision2) => {
|
|
1048
|
+
DecisionResponse_Decision2[DecisionResponse_Decision2["DECISION_UNSPECIFIED"] = 0] = "DECISION_UNSPECIFIED";
|
|
1049
|
+
DecisionResponse_Decision2[DecisionResponse_Decision2["CONTINUE"] = 1] = "CONTINUE";
|
|
1050
|
+
DecisionResponse_Decision2[DecisionResponse_Decision2["DEGRADE"] = 2] = "DEGRADE";
|
|
1051
|
+
DecisionResponse_Decision2[DecisionResponse_Decision2["SKIP"] = 3] = "SKIP";
|
|
1052
|
+
DecisionResponse_Decision2[DecisionResponse_Decision2["STOP"] = 4] = "STOP";
|
|
1053
|
+
DecisionResponse_Decision2[DecisionResponse_Decision2["REQUIRE_APPROVAL"] = 5] = "REQUIRE_APPROVAL";
|
|
1054
|
+
DecisionResponse_Decision2[DecisionResponse_Decision2["STOP_RUN_PROJECTION"] = 6] = "STOP_RUN_PROJECTION";
|
|
1055
|
+
return DecisionResponse_Decision2;
|
|
1056
|
+
})(DecisionResponse_Decision || {});
|
|
1057
|
+
var PublishOutcomeRequest_Outcome = /* @__PURE__ */ ((PublishOutcomeRequest_Outcome2) => {
|
|
1058
|
+
PublishOutcomeRequest_Outcome2[PublishOutcomeRequest_Outcome2["OUTCOME_UNSPECIFIED"] = 0] = "OUTCOME_UNSPECIFIED";
|
|
1059
|
+
PublishOutcomeRequest_Outcome2[PublishOutcomeRequest_Outcome2["APPLIED"] = 1] = "APPLIED";
|
|
1060
|
+
PublishOutcomeRequest_Outcome2[PublishOutcomeRequest_Outcome2["APPLIED_NOOP"] = 2] = "APPLIED_NOOP";
|
|
1061
|
+
PublishOutcomeRequest_Outcome2[PublishOutcomeRequest_Outcome2["APPLY_FAILED"] = 3] = "APPLY_FAILED";
|
|
1062
|
+
PublishOutcomeRequest_Outcome2[PublishOutcomeRequest_Outcome2["APPROVAL_GRANTED"] = 4] = "APPROVAL_GRANTED";
|
|
1063
|
+
PublishOutcomeRequest_Outcome2[PublishOutcomeRequest_Outcome2["APPROVAL_DENIED"] = 5] = "APPROVAL_DENIED";
|
|
1064
|
+
PublishOutcomeRequest_Outcome2[PublishOutcomeRequest_Outcome2["APPROVAL_TIMED_OUT"] = 6] = "APPROVAL_TIMED_OUT";
|
|
1065
|
+
return PublishOutcomeRequest_Outcome2;
|
|
1066
|
+
})(PublishOutcomeRequest_Outcome || {});
|
|
1067
|
+
var TraceEvent_EventKind = /* @__PURE__ */ ((TraceEvent_EventKind2) => {
|
|
1068
|
+
TraceEvent_EventKind2[TraceEvent_EventKind2["EVENT_KIND_UNSPECIFIED"] = 0] = "EVENT_KIND_UNSPECIFIED";
|
|
1069
|
+
TraceEvent_EventKind2[TraceEvent_EventKind2["RUN_START"] = 1] = "RUN_START";
|
|
1070
|
+
TraceEvent_EventKind2[TraceEvent_EventKind2["RUN_END"] = 2] = "RUN_END";
|
|
1071
|
+
TraceEvent_EventKind2[TraceEvent_EventKind2["AGENT_STEP_POST"] = 3] = "AGENT_STEP_POST";
|
|
1072
|
+
TraceEvent_EventKind2[TraceEvent_EventKind2["LLM_CALL_POST"] = 4] = "LLM_CALL_POST";
|
|
1073
|
+
TraceEvent_EventKind2[TraceEvent_EventKind2["TOOL_CALL_POST"] = 5] = "TOOL_CALL_POST";
|
|
1074
|
+
TraceEvent_EventKind2[TraceEvent_EventKind2["SPAN_DELTA"] = 6] = "SPAN_DELTA";
|
|
1075
|
+
TraceEvent_EventKind2[TraceEvent_EventKind2["APPROVAL_LIFECYCLE"] = 7] = "APPROVAL_LIFECYCLE";
|
|
1076
|
+
TraceEvent_EventKind2[TraceEvent_EventKind2["ROLLBACK"] = 8] = "ROLLBACK";
|
|
1077
|
+
return TraceEvent_EventKind2;
|
|
1078
|
+
})(TraceEvent_EventKind || {});
|
|
1079
|
+
var LlmCallPostPayload_Outcome = /* @__PURE__ */ ((LlmCallPostPayload_Outcome2) => {
|
|
1080
|
+
LlmCallPostPayload_Outcome2[LlmCallPostPayload_Outcome2["OUTCOME_UNSPECIFIED"] = 0] = "OUTCOME_UNSPECIFIED";
|
|
1081
|
+
LlmCallPostPayload_Outcome2[LlmCallPostPayload_Outcome2["SUCCESS"] = 1] = "SUCCESS";
|
|
1082
|
+
LlmCallPostPayload_Outcome2[LlmCallPostPayload_Outcome2["PROVIDER_ERROR"] = 2] = "PROVIDER_ERROR";
|
|
1083
|
+
LlmCallPostPayload_Outcome2[LlmCallPostPayload_Outcome2["CLIENT_TIMEOUT"] = 3] = "CLIENT_TIMEOUT";
|
|
1084
|
+
LlmCallPostPayload_Outcome2[LlmCallPostPayload_Outcome2["RUN_ABORTED"] = 4] = "RUN_ABORTED";
|
|
1085
|
+
return LlmCallPostPayload_Outcome2;
|
|
1086
|
+
})(LlmCallPostPayload_Outcome || {});
|
|
1087
|
+
var ApprovalLifecyclePayload_State = /* @__PURE__ */ ((ApprovalLifecyclePayload_State2) => {
|
|
1088
|
+
ApprovalLifecyclePayload_State2[ApprovalLifecyclePayload_State2["STATE_UNSPECIFIED"] = 0] = "STATE_UNSPECIFIED";
|
|
1089
|
+
ApprovalLifecyclePayload_State2[ApprovalLifecyclePayload_State2["REQUESTED"] = 1] = "REQUESTED";
|
|
1090
|
+
ApprovalLifecyclePayload_State2[ApprovalLifecyclePayload_State2["GRANTED"] = 2] = "GRANTED";
|
|
1091
|
+
ApprovalLifecyclePayload_State2[ApprovalLifecyclePayload_State2["DENIED"] = 3] = "DENIED";
|
|
1092
|
+
ApprovalLifecyclePayload_State2[ApprovalLifecyclePayload_State2["EXPIRED"] = 4] = "EXPIRED";
|
|
1093
|
+
return ApprovalLifecyclePayload_State2;
|
|
1094
|
+
})(ApprovalLifecyclePayload_State || {});
|
|
1095
|
+
var TraceEventAck_Status = /* @__PURE__ */ ((TraceEventAck_Status2) => {
|
|
1096
|
+
TraceEventAck_Status2[TraceEventAck_Status2["STATUS_UNSPECIFIED"] = 0] = "STATUS_UNSPECIFIED";
|
|
1097
|
+
TraceEventAck_Status2[TraceEventAck_Status2["ACCEPTED"] = 1] = "ACCEPTED";
|
|
1098
|
+
TraceEventAck_Status2[TraceEventAck_Status2["QUARANTINED"] = 2] = "QUARANTINED";
|
|
1099
|
+
TraceEventAck_Status2[TraceEventAck_Status2["REJECTED"] = 3] = "REJECTED";
|
|
1100
|
+
return TraceEventAck_Status2;
|
|
1101
|
+
})(TraceEventAck_Status || {});
|
|
1102
|
+
var DrainSignal_Phase = /* @__PURE__ */ ((DrainSignal_Phase2) => {
|
|
1103
|
+
DrainSignal_Phase2[DrainSignal_Phase2["PHASE_UNSPECIFIED"] = 0] = "PHASE_UNSPECIFIED";
|
|
1104
|
+
DrainSignal_Phase2[DrainSignal_Phase2["DRAIN_INITIATED"] = 1] = "DRAIN_INITIATED";
|
|
1105
|
+
DrainSignal_Phase2[DrainSignal_Phase2["DRAIN_TIMEOUT_APPROACHING"] = 2] = "DRAIN_TIMEOUT_APPROACHING";
|
|
1106
|
+
DrainSignal_Phase2[DrainSignal_Phase2["DRAIN_COMPLETE"] = 3] = "DRAIN_COMPLETE";
|
|
1107
|
+
return DrainSignal_Phase2;
|
|
1108
|
+
})(DrainSignal_Phase || {});
|
|
1109
|
+
var CommitSessionDeltaRequest_Outcome = /* @__PURE__ */ ((CommitSessionDeltaRequest_Outcome2) => {
|
|
1110
|
+
CommitSessionDeltaRequest_Outcome2[CommitSessionDeltaRequest_Outcome2["OUTCOME_UNSPECIFIED"] = 0] = "OUTCOME_UNSPECIFIED";
|
|
1111
|
+
CommitSessionDeltaRequest_Outcome2[CommitSessionDeltaRequest_Outcome2["SUCCESS"] = 1] = "SUCCESS";
|
|
1112
|
+
CommitSessionDeltaRequest_Outcome2[CommitSessionDeltaRequest_Outcome2["PROVIDER_ERROR"] = 2] = "PROVIDER_ERROR";
|
|
1113
|
+
CommitSessionDeltaRequest_Outcome2[CommitSessionDeltaRequest_Outcome2["CLIENT_TIMEOUT"] = 3] = "CLIENT_TIMEOUT";
|
|
1114
|
+
CommitSessionDeltaRequest_Outcome2[CommitSessionDeltaRequest_Outcome2["RUN_ABORTED"] = 4] = "RUN_ABORTED";
|
|
1115
|
+
return CommitSessionDeltaRequest_Outcome2;
|
|
1116
|
+
})(CommitSessionDeltaRequest_Outcome || {});
|
|
1117
|
+
var ResumeAfterApprovalRequest$Type = class extends MessageType {
|
|
1118
|
+
constructor() {
|
|
1119
|
+
super("spendguard.sidecar_adapter.v1.ResumeAfterApprovalRequest", [
|
|
1120
|
+
{
|
|
1121
|
+
no: 1,
|
|
1122
|
+
name: "tenant_id",
|
|
1123
|
+
kind: "scalar",
|
|
1124
|
+
T: 9
|
|
1125
|
+
/*ScalarType.STRING*/
|
|
1126
|
+
},
|
|
1127
|
+
{
|
|
1128
|
+
no: 2,
|
|
1129
|
+
name: "decision_id",
|
|
1130
|
+
kind: "scalar",
|
|
1131
|
+
T: 9
|
|
1132
|
+
/*ScalarType.STRING*/
|
|
1133
|
+
},
|
|
1134
|
+
{
|
|
1135
|
+
no: 3,
|
|
1136
|
+
name: "approval_id",
|
|
1137
|
+
kind: "scalar",
|
|
1138
|
+
T: 9
|
|
1139
|
+
/*ScalarType.STRING*/
|
|
1140
|
+
},
|
|
1141
|
+
{
|
|
1142
|
+
no: 4,
|
|
1143
|
+
name: "workload_instance_id",
|
|
1144
|
+
kind: "scalar",
|
|
1145
|
+
T: 9
|
|
1146
|
+
/*ScalarType.STRING*/
|
|
1147
|
+
},
|
|
1148
|
+
{
|
|
1149
|
+
no: 5,
|
|
1150
|
+
name: "session_id",
|
|
1151
|
+
kind: "scalar",
|
|
1152
|
+
T: 9
|
|
1153
|
+
/*ScalarType.STRING*/
|
|
1154
|
+
}
|
|
1155
|
+
]);
|
|
1156
|
+
}
|
|
1157
|
+
};
|
|
1158
|
+
var ResumeAfterApprovalRequest = new ResumeAfterApprovalRequest$Type();
|
|
1159
|
+
var ResumeAfterApprovalResponse$Type = class extends MessageType {
|
|
1160
|
+
constructor() {
|
|
1161
|
+
super("spendguard.sidecar_adapter.v1.ResumeAfterApprovalResponse", [
|
|
1162
|
+
{ no: 1, name: "decision", kind: "message", oneof: "outcome", T: () => DecisionResponse },
|
|
1163
|
+
{ no: 2, name: "denied", kind: "message", oneof: "outcome", T: () => ResumeAfterApprovalDenied },
|
|
1164
|
+
{ no: 3, name: "error", kind: "message", oneof: "outcome", T: () => Error2 }
|
|
1165
|
+
]);
|
|
1166
|
+
}
|
|
1167
|
+
};
|
|
1168
|
+
var ResumeAfterApprovalResponse = new ResumeAfterApprovalResponse$Type();
|
|
1169
|
+
var ResumeAfterApprovalDenied$Type = class extends MessageType {
|
|
1170
|
+
constructor() {
|
|
1171
|
+
super("spendguard.sidecar_adapter.v1.ResumeAfterApprovalDenied", [
|
|
1172
|
+
{
|
|
1173
|
+
no: 1,
|
|
1174
|
+
name: "audit_decision_event_id",
|
|
1175
|
+
kind: "scalar",
|
|
1176
|
+
T: 9
|
|
1177
|
+
/*ScalarType.STRING*/
|
|
1178
|
+
},
|
|
1179
|
+
{
|
|
1180
|
+
no: 2,
|
|
1181
|
+
name: "approver_reason",
|
|
1182
|
+
kind: "scalar",
|
|
1183
|
+
T: 9
|
|
1184
|
+
/*ScalarType.STRING*/
|
|
1185
|
+
},
|
|
1186
|
+
{
|
|
1187
|
+
no: 3,
|
|
1188
|
+
name: "approver_subject",
|
|
1189
|
+
kind: "scalar",
|
|
1190
|
+
T: 9
|
|
1191
|
+
/*ScalarType.STRING*/
|
|
1192
|
+
},
|
|
1193
|
+
{
|
|
1194
|
+
no: 4,
|
|
1195
|
+
name: "matched_rule_ids",
|
|
1196
|
+
kind: "scalar",
|
|
1197
|
+
repeat: 2,
|
|
1198
|
+
T: 9
|
|
1199
|
+
/*ScalarType.STRING*/
|
|
1200
|
+
}
|
|
1201
|
+
]);
|
|
1202
|
+
}
|
|
1203
|
+
};
|
|
1204
|
+
var ResumeAfterApprovalDenied = new ResumeAfterApprovalDenied$Type();
|
|
1205
|
+
var HandshakeRequest$Type = class extends MessageType {
|
|
1206
|
+
constructor() {
|
|
1207
|
+
super("spendguard.sidecar_adapter.v1.HandshakeRequest", [
|
|
1208
|
+
{
|
|
1209
|
+
no: 1,
|
|
1210
|
+
name: "sdk_version",
|
|
1211
|
+
kind: "scalar",
|
|
1212
|
+
T: 9
|
|
1213
|
+
/*ScalarType.STRING*/
|
|
1214
|
+
},
|
|
1215
|
+
{
|
|
1216
|
+
no: 2,
|
|
1217
|
+
name: "runtime_kind",
|
|
1218
|
+
kind: "scalar",
|
|
1219
|
+
T: 9
|
|
1220
|
+
/*ScalarType.STRING*/
|
|
1221
|
+
},
|
|
1222
|
+
{
|
|
1223
|
+
no: 3,
|
|
1224
|
+
name: "runtime_version",
|
|
1225
|
+
kind: "scalar",
|
|
1226
|
+
T: 9
|
|
1227
|
+
/*ScalarType.STRING*/
|
|
1228
|
+
},
|
|
1229
|
+
{ no: 4, name: "capability_level", kind: "enum", T: () => ["spendguard.sidecar_adapter.v1.HandshakeRequest.CapabilityLevel", HandshakeRequest_CapabilityLevel] },
|
|
1230
|
+
{
|
|
1231
|
+
no: 5,
|
|
1232
|
+
name: "tenant_id_assertion",
|
|
1233
|
+
kind: "scalar",
|
|
1234
|
+
T: 9
|
|
1235
|
+
/*ScalarType.STRING*/
|
|
1236
|
+
},
|
|
1237
|
+
{
|
|
1238
|
+
no: 6,
|
|
1239
|
+
name: "workload_instance_id",
|
|
1240
|
+
kind: "scalar",
|
|
1241
|
+
T: 9
|
|
1242
|
+
/*ScalarType.STRING*/
|
|
1243
|
+
},
|
|
1244
|
+
{
|
|
1245
|
+
no: 7,
|
|
1246
|
+
name: "protocol_version",
|
|
1247
|
+
kind: "scalar",
|
|
1248
|
+
T: 13
|
|
1249
|
+
/*ScalarType.UINT32*/
|
|
1250
|
+
}
|
|
1251
|
+
]);
|
|
1252
|
+
}
|
|
1253
|
+
};
|
|
1254
|
+
var HandshakeRequest = new HandshakeRequest$Type();
|
|
1255
|
+
var HandshakeResponse$Type = class extends MessageType {
|
|
1256
|
+
constructor() {
|
|
1257
|
+
super("spendguard.sidecar_adapter.v1.HandshakeResponse", [
|
|
1258
|
+
{
|
|
1259
|
+
no: 1,
|
|
1260
|
+
name: "sidecar_version",
|
|
1261
|
+
kind: "scalar",
|
|
1262
|
+
T: 9
|
|
1263
|
+
/*ScalarType.STRING*/
|
|
1264
|
+
},
|
|
1265
|
+
{ no: 2, name: "schema_bundle", kind: "message", T: () => SchemaBundleRef },
|
|
1266
|
+
{ no: 3, name: "contract_bundle", kind: "message", T: () => ContractBundleRef },
|
|
1267
|
+
{ no: 4, name: "capability_required", kind: "enum", T: () => ["spendguard.sidecar_adapter.v1.HandshakeRequest.CapabilityLevel", HandshakeRequest_CapabilityLevel] },
|
|
1268
|
+
{ no: 5, name: "active_key_epochs", kind: "message", T: () => HandshakeResponse_KeyEpochs },
|
|
1269
|
+
{
|
|
1270
|
+
no: 6,
|
|
1271
|
+
name: "protocol_version",
|
|
1272
|
+
kind: "scalar",
|
|
1273
|
+
T: 13
|
|
1274
|
+
/*ScalarType.UINT32*/
|
|
1275
|
+
},
|
|
1276
|
+
{
|
|
1277
|
+
no: 7,
|
|
1278
|
+
name: "session_id",
|
|
1279
|
+
kind: "scalar",
|
|
1280
|
+
T: 9
|
|
1281
|
+
/*ScalarType.STRING*/
|
|
1282
|
+
},
|
|
1283
|
+
{
|
|
1284
|
+
no: 8,
|
|
1285
|
+
name: "signing_key_id",
|
|
1286
|
+
kind: "scalar",
|
|
1287
|
+
T: 9
|
|
1288
|
+
/*ScalarType.STRING*/
|
|
1289
|
+
},
|
|
1290
|
+
{
|
|
1291
|
+
no: 9,
|
|
1292
|
+
name: "announcement_signature",
|
|
1293
|
+
kind: "scalar",
|
|
1294
|
+
T: 12
|
|
1295
|
+
/*ScalarType.BYTES*/
|
|
1296
|
+
}
|
|
1297
|
+
]);
|
|
1298
|
+
}
|
|
1299
|
+
};
|
|
1300
|
+
var HandshakeResponse = new HandshakeResponse$Type();
|
|
1301
|
+
var HandshakeResponse_KeyEpochs$Type = class extends MessageType {
|
|
1302
|
+
constructor() {
|
|
1303
|
+
super("spendguard.sidecar_adapter.v1.HandshakeResponse.KeyEpochs", [
|
|
1304
|
+
{
|
|
1305
|
+
no: 1,
|
|
1306
|
+
name: "producer_signing_key_epochs",
|
|
1307
|
+
kind: "scalar",
|
|
1308
|
+
repeat: 2,
|
|
1309
|
+
T: 9
|
|
1310
|
+
/*ScalarType.STRING*/
|
|
1311
|
+
},
|
|
1312
|
+
{
|
|
1313
|
+
no: 2,
|
|
1314
|
+
name: "hmac_tenant_salt_epochs",
|
|
1315
|
+
kind: "scalar",
|
|
1316
|
+
repeat: 2,
|
|
1317
|
+
T: 9
|
|
1318
|
+
/*ScalarType.STRING*/
|
|
1319
|
+
}
|
|
1320
|
+
]);
|
|
1321
|
+
}
|
|
1322
|
+
};
|
|
1323
|
+
var HandshakeResponse_KeyEpochs = new HandshakeResponse_KeyEpochs$Type();
|
|
1324
|
+
var ClaimEstimate$Type = class extends MessageType {
|
|
1325
|
+
constructor() {
|
|
1326
|
+
super("spendguard.sidecar_adapter.v1.ClaimEstimate", [
|
|
1327
|
+
{
|
|
1328
|
+
no: 1,
|
|
1329
|
+
name: "tokenizer_tier",
|
|
1330
|
+
kind: "scalar",
|
|
1331
|
+
T: 9
|
|
1332
|
+
/*ScalarType.STRING*/
|
|
1333
|
+
},
|
|
1334
|
+
{
|
|
1335
|
+
no: 2,
|
|
1336
|
+
name: "tokenizer_version_id",
|
|
1337
|
+
kind: "scalar",
|
|
1338
|
+
T: 9
|
|
1339
|
+
/*ScalarType.STRING*/
|
|
1340
|
+
},
|
|
1341
|
+
{
|
|
1342
|
+
no: 3,
|
|
1343
|
+
name: "input_tokens",
|
|
1344
|
+
kind: "scalar",
|
|
1345
|
+
T: 3
|
|
1346
|
+
/*ScalarType.INT64*/
|
|
1347
|
+
},
|
|
1348
|
+
{
|
|
1349
|
+
no: 4,
|
|
1350
|
+
name: "predicted_a_tokens",
|
|
1351
|
+
kind: "scalar",
|
|
1352
|
+
T: 3
|
|
1353
|
+
/*ScalarType.INT64*/
|
|
1354
|
+
},
|
|
1355
|
+
{
|
|
1356
|
+
no: 5,
|
|
1357
|
+
name: "predicted_b_tokens",
|
|
1358
|
+
kind: "scalar",
|
|
1359
|
+
T: 3
|
|
1360
|
+
/*ScalarType.INT64*/
|
|
1361
|
+
},
|
|
1362
|
+
{
|
|
1363
|
+
no: 6,
|
|
1364
|
+
name: "predicted_c_tokens",
|
|
1365
|
+
kind: "scalar",
|
|
1366
|
+
T: 3
|
|
1367
|
+
/*ScalarType.INT64*/
|
|
1368
|
+
},
|
|
1369
|
+
{
|
|
1370
|
+
no: 7,
|
|
1371
|
+
name: "reserved_strategy",
|
|
1372
|
+
kind: "scalar",
|
|
1373
|
+
T: 9
|
|
1374
|
+
/*ScalarType.STRING*/
|
|
1375
|
+
},
|
|
1376
|
+
{
|
|
1377
|
+
no: 8,
|
|
1378
|
+
name: "prediction_strategy_used",
|
|
1379
|
+
kind: "scalar",
|
|
1380
|
+
T: 9
|
|
1381
|
+
/*ScalarType.STRING*/
|
|
1382
|
+
},
|
|
1383
|
+
{
|
|
1384
|
+
no: 9,
|
|
1385
|
+
name: "prediction_policy_used",
|
|
1386
|
+
kind: "scalar",
|
|
1387
|
+
T: 9
|
|
1388
|
+
/*ScalarType.STRING*/
|
|
1389
|
+
},
|
|
1390
|
+
{
|
|
1391
|
+
no: 10,
|
|
1392
|
+
name: "prediction_confidence",
|
|
1393
|
+
kind: "scalar",
|
|
1394
|
+
T: 2
|
|
1395
|
+
/*ScalarType.FLOAT*/
|
|
1396
|
+
},
|
|
1397
|
+
{
|
|
1398
|
+
no: 11,
|
|
1399
|
+
name: "prediction_sample_size",
|
|
1400
|
+
kind: "scalar",
|
|
1401
|
+
T: 3
|
|
1402
|
+
/*ScalarType.INT64*/
|
|
1403
|
+
},
|
|
1404
|
+
{
|
|
1405
|
+
no: 12,
|
|
1406
|
+
name: "cold_start_layer_used",
|
|
1407
|
+
kind: "scalar",
|
|
1408
|
+
T: 9
|
|
1409
|
+
/*ScalarType.STRING*/
|
|
1410
|
+
},
|
|
1411
|
+
{
|
|
1412
|
+
no: 13,
|
|
1413
|
+
name: "classifier_version",
|
|
1414
|
+
kind: "scalar",
|
|
1415
|
+
T: 9
|
|
1416
|
+
/*ScalarType.STRING*/
|
|
1417
|
+
},
|
|
1418
|
+
{
|
|
1419
|
+
no: 14,
|
|
1420
|
+
name: "fingerprint_version",
|
|
1421
|
+
kind: "scalar",
|
|
1422
|
+
T: 9
|
|
1423
|
+
/*ScalarType.STRING*/
|
|
1424
|
+
},
|
|
1425
|
+
{
|
|
1426
|
+
no: 15,
|
|
1427
|
+
name: "prompt_class_fingerprint",
|
|
1428
|
+
kind: "scalar",
|
|
1429
|
+
T: 9
|
|
1430
|
+
/*ScalarType.STRING*/
|
|
1431
|
+
},
|
|
1432
|
+
{
|
|
1433
|
+
no: 16,
|
|
1434
|
+
name: "run_projection_at_decision_atomic",
|
|
1435
|
+
kind: "scalar",
|
|
1436
|
+
T: 3
|
|
1437
|
+
/*ScalarType.INT64*/
|
|
1438
|
+
},
|
|
1439
|
+
{
|
|
1440
|
+
no: 17,
|
|
1441
|
+
name: "run_predicted_remaining_steps",
|
|
1442
|
+
kind: "scalar",
|
|
1443
|
+
T: 5
|
|
1444
|
+
/*ScalarType.INT32*/
|
|
1445
|
+
},
|
|
1446
|
+
{
|
|
1447
|
+
no: 18,
|
|
1448
|
+
name: "run_steps_completed_so_far",
|
|
1449
|
+
kind: "scalar",
|
|
1450
|
+
T: 3
|
|
1451
|
+
/*ScalarType.INT64*/
|
|
1452
|
+
},
|
|
1453
|
+
{
|
|
1454
|
+
no: 19,
|
|
1455
|
+
name: "run_code_triggered",
|
|
1456
|
+
kind: "scalar",
|
|
1457
|
+
T: 9
|
|
1458
|
+
/*ScalarType.STRING*/
|
|
1459
|
+
},
|
|
1460
|
+
{
|
|
1461
|
+
no: 20,
|
|
1462
|
+
name: "model",
|
|
1463
|
+
kind: "scalar",
|
|
1464
|
+
T: 9
|
|
1465
|
+
/*ScalarType.STRING*/
|
|
1466
|
+
},
|
|
1467
|
+
{
|
|
1468
|
+
no: 21,
|
|
1469
|
+
name: "prompt_class",
|
|
1470
|
+
kind: "scalar",
|
|
1471
|
+
T: 9
|
|
1472
|
+
/*ScalarType.STRING*/
|
|
1473
|
+
}
|
|
1474
|
+
]);
|
|
1475
|
+
}
|
|
1476
|
+
};
|
|
1477
|
+
var ClaimEstimate = new ClaimEstimate$Type();
|
|
1478
|
+
var DecisionRequest$Type = class extends MessageType {
|
|
1479
|
+
constructor() {
|
|
1480
|
+
super("spendguard.sidecar_adapter.v1.DecisionRequest", [
|
|
1481
|
+
{
|
|
1482
|
+
no: 1,
|
|
1483
|
+
name: "session_id",
|
|
1484
|
+
kind: "scalar",
|
|
1485
|
+
T: 9
|
|
1486
|
+
/*ScalarType.STRING*/
|
|
1487
|
+
},
|
|
1488
|
+
{ no: 2, name: "trigger", kind: "enum", T: () => ["spendguard.sidecar_adapter.v1.DecisionRequest.Trigger", DecisionRequest_Trigger] },
|
|
1489
|
+
{ no: 3, name: "trace", kind: "message", T: () => TraceContext },
|
|
1490
|
+
{ no: 4, name: "ids", kind: "message", T: () => SpendGuardIds },
|
|
1491
|
+
{
|
|
1492
|
+
no: 5,
|
|
1493
|
+
name: "route",
|
|
1494
|
+
kind: "scalar",
|
|
1495
|
+
T: 9
|
|
1496
|
+
/*ScalarType.STRING*/
|
|
1497
|
+
},
|
|
1498
|
+
{ no: 6, name: "inputs", kind: "message", T: () => DecisionRequest_Inputs },
|
|
1499
|
+
{
|
|
1500
|
+
no: 7,
|
|
1501
|
+
name: "parent_run_id",
|
|
1502
|
+
kind: "scalar",
|
|
1503
|
+
T: 9
|
|
1504
|
+
/*ScalarType.STRING*/
|
|
1505
|
+
},
|
|
1506
|
+
{
|
|
1507
|
+
no: 8,
|
|
1508
|
+
name: "budget_grant_jti",
|
|
1509
|
+
kind: "scalar",
|
|
1510
|
+
T: 9
|
|
1511
|
+
/*ScalarType.STRING*/
|
|
1512
|
+
},
|
|
1513
|
+
{ no: 9, name: "idempotency", kind: "message", T: () => Idempotency },
|
|
1514
|
+
{
|
|
1515
|
+
no: 17,
|
|
1516
|
+
name: "planned_steps_hint",
|
|
1517
|
+
kind: "scalar",
|
|
1518
|
+
T: 5
|
|
1519
|
+
/*ScalarType.INT32*/
|
|
1520
|
+
},
|
|
1521
|
+
{ no: 18, name: "reservation_source", kind: "enum", T: () => ["spendguard.common.v1.ReservationSource", ReservationSource, "RESERVATION_SOURCE_"] },
|
|
1522
|
+
{
|
|
1523
|
+
no: 19,
|
|
1524
|
+
name: "meter_only_estimate",
|
|
1525
|
+
kind: "scalar",
|
|
1526
|
+
T: 8
|
|
1527
|
+
/*ScalarType.BOOL*/
|
|
1528
|
+
}
|
|
1529
|
+
]);
|
|
1530
|
+
}
|
|
1531
|
+
};
|
|
1532
|
+
var DecisionRequest = new DecisionRequest$Type();
|
|
1533
|
+
var DecisionRequest_Inputs$Type = class extends MessageType {
|
|
1534
|
+
constructor() {
|
|
1535
|
+
super("spendguard.sidecar_adapter.v1.DecisionRequest.Inputs", [
|
|
1536
|
+
{ no: 1, name: "projected_claims", kind: "message", repeat: 2, T: () => BudgetClaim },
|
|
1537
|
+
{
|
|
1538
|
+
no: 2,
|
|
1539
|
+
name: "projected_p50_atomic",
|
|
1540
|
+
kind: "scalar",
|
|
1541
|
+
T: 9
|
|
1542
|
+
/*ScalarType.STRING*/
|
|
1543
|
+
},
|
|
1544
|
+
{
|
|
1545
|
+
no: 3,
|
|
1546
|
+
name: "projected_p90_atomic",
|
|
1547
|
+
kind: "scalar",
|
|
1548
|
+
T: 9
|
|
1549
|
+
/*ScalarType.STRING*/
|
|
1550
|
+
},
|
|
1551
|
+
{
|
|
1552
|
+
no: 4,
|
|
1553
|
+
name: "projected_p95_atomic",
|
|
1554
|
+
kind: "scalar",
|
|
1555
|
+
T: 9
|
|
1556
|
+
/*ScalarType.STRING*/
|
|
1557
|
+
},
|
|
1558
|
+
{
|
|
1559
|
+
no: 5,
|
|
1560
|
+
name: "projected_p99_atomic",
|
|
1561
|
+
kind: "scalar",
|
|
1562
|
+
T: 9
|
|
1563
|
+
/*ScalarType.STRING*/
|
|
1564
|
+
},
|
|
1565
|
+
{ no: 6, name: "projected_unit", kind: "message", T: () => UnitRef },
|
|
1566
|
+
{ no: 7, name: "runtime_metadata", kind: "message", T: () => Struct },
|
|
1567
|
+
{ no: 8, name: "claim_estimate", kind: "message", T: () => ClaimEstimate }
|
|
1568
|
+
]);
|
|
1569
|
+
}
|
|
1570
|
+
};
|
|
1571
|
+
var DecisionRequest_Inputs = new DecisionRequest_Inputs$Type();
|
|
1572
|
+
var DecisionResponse$Type = class extends MessageType {
|
|
1573
|
+
constructor() {
|
|
1574
|
+
super("spendguard.sidecar_adapter.v1.DecisionResponse", [
|
|
1575
|
+
{
|
|
1576
|
+
no: 1,
|
|
1577
|
+
name: "decision_id",
|
|
1578
|
+
kind: "scalar",
|
|
1579
|
+
T: 9
|
|
1580
|
+
/*ScalarType.STRING*/
|
|
1581
|
+
},
|
|
1582
|
+
{
|
|
1583
|
+
no: 2,
|
|
1584
|
+
name: "audit_decision_event_id",
|
|
1585
|
+
kind: "scalar",
|
|
1586
|
+
T: 9
|
|
1587
|
+
/*ScalarType.STRING*/
|
|
1588
|
+
},
|
|
1589
|
+
{ no: 3, name: "decision", kind: "enum", T: () => ["spendguard.sidecar_adapter.v1.DecisionResponse.Decision", DecisionResponse_Decision] },
|
|
1590
|
+
{
|
|
1591
|
+
no: 4,
|
|
1592
|
+
name: "reason_codes",
|
|
1593
|
+
kind: "scalar",
|
|
1594
|
+
repeat: 2,
|
|
1595
|
+
T: 9
|
|
1596
|
+
/*ScalarType.STRING*/
|
|
1597
|
+
},
|
|
1598
|
+
{
|
|
1599
|
+
no: 5,
|
|
1600
|
+
name: "matched_rule_ids",
|
|
1601
|
+
kind: "scalar",
|
|
1602
|
+
repeat: 2,
|
|
1603
|
+
T: 9
|
|
1604
|
+
/*ScalarType.STRING*/
|
|
1605
|
+
},
|
|
1606
|
+
{
|
|
1607
|
+
no: 6,
|
|
1608
|
+
name: "mutation_patch_json",
|
|
1609
|
+
kind: "scalar",
|
|
1610
|
+
T: 9
|
|
1611
|
+
/*ScalarType.STRING*/
|
|
1612
|
+
},
|
|
1613
|
+
{
|
|
1614
|
+
no: 7,
|
|
1615
|
+
name: "effect_hash",
|
|
1616
|
+
kind: "scalar",
|
|
1617
|
+
T: 12
|
|
1618
|
+
/*ScalarType.BYTES*/
|
|
1619
|
+
},
|
|
1620
|
+
{
|
|
1621
|
+
no: 8,
|
|
1622
|
+
name: "ledger_transaction_id",
|
|
1623
|
+
kind: "scalar",
|
|
1624
|
+
T: 9
|
|
1625
|
+
/*ScalarType.STRING*/
|
|
1626
|
+
},
|
|
1627
|
+
{
|
|
1628
|
+
no: 9,
|
|
1629
|
+
name: "reservation_ids",
|
|
1630
|
+
kind: "scalar",
|
|
1631
|
+
repeat: 2,
|
|
1632
|
+
T: 9
|
|
1633
|
+
/*ScalarType.STRING*/
|
|
1634
|
+
},
|
|
1635
|
+
{ no: 10, name: "ttl_expires_at", kind: "message", T: () => Timestamp },
|
|
1636
|
+
{
|
|
1637
|
+
no: 11,
|
|
1638
|
+
name: "approval_request_id",
|
|
1639
|
+
kind: "scalar",
|
|
1640
|
+
T: 9
|
|
1641
|
+
/*ScalarType.STRING*/
|
|
1642
|
+
},
|
|
1643
|
+
{ no: 12, name: "approval_ttl", kind: "message", T: () => Timestamp },
|
|
1644
|
+
{
|
|
1645
|
+
no: 13,
|
|
1646
|
+
name: "approver_role",
|
|
1647
|
+
kind: "scalar",
|
|
1648
|
+
T: 9
|
|
1649
|
+
/*ScalarType.STRING*/
|
|
1650
|
+
},
|
|
1651
|
+
{
|
|
1652
|
+
no: 14,
|
|
1653
|
+
name: "terminal",
|
|
1654
|
+
kind: "scalar",
|
|
1655
|
+
T: 8
|
|
1656
|
+
/*ScalarType.BOOL*/
|
|
1657
|
+
},
|
|
1658
|
+
{ no: 15, name: "error", kind: "message", T: () => Error2 },
|
|
1659
|
+
{
|
|
1660
|
+
no: 16,
|
|
1661
|
+
name: "run_code_triggered",
|
|
1662
|
+
kind: "scalar",
|
|
1663
|
+
T: 9
|
|
1664
|
+
/*ScalarType.STRING*/
|
|
1665
|
+
},
|
|
1666
|
+
{ no: 17, name: "subscription_meter", kind: "message", T: () => SubscriptionMeter }
|
|
1667
|
+
]);
|
|
1668
|
+
}
|
|
1669
|
+
};
|
|
1670
|
+
var DecisionResponse = new DecisionResponse$Type();
|
|
1671
|
+
var PublishOutcomeRequest$Type = class extends MessageType {
|
|
1672
|
+
constructor() {
|
|
1673
|
+
super("spendguard.sidecar_adapter.v1.PublishOutcomeRequest", [
|
|
1674
|
+
{
|
|
1675
|
+
no: 1,
|
|
1676
|
+
name: "session_id",
|
|
1677
|
+
kind: "scalar",
|
|
1678
|
+
T: 9
|
|
1679
|
+
/*ScalarType.STRING*/
|
|
1680
|
+
},
|
|
1681
|
+
{
|
|
1682
|
+
no: 2,
|
|
1683
|
+
name: "decision_id",
|
|
1684
|
+
kind: "scalar",
|
|
1685
|
+
T: 9
|
|
1686
|
+
/*ScalarType.STRING*/
|
|
1687
|
+
},
|
|
1688
|
+
{
|
|
1689
|
+
no: 3,
|
|
1690
|
+
name: "effect_hash",
|
|
1691
|
+
kind: "scalar",
|
|
1692
|
+
T: 12
|
|
1693
|
+
/*ScalarType.BYTES*/
|
|
1694
|
+
},
|
|
1695
|
+
{ no: 4, name: "outcome", kind: "enum", T: () => ["spendguard.sidecar_adapter.v1.PublishOutcomeRequest.Outcome", PublishOutcomeRequest_Outcome] },
|
|
1696
|
+
{
|
|
1697
|
+
no: 5,
|
|
1698
|
+
name: "adapter_error",
|
|
1699
|
+
kind: "scalar",
|
|
1700
|
+
T: 9
|
|
1701
|
+
/*ScalarType.STRING*/
|
|
1702
|
+
}
|
|
1703
|
+
]);
|
|
1704
|
+
}
|
|
1705
|
+
};
|
|
1706
|
+
var PublishOutcomeRequest = new PublishOutcomeRequest$Type();
|
|
1707
|
+
var PublishOutcomeResponse$Type = class extends MessageType {
|
|
1708
|
+
constructor() {
|
|
1709
|
+
super("spendguard.sidecar_adapter.v1.PublishOutcomeResponse", [
|
|
1710
|
+
{
|
|
1711
|
+
no: 1,
|
|
1712
|
+
name: "audit_outcome_event_id",
|
|
1713
|
+
kind: "scalar",
|
|
1714
|
+
T: 9
|
|
1715
|
+
/*ScalarType.STRING*/
|
|
1716
|
+
},
|
|
1717
|
+
{ no: 2, name: "recorded_at", kind: "message", T: () => Timestamp },
|
|
1718
|
+
{ no: 3, name: "error", kind: "message", T: () => Error2 }
|
|
1719
|
+
]);
|
|
1720
|
+
}
|
|
1721
|
+
};
|
|
1722
|
+
var PublishOutcomeResponse = new PublishOutcomeResponse$Type();
|
|
1723
|
+
var TraceEvent$Type = class extends MessageType {
|
|
1724
|
+
constructor() {
|
|
1725
|
+
super("spendguard.sidecar_adapter.v1.TraceEvent", [
|
|
1726
|
+
{
|
|
1727
|
+
no: 1,
|
|
1728
|
+
name: "session_id",
|
|
1729
|
+
kind: "scalar",
|
|
1730
|
+
T: 9
|
|
1731
|
+
/*ScalarType.STRING*/
|
|
1732
|
+
},
|
|
1733
|
+
{ no: 2, name: "trace", kind: "message", T: () => TraceContext },
|
|
1734
|
+
{ no: 3, name: "ids", kind: "message", T: () => SpendGuardIds },
|
|
1735
|
+
{ no: 4, name: "kind", kind: "enum", T: () => ["spendguard.sidecar_adapter.v1.TraceEvent.EventKind", TraceEvent_EventKind] },
|
|
1736
|
+
{ no: 5, name: "event_time", kind: "message", T: () => Timestamp },
|
|
1737
|
+
{ no: 6, name: "generic", kind: "message", oneof: "payload", T: () => Struct },
|
|
1738
|
+
{ no: 8, name: "llm_call_post", kind: "message", oneof: "payload", T: () => LlmCallPostPayload },
|
|
1739
|
+
{ no: 9, name: "approval", kind: "message", oneof: "payload", T: () => ApprovalLifecyclePayload },
|
|
1740
|
+
{ no: 10, name: "rollback", kind: "message", oneof: "payload", T: () => RollbackPayload },
|
|
1741
|
+
{
|
|
1742
|
+
no: 7,
|
|
1743
|
+
name: "provider_response_metadata",
|
|
1744
|
+
kind: "scalar",
|
|
1745
|
+
T: 9
|
|
1746
|
+
/*ScalarType.STRING*/
|
|
1747
|
+
}
|
|
1748
|
+
]);
|
|
1749
|
+
}
|
|
1750
|
+
};
|
|
1751
|
+
var TraceEvent = new TraceEvent$Type();
|
|
1752
|
+
var LlmCallPostPayload$Type = class extends MessageType {
|
|
1753
|
+
constructor() {
|
|
1754
|
+
super("spendguard.sidecar_adapter.v1.LlmCallPostPayload", [
|
|
1755
|
+
{
|
|
1756
|
+
no: 1,
|
|
1757
|
+
name: "reservation_id",
|
|
1758
|
+
kind: "scalar",
|
|
1759
|
+
T: 9
|
|
1760
|
+
/*ScalarType.STRING*/
|
|
1761
|
+
},
|
|
1762
|
+
{
|
|
1763
|
+
no: 2,
|
|
1764
|
+
name: "provider_reported_amount_atomic",
|
|
1765
|
+
kind: "scalar",
|
|
1766
|
+
T: 9
|
|
1767
|
+
/*ScalarType.STRING*/
|
|
1768
|
+
},
|
|
1769
|
+
{ no: 3, name: "unit", kind: "message", T: () => UnitRef },
|
|
1770
|
+
{ no: 4, name: "pricing", kind: "message", T: () => PricingFreeze },
|
|
1771
|
+
{
|
|
1772
|
+
no: 5,
|
|
1773
|
+
name: "provider_event_id",
|
|
1774
|
+
kind: "scalar",
|
|
1775
|
+
T: 9
|
|
1776
|
+
/*ScalarType.STRING*/
|
|
1777
|
+
},
|
|
1778
|
+
{ no: 6, name: "outcome", kind: "enum", T: () => ["spendguard.sidecar_adapter.v1.LlmCallPostPayload.Outcome", LlmCallPostPayload_Outcome] },
|
|
1779
|
+
{
|
|
1780
|
+
no: 7,
|
|
1781
|
+
name: "estimated_amount_atomic",
|
|
1782
|
+
kind: "scalar",
|
|
1783
|
+
T: 9
|
|
1784
|
+
/*ScalarType.STRING*/
|
|
1785
|
+
},
|
|
1786
|
+
{
|
|
1787
|
+
no: 8,
|
|
1788
|
+
name: "actual_input_tokens",
|
|
1789
|
+
kind: "scalar",
|
|
1790
|
+
opt: true,
|
|
1791
|
+
T: 3
|
|
1792
|
+
/*ScalarType.INT64*/
|
|
1793
|
+
},
|
|
1794
|
+
{
|
|
1795
|
+
no: 9,
|
|
1796
|
+
name: "actual_output_tokens",
|
|
1797
|
+
kind: "scalar",
|
|
1798
|
+
opt: true,
|
|
1799
|
+
T: 3
|
|
1800
|
+
/*ScalarType.INT64*/
|
|
1801
|
+
},
|
|
1802
|
+
{
|
|
1803
|
+
no: 10,
|
|
1804
|
+
name: "delta_b_ratio",
|
|
1805
|
+
kind: "scalar",
|
|
1806
|
+
opt: true,
|
|
1807
|
+
T: 2
|
|
1808
|
+
/*ScalarType.FLOAT*/
|
|
1809
|
+
},
|
|
1810
|
+
{
|
|
1811
|
+
no: 11,
|
|
1812
|
+
name: "delta_c_ratio",
|
|
1813
|
+
kind: "scalar",
|
|
1814
|
+
opt: true,
|
|
1815
|
+
T: 2
|
|
1816
|
+
/*ScalarType.FLOAT*/
|
|
1817
|
+
}
|
|
1818
|
+
]);
|
|
1819
|
+
}
|
|
1820
|
+
};
|
|
1821
|
+
var LlmCallPostPayload = new LlmCallPostPayload$Type();
|
|
1822
|
+
var ApprovalLifecyclePayload$Type = class extends MessageType {
|
|
1823
|
+
constructor() {
|
|
1824
|
+
super("spendguard.sidecar_adapter.v1.ApprovalLifecyclePayload", [
|
|
1825
|
+
{
|
|
1826
|
+
no: 1,
|
|
1827
|
+
name: "approval_request_id",
|
|
1828
|
+
kind: "scalar",
|
|
1829
|
+
T: 9
|
|
1830
|
+
/*ScalarType.STRING*/
|
|
1831
|
+
},
|
|
1832
|
+
{ no: 2, name: "state", kind: "enum", T: () => ["spendguard.sidecar_adapter.v1.ApprovalLifecyclePayload.State", ApprovalLifecyclePayload_State] },
|
|
1833
|
+
{
|
|
1834
|
+
no: 3,
|
|
1835
|
+
name: "approver",
|
|
1836
|
+
kind: "scalar",
|
|
1837
|
+
T: 9
|
|
1838
|
+
/*ScalarType.STRING*/
|
|
1839
|
+
},
|
|
1840
|
+
{ no: 4, name: "deadline", kind: "message", T: () => Timestamp }
|
|
1841
|
+
]);
|
|
1842
|
+
}
|
|
1843
|
+
};
|
|
1844
|
+
var ApprovalLifecyclePayload = new ApprovalLifecyclePayload$Type();
|
|
1845
|
+
var RollbackPayload$Type = class extends MessageType {
|
|
1846
|
+
constructor() {
|
|
1847
|
+
super("spendguard.sidecar_adapter.v1.RollbackPayload", [
|
|
1848
|
+
{
|
|
1849
|
+
no: 1,
|
|
1850
|
+
name: "ledger_transaction_id",
|
|
1851
|
+
kind: "scalar",
|
|
1852
|
+
T: 9
|
|
1853
|
+
/*ScalarType.STRING*/
|
|
1854
|
+
},
|
|
1855
|
+
{
|
|
1856
|
+
no: 2,
|
|
1857
|
+
name: "reason_code",
|
|
1858
|
+
kind: "scalar",
|
|
1859
|
+
T: 9
|
|
1860
|
+
/*ScalarType.STRING*/
|
|
1861
|
+
},
|
|
1862
|
+
{
|
|
1863
|
+
no: 3,
|
|
1864
|
+
name: "compensating_ledger_transaction_id",
|
|
1865
|
+
kind: "scalar",
|
|
1866
|
+
T: 9
|
|
1867
|
+
/*ScalarType.STRING*/
|
|
1868
|
+
}
|
|
1869
|
+
]);
|
|
1870
|
+
}
|
|
1871
|
+
};
|
|
1872
|
+
var RollbackPayload = new RollbackPayload$Type();
|
|
1873
|
+
var TraceEventAck$Type = class extends MessageType {
|
|
1874
|
+
constructor() {
|
|
1875
|
+
super("spendguard.sidecar_adapter.v1.TraceEventAck", [
|
|
1876
|
+
{
|
|
1877
|
+
no: 1,
|
|
1878
|
+
name: "event_id",
|
|
1879
|
+
kind: "scalar",
|
|
1880
|
+
T: 9
|
|
1881
|
+
/*ScalarType.STRING*/
|
|
1882
|
+
},
|
|
1883
|
+
{ no: 2, name: "status", kind: "enum", T: () => ["spendguard.sidecar_adapter.v1.TraceEventAck.Status", TraceEventAck_Status] },
|
|
1884
|
+
{ no: 3, name: "error", kind: "message", T: () => Error2 }
|
|
1885
|
+
]);
|
|
1886
|
+
}
|
|
1887
|
+
};
|
|
1888
|
+
var TraceEventAck = new TraceEventAck$Type();
|
|
1889
|
+
var IssueBudgetGrantRequest$Type = class extends MessageType {
|
|
1890
|
+
constructor() {
|
|
1891
|
+
super("spendguard.sidecar_adapter.v1.IssueBudgetGrantRequest", [
|
|
1892
|
+
{
|
|
1893
|
+
no: 1,
|
|
1894
|
+
name: "session_id",
|
|
1895
|
+
kind: "scalar",
|
|
1896
|
+
T: 9
|
|
1897
|
+
/*ScalarType.STRING*/
|
|
1898
|
+
},
|
|
1899
|
+
{
|
|
1900
|
+
no: 2,
|
|
1901
|
+
name: "parent_run_id",
|
|
1902
|
+
kind: "scalar",
|
|
1903
|
+
T: 9
|
|
1904
|
+
/*ScalarType.STRING*/
|
|
1905
|
+
},
|
|
1906
|
+
{
|
|
1907
|
+
no: 3,
|
|
1908
|
+
name: "child_workload_kind",
|
|
1909
|
+
kind: "scalar",
|
|
1910
|
+
T: 9
|
|
1911
|
+
/*ScalarType.STRING*/
|
|
1912
|
+
},
|
|
1913
|
+
{ no: 4, name: "scope", kind: "message", T: () => IssueBudgetGrantRequest_Scope }
|
|
1914
|
+
]);
|
|
1915
|
+
}
|
|
1916
|
+
};
|
|
1917
|
+
var IssueBudgetGrantRequest = new IssueBudgetGrantRequest$Type();
|
|
1918
|
+
var IssueBudgetGrantRequest_Scope$Type = class extends MessageType {
|
|
1919
|
+
constructor() {
|
|
1920
|
+
super("spendguard.sidecar_adapter.v1.IssueBudgetGrantRequest.Scope", [
|
|
1921
|
+
{
|
|
1922
|
+
no: 1,
|
|
1923
|
+
name: "allowed_routes",
|
|
1924
|
+
kind: "scalar",
|
|
1925
|
+
repeat: 2,
|
|
1926
|
+
T: 9
|
|
1927
|
+
/*ScalarType.STRING*/
|
|
1928
|
+
},
|
|
1929
|
+
{
|
|
1930
|
+
no: 2,
|
|
1931
|
+
name: "allowed_runtimes",
|
|
1932
|
+
kind: "scalar",
|
|
1933
|
+
repeat: 2,
|
|
1934
|
+
T: 9
|
|
1935
|
+
/*ScalarType.STRING*/
|
|
1936
|
+
},
|
|
1937
|
+
{
|
|
1938
|
+
no: 3,
|
|
1939
|
+
name: "max_amount_atomic",
|
|
1940
|
+
kind: "scalar",
|
|
1941
|
+
T: 9
|
|
1942
|
+
/*ScalarType.STRING*/
|
|
1943
|
+
},
|
|
1944
|
+
{ no: 4, name: "max_amount_unit", kind: "message", T: () => UnitRef },
|
|
1945
|
+
{ no: 5, name: "expires_at", kind: "message", T: () => Timestamp },
|
|
1946
|
+
{
|
|
1947
|
+
no: 6,
|
|
1948
|
+
name: "reservation_id",
|
|
1949
|
+
kind: "scalar",
|
|
1950
|
+
T: 9
|
|
1951
|
+
/*ScalarType.STRING*/
|
|
1952
|
+
}
|
|
1953
|
+
]);
|
|
1954
|
+
}
|
|
1955
|
+
};
|
|
1956
|
+
var IssueBudgetGrantRequest_Scope = new IssueBudgetGrantRequest_Scope$Type();
|
|
1957
|
+
var IssueBudgetGrantResponse$Type = class extends MessageType {
|
|
1958
|
+
constructor() {
|
|
1959
|
+
super("spendguard.sidecar_adapter.v1.IssueBudgetGrantResponse", [
|
|
1960
|
+
{
|
|
1961
|
+
no: 1,
|
|
1962
|
+
name: "jwt_grant",
|
|
1963
|
+
kind: "scalar",
|
|
1964
|
+
T: 9
|
|
1965
|
+
/*ScalarType.STRING*/
|
|
1966
|
+
},
|
|
1967
|
+
{
|
|
1968
|
+
no: 2,
|
|
1969
|
+
name: "grant_jti",
|
|
1970
|
+
kind: "scalar",
|
|
1971
|
+
T: 9
|
|
1972
|
+
/*ScalarType.STRING*/
|
|
1973
|
+
},
|
|
1974
|
+
{ no: 3, name: "issued_at", kind: "message", T: () => Timestamp },
|
|
1975
|
+
{ no: 4, name: "expires_at", kind: "message", T: () => Timestamp }
|
|
1976
|
+
]);
|
|
1977
|
+
}
|
|
1978
|
+
};
|
|
1979
|
+
var IssueBudgetGrantResponse = new IssueBudgetGrantResponse$Type();
|
|
1980
|
+
var RevokeBudgetGrantRequest$Type = class extends MessageType {
|
|
1981
|
+
constructor() {
|
|
1982
|
+
super("spendguard.sidecar_adapter.v1.RevokeBudgetGrantRequest", [
|
|
1983
|
+
{
|
|
1984
|
+
no: 1,
|
|
1985
|
+
name: "session_id",
|
|
1986
|
+
kind: "scalar",
|
|
1987
|
+
T: 9
|
|
1988
|
+
/*ScalarType.STRING*/
|
|
1989
|
+
},
|
|
1990
|
+
{
|
|
1991
|
+
no: 2,
|
|
1992
|
+
name: "grant_jti",
|
|
1993
|
+
kind: "scalar",
|
|
1994
|
+
T: 9
|
|
1995
|
+
/*ScalarType.STRING*/
|
|
1996
|
+
},
|
|
1997
|
+
{
|
|
1998
|
+
no: 3,
|
|
1999
|
+
name: "reason",
|
|
2000
|
+
kind: "scalar",
|
|
2001
|
+
T: 9
|
|
2002
|
+
/*ScalarType.STRING*/
|
|
2003
|
+
}
|
|
2004
|
+
]);
|
|
2005
|
+
}
|
|
2006
|
+
};
|
|
2007
|
+
var RevokeBudgetGrantRequest = new RevokeBudgetGrantRequest$Type();
|
|
2008
|
+
var RevokeBudgetGrantResponse$Type = class extends MessageType {
|
|
2009
|
+
constructor() {
|
|
2010
|
+
super("spendguard.sidecar_adapter.v1.RevokeBudgetGrantResponse", [
|
|
2011
|
+
{
|
|
2012
|
+
no: 1,
|
|
2013
|
+
name: "revoked",
|
|
2014
|
+
kind: "scalar",
|
|
2015
|
+
T: 8
|
|
2016
|
+
/*ScalarType.BOOL*/
|
|
2017
|
+
},
|
|
2018
|
+
{ no: 2, name: "revoked_at", kind: "message", T: () => Timestamp }
|
|
2019
|
+
]);
|
|
2020
|
+
}
|
|
2021
|
+
};
|
|
2022
|
+
var RevokeBudgetGrantResponse = new RevokeBudgetGrantResponse$Type();
|
|
2023
|
+
var ConsumeBudgetGrantRequest$Type = class extends MessageType {
|
|
2024
|
+
constructor() {
|
|
2025
|
+
super("spendguard.sidecar_adapter.v1.ConsumeBudgetGrantRequest", [
|
|
2026
|
+
{
|
|
2027
|
+
no: 1,
|
|
2028
|
+
name: "session_id",
|
|
2029
|
+
kind: "scalar",
|
|
2030
|
+
T: 9
|
|
2031
|
+
/*ScalarType.STRING*/
|
|
2032
|
+
},
|
|
2033
|
+
{
|
|
2034
|
+
no: 2,
|
|
2035
|
+
name: "jwt_grant",
|
|
2036
|
+
kind: "scalar",
|
|
2037
|
+
T: 9
|
|
2038
|
+
/*ScalarType.STRING*/
|
|
2039
|
+
}
|
|
2040
|
+
]);
|
|
2041
|
+
}
|
|
2042
|
+
};
|
|
2043
|
+
var ConsumeBudgetGrantRequest = new ConsumeBudgetGrantRequest$Type();
|
|
2044
|
+
var ConsumeBudgetGrantResponse$Type = class extends MessageType {
|
|
2045
|
+
constructor() {
|
|
2046
|
+
super("spendguard.sidecar_adapter.v1.ConsumeBudgetGrantResponse", [
|
|
2047
|
+
{
|
|
2048
|
+
no: 1,
|
|
2049
|
+
name: "accepted",
|
|
2050
|
+
kind: "scalar",
|
|
2051
|
+
T: 8
|
|
2052
|
+
/*ScalarType.BOOL*/
|
|
2053
|
+
},
|
|
2054
|
+
{
|
|
2055
|
+
no: 2,
|
|
2056
|
+
name: "parent_run_id",
|
|
2057
|
+
kind: "scalar",
|
|
2058
|
+
T: 9
|
|
2059
|
+
/*ScalarType.STRING*/
|
|
2060
|
+
},
|
|
2061
|
+
{
|
|
2062
|
+
no: 3,
|
|
2063
|
+
name: "parent_tenant_id",
|
|
2064
|
+
kind: "scalar",
|
|
2065
|
+
T: 9
|
|
2066
|
+
/*ScalarType.STRING*/
|
|
2067
|
+
},
|
|
2068
|
+
{ no: 4, name: "expires_at", kind: "message", T: () => Timestamp },
|
|
2069
|
+
{ no: 5, name: "error", kind: "message", T: () => Error2 }
|
|
2070
|
+
]);
|
|
2071
|
+
}
|
|
2072
|
+
};
|
|
2073
|
+
var ConsumeBudgetGrantResponse = new ConsumeBudgetGrantResponse$Type();
|
|
2074
|
+
var DrainSubscribeRequest$Type = class extends MessageType {
|
|
2075
|
+
constructor() {
|
|
2076
|
+
super("spendguard.sidecar_adapter.v1.DrainSubscribeRequest", [
|
|
2077
|
+
{
|
|
2078
|
+
no: 1,
|
|
2079
|
+
name: "session_id",
|
|
2080
|
+
kind: "scalar",
|
|
2081
|
+
T: 9
|
|
2082
|
+
/*ScalarType.STRING*/
|
|
2083
|
+
}
|
|
2084
|
+
]);
|
|
2085
|
+
}
|
|
2086
|
+
};
|
|
2087
|
+
var DrainSubscribeRequest = new DrainSubscribeRequest$Type();
|
|
2088
|
+
var DrainSignal$Type = class extends MessageType {
|
|
2089
|
+
constructor() {
|
|
2090
|
+
super("spendguard.sidecar_adapter.v1.DrainSignal", [
|
|
2091
|
+
{ no: 1, name: "phase", kind: "enum", T: () => ["spendguard.sidecar_adapter.v1.DrainSignal.Phase", DrainSignal_Phase] },
|
|
2092
|
+
{ no: 2, name: "deadline", kind: "message", T: () => Timestamp },
|
|
2093
|
+
{
|
|
2094
|
+
no: 3,
|
|
2095
|
+
name: "drain_trigger",
|
|
2096
|
+
kind: "scalar",
|
|
2097
|
+
T: 9
|
|
2098
|
+
/*ScalarType.STRING*/
|
|
2099
|
+
}
|
|
2100
|
+
]);
|
|
2101
|
+
}
|
|
2102
|
+
};
|
|
2103
|
+
var DrainSignal = new DrainSignal$Type();
|
|
2104
|
+
var ReleaseReservationRequest$Type = class extends MessageType {
|
|
2105
|
+
constructor() {
|
|
2106
|
+
super("spendguard.sidecar_adapter.v1.ReleaseReservationRequest", [
|
|
2107
|
+
{
|
|
2108
|
+
no: 1,
|
|
2109
|
+
name: "reservation_id",
|
|
2110
|
+
kind: "scalar",
|
|
2111
|
+
T: 9
|
|
2112
|
+
/*ScalarType.STRING*/
|
|
2113
|
+
},
|
|
2114
|
+
{
|
|
2115
|
+
no: 2,
|
|
2116
|
+
name: "idempotency_key",
|
|
2117
|
+
kind: "scalar",
|
|
2118
|
+
T: 9
|
|
2119
|
+
/*ScalarType.STRING*/
|
|
2120
|
+
},
|
|
2121
|
+
{
|
|
2122
|
+
no: 3,
|
|
2123
|
+
name: "reason_codes",
|
|
2124
|
+
kind: "scalar",
|
|
2125
|
+
repeat: 2,
|
|
2126
|
+
T: 9
|
|
2127
|
+
/*ScalarType.STRING*/
|
|
2128
|
+
},
|
|
2129
|
+
{
|
|
2130
|
+
no: 100,
|
|
2131
|
+
name: "tenant_id",
|
|
2132
|
+
kind: "scalar",
|
|
2133
|
+
T: 9
|
|
2134
|
+
/*ScalarType.STRING*/
|
|
2135
|
+
},
|
|
2136
|
+
{
|
|
2137
|
+
no: 101,
|
|
2138
|
+
name: "workload_instance_id",
|
|
2139
|
+
kind: "scalar",
|
|
2140
|
+
T: 9
|
|
2141
|
+
/*ScalarType.STRING*/
|
|
2142
|
+
},
|
|
2143
|
+
{
|
|
2144
|
+
no: 102,
|
|
2145
|
+
name: "session_id",
|
|
2146
|
+
kind: "scalar",
|
|
2147
|
+
T: 9
|
|
2148
|
+
/*ScalarType.STRING*/
|
|
2149
|
+
}
|
|
2150
|
+
]);
|
|
2151
|
+
}
|
|
2152
|
+
};
|
|
2153
|
+
var ReleaseReservationRequest = new ReleaseReservationRequest$Type();
|
|
2154
|
+
var ReleaseReservationResponse$Type = class extends MessageType {
|
|
2155
|
+
constructor() {
|
|
2156
|
+
super("spendguard.sidecar_adapter.v1.ReleaseReservationResponse", [
|
|
2157
|
+
{
|
|
2158
|
+
no: 1,
|
|
2159
|
+
name: "audit_event_signature",
|
|
2160
|
+
kind: "scalar",
|
|
2161
|
+
T: 12
|
|
2162
|
+
/*ScalarType.BYTES*/
|
|
2163
|
+
},
|
|
2164
|
+
{
|
|
2165
|
+
no: 100,
|
|
2166
|
+
name: "ledger_transaction_id",
|
|
2167
|
+
kind: "scalar",
|
|
2168
|
+
T: 9
|
|
2169
|
+
/*ScalarType.STRING*/
|
|
2170
|
+
},
|
|
2171
|
+
{
|
|
2172
|
+
no: 101,
|
|
2173
|
+
name: "released_reservation_ids",
|
|
2174
|
+
kind: "scalar",
|
|
2175
|
+
repeat: 2,
|
|
2176
|
+
T: 9
|
|
2177
|
+
/*ScalarType.STRING*/
|
|
2178
|
+
}
|
|
2179
|
+
]);
|
|
2180
|
+
}
|
|
2181
|
+
};
|
|
2182
|
+
var ReleaseReservationResponse = new ReleaseReservationResponse$Type();
|
|
2183
|
+
var ReserveSessionRequest$Type = class extends MessageType {
|
|
2184
|
+
constructor() {
|
|
2185
|
+
super("spendguard.sidecar_adapter.v1.ReserveSessionRequest", [
|
|
2186
|
+
{
|
|
2187
|
+
no: 1,
|
|
2188
|
+
name: "tenant_id",
|
|
2189
|
+
kind: "scalar",
|
|
2190
|
+
T: 9
|
|
2191
|
+
/*ScalarType.STRING*/
|
|
2192
|
+
},
|
|
2193
|
+
{
|
|
2194
|
+
no: 2,
|
|
2195
|
+
name: "budget_id",
|
|
2196
|
+
kind: "scalar",
|
|
2197
|
+
T: 9
|
|
2198
|
+
/*ScalarType.STRING*/
|
|
2199
|
+
},
|
|
2200
|
+
{
|
|
2201
|
+
no: 3,
|
|
2202
|
+
name: "window_instance_id",
|
|
2203
|
+
kind: "scalar",
|
|
2204
|
+
T: 9
|
|
2205
|
+
/*ScalarType.STRING*/
|
|
2206
|
+
},
|
|
2207
|
+
{ no: 4, name: "unit", kind: "message", T: () => UnitRef },
|
|
2208
|
+
{ no: 5, name: "pricing", kind: "message", T: () => PricingFreeze },
|
|
2209
|
+
{
|
|
2210
|
+
no: 6,
|
|
2211
|
+
name: "session_id",
|
|
2212
|
+
kind: "scalar",
|
|
2213
|
+
T: 9
|
|
2214
|
+
/*ScalarType.STRING*/
|
|
2215
|
+
},
|
|
2216
|
+
{
|
|
2217
|
+
no: 7,
|
|
2218
|
+
name: "route",
|
|
2219
|
+
kind: "scalar",
|
|
2220
|
+
T: 9
|
|
2221
|
+
/*ScalarType.STRING*/
|
|
2222
|
+
},
|
|
2223
|
+
{
|
|
2224
|
+
no: 8,
|
|
2225
|
+
name: "estimated_amount_atomic",
|
|
2226
|
+
kind: "scalar",
|
|
2227
|
+
T: 9
|
|
2228
|
+
/*ScalarType.STRING*/
|
|
2229
|
+
},
|
|
2230
|
+
{
|
|
2231
|
+
no: 9,
|
|
2232
|
+
name: "ttl_seconds",
|
|
2233
|
+
kind: "scalar",
|
|
2234
|
+
T: 13
|
|
2235
|
+
/*ScalarType.UINT32*/
|
|
2236
|
+
},
|
|
2237
|
+
{
|
|
2238
|
+
no: 10,
|
|
2239
|
+
name: "idempotency_key",
|
|
2240
|
+
kind: "scalar",
|
|
2241
|
+
T: 9
|
|
2242
|
+
/*ScalarType.STRING*/
|
|
2243
|
+
}
|
|
2244
|
+
]);
|
|
2245
|
+
}
|
|
2246
|
+
};
|
|
2247
|
+
var ReserveSessionRequest = new ReserveSessionRequest$Type();
|
|
2248
|
+
var ReserveSessionOutcome$Type = class extends MessageType {
|
|
2249
|
+
constructor() {
|
|
2250
|
+
super("spendguard.sidecar_adapter.v1.ReserveSessionOutcome", [
|
|
2251
|
+
{ no: 1, name: "accepted", kind: "message", oneof: "outcome", T: () => ReserveSessionAccepted },
|
|
2252
|
+
{ no: 2, name: "denied", kind: "message", oneof: "outcome", T: () => ReserveSessionDenied },
|
|
2253
|
+
{ no: 3, name: "error", kind: "message", oneof: "outcome", T: () => Error2 }
|
|
2254
|
+
]);
|
|
2255
|
+
}
|
|
2256
|
+
};
|
|
2257
|
+
var ReserveSessionOutcome = new ReserveSessionOutcome$Type();
|
|
2258
|
+
var ReserveSessionAccepted$Type = class extends MessageType {
|
|
2259
|
+
constructor() {
|
|
2260
|
+
super("spendguard.sidecar_adapter.v1.ReserveSessionAccepted", [
|
|
2261
|
+
{
|
|
2262
|
+
no: 1,
|
|
2263
|
+
name: "session_reservation_id",
|
|
2264
|
+
kind: "scalar",
|
|
2265
|
+
T: 9
|
|
2266
|
+
/*ScalarType.STRING*/
|
|
2267
|
+
},
|
|
2268
|
+
{
|
|
2269
|
+
no: 2,
|
|
2270
|
+
name: "ledger_transaction_id",
|
|
2271
|
+
kind: "scalar",
|
|
2272
|
+
T: 9
|
|
2273
|
+
/*ScalarType.STRING*/
|
|
2274
|
+
},
|
|
2275
|
+
{
|
|
2276
|
+
no: 3,
|
|
2277
|
+
name: "audit_session_event_id",
|
|
2278
|
+
kind: "scalar",
|
|
2279
|
+
T: 9
|
|
2280
|
+
/*ScalarType.STRING*/
|
|
2281
|
+
},
|
|
2282
|
+
{ no: 4, name: "ttl_expires_at", kind: "message", T: () => Timestamp },
|
|
2283
|
+
{
|
|
2284
|
+
no: 5,
|
|
2285
|
+
name: "reserved_amount_atomic",
|
|
2286
|
+
kind: "scalar",
|
|
2287
|
+
T: 9
|
|
2288
|
+
/*ScalarType.STRING*/
|
|
2289
|
+
},
|
|
2290
|
+
{
|
|
2291
|
+
no: 6,
|
|
2292
|
+
name: "remaining_amount_atomic",
|
|
2293
|
+
kind: "scalar",
|
|
2294
|
+
T: 9
|
|
2295
|
+
/*ScalarType.STRING*/
|
|
2296
|
+
}
|
|
2297
|
+
]);
|
|
2298
|
+
}
|
|
2299
|
+
};
|
|
2300
|
+
var ReserveSessionAccepted = new ReserveSessionAccepted$Type();
|
|
2301
|
+
var ReserveSessionDenied$Type = class extends MessageType {
|
|
2302
|
+
constructor() {
|
|
2303
|
+
super("spendguard.sidecar_adapter.v1.ReserveSessionDenied", [
|
|
2304
|
+
{
|
|
2305
|
+
no: 1,
|
|
2306
|
+
name: "audit_session_event_id",
|
|
2307
|
+
kind: "scalar",
|
|
2308
|
+
T: 9
|
|
2309
|
+
/*ScalarType.STRING*/
|
|
2310
|
+
},
|
|
2311
|
+
{
|
|
2312
|
+
no: 2,
|
|
2313
|
+
name: "reason_codes",
|
|
2314
|
+
kind: "scalar",
|
|
2315
|
+
repeat: 2,
|
|
2316
|
+
T: 9
|
|
2317
|
+
/*ScalarType.STRING*/
|
|
2318
|
+
},
|
|
2319
|
+
{
|
|
2320
|
+
no: 3,
|
|
2321
|
+
name: "matched_rule_ids",
|
|
2322
|
+
kind: "scalar",
|
|
2323
|
+
repeat: 2,
|
|
2324
|
+
T: 9
|
|
2325
|
+
/*ScalarType.STRING*/
|
|
2326
|
+
},
|
|
2327
|
+
{ no: 4, name: "error", kind: "message", T: () => Error2 }
|
|
2328
|
+
]);
|
|
2329
|
+
}
|
|
2330
|
+
};
|
|
2331
|
+
var ReserveSessionDenied = new ReserveSessionDenied$Type();
|
|
2332
|
+
var CommitSessionDeltaRequest$Type = class extends MessageType {
|
|
2333
|
+
constructor() {
|
|
2334
|
+
super("spendguard.sidecar_adapter.v1.CommitSessionDeltaRequest", [
|
|
2335
|
+
{
|
|
2336
|
+
no: 1,
|
|
2337
|
+
name: "session_reservation_id",
|
|
2338
|
+
kind: "scalar",
|
|
2339
|
+
T: 9
|
|
2340
|
+
/*ScalarType.STRING*/
|
|
2341
|
+
},
|
|
2342
|
+
{
|
|
2343
|
+
no: 2,
|
|
2344
|
+
name: "streaming_commit_id",
|
|
2345
|
+
kind: "scalar",
|
|
2346
|
+
T: 9
|
|
2347
|
+
/*ScalarType.STRING*/
|
|
2348
|
+
},
|
|
2349
|
+
{
|
|
2350
|
+
no: 3,
|
|
2351
|
+
name: "amount_atomic_delta",
|
|
2352
|
+
kind: "scalar",
|
|
2353
|
+
T: 9
|
|
2354
|
+
/*ScalarType.STRING*/
|
|
2355
|
+
},
|
|
2356
|
+
{ no: 4, name: "outcome", kind: "enum", T: () => ["spendguard.sidecar_adapter.v1.CommitSessionDeltaRequest.Outcome", CommitSessionDeltaRequest_Outcome] },
|
|
2357
|
+
{ no: 5, name: "event_time", kind: "message", T: () => Timestamp },
|
|
2358
|
+
{
|
|
2359
|
+
no: 6,
|
|
2360
|
+
name: "idempotency_key",
|
|
2361
|
+
kind: "scalar",
|
|
2362
|
+
T: 9
|
|
2363
|
+
/*ScalarType.STRING*/
|
|
2364
|
+
}
|
|
2365
|
+
]);
|
|
2366
|
+
}
|
|
2367
|
+
};
|
|
2368
|
+
var CommitSessionDeltaRequest = new CommitSessionDeltaRequest$Type();
|
|
2369
|
+
var CommitSessionDeltaOutcome$Type = class extends MessageType {
|
|
2370
|
+
constructor() {
|
|
2371
|
+
super("spendguard.sidecar_adapter.v1.CommitSessionDeltaOutcome", [
|
|
2372
|
+
{ no: 1, name: "accepted", kind: "message", oneof: "outcome", T: () => CommitSessionDeltaAccepted },
|
|
2373
|
+
{ no: 2, name: "error", kind: "message", oneof: "outcome", T: () => Error2 }
|
|
2374
|
+
]);
|
|
2375
|
+
}
|
|
2376
|
+
};
|
|
2377
|
+
var CommitSessionDeltaOutcome = new CommitSessionDeltaOutcome$Type();
|
|
2378
|
+
var CommitSessionDeltaAccepted$Type = class extends MessageType {
|
|
2379
|
+
constructor() {
|
|
2380
|
+
super("spendguard.sidecar_adapter.v1.CommitSessionDeltaAccepted", [
|
|
2381
|
+
{
|
|
2382
|
+
no: 1,
|
|
2383
|
+
name: "session_reservation_id",
|
|
2384
|
+
kind: "scalar",
|
|
2385
|
+
T: 9
|
|
2386
|
+
/*ScalarType.STRING*/
|
|
2387
|
+
},
|
|
2388
|
+
{
|
|
2389
|
+
no: 2,
|
|
2390
|
+
name: "streaming_commit_id",
|
|
2391
|
+
kind: "scalar",
|
|
2392
|
+
T: 9
|
|
2393
|
+
/*ScalarType.STRING*/
|
|
2394
|
+
},
|
|
2395
|
+
{
|
|
2396
|
+
no: 3,
|
|
2397
|
+
name: "ledger_transaction_id",
|
|
2398
|
+
kind: "scalar",
|
|
2399
|
+
T: 9
|
|
2400
|
+
/*ScalarType.STRING*/
|
|
2401
|
+
},
|
|
2402
|
+
{
|
|
2403
|
+
no: 4,
|
|
2404
|
+
name: "audit_session_event_id",
|
|
2405
|
+
kind: "scalar",
|
|
2406
|
+
T: 9
|
|
2407
|
+
/*ScalarType.STRING*/
|
|
2408
|
+
},
|
|
2409
|
+
{
|
|
2410
|
+
no: 5,
|
|
2411
|
+
name: "committed_delta_atomic",
|
|
2412
|
+
kind: "scalar",
|
|
2413
|
+
T: 9
|
|
2414
|
+
/*ScalarType.STRING*/
|
|
2415
|
+
},
|
|
2416
|
+
{
|
|
2417
|
+
no: 6,
|
|
2418
|
+
name: "cumulative_committed_atomic",
|
|
2419
|
+
kind: "scalar",
|
|
2420
|
+
T: 9
|
|
2421
|
+
/*ScalarType.STRING*/
|
|
2422
|
+
},
|
|
2423
|
+
{
|
|
2424
|
+
no: 7,
|
|
2425
|
+
name: "remaining_amount_atomic",
|
|
2426
|
+
kind: "scalar",
|
|
2427
|
+
T: 9
|
|
2428
|
+
/*ScalarType.STRING*/
|
|
2429
|
+
},
|
|
2430
|
+
{ no: 8, name: "recorded_at", kind: "message", T: () => Timestamp }
|
|
2431
|
+
]);
|
|
2432
|
+
}
|
|
2433
|
+
};
|
|
2434
|
+
var CommitSessionDeltaAccepted = new CommitSessionDeltaAccepted$Type();
|
|
2435
|
+
var ReleaseSessionRequest$Type = class extends MessageType {
|
|
2436
|
+
constructor() {
|
|
2437
|
+
super("spendguard.sidecar_adapter.v1.ReleaseSessionRequest", [
|
|
2438
|
+
{
|
|
2439
|
+
no: 1,
|
|
2440
|
+
name: "session_reservation_id",
|
|
2441
|
+
kind: "scalar",
|
|
2442
|
+
T: 9
|
|
2443
|
+
/*ScalarType.STRING*/
|
|
2444
|
+
},
|
|
2445
|
+
{
|
|
2446
|
+
no: 2,
|
|
2447
|
+
name: "reason_code",
|
|
2448
|
+
kind: "scalar",
|
|
2449
|
+
T: 9
|
|
2450
|
+
/*ScalarType.STRING*/
|
|
2451
|
+
},
|
|
2452
|
+
{ no: 3, name: "event_time", kind: "message", T: () => Timestamp },
|
|
2453
|
+
{
|
|
2454
|
+
no: 4,
|
|
2455
|
+
name: "idempotency_key",
|
|
2456
|
+
kind: "scalar",
|
|
2457
|
+
T: 9
|
|
2458
|
+
/*ScalarType.STRING*/
|
|
2459
|
+
}
|
|
2460
|
+
]);
|
|
2461
|
+
}
|
|
2462
|
+
};
|
|
2463
|
+
var ReleaseSessionRequest = new ReleaseSessionRequest$Type();
|
|
2464
|
+
var ReleaseSessionOutcome$Type = class extends MessageType {
|
|
2465
|
+
constructor() {
|
|
2466
|
+
super("spendguard.sidecar_adapter.v1.ReleaseSessionOutcome", [
|
|
2467
|
+
{ no: 1, name: "accepted", kind: "message", oneof: "outcome", T: () => ReleaseSessionAccepted },
|
|
2468
|
+
{ no: 2, name: "error", kind: "message", oneof: "outcome", T: () => Error2 }
|
|
2469
|
+
]);
|
|
2470
|
+
}
|
|
2471
|
+
};
|
|
2472
|
+
var ReleaseSessionOutcome = new ReleaseSessionOutcome$Type();
|
|
2473
|
+
var ReleaseSessionAccepted$Type = class extends MessageType {
|
|
2474
|
+
constructor() {
|
|
2475
|
+
super("spendguard.sidecar_adapter.v1.ReleaseSessionAccepted", [
|
|
2476
|
+
{
|
|
2477
|
+
no: 1,
|
|
2478
|
+
name: "session_reservation_id",
|
|
2479
|
+
kind: "scalar",
|
|
2480
|
+
T: 9
|
|
2481
|
+
/*ScalarType.STRING*/
|
|
2482
|
+
},
|
|
2483
|
+
{
|
|
2484
|
+
no: 2,
|
|
2485
|
+
name: "ledger_transaction_id",
|
|
2486
|
+
kind: "scalar",
|
|
2487
|
+
T: 9
|
|
2488
|
+
/*ScalarType.STRING*/
|
|
2489
|
+
},
|
|
2490
|
+
{
|
|
2491
|
+
no: 3,
|
|
2492
|
+
name: "audit_session_event_id",
|
|
2493
|
+
kind: "scalar",
|
|
2494
|
+
T: 9
|
|
2495
|
+
/*ScalarType.STRING*/
|
|
2496
|
+
},
|
|
2497
|
+
{
|
|
2498
|
+
no: 4,
|
|
2499
|
+
name: "released_amount_atomic",
|
|
2500
|
+
kind: "scalar",
|
|
2501
|
+
T: 9
|
|
2502
|
+
/*ScalarType.STRING*/
|
|
2503
|
+
},
|
|
2504
|
+
{
|
|
2505
|
+
no: 5,
|
|
2506
|
+
name: "committed_amount_atomic",
|
|
2507
|
+
kind: "scalar",
|
|
2508
|
+
T: 9
|
|
2509
|
+
/*ScalarType.STRING*/
|
|
2510
|
+
},
|
|
2511
|
+
{ no: 6, name: "recorded_at", kind: "message", T: () => Timestamp }
|
|
2512
|
+
]);
|
|
2513
|
+
}
|
|
2514
|
+
};
|
|
2515
|
+
var ReleaseSessionAccepted = new ReleaseSessionAccepted$Type();
|
|
2516
|
+
var SidecarAdapter = new ServiceType("spendguard.sidecar_adapter.v1.SidecarAdapter", [
|
|
2517
|
+
{ name: "Handshake", options: {}, I: HandshakeRequest, O: HandshakeResponse },
|
|
2518
|
+
{ name: "RequestDecision", options: {}, I: DecisionRequest, O: DecisionResponse },
|
|
2519
|
+
{ name: "ConfirmPublishOutcome", options: {}, I: PublishOutcomeRequest, O: PublishOutcomeResponse },
|
|
2520
|
+
{ name: "EmitTraceEvents", serverStreaming: true, clientStreaming: true, options: {}, I: TraceEvent, O: TraceEventAck },
|
|
2521
|
+
{ name: "IssueBudgetGrant", options: {}, I: IssueBudgetGrantRequest, O: IssueBudgetGrantResponse },
|
|
2522
|
+
{ name: "RevokeBudgetGrant", options: {}, I: RevokeBudgetGrantRequest, O: RevokeBudgetGrantResponse },
|
|
2523
|
+
{ name: "ConsumeBudgetGrant", options: {}, I: ConsumeBudgetGrantRequest, O: ConsumeBudgetGrantResponse },
|
|
2524
|
+
{ name: "StreamDrainSignal", serverStreaming: true, options: {}, I: DrainSubscribeRequest, O: DrainSignal },
|
|
2525
|
+
{ name: "ResumeAfterApproval", options: {}, I: ResumeAfterApprovalRequest, O: ResumeAfterApprovalResponse },
|
|
2526
|
+
{ name: "ReleaseReservation", options: {}, I: ReleaseReservationRequest, O: ReleaseReservationResponse },
|
|
2527
|
+
{ name: "ReserveSession", options: {}, I: ReserveSessionRequest, O: ReserveSessionOutcome },
|
|
2528
|
+
{ name: "CommitSessionDelta", options: {}, I: CommitSessionDeltaRequest, O: CommitSessionDeltaOutcome },
|
|
2529
|
+
{ name: "ReleaseSession", options: {}, I: ReleaseSessionRequest, O: ReleaseSessionOutcome }
|
|
2530
|
+
]);
|
|
2531
|
+
var SidecarAdapterClient = class {
|
|
2532
|
+
constructor(_transport) {
|
|
2533
|
+
this._transport = _transport;
|
|
2534
|
+
}
|
|
2535
|
+
_transport;
|
|
2536
|
+
typeName = SidecarAdapter.typeName;
|
|
2537
|
+
methods = SidecarAdapter.methods;
|
|
2538
|
+
options = SidecarAdapter.options;
|
|
2539
|
+
/**
|
|
2540
|
+
* Initial handshake; mandatory before any other RPC. Negotiates SDK version,
|
|
2541
|
+
* runtime kind, capability level, tenant_id assertion, key epochs.
|
|
2542
|
+
*
|
|
2543
|
+
* @generated from protobuf rpc: Handshake
|
|
2544
|
+
*/
|
|
2545
|
+
handshake(input, options) {
|
|
2546
|
+
const method = this.methods[0], opt = this._transport.mergeOptions(options);
|
|
2547
|
+
return stackIntercept("unary", this._transport, method, opt, input);
|
|
2548
|
+
}
|
|
2549
|
+
// -- Decision boundary (per Contract §15 trigger points) -----------------
|
|
2550
|
+
/**
|
|
2551
|
+
* Adapter requests a decision at a *.pre trigger point.
|
|
2552
|
+
* Sidecar runs Contract §6 stages 1-5 and returns DecisionResult.
|
|
2553
|
+
* Sidecar may take up to Contract §14 latency budget (50ms p99 warm).
|
|
2554
|
+
*
|
|
2555
|
+
* @generated from protobuf rpc: RequestDecision
|
|
2556
|
+
*/
|
|
2557
|
+
requestDecision(input, options) {
|
|
2558
|
+
const method = this.methods[1], opt = this._transport.mergeOptions(options);
|
|
2559
|
+
return stackIntercept("unary", this._transport, method, opt, input);
|
|
2560
|
+
}
|
|
2561
|
+
/**
|
|
2562
|
+
* Adapter confirms publish_effect outcome (per Contract §6 stage 7).
|
|
2563
|
+
* Idempotent via effect_hash (Stage 2 §4.6).
|
|
2564
|
+
*
|
|
2565
|
+
* @generated from protobuf rpc: ConfirmPublishOutcome
|
|
2566
|
+
*/
|
|
2567
|
+
confirmPublishOutcome(input, options) {
|
|
2568
|
+
const method = this.methods[2], opt = this._transport.mergeOptions(options);
|
|
2569
|
+
return stackIntercept("unary", this._transport, method, opt, input);
|
|
2570
|
+
}
|
|
2571
|
+
// -- Trace events (per Contract §15 *.post triggers; observation only) ---
|
|
2572
|
+
/**
|
|
2573
|
+
* Adapter emits canonical/lifecycle events (agent.run.start, agent.step.post
|
|
2574
|
+
* tool.call.post, llm.call.post for commit, etc.). Server-streamed because
|
|
2575
|
+
* sidecar may emit follow-up acks or correction events.
|
|
2576
|
+
*
|
|
2577
|
+
* @generated from protobuf rpc: EmitTraceEvents
|
|
2578
|
+
*/
|
|
2579
|
+
emitTraceEvents(options) {
|
|
2580
|
+
const method = this.methods[3], opt = this._transport.mergeOptions(options);
|
|
2581
|
+
return stackIntercept("duplex", this._transport, method, opt);
|
|
2582
|
+
}
|
|
2583
|
+
// -- Sub-agent budget grant (per Contract §8) ----------------------------
|
|
2584
|
+
/**
|
|
2585
|
+
* Parent agent requests budget_grant JWT to delegate to child agent.
|
|
2586
|
+
*
|
|
2587
|
+
* @generated from protobuf rpc: IssueBudgetGrant
|
|
2588
|
+
*/
|
|
2589
|
+
issueBudgetGrant(input, options) {
|
|
2590
|
+
const method = this.methods[4], opt = this._transport.mergeOptions(options);
|
|
2591
|
+
return stackIntercept("unary", this._transport, method, opt, input);
|
|
2592
|
+
}
|
|
2593
|
+
/**
|
|
2594
|
+
* Parent revokes a previously issued grant.
|
|
2595
|
+
*
|
|
2596
|
+
* @generated from protobuf rpc: RevokeBudgetGrant
|
|
2597
|
+
*/
|
|
2598
|
+
revokeBudgetGrant(input, options) {
|
|
2599
|
+
const method = this.methods[5], opt = this._transport.mergeOptions(options);
|
|
2600
|
+
return stackIntercept("unary", this._transport, method, opt, input);
|
|
2601
|
+
}
|
|
2602
|
+
/**
|
|
2603
|
+
* Child agent uses grant to bootstrap budget context.
|
|
2604
|
+
*
|
|
2605
|
+
* @generated from protobuf rpc: ConsumeBudgetGrant
|
|
2606
|
+
*/
|
|
2607
|
+
consumeBudgetGrant(input, options) {
|
|
2608
|
+
const method = this.methods[6], opt = this._transport.mergeOptions(options);
|
|
2609
|
+
return stackIntercept("unary", this._transport, method, opt, input);
|
|
2610
|
+
}
|
|
2611
|
+
// -- Lifecycle drain (per Sidecar §11) -----------------------------------
|
|
2612
|
+
/**
|
|
2613
|
+
* Sidecar signals adapter that drain has begun; adapter should stop
|
|
2614
|
+
* initiating new decision boundaries and let in-flight finish.
|
|
2615
|
+
*
|
|
2616
|
+
* @generated from protobuf rpc: StreamDrainSignal
|
|
2617
|
+
*/
|
|
2618
|
+
streamDrainSignal(input, options) {
|
|
2619
|
+
const method = this.methods[7], opt = this._transport.mergeOptions(options);
|
|
2620
|
+
return stackIntercept("serverStreaming", this._transport, method, opt, input);
|
|
2621
|
+
}
|
|
2622
|
+
// -- Approval resume (Phase 5 GA hardening S16) --------------------------
|
|
2623
|
+
/**
|
|
2624
|
+
* Adapter calls this AFTER the human approver has approved/denied the
|
|
2625
|
+
* pending approval (REQUIRE_APPROVAL outcome from RequestDecision).
|
|
2626
|
+
* Sidecar:
|
|
2627
|
+
* 1. Looks up the approval by (tenant_id, decision_id, approval_id).
|
|
2628
|
+
* 2. Reads the current state (must be `approved` or `denied`).
|
|
2629
|
+
* 3. For `approved`: re-runs Contract evaluation + Ledger.ReserveSet
|
|
2630
|
+
* with a NEW idempotency key derived from approval_id (so a
|
|
2631
|
+
* replay can never double-publish the effect).
|
|
2632
|
+
* 4. For `denied`: emits the deny audit row + returns Decision::STOP.
|
|
2633
|
+
* 5. For other states (pending/expired/cancelled): returns the
|
|
2634
|
+
* typed Error code so the adapter raises the right exception.
|
|
2635
|
+
*
|
|
2636
|
+
* Idempotent: repeated ResumeAfterApproval calls with the same
|
|
2637
|
+
* (decision_id, approval_id) produce the same DecisionResponse
|
|
2638
|
+
* because the idempotency key includes both.
|
|
2639
|
+
*
|
|
2640
|
+
* @generated from protobuf rpc: ResumeAfterApproval
|
|
2641
|
+
*/
|
|
2642
|
+
resumeAfterApproval(input, options) {
|
|
2643
|
+
const method = this.methods[8], opt = this._transport.mergeOptions(options);
|
|
2644
|
+
return stackIntercept("unary", this._transport, method, opt, input);
|
|
2645
|
+
}
|
|
2646
|
+
// -- Explicit Release (Draft-01 §4 of Agent Spend Protocol) ---------------
|
|
2647
|
+
/**
|
|
2648
|
+
* Adapter-initiated release of a held reservation before commit.
|
|
2649
|
+
* Use when the provider call is aborted, the client times out, or the
|
|
2650
|
+
* agent run is cancelled — and the adapter wants to surface that
|
|
2651
|
+
* explicitly rather than waiting for an outcome-driven (APPLY_FAILED
|
|
2652
|
+
* or trace-event-driven) implicit release.
|
|
2653
|
+
*
|
|
2654
|
+
* Coexists with the implicit release paths in ConfirmPublishOutcome and
|
|
2655
|
+
* EmitTraceEvents; those remain unchanged. Implicit paths are still the
|
|
2656
|
+
* default for adapters that report outcomes naturally; the explicit RPC
|
|
2657
|
+
* is for adapters that want to match the Agent Spend Protocol Draft-01
|
|
2658
|
+
* wire shape (docs/specs/agent-spend-protocol/draft-01.md §4).
|
|
2659
|
+
*
|
|
2660
|
+
* Idempotent: repeated ReleaseReservation calls with the same
|
|
2661
|
+
* (reservation_id, idempotency_key) pair return the original outcome.
|
|
2662
|
+
*
|
|
2663
|
+
* @generated from protobuf rpc: ReleaseReservation
|
|
2664
|
+
*/
|
|
2665
|
+
releaseReservation(input, options) {
|
|
2666
|
+
const method = this.methods[9], opt = this._transport.mergeOptions(options);
|
|
2667
|
+
return stackIntercept("unary", this._transport, method, opt, input);
|
|
2668
|
+
}
|
|
2669
|
+
// -- Session reservation (D41 voice substrate SR-V1) ---------------------
|
|
2670
|
+
/**
|
|
2671
|
+
* Reserve a session-scoped ledger hold before a realtime voice session
|
|
2672
|
+
* connects to paid model providers. Idempotent by
|
|
2673
|
+
* (tenant_id, session_id, route, idempotency_key).
|
|
2674
|
+
*
|
|
2675
|
+
* @generated from protobuf rpc: ReserveSession
|
|
2676
|
+
*/
|
|
2677
|
+
reserveSession(input, options) {
|
|
2678
|
+
const method = this.methods[10], opt = this._transport.mergeOptions(options);
|
|
2679
|
+
return stackIntercept("unary", this._transport, method, opt, input);
|
|
2680
|
+
}
|
|
2681
|
+
/**
|
|
2682
|
+
* Commit one positive streaming spend delta against an existing session
|
|
2683
|
+
* reservation. Idempotent by (session_reservation_id,
|
|
2684
|
+
* streaming_commit_id). amount_atomic_delta MUST be > 0.
|
|
2685
|
+
*
|
|
2686
|
+
* @generated from protobuf rpc: CommitSessionDelta
|
|
2687
|
+
*/
|
|
2688
|
+
commitSessionDelta(input, options) {
|
|
2689
|
+
const method = this.methods[11], opt = this._transport.mergeOptions(options);
|
|
2690
|
+
return stackIntercept("unary", this._transport, method, opt, input);
|
|
2691
|
+
}
|
|
2692
|
+
/**
|
|
2693
|
+
* Release the uncommitted remainder of a session-scoped reservation.
|
|
2694
|
+
* Idempotent by (session_reservation_id, idempotency_key).
|
|
2695
|
+
*
|
|
2696
|
+
* @generated from protobuf rpc: ReleaseSession
|
|
2697
|
+
*/
|
|
2698
|
+
releaseSession(input, options) {
|
|
2699
|
+
const method = this.methods[12], opt = this._transport.mergeOptions(options);
|
|
2700
|
+
return stackIntercept("unary", this._transport, method, opt, input);
|
|
2701
|
+
}
|
|
2702
|
+
};
|
|
2703
|
+
|
|
2704
|
+
// src/errors.ts
|
|
2705
|
+
var SpendGuardError = class extends Error {
|
|
2706
|
+
name = "SpendGuardError";
|
|
2707
|
+
constructor(message, opts) {
|
|
2708
|
+
super(message);
|
|
2709
|
+
if (opts?.cause !== void 0) {
|
|
2710
|
+
this.cause = opts.cause;
|
|
2711
|
+
}
|
|
2712
|
+
Object.defineProperty(this, "name", {
|
|
2713
|
+
value: this.name,
|
|
2714
|
+
enumerable: true,
|
|
2715
|
+
configurable: true,
|
|
2716
|
+
writable: true
|
|
2717
|
+
});
|
|
2718
|
+
}
|
|
2719
|
+
};
|
|
2720
|
+
var SpendGuardConfigError = class extends SpendGuardError {
|
|
2721
|
+
name = "SpendGuardConfigError";
|
|
2722
|
+
};
|
|
2723
|
+
var SidecarUnavailable = class extends SpendGuardError {
|
|
2724
|
+
name = "SidecarUnavailable";
|
|
2725
|
+
statusCode = 503;
|
|
2726
|
+
};
|
|
2727
|
+
var SpendGuardConnectionError = class extends SpendGuardError {
|
|
2728
|
+
name = "SpendGuardConnectionError";
|
|
2729
|
+
};
|
|
2730
|
+
var HandshakeError = class extends SpendGuardError {
|
|
2731
|
+
name = "HandshakeError";
|
|
2732
|
+
};
|
|
2733
|
+
var DecisionDenied = class extends SpendGuardError {
|
|
2734
|
+
name = "DecisionDenied";
|
|
2735
|
+
statusCode = 403;
|
|
2736
|
+
decisionId;
|
|
2737
|
+
reasonCodes;
|
|
2738
|
+
auditDecisionEventId;
|
|
2739
|
+
matchedRuleIds;
|
|
2740
|
+
constructor(message, init, opts) {
|
|
2741
|
+
super(message, opts);
|
|
2742
|
+
this.decisionId = init.decisionId;
|
|
2743
|
+
this.reasonCodes = init.reasonCodes ?? [];
|
|
2744
|
+
if (init.auditDecisionEventId !== void 0) {
|
|
2745
|
+
this.auditDecisionEventId = init.auditDecisionEventId;
|
|
2746
|
+
}
|
|
2747
|
+
this.matchedRuleIds = init.matchedRuleIds ?? [];
|
|
2748
|
+
}
|
|
2749
|
+
};
|
|
2750
|
+
var DecisionStopped = class extends DecisionDenied {
|
|
2751
|
+
name = "DecisionStopped";
|
|
2752
|
+
};
|
|
2753
|
+
var DecisionSkipped = class extends DecisionDenied {
|
|
2754
|
+
name = "DecisionSkipped";
|
|
2755
|
+
};
|
|
2756
|
+
var ApprovalRequired = class extends DecisionDenied {
|
|
2757
|
+
name = "ApprovalRequired";
|
|
2758
|
+
approvalRequestId;
|
|
2759
|
+
approverRole;
|
|
2760
|
+
tenantId;
|
|
2761
|
+
constructor(message, init, opts) {
|
|
2762
|
+
super(message, init, opts);
|
|
2763
|
+
this.approvalRequestId = init.approvalRequestId;
|
|
2764
|
+
if (init.approverRole !== void 0) {
|
|
2765
|
+
this.approverRole = init.approverRole;
|
|
2766
|
+
}
|
|
2767
|
+
if (init.tenantId !== void 0) {
|
|
2768
|
+
this.tenantId = init.tenantId;
|
|
2769
|
+
}
|
|
2770
|
+
}
|
|
2771
|
+
/**
|
|
2772
|
+
* Resume the decision after a human operator has acted. Delegates to
|
|
2773
|
+
* `client.resumeAfterApproval(...)`.
|
|
2774
|
+
*
|
|
2775
|
+
* @throws ApprovalDeniedError when the operator rejected.
|
|
2776
|
+
* @throws ApprovalLapsedError when the approval expired / was cancelled.
|
|
2777
|
+
* @throws ApprovalBundleHotReloadedError when bundle rotated mid-approval.
|
|
2778
|
+
*/
|
|
2779
|
+
async resume(client) {
|
|
2780
|
+
return client.resumeAfterApproval({
|
|
2781
|
+
approvalId: this.approvalRequestId,
|
|
2782
|
+
tenantId: this.tenantId ?? "",
|
|
2783
|
+
decisionId: this.decisionId
|
|
2784
|
+
});
|
|
2785
|
+
}
|
|
2786
|
+
};
|
|
2787
|
+
var ApprovalBundleHotReloadedError = class extends SpendGuardError {
|
|
2788
|
+
name = "ApprovalBundleHotReloadedError";
|
|
2789
|
+
originalBundleHash;
|
|
2790
|
+
currentBundleHash;
|
|
2791
|
+
constructor(message, init, opts) {
|
|
2792
|
+
super(message, opts);
|
|
2793
|
+
this.originalBundleHash = init.originalBundleHash;
|
|
2794
|
+
this.currentBundleHash = init.currentBundleHash;
|
|
2795
|
+
}
|
|
2796
|
+
};
|
|
2797
|
+
var MutationApplyFailed = class extends SpendGuardError {
|
|
2798
|
+
name = "MutationApplyFailed";
|
|
2799
|
+
};
|
|
2800
|
+
|
|
2801
|
+
// src/config.ts
|
|
2802
|
+
var DEFAULT_DECISION_TIMEOUT_MS = 250;
|
|
2803
|
+
var DEFAULT_HANDSHAKE_TIMEOUT_MS = 2e3;
|
|
2804
|
+
var DEFAULT_PUBLISH_TIMEOUT_MS = 150;
|
|
2805
|
+
var DEFAULT_TRACE_TIMEOUT_MS = 500;
|
|
2806
|
+
var DEFAULT_CAPABILITY_LEVEL = 64;
|
|
2807
|
+
var DEFAULT_PROTOCOL_VERSION = 1;
|
|
2808
|
+
function validateConfig(cfg) {
|
|
2809
|
+
if (cfg.socketPath.length === 0) {
|
|
2810
|
+
throw new SpendGuardConfigError(
|
|
2811
|
+
"socketPath is required (or set SPENDGUARD_SOCKET_PATH / SPENDGUARD_SIDECAR_UDS)"
|
|
2812
|
+
);
|
|
2813
|
+
}
|
|
2814
|
+
if (cfg.tenantId.length === 0) {
|
|
2815
|
+
throw new SpendGuardConfigError("tenantId is required (or set SPENDGUARD_TENANT_ID)");
|
|
2816
|
+
}
|
|
2817
|
+
if (cfg.otelTracer !== void 0 && cfg.onSpan !== void 0) {
|
|
2818
|
+
throw new SpendGuardConfigError("otelTracer and onSpan are mutually exclusive");
|
|
2819
|
+
}
|
|
2820
|
+
if (cfg.runtime !== "uds-grpc") {
|
|
2821
|
+
throw new SpendGuardConfigError(
|
|
2822
|
+
`runtime=${JSON.stringify(cfg.runtime)} is not supported in v0.1.x; only "uds-grpc" is wired`
|
|
2823
|
+
);
|
|
2824
|
+
}
|
|
2825
|
+
if (cfg.protocolVersion !== 1) {
|
|
2826
|
+
throw new SpendGuardConfigError(
|
|
2827
|
+
`protocolVersion=${cfg.protocolVersion} is not supported in v0.1.x; only 1 is wired`
|
|
2828
|
+
);
|
|
2829
|
+
}
|
|
2830
|
+
assertPositiveIntegerField(cfg.capabilityLevel, "capabilityLevel");
|
|
2831
|
+
assertPositiveIntegerField(cfg.decisionTimeoutMs, "decisionTimeoutMs");
|
|
2832
|
+
assertPositiveIntegerField(cfg.handshakeTimeoutMs, "handshakeTimeoutMs");
|
|
2833
|
+
assertPositiveIntegerField(cfg.publishTimeoutMs, "publishTimeoutMs");
|
|
2834
|
+
assertPositiveIntegerField(cfg.traceTimeoutMs, "traceTimeoutMs");
|
|
2835
|
+
}
|
|
2836
|
+
function assertPositiveIntegerField(value, field) {
|
|
2837
|
+
if (!Number.isFinite(value) || !Number.isInteger(value) || value < 0) {
|
|
2838
|
+
throw new SpendGuardConfigError(`${field}=${value} must be a finite non-negative integer`);
|
|
2839
|
+
}
|
|
2840
|
+
}
|
|
2841
|
+
|
|
2842
|
+
// src/env.ts
|
|
2843
|
+
var DEFAULT_SOCKET_PATH = "/var/run/spendguard/adapter.sock";
|
|
2844
|
+
function resolveEnvConfig(env = process.env) {
|
|
2845
|
+
const out = {};
|
|
2846
|
+
const socketPath = env.SPENDGUARD_SOCKET_PATH ?? env.SPENDGUARD_SIDECAR_UDS;
|
|
2847
|
+
if (socketPath !== void 0 && socketPath.length > 0) {
|
|
2848
|
+
out.socketPath = socketPath;
|
|
2849
|
+
}
|
|
2850
|
+
const tenantId = env.SPENDGUARD_TENANT_ID;
|
|
2851
|
+
if (tenantId !== void 0 && tenantId.length > 0) {
|
|
2852
|
+
out.tenantId = tenantId;
|
|
2853
|
+
}
|
|
2854
|
+
const workloadInstanceId = env.SPENDGUARD_WORKLOAD_INSTANCE_ID;
|
|
2855
|
+
if (workloadInstanceId !== void 0 && workloadInstanceId.length > 0) {
|
|
2856
|
+
out.workloadInstanceId = workloadInstanceId;
|
|
2857
|
+
}
|
|
2858
|
+
const decisionTimeoutMs = parsePositiveIntegerEnv(
|
|
2859
|
+
env.SPENDGUARD_DECISION_TIMEOUT_MS,
|
|
2860
|
+
"SPENDGUARD_DECISION_TIMEOUT_MS"
|
|
2861
|
+
);
|
|
2862
|
+
if (decisionTimeoutMs !== void 0) {
|
|
2863
|
+
out.decisionTimeoutMs = decisionTimeoutMs;
|
|
2864
|
+
}
|
|
2865
|
+
const handshakeTimeoutMs = parsePositiveIntegerEnv(
|
|
2866
|
+
env.SPENDGUARD_HANDSHAKE_TIMEOUT_MS,
|
|
2867
|
+
"SPENDGUARD_HANDSHAKE_TIMEOUT_MS"
|
|
2868
|
+
);
|
|
2869
|
+
if (handshakeTimeoutMs !== void 0) {
|
|
2870
|
+
out.handshakeTimeoutMs = handshakeTimeoutMs;
|
|
2871
|
+
}
|
|
2872
|
+
const runProjectionDefault = env.SPENDGUARD_RUN_PROJECTION_DEFAULT;
|
|
2873
|
+
if (runProjectionDefault !== void 0 && runProjectionDefault.length > 0) {
|
|
2874
|
+
out.runProjectionDefault = runProjectionDefault;
|
|
2875
|
+
}
|
|
2876
|
+
const profile = env.SPENDGUARD_PROFILE;
|
|
2877
|
+
if (profile !== void 0 && profile.length > 0) {
|
|
2878
|
+
out.profile = profile.toLowerCase();
|
|
2879
|
+
}
|
|
2880
|
+
const disabled = env.SPENDGUARD_DISABLE;
|
|
2881
|
+
if (disabled !== void 0) {
|
|
2882
|
+
const norm = disabled.toLowerCase();
|
|
2883
|
+
if (norm === "1" || norm === "true" || norm === "yes" || norm === "on") {
|
|
2884
|
+
out.disabled = true;
|
|
2885
|
+
}
|
|
2886
|
+
}
|
|
2887
|
+
return out;
|
|
2888
|
+
}
|
|
2889
|
+
function parsePositiveIntegerEnv(raw, name) {
|
|
2890
|
+
if (raw === void 0 || raw.length === 0) return void 0;
|
|
2891
|
+
const n = Number(raw);
|
|
2892
|
+
if (!Number.isFinite(n) || !Number.isInteger(n) || n < 0) {
|
|
2893
|
+
throw new EnvParseError(
|
|
2894
|
+
`env var ${name}=${JSON.stringify(raw)} is not a finite non-negative integer`,
|
|
2895
|
+
name
|
|
2896
|
+
);
|
|
2897
|
+
}
|
|
2898
|
+
return n;
|
|
2899
|
+
}
|
|
2900
|
+
var EnvParseError = class extends Error {
|
|
2901
|
+
name = "EnvParseError";
|
|
2902
|
+
varName;
|
|
2903
|
+
constructor(message, varName) {
|
|
2904
|
+
super(message);
|
|
2905
|
+
this.varName = varName;
|
|
2906
|
+
}
|
|
2907
|
+
};
|
|
2908
|
+
|
|
2909
|
+
// src/otel.ts
|
|
2910
|
+
var SPENDGUARD_OTEL_ATTR = {
|
|
2911
|
+
TENANT_ID: "spendguard.tenant_id",
|
|
2912
|
+
DECISION_ID: "spendguard.decision_id",
|
|
2913
|
+
TRIGGER: "spendguard.trigger",
|
|
2914
|
+
SDK_VERSION: "spendguard.sdk.version",
|
|
2915
|
+
RESERVATION_ID: "spendguard.reservation_id",
|
|
2916
|
+
SCOPE_ID: "spendguard.scope_id"
|
|
2917
|
+
};
|
|
2918
|
+
var SPAN_STATUS_ERROR = 2;
|
|
2919
|
+
async function withOtelSpan(tracer, rpcName, attributes, fn, onSpan) {
|
|
2920
|
+
if (tracer === void 0 && onSpan === void 0) return await fn();
|
|
2921
|
+
const spanName = `spendguard.${rpcName}`;
|
|
2922
|
+
const filtered = {};
|
|
2923
|
+
for (const [k, v] of Object.entries(attributes)) {
|
|
2924
|
+
if (v !== void 0) filtered[k] = v;
|
|
2925
|
+
}
|
|
2926
|
+
if (tracer === void 0) {
|
|
2927
|
+
const startTimeMs2 = Date.now();
|
|
2928
|
+
let error;
|
|
2929
|
+
try {
|
|
2930
|
+
return await fn();
|
|
2931
|
+
} catch (err) {
|
|
2932
|
+
error = err instanceof Error ? err : new Error(String(err));
|
|
2933
|
+
throw err;
|
|
2934
|
+
} finally {
|
|
2935
|
+
emitSpanRecord(onSpan, spanName, startTimeMs2, filtered, error);
|
|
2936
|
+
}
|
|
2937
|
+
}
|
|
2938
|
+
const startTimeMs = Date.now();
|
|
2939
|
+
let observerError;
|
|
2940
|
+
const span = tracer.startSpan(spanName, { attributes: filtered });
|
|
2941
|
+
try {
|
|
2942
|
+
const result = await fn();
|
|
2943
|
+
return result;
|
|
2944
|
+
} catch (err) {
|
|
2945
|
+
if (err instanceof Error) {
|
|
2946
|
+
observerError = err;
|
|
2947
|
+
span.recordException(err);
|
|
2948
|
+
span.setStatus({ code: SPAN_STATUS_ERROR, message: err.message });
|
|
2949
|
+
} else {
|
|
2950
|
+
const message = typeof err === "string" ? err : String(err);
|
|
2951
|
+
observerError = new Error(message);
|
|
2952
|
+
span.recordException({ name: "SpendGuardError", message });
|
|
2953
|
+
span.setStatus({ code: SPAN_STATUS_ERROR, message });
|
|
2954
|
+
}
|
|
2955
|
+
throw err;
|
|
2956
|
+
} finally {
|
|
2957
|
+
span.end();
|
|
2958
|
+
emitSpanRecord(onSpan, spanName, startTimeMs, filtered, observerError);
|
|
2959
|
+
}
|
|
2960
|
+
}
|
|
2961
|
+
function emitSpanRecord(onSpan, name, startTimeMs, filtered, error) {
|
|
2962
|
+
if (onSpan === void 0) return;
|
|
2963
|
+
const attributes = {};
|
|
2964
|
+
for (const [k, v] of Object.entries(filtered)) {
|
|
2965
|
+
if (typeof v === "string" || typeof v === "number" || typeof v === "boolean") {
|
|
2966
|
+
attributes[k] = v;
|
|
2967
|
+
}
|
|
2968
|
+
}
|
|
2969
|
+
const record = {
|
|
2970
|
+
name,
|
|
2971
|
+
startTimeMs,
|
|
2972
|
+
durationMs: Date.now() - startTimeMs,
|
|
2973
|
+
attributes,
|
|
2974
|
+
...error !== void 0 ? { error } : {}
|
|
2975
|
+
};
|
|
2976
|
+
try {
|
|
2977
|
+
onSpan(record);
|
|
2978
|
+
} catch {
|
|
2979
|
+
}
|
|
2980
|
+
}
|
|
2981
|
+
var ASCII_WHITESPACE = /* @__PURE__ */ new Set([" ", " ", "\n", "\f", "\r"]);
|
|
2982
|
+
var UUID_RE = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
|
2983
|
+
function canonicalizeTenant(tenantId) {
|
|
2984
|
+
if (UUID_RE.test(tenantId)) return tenantId.toLowerCase();
|
|
2985
|
+
return tenantId;
|
|
2986
|
+
}
|
|
2987
|
+
function stripAscii(s) {
|
|
2988
|
+
let i = 0;
|
|
2989
|
+
while (i < s.length && ASCII_WHITESPACE.has(s.charAt(i))) i++;
|
|
2990
|
+
let j = s.length;
|
|
2991
|
+
while (j > i && ASCII_WHITESPACE.has(s.charAt(j - 1))) j--;
|
|
2992
|
+
return s.slice(i, j);
|
|
2993
|
+
}
|
|
2994
|
+
function computePromptHash(promptText, tenantId) {
|
|
2995
|
+
const key = canonicalizeTenant(tenantId);
|
|
2996
|
+
const trimmed = stripAscii(promptText);
|
|
2997
|
+
return createHmac("sha256", key).update(trimmed, "utf8").digest("hex");
|
|
2998
|
+
}
|
|
2999
|
+
|
|
3000
|
+
// src/retry.ts
|
|
3001
|
+
var TRANSIENT_STATUS_CODES = /* @__PURE__ */ new Set([
|
|
3002
|
+
"UNAVAILABLE",
|
|
3003
|
+
"DEADLINE_EXCEEDED",
|
|
3004
|
+
"CANCELLED"
|
|
3005
|
+
]);
|
|
3006
|
+
function classifyRpcError(err) {
|
|
3007
|
+
if (err instanceof SidecarUnavailable) return "transient";
|
|
3008
|
+
if (err !== null && typeof err === "object" && "code" in err) {
|
|
3009
|
+
const code = err.code;
|
|
3010
|
+
if (typeof code === "string" && TRANSIENT_STATUS_CODES.has(code)) {
|
|
3011
|
+
return "transient";
|
|
3012
|
+
}
|
|
3013
|
+
}
|
|
3014
|
+
return "permanent";
|
|
3015
|
+
}
|
|
3016
|
+
async function runWithRetry(fn, opts = {}) {
|
|
3017
|
+
const idempotencyKey = opts.idempotencyKey;
|
|
3018
|
+
const maxAttempts = clampMaxAttempts(opts.maxAttempts ?? 2);
|
|
3019
|
+
const baseBackoffMs = opts.baseBackoffMs ?? 25;
|
|
3020
|
+
const jitterMs = opts.jitterMs ?? 25;
|
|
3021
|
+
const sleep = opts.sleep ?? defaultSleep;
|
|
3022
|
+
let lastErr;
|
|
3023
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
3024
|
+
try {
|
|
3025
|
+
return await fn();
|
|
3026
|
+
} catch (err) {
|
|
3027
|
+
const classification = classifyRpcError(err);
|
|
3028
|
+
if (classification === "permanent") {
|
|
3029
|
+
throw err;
|
|
3030
|
+
}
|
|
3031
|
+
if (idempotencyKey === void 0 || idempotencyKey.length === 0) {
|
|
3032
|
+
if (err instanceof SidecarUnavailable) {
|
|
3033
|
+
throw err;
|
|
3034
|
+
}
|
|
3035
|
+
throw new SidecarUnavailable(
|
|
3036
|
+
`transient RPC failure with no idempotency key; refusing to retry: ${errorMessage(err)}`,
|
|
3037
|
+
{ cause: err }
|
|
3038
|
+
);
|
|
3039
|
+
}
|
|
3040
|
+
lastErr = err;
|
|
3041
|
+
if (attempt < maxAttempts) {
|
|
3042
|
+
const delay = baseBackoffMs + Math.floor(Math.random() * (jitterMs + 1));
|
|
3043
|
+
await sleep(delay);
|
|
3044
|
+
continue;
|
|
3045
|
+
}
|
|
3046
|
+
throw err;
|
|
3047
|
+
}
|
|
3048
|
+
}
|
|
3049
|
+
throw lastErr ?? new SpendGuardError("runWithRetry: unreachable");
|
|
3050
|
+
}
|
|
3051
|
+
function clampMaxAttempts(value) {
|
|
3052
|
+
if (!Number.isFinite(value) || !Number.isInteger(value)) return 2;
|
|
3053
|
+
if (value < 1) return 1;
|
|
3054
|
+
if (value > 5) return 5;
|
|
3055
|
+
return value;
|
|
3056
|
+
}
|
|
3057
|
+
function defaultSleep(ms) {
|
|
3058
|
+
return new Promise((resolve) => {
|
|
3059
|
+
setTimeout(resolve, ms);
|
|
3060
|
+
});
|
|
3061
|
+
}
|
|
3062
|
+
function errorMessage(err) {
|
|
3063
|
+
if (err instanceof Error) return err.message;
|
|
3064
|
+
if (typeof err === "string") return err;
|
|
3065
|
+
return String(err);
|
|
3066
|
+
}
|
|
3067
|
+
var storage = new AsyncLocalStorage();
|
|
3068
|
+
function currentRunPlan() {
|
|
3069
|
+
return storage.getStore() ?? null;
|
|
3070
|
+
}
|
|
3071
|
+
|
|
3072
|
+
// src/session.ts
|
|
3073
|
+
function buildReserveSessionRequest(req) {
|
|
3074
|
+
assertPositiveDecimal(req.estimatedAmountAtomic, "estimatedAmountAtomic");
|
|
3075
|
+
assertPositiveInteger(req.ttlSeconds, "ttlSeconds");
|
|
3076
|
+
return {
|
|
3077
|
+
tenantId: req.tenantId,
|
|
3078
|
+
budgetId: req.budgetId,
|
|
3079
|
+
windowInstanceId: req.windowInstanceId,
|
|
3080
|
+
unit: mapUnitRef(req.unit),
|
|
3081
|
+
pricing: {
|
|
3082
|
+
pricingVersion: req.pricing.pricingVersion,
|
|
3083
|
+
priceSnapshotHash: req.pricing.pricingHash,
|
|
3084
|
+
fxRateVersion: req.pricing.fxRateVersion ?? "",
|
|
3085
|
+
unitConversionVersion: req.pricing.unitConversionVersion ?? ""
|
|
3086
|
+
},
|
|
3087
|
+
sessionId: req.sessionId,
|
|
3088
|
+
route: req.route,
|
|
3089
|
+
estimatedAmountAtomic: req.estimatedAmountAtomic,
|
|
3090
|
+
ttlSeconds: req.ttlSeconds,
|
|
3091
|
+
idempotencyKey: req.idempotencyKey
|
|
3092
|
+
};
|
|
3093
|
+
}
|
|
3094
|
+
function buildCommitSessionDeltaRequest(req) {
|
|
3095
|
+
assertPositiveDecimal(req.amountAtomicDelta, "amountAtomicDelta");
|
|
3096
|
+
return {
|
|
3097
|
+
sessionReservationId: req.sessionReservationId,
|
|
3098
|
+
streamingCommitId: req.streamingCommitId,
|
|
3099
|
+
amountAtomicDelta: req.amountAtomicDelta,
|
|
3100
|
+
outcome: commitOutcomeEnumOf(req.outcome),
|
|
3101
|
+
eventTime: toTimestamp(req.eventTime),
|
|
3102
|
+
idempotencyKey: req.idempotencyKey
|
|
3103
|
+
};
|
|
3104
|
+
}
|
|
3105
|
+
function buildReleaseSessionRequest(req) {
|
|
3106
|
+
return {
|
|
3107
|
+
sessionReservationId: req.sessionReservationId,
|
|
3108
|
+
reasonCode: req.reasonCode,
|
|
3109
|
+
eventTime: toTimestamp(req.eventTime),
|
|
3110
|
+
idempotencyKey: req.idempotencyKey
|
|
3111
|
+
};
|
|
3112
|
+
}
|
|
3113
|
+
function mapUnitRef(unit) {
|
|
3114
|
+
return {
|
|
3115
|
+
unitId: unit.unitId ?? "",
|
|
3116
|
+
kind: 0,
|
|
3117
|
+
currency: "",
|
|
3118
|
+
unitName: unit.unit,
|
|
3119
|
+
tokenKind: "",
|
|
3120
|
+
modelFamily: "",
|
|
3121
|
+
creditProgram: ""
|
|
3122
|
+
};
|
|
3123
|
+
}
|
|
3124
|
+
function commitOutcomeEnumOf(outcome) {
|
|
3125
|
+
switch (outcome) {
|
|
3126
|
+
case "SUCCESS":
|
|
3127
|
+
return 1 /* SUCCESS */;
|
|
3128
|
+
case "PROVIDER_ERROR":
|
|
3129
|
+
return 2 /* PROVIDER_ERROR */;
|
|
3130
|
+
case "CLIENT_TIMEOUT":
|
|
3131
|
+
return 3 /* CLIENT_TIMEOUT */;
|
|
3132
|
+
case "RUN_ABORTED":
|
|
3133
|
+
return 4 /* RUN_ABORTED */;
|
|
3134
|
+
}
|
|
3135
|
+
}
|
|
3136
|
+
function assertPositiveDecimal(value, field) {
|
|
3137
|
+
if (!/^[0-9]+$/.test(value)) {
|
|
3138
|
+
throw new RangeError(`${field} must be a positive decimal string`);
|
|
3139
|
+
}
|
|
3140
|
+
if (BigInt(value) <= 0n) {
|
|
3141
|
+
throw new RangeError(`${field} must be greater than zero`);
|
|
3142
|
+
}
|
|
3143
|
+
}
|
|
3144
|
+
function assertPositiveInteger(value, field) {
|
|
3145
|
+
if (!Number.isInteger(value) || value <= 0) {
|
|
3146
|
+
throw new RangeError(`${field} must be a positive integer`);
|
|
3147
|
+
}
|
|
3148
|
+
}
|
|
3149
|
+
function toTimestamp(value) {
|
|
3150
|
+
if (value instanceof Date) return epochMsToTimestamp(value.getTime());
|
|
3151
|
+
if (typeof value === "number") return epochMsToTimestamp(value);
|
|
3152
|
+
return value;
|
|
3153
|
+
}
|
|
3154
|
+
function epochMsToTimestamp(epochMs) {
|
|
3155
|
+
if (!Number.isFinite(epochMs)) {
|
|
3156
|
+
throw new RangeError("eventTime must be finite");
|
|
3157
|
+
}
|
|
3158
|
+
const seconds = Math.floor(epochMs / 1e3);
|
|
3159
|
+
const nanos = (epochMs - seconds * 1e3) * 1e6;
|
|
3160
|
+
return { seconds: seconds.toString(), nanos };
|
|
3161
|
+
}
|
|
3162
|
+
function timestampToDate(value) {
|
|
3163
|
+
if (value === void 0) return null;
|
|
3164
|
+
const seconds = typeof value.seconds === "bigint" ? Number(value.seconds) : Number.parseInt(value.seconds, 10);
|
|
3165
|
+
if (!Number.isFinite(seconds)) return null;
|
|
3166
|
+
return new Date(seconds * 1e3 + Math.floor(value.nanos / 1e6));
|
|
3167
|
+
}
|
|
3168
|
+
|
|
3169
|
+
// src/version.ts
|
|
3170
|
+
var VERSION = "0.5.0";
|
|
3171
|
+
|
|
3172
|
+
// src/client.ts
|
|
3173
|
+
var SLICE_7_NOT_WIRED = "not yet wired \u2014 SLICE 7 (see docs/internal/slices/COV_S05_05_d05_release_query.md anti-scope)";
|
|
3174
|
+
var QUERY_BUDGET_NOT_YET_WIRED = "query_budget not yet wired in sidecar; tracked at https://github.com/m24927605/agentic-spendguard/issues/TBD-queryBudget";
|
|
3175
|
+
function resolveDisabled(explicitDisabled, envSnapshot) {
|
|
3176
|
+
if (explicitDisabled === true) {
|
|
3177
|
+
emitDisabledWarning(
|
|
3178
|
+
"SpendGuard ENFORCEMENT DISABLED via the explicit `disabled: true` option \u2014 all decisions return CONTINUE with no reservation and no audit record. This is for tests only and must never be set in production."
|
|
3179
|
+
);
|
|
3180
|
+
return true;
|
|
3181
|
+
}
|
|
3182
|
+
if (envSnapshot.disabled === true) {
|
|
3183
|
+
if (envSnapshot.profile === "demo") {
|
|
3184
|
+
emitDisabledWarning(
|
|
3185
|
+
"SpendGuard ENFORCEMENT DISABLED via SPENDGUARD_DISABLE under SPENDGUARD_PROFILE=demo \u2014 all decisions return CONTINUE with no reservation and no audit record. Never set this in production."
|
|
3186
|
+
);
|
|
3187
|
+
return true;
|
|
3188
|
+
}
|
|
3189
|
+
emitDisabledWarning(
|
|
3190
|
+
`SPENDGUARD_DISABLE is set but SPENDGUARD_PROFILE is not 'demo' (got ${JSON.stringify(envSnapshot.profile ?? "")}); IGNORING the disable request and keeping enforcement ON. To intentionally disable enforcement (tests/demos only) set SPENDGUARD_PROFILE=demo or pass \`disabled: true\` explicitly.`
|
|
3191
|
+
);
|
|
3192
|
+
return false;
|
|
3193
|
+
}
|
|
3194
|
+
return false;
|
|
3195
|
+
}
|
|
3196
|
+
function emitDisabledWarning(message) {
|
|
3197
|
+
const proc = globalThis.process;
|
|
3198
|
+
if (proc?.emitWarning !== void 0) {
|
|
3199
|
+
proc.emitWarning(message, "SpendGuardEnforcementWarning");
|
|
3200
|
+
}
|
|
3201
|
+
}
|
|
3202
|
+
var SpendGuardClient = class _SpendGuardClient {
|
|
3203
|
+
/** Frozen, merged + validated configuration. */
|
|
3204
|
+
cfg;
|
|
3205
|
+
/** Active gRPC transport, or `null` before `connect()` / after `close()`. */
|
|
3206
|
+
transport = null;
|
|
3207
|
+
/** Active SidecarAdapter gRPC client; mirrors `transport` lifetime. */
|
|
3208
|
+
adapterClient = null;
|
|
3209
|
+
/** Cached handshake outcome; first `handshake()` populates, subsequent reads reuse. */
|
|
3210
|
+
handshakeResult = null;
|
|
3211
|
+
/**
|
|
3212
|
+
* Coalesces concurrent `handshake()` callers into a single in-flight RPC.
|
|
3213
|
+
* Mirrors Python `self._handshake_lock` in `client.py`. Stays non-null only
|
|
3214
|
+
* while a handshake RPC is pending; cleared after success or failure so a
|
|
3215
|
+
* post-failure retry can re-enter.
|
|
3216
|
+
*/
|
|
3217
|
+
handshakeInFlight = null;
|
|
3218
|
+
/**
|
|
3219
|
+
* Construct a client. Per design.md §5.2: explicit options win over env
|
|
3220
|
+
* fallback; required fields without either throw `SpendGuardConfigError`
|
|
3221
|
+
* immediately.
|
|
3222
|
+
*/
|
|
3223
|
+
constructor(rawOpts = {}) {
|
|
3224
|
+
let envSnapshot;
|
|
3225
|
+
try {
|
|
3226
|
+
envSnapshot = resolveEnvConfig();
|
|
3227
|
+
} catch (err) {
|
|
3228
|
+
if (err instanceof EnvParseError) {
|
|
3229
|
+
throw new SpendGuardConfigError(err.message);
|
|
3230
|
+
}
|
|
3231
|
+
throw err;
|
|
3232
|
+
}
|
|
3233
|
+
const socketPath = rawOpts.socketPath ?? envSnapshot.socketPath ?? "";
|
|
3234
|
+
const tenantId = rawOpts.tenantId ?? envSnapshot.tenantId ?? "";
|
|
3235
|
+
const disabled = resolveDisabled(rawOpts.disabled, envSnapshot);
|
|
3236
|
+
const cfg = {
|
|
3237
|
+
socketPath,
|
|
3238
|
+
tenantId,
|
|
3239
|
+
runtimeKind: rawOpts.runtimeKind ?? "",
|
|
3240
|
+
runtimeVersion: rawOpts.runtimeVersion ?? "",
|
|
3241
|
+
sdkVersion: rawOpts.sdkVersion ?? VERSION,
|
|
3242
|
+
protocolVersion: rawOpts.protocolVersion ?? DEFAULT_PROTOCOL_VERSION,
|
|
3243
|
+
capabilityLevel: rawOpts.capabilityLevel ?? DEFAULT_CAPABILITY_LEVEL,
|
|
3244
|
+
workloadInstanceId: rawOpts.workloadInstanceId ?? envSnapshot.workloadInstanceId ?? "",
|
|
3245
|
+
decisionTimeoutMs: rawOpts.decisionTimeoutMs ?? envSnapshot.decisionTimeoutMs ?? DEFAULT_DECISION_TIMEOUT_MS,
|
|
3246
|
+
handshakeTimeoutMs: rawOpts.handshakeTimeoutMs ?? envSnapshot.handshakeTimeoutMs ?? DEFAULT_HANDSHAKE_TIMEOUT_MS,
|
|
3247
|
+
publishTimeoutMs: rawOpts.publishTimeoutMs ?? DEFAULT_PUBLISH_TIMEOUT_MS,
|
|
3248
|
+
traceTimeoutMs: rawOpts.traceTimeoutMs ?? DEFAULT_TRACE_TIMEOUT_MS,
|
|
3249
|
+
runtime: rawOpts.runtime ?? "uds-grpc",
|
|
3250
|
+
disabled,
|
|
3251
|
+
runProjectionDefault: rawOpts.runProjectionDefault ?? envSnapshot.runProjectionDefault ?? ""
|
|
3252
|
+
};
|
|
3253
|
+
if (rawOpts.onSpan !== void 0) {
|
|
3254
|
+
cfg.onSpan = rawOpts.onSpan;
|
|
3255
|
+
}
|
|
3256
|
+
if (rawOpts.otelTracer !== void 0) {
|
|
3257
|
+
cfg.otelTracer = rawOpts.otelTracer;
|
|
3258
|
+
}
|
|
3259
|
+
if (rawOpts.idempotencyCache !== void 0) {
|
|
3260
|
+
cfg.idempotencyCache = rawOpts.idempotencyCache;
|
|
3261
|
+
}
|
|
3262
|
+
validateConfig(cfg);
|
|
3263
|
+
this.cfg = Object.freeze(cfg);
|
|
3264
|
+
}
|
|
3265
|
+
/**
|
|
3266
|
+
* Wrap an RPC body in the configured observability hook(s). Threads BOTH
|
|
3267
|
+
* `cfg.otelTracer` and `cfg.onSpan` into `withOtelSpan` so every RPC site
|
|
3268
|
+
* gets span emission uniformly — the documented `onSpan` observer (the
|
|
3269
|
+
* no-OTel-dep path) is invoked once per RPC, fixing the prior drift where
|
|
3270
|
+
* `onSpan` was stored but never called. The two are mutually exclusive at
|
|
3271
|
+
* config-validation time, so at most one fires.
|
|
3272
|
+
*/
|
|
3273
|
+
withSpan(rpcName, attributes, fn) {
|
|
3274
|
+
return withOtelSpan(this.cfg.otelTracer, rpcName, attributes, fn, this.cfg.onSpan);
|
|
3275
|
+
}
|
|
3276
|
+
/**
|
|
3277
|
+
* Convenience factory that reads required config from env vars and falls
|
|
3278
|
+
* back to `/var/run/spendguard/adapter.sock` when `SPENDGUARD_SOCKET_PATH`
|
|
3279
|
+
* is unset.
|
|
3280
|
+
*
|
|
3281
|
+
* Env vars consumed:
|
|
3282
|
+
* - `SPENDGUARD_SOCKET_PATH` (slice-doc alias) / `SPENDGUARD_SIDECAR_UDS`
|
|
3283
|
+
* (design §5.1) — UDS path; defaults to `/var/run/spendguard/adapter.sock`.
|
|
3284
|
+
* - `SPENDGUARD_TENANT_ID` — **required**; throws `SpendGuardConfigError`
|
|
3285
|
+
* when unset.
|
|
3286
|
+
* - `SPENDGUARD_RUN_PROJECTION_DEFAULT` — optional default
|
|
3287
|
+
* `run_projection` policy name; SLICE 4 wires consumption.
|
|
3288
|
+
* - `SPENDGUARD_WORKLOAD_INSTANCE_ID` / `SPENDGUARD_DECISION_TIMEOUT_MS`
|
|
3289
|
+
* / `SPENDGUARD_HANDSHAKE_TIMEOUT_MS` / `SPENDGUARD_DISABLE` — optional
|
|
3290
|
+
* per design §5.1.
|
|
3291
|
+
*
|
|
3292
|
+
* Extra options provided as the `overrides` argument win over env per
|
|
3293
|
+
* design.md §5.2.
|
|
3294
|
+
*
|
|
3295
|
+
* @throws SpendGuardConfigError when `SPENDGUARD_TENANT_ID` is missing.
|
|
3296
|
+
*/
|
|
3297
|
+
static fromEnv(overrides = {}) {
|
|
3298
|
+
let envSnapshot;
|
|
3299
|
+
try {
|
|
3300
|
+
envSnapshot = resolveEnvConfig();
|
|
3301
|
+
} catch (err) {
|
|
3302
|
+
if (err instanceof EnvParseError) {
|
|
3303
|
+
throw new SpendGuardConfigError(err.message);
|
|
3304
|
+
}
|
|
3305
|
+
throw err;
|
|
3306
|
+
}
|
|
3307
|
+
const resolvedTenant = overrides.tenantId ?? envSnapshot.tenantId;
|
|
3308
|
+
const merged = {
|
|
3309
|
+
socketPath: overrides.socketPath ?? envSnapshot.socketPath ?? DEFAULT_SOCKET_PATH,
|
|
3310
|
+
...resolvedTenant !== void 0 ? { tenantId: resolvedTenant } : {},
|
|
3311
|
+
...envSnapshot.workloadInstanceId !== void 0 ? { workloadInstanceId: envSnapshot.workloadInstanceId } : {},
|
|
3312
|
+
...envSnapshot.runProjectionDefault !== void 0 ? { runProjectionDefault: envSnapshot.runProjectionDefault } : {},
|
|
3313
|
+
...envSnapshot.decisionTimeoutMs !== void 0 ? { decisionTimeoutMs: envSnapshot.decisionTimeoutMs } : {},
|
|
3314
|
+
...envSnapshot.handshakeTimeoutMs !== void 0 ? { handshakeTimeoutMs: envSnapshot.handshakeTimeoutMs } : {},
|
|
3315
|
+
// NOTE: we deliberately do NOT promote `envSnapshot.disabled` into an
|
|
3316
|
+
// explicit `disabled: true` option here. Doing so would bypass the
|
|
3317
|
+
// fail-closed profile gate in `resolveDisabled` (an explicit option is
|
|
3318
|
+
// honored unconditionally). The constructor re-reads the env itself and
|
|
3319
|
+
// applies the `SPENDGUARD_PROFILE=demo` gate to the env-var disable
|
|
3320
|
+
// path. An explicit `overrides.disabled` (deliberate code-level opt-in)
|
|
3321
|
+
// still wins via the spread below.
|
|
3322
|
+
...overrides
|
|
3323
|
+
};
|
|
3324
|
+
return new _SpendGuardClient(merged);
|
|
3325
|
+
}
|
|
3326
|
+
// ── Lifecycle ────────────────────────────────────────────────────────────
|
|
3327
|
+
/**
|
|
3328
|
+
* Open the UDS gRPC channel. Idempotent — a second call when already
|
|
3329
|
+
* connected is a no-op.
|
|
3330
|
+
*
|
|
3331
|
+
* Per design.md §6.3 / Python `client.py:240-251`, the `unix:` URI scheme
|
|
3332
|
+
* is used and `grpc.default_authority=localhost` is set so the tonic-based
|
|
3333
|
+
* sidecar accepts the HTTP/2 `:authority` pseudo-header. Without this
|
|
3334
|
+
* channel option, tonic resets every stream with `PROTOCOL_ERROR`.
|
|
3335
|
+
*
|
|
3336
|
+
* In disabled mode (`SPENDGUARD_DISABLE=1` or `disabled: true`), no
|
|
3337
|
+
* transport is opened — the call returns immediately. Subsequent RPCs
|
|
3338
|
+
* short-circuit to no-op outcomes in SLICE 4.
|
|
3339
|
+
*
|
|
3340
|
+
* @throws SpendGuardConnectionError when the underlying transport could
|
|
3341
|
+
* not be opened (e.g. malformed socket path).
|
|
3342
|
+
*/
|
|
3343
|
+
async connect() {
|
|
3344
|
+
if (this.cfg.disabled) return;
|
|
3345
|
+
if (this.transport !== null) return;
|
|
3346
|
+
const target = `unix:${this.cfg.socketPath}`;
|
|
3347
|
+
try {
|
|
3348
|
+
this.transport = new GrpcTransport({
|
|
3349
|
+
host: target,
|
|
3350
|
+
channelCredentials: this.buildChannelCredentials(),
|
|
3351
|
+
clientOptions: {
|
|
3352
|
+
// tonic-compat: see design §6.3 + Python `client.py:240-251`.
|
|
3353
|
+
"grpc.default_authority": "localhost",
|
|
3354
|
+
// v1 message ceiling per review-standards §6.3 (≥ 4 MiB).
|
|
3355
|
+
"grpc.max_receive_message_length": 4 * 1024 * 1024,
|
|
3356
|
+
"grpc.max_send_message_length": 4 * 1024 * 1024
|
|
3357
|
+
}
|
|
3358
|
+
});
|
|
3359
|
+
this.adapterClient = new SidecarAdapterClient(this.transport);
|
|
3360
|
+
} catch (err) {
|
|
3361
|
+
this.transport = null;
|
|
3362
|
+
this.adapterClient = null;
|
|
3363
|
+
throw new SpendGuardConnectionError(
|
|
3364
|
+
`failed to open UDS transport to ${target}: ${errorMessage2(err)}`,
|
|
3365
|
+
{ cause: err }
|
|
3366
|
+
);
|
|
3367
|
+
}
|
|
3368
|
+
}
|
|
3369
|
+
/**
|
|
3370
|
+
* Graceful close. Idempotent — calling `close()` twice (or `close()` before
|
|
3371
|
+
* `connect()`) does not throw.
|
|
3372
|
+
*
|
|
3373
|
+
* On success the transport is dropped; the next `connect()` allocates a new
|
|
3374
|
+
* channel. In-flight RPCs may complete with a `CANCELLED` status; SLICE 8
|
|
3375
|
+
* adds the grace-period drain semantics that mirror the Python SDK's
|
|
3376
|
+
* `await ch.close(grace=0.5)` path.
|
|
3377
|
+
*/
|
|
3378
|
+
async close() {
|
|
3379
|
+
const t = this.transport;
|
|
3380
|
+
this.transport = null;
|
|
3381
|
+
this.adapterClient = null;
|
|
3382
|
+
if (t === null) return;
|
|
3383
|
+
try {
|
|
3384
|
+
t.close();
|
|
3385
|
+
} catch {
|
|
3386
|
+
}
|
|
3387
|
+
}
|
|
3388
|
+
/**
|
|
3389
|
+
* ESM 2024 `await using` hook. Equivalent to `await this.close()`.
|
|
3390
|
+
*
|
|
3391
|
+
* Usage:
|
|
3392
|
+
*
|
|
3393
|
+
* await using client = new SpendGuardClient({ ... });
|
|
3394
|
+
* // ... use client ...
|
|
3395
|
+
* // [Symbol.asyncDispose] runs here automatically.
|
|
3396
|
+
*/
|
|
3397
|
+
async [Symbol.asyncDispose]() {
|
|
3398
|
+
await this.close();
|
|
3399
|
+
}
|
|
3400
|
+
// ── Read-only state ──────────────────────────────────────────────────────
|
|
3401
|
+
/** The tenant id this client asserted at construction. Stable for the client's lifetime. */
|
|
3402
|
+
get tenantId() {
|
|
3403
|
+
return this.cfg.tenantId;
|
|
3404
|
+
}
|
|
3405
|
+
/**
|
|
3406
|
+
* The negotiated session id. Throws `HandshakeError` until `handshake()`
|
|
3407
|
+
* has completed (SLICE 4 wires the handshake; until then the getter is
|
|
3408
|
+
* effectively unusable, which is intentional — adapters should call
|
|
3409
|
+
* `handshake()` before reading state).
|
|
3410
|
+
*
|
|
3411
|
+
* @throws HandshakeError before `handshake()` completes.
|
|
3412
|
+
*/
|
|
3413
|
+
get sessionId() {
|
|
3414
|
+
if (this.handshakeResult === null) {
|
|
3415
|
+
throw new HandshakeError("handshake() has not completed; sessionId is not yet known");
|
|
3416
|
+
}
|
|
3417
|
+
return this.handshakeResult.sessionId;
|
|
3418
|
+
}
|
|
3419
|
+
/** Full handshake outcome. Throws `HandshakeError` until `handshake()` completes. */
|
|
3420
|
+
get handshakeOutcome() {
|
|
3421
|
+
if (this.handshakeResult === null) {
|
|
3422
|
+
throw new HandshakeError("handshake() has not completed");
|
|
3423
|
+
}
|
|
3424
|
+
return this.handshakeResult;
|
|
3425
|
+
}
|
|
3426
|
+
/** Whether the client is currently connected to the sidecar. */
|
|
3427
|
+
get isConnected() {
|
|
3428
|
+
return this.transport !== null;
|
|
3429
|
+
}
|
|
3430
|
+
/** Frozen view of the resolved configuration. Useful for tests + debugging. */
|
|
3431
|
+
get config() {
|
|
3432
|
+
return this.cfg;
|
|
3433
|
+
}
|
|
3434
|
+
// ── Handshake (design.md §4.5 lifecycle) ────────────────────────────────
|
|
3435
|
+
/**
|
|
3436
|
+
* Mandatory initial handshake. Idempotent — a second call returns the cached
|
|
3437
|
+
* outcome without re-issuing the RPC (design.md §4.5). Concurrent callers
|
|
3438
|
+
* are coalesced into the same in-flight RPC via `handshakeInFlight`.
|
|
3439
|
+
*
|
|
3440
|
+
* Disabled mode (`SPENDGUARD_DISABLE=1` / `disabled: true`) short-circuits
|
|
3441
|
+
* to a synthetic `HandshakeOutcome` so unit tests can run without a real
|
|
3442
|
+
* sidecar (`makeDisabledHandshake`).
|
|
3443
|
+
*
|
|
3444
|
+
* @throws HandshakeError on protocol-version mismatch or insufficient
|
|
3445
|
+
* capability advertisement.
|
|
3446
|
+
* @throws SidecarUnavailable on UNAVAILABLE / DEADLINE_EXCEEDED / CANCELLED.
|
|
3447
|
+
* @throws SpendGuardError on any other gRPC failure surface.
|
|
3448
|
+
*/
|
|
3449
|
+
async handshake(opts = {}) {
|
|
3450
|
+
if (this.cfg.disabled) {
|
|
3451
|
+
if (this.handshakeResult === null) {
|
|
3452
|
+
this.handshakeResult = makeDisabledHandshake();
|
|
3453
|
+
}
|
|
3454
|
+
return this.handshakeResult;
|
|
3455
|
+
}
|
|
3456
|
+
if (this.handshakeResult !== null) return this.handshakeResult;
|
|
3457
|
+
if (this.handshakeInFlight !== null) return this.handshakeInFlight;
|
|
3458
|
+
const promise = this.doHandshake(opts).finally(() => {
|
|
3459
|
+
this.handshakeInFlight = null;
|
|
3460
|
+
});
|
|
3461
|
+
this.handshakeInFlight = promise;
|
|
3462
|
+
return promise;
|
|
3463
|
+
}
|
|
3464
|
+
/**
|
|
3465
|
+
* Internal: issue the real Handshake RPC and map the response.
|
|
3466
|
+
*
|
|
3467
|
+
* Splits out from `handshake()` so the idempotency guard there stays
|
|
3468
|
+
* obviously correct: `doHandshake` never reads `handshakeResult` itself;
|
|
3469
|
+
* it only writes it on success.
|
|
3470
|
+
*/
|
|
3471
|
+
async doHandshake(opts) {
|
|
3472
|
+
if (this.adapterClient === null) {
|
|
3473
|
+
await this.connect();
|
|
3474
|
+
}
|
|
3475
|
+
const adapter = this.adapterClient;
|
|
3476
|
+
if (adapter === null) {
|
|
3477
|
+
throw new SidecarUnavailable("transport not established for handshake");
|
|
3478
|
+
}
|
|
3479
|
+
const workloadInstanceId = opts.workloadInstanceId ?? this.cfg.workloadInstanceId ?? "";
|
|
3480
|
+
const req = {
|
|
3481
|
+
sdkVersion: this.cfg.sdkVersion,
|
|
3482
|
+
runtimeKind: this.cfg.runtimeKind,
|
|
3483
|
+
runtimeVersion: this.cfg.runtimeVersion,
|
|
3484
|
+
// Wire-level enum uses the same numeric value as cfg.capabilityLevel
|
|
3485
|
+
// (DEFAULT_CAPABILITY_LEVEL = 0x40 = L3_POLICY_HOOK = 64).
|
|
3486
|
+
capabilityLevel: this.cfg.capabilityLevel,
|
|
3487
|
+
tenantIdAssertion: this.cfg.tenantId,
|
|
3488
|
+
workloadInstanceId,
|
|
3489
|
+
protocolVersion: this.cfg.protocolVersion
|
|
3490
|
+
};
|
|
3491
|
+
const resp = await this.withSpan(
|
|
3492
|
+
"handshake",
|
|
3493
|
+
{
|
|
3494
|
+
[SPENDGUARD_OTEL_ATTR.TENANT_ID]: this.cfg.tenantId,
|
|
3495
|
+
[SPENDGUARD_OTEL_ATTR.SDK_VERSION]: this.cfg.sdkVersion
|
|
3496
|
+
},
|
|
3497
|
+
async () => {
|
|
3498
|
+
try {
|
|
3499
|
+
return await adapter.handshake(req, {
|
|
3500
|
+
timeout: this.cfg.handshakeTimeoutMs
|
|
3501
|
+
}).response;
|
|
3502
|
+
} catch (err) {
|
|
3503
|
+
throw mapGrpcStatusToError(err, { rpc: "handshake" });
|
|
3504
|
+
}
|
|
3505
|
+
}
|
|
3506
|
+
);
|
|
3507
|
+
if (resp.protocolVersion !== this.cfg.protocolVersion) {
|
|
3508
|
+
throw new HandshakeError(
|
|
3509
|
+
`protocol version mismatch: adapter=${this.cfg.protocolVersion} sidecar=${resp.protocolVersion}`
|
|
3510
|
+
);
|
|
3511
|
+
}
|
|
3512
|
+
const outcome = {
|
|
3513
|
+
sessionId: resp.sessionId,
|
|
3514
|
+
sidecarVersion: resp.sidecarVersion,
|
|
3515
|
+
schemaBundleId: resp.schemaBundle?.schemaBundleId ?? "",
|
|
3516
|
+
schemaBundleHash: resp.schemaBundle?.schemaBundleHash ?? new Uint8Array(),
|
|
3517
|
+
contractBundleId: resp.contractBundle?.bundleId ?? "",
|
|
3518
|
+
contractBundleHash: resp.contractBundle?.bundleHash ?? new Uint8Array(),
|
|
3519
|
+
capabilityRequired: Number(resp.capabilityRequired ?? 0),
|
|
3520
|
+
signingKeyId: resp.signingKeyId,
|
|
3521
|
+
announcementSignature: resp.announcementSignature ?? new Uint8Array()
|
|
3522
|
+
};
|
|
3523
|
+
if (outcome.capabilityRequired > this.cfg.capabilityLevel) {
|
|
3524
|
+
throw new HandshakeError(
|
|
3525
|
+
`sidecar requires capability ${toHex(outcome.capabilityRequired)} but adapter advertised ${toHex(this.cfg.capabilityLevel)}; refusing`
|
|
3526
|
+
);
|
|
3527
|
+
}
|
|
3528
|
+
this.handshakeResult = outcome;
|
|
3529
|
+
return outcome;
|
|
3530
|
+
}
|
|
3531
|
+
// ── Core RPC surface (handshake / reserve / commitEstimated wired) ───────
|
|
3532
|
+
/**
|
|
3533
|
+
* Run a `*.pre` decision boundary through the sidecar. Equivalent to the
|
|
3534
|
+
* Python SDK's `request_decision` (design.md §4.7).
|
|
3535
|
+
*
|
|
3536
|
+
* The wire shape is built in `buildDecisionRequest()` and consumes:
|
|
3537
|
+
* - the cached handshake `sessionId` (auto-handshakes on first use),
|
|
3538
|
+
* - the caller-supplied `idempotencyKey` (REQUIRED — see design §6.5),
|
|
3539
|
+
* - `runProjectionDefault` from config when the caller did not pass
|
|
3540
|
+
* one in `decisionContextJson.run_projection_policy` (closes MJ-1).
|
|
3541
|
+
*
|
|
3542
|
+
* The response is mapped through `mapDecisionResponse()`: CONTINUE / DEGRADE
|
|
3543
|
+
* return a `DecisionOutcome`; STOP / STOP_RUN_PROJECTION / SKIP /
|
|
3544
|
+
* REQUIRE_APPROVAL raise the matching typed exception so adapters can route
|
|
3545
|
+
* on `instanceof DecisionDenied` (and its subclasses) per review-standards §5.
|
|
3546
|
+
*
|
|
3547
|
+
* @throws DecisionStopped on STOP / STOP_RUN_PROJECTION.
|
|
3548
|
+
* @throws DecisionSkipped on SKIP.
|
|
3549
|
+
* @throws ApprovalRequired on REQUIRE_APPROVAL — `await err.resume(client)`
|
|
3550
|
+
* surfaces the operator decision.
|
|
3551
|
+
* @throws DecisionDenied on an unknown decision enum.
|
|
3552
|
+
* @throws SidecarUnavailable on UNAVAILABLE / DEADLINE_EXCEEDED / CANCELLED.
|
|
3553
|
+
* @throws SpendGuardError on any other gRPC failure surface.
|
|
3554
|
+
*/
|
|
3555
|
+
async reserve(req) {
|
|
3556
|
+
if (this.cfg.disabled) return makeDisabledDecision(req);
|
|
3557
|
+
if (this.handshakeResult === null) {
|
|
3558
|
+
throw new HandshakeError(
|
|
3559
|
+
"reserve() requires handshake(); call await client.handshake() before reserve()"
|
|
3560
|
+
);
|
|
3561
|
+
}
|
|
3562
|
+
const cache = this.cfg.idempotencyCache;
|
|
3563
|
+
const bodyHash = cache !== void 0 && req.idempotencyKey.length > 0 ? computeReserveBodyHash(req) : void 0;
|
|
3564
|
+
if (cache !== void 0 && req.idempotencyKey.length > 0) {
|
|
3565
|
+
const cached = cache.get(req.idempotencyKey, bodyHash);
|
|
3566
|
+
if (cached !== void 0) return cached;
|
|
3567
|
+
}
|
|
3568
|
+
if (this.adapterClient === null) {
|
|
3569
|
+
await this.connect();
|
|
3570
|
+
}
|
|
3571
|
+
const adapter = this.adapterClient;
|
|
3572
|
+
if (adapter === null) {
|
|
3573
|
+
throw new SidecarUnavailable("transport not established for reserve");
|
|
3574
|
+
}
|
|
3575
|
+
const grpcReq = this.buildDecisionRequest(req);
|
|
3576
|
+
return await this.withSpan(
|
|
3577
|
+
"reserve",
|
|
3578
|
+
{
|
|
3579
|
+
[SPENDGUARD_OTEL_ATTR.TENANT_ID]: this.cfg.tenantId,
|
|
3580
|
+
[SPENDGUARD_OTEL_ATTR.DECISION_ID]: req.decisionId,
|
|
3581
|
+
[SPENDGUARD_OTEL_ATTR.TRIGGER]: req.trigger,
|
|
3582
|
+
[SPENDGUARD_OTEL_ATTR.SDK_VERSION]: this.cfg.sdkVersion
|
|
3583
|
+
},
|
|
3584
|
+
async () => {
|
|
3585
|
+
let resp;
|
|
3586
|
+
try {
|
|
3587
|
+
resp = await runWithRetry(
|
|
3588
|
+
async () => {
|
|
3589
|
+
try {
|
|
3590
|
+
return await adapter.requestDecision(grpcReq, {
|
|
3591
|
+
timeout: this.cfg.decisionTimeoutMs
|
|
3592
|
+
}).response;
|
|
3593
|
+
} catch (err) {
|
|
3594
|
+
throw mapGrpcStatusToError(err, { rpc: "reserve" });
|
|
3595
|
+
}
|
|
3596
|
+
},
|
|
3597
|
+
{ idempotencyKey: req.idempotencyKey }
|
|
3598
|
+
);
|
|
3599
|
+
} catch (err) {
|
|
3600
|
+
if (err instanceof SpendGuardError) throw err;
|
|
3601
|
+
throw mapGrpcStatusToError(err, { rpc: "reserve" });
|
|
3602
|
+
}
|
|
3603
|
+
if (resp.error && resp.error.code !== 0) {
|
|
3604
|
+
throw new SpendGuardError(
|
|
3605
|
+
`sidecar error code=${resp.error.code} message=${resp.error.message}`
|
|
3606
|
+
);
|
|
3607
|
+
}
|
|
3608
|
+
const outcome = mapDecisionResponse(resp, this.cfg.tenantId);
|
|
3609
|
+
if (cache !== void 0 && req.idempotencyKey.length > 0) {
|
|
3610
|
+
cache.set(req.idempotencyKey, outcome, void 0, bodyHash);
|
|
3611
|
+
}
|
|
3612
|
+
return outcome;
|
|
3613
|
+
}
|
|
3614
|
+
);
|
|
3615
|
+
}
|
|
3616
|
+
/**
|
|
3617
|
+
* Alias for `reserve()` — identical function reference (review-standards §1.5
|
|
3618
|
+
* P0 BLOCKER). The Python SDK exposes the symbol as `request_decision`; the
|
|
3619
|
+
* TS surface keeps `reserve` as the canonical name AND exposes
|
|
3620
|
+
* `requestDecision` so cross-language docs work without surprise.
|
|
3621
|
+
*
|
|
3622
|
+
* Implemented as an instance-field initializer that reads `this.reserve`
|
|
3623
|
+
* during construction. The dot-lookup on `this.reserve` (inside the field
|
|
3624
|
+
* initializer, before any instance shadow exists) resolves to the prototype
|
|
3625
|
+
* method `SpendGuardClient.prototype.reserve`. Assigning it to the field
|
|
3626
|
+
* makes `client.requestDecision === client.reserve` Boolean-true at runtime
|
|
3627
|
+
* (both resolve to the same prototype function reference).
|
|
3628
|
+
*
|
|
3629
|
+
* NOTE on `.bind(this)`: implementation.md §4 line 581 sketches the field
|
|
3630
|
+
* as `this.reserve.bind(this)`. The literal `bind` would produce a NEW
|
|
3631
|
+
* function object and break the §1.5 identity gate; the constraint cited
|
|
3632
|
+
* by the slice doc (review-standards §1.5 P0 BLOCKER) wins, so we drop
|
|
3633
|
+
* `.bind(this)`. Callers always invoke as `client.requestDecision(req)`
|
|
3634
|
+
* (method-call form) which preserves `this` via JS dispatch semantics —
|
|
3635
|
+
* the bind was over-specification for the Pythonic detached-method
|
|
3636
|
+
* pattern, which the TS SDK does not advertise.
|
|
3637
|
+
*
|
|
3638
|
+
* NOTE: do NOT add a JSDoc `@throws` block here — TypeScript erases JSDoc
|
|
3639
|
+
* from runtime fields and the identity invariant is the primary contract
|
|
3640
|
+
* this declaration enforces.
|
|
3641
|
+
*/
|
|
3642
|
+
requestDecision = this.reserve;
|
|
3643
|
+
/**
|
|
3644
|
+
* Commit an estimated LLM-call outcome. Equivalent to the Python SDK's
|
|
3645
|
+
* `emit_llm_call_post` with `estimated_amount_atomic` (design.md §4.8).
|
|
3646
|
+
*
|
|
3647
|
+
* Single-event LlmCallPostPayload over the EmitTraceEvents duplex stream:
|
|
3648
|
+
* the client opens a fresh stream per commit, sends one event, awaits one
|
|
3649
|
+
* ack, and closes (Python parity — `emit_llm_call_post` at client.py:818).
|
|
3650
|
+
* SLICE 5+ may switch to a long-lived stream for production latency, but
|
|
3651
|
+
* the per-event setup cost is acceptable in v0.1.x.
|
|
3652
|
+
*
|
|
3653
|
+
* Ack semantics: the sidecar emits exactly one `TraceEventAck` per inbound
|
|
3654
|
+
* event in this POC. Status != ACCEPTED surfaces as `SpendGuardError`
|
|
3655
|
+
* (Codex round-2 P1.1 from Python parity — silent failure here would mask
|
|
3656
|
+
* a commit-lifecycle bug).
|
|
3657
|
+
*
|
|
3658
|
+
* Mutually exclusive with the deferred provider-report path: this method
|
|
3659
|
+
* always sends `estimated_amount_atomic`; the `provider_reported_amount_atomic`
|
|
3660
|
+
* wire field stays empty. Adapters needing the provider-report path use the
|
|
3661
|
+
* lower-level `emitLlmCallPost` (SLICE 7+).
|
|
3662
|
+
*
|
|
3663
|
+
* **SLICE 5 multi-event extension.** When `req.outcomeKind` is set, the
|
|
3664
|
+
* client emits TWO events on the same bidi stream — the original
|
|
3665
|
+
* LLM_CALL_POST event first, then a second LLM_CALL_POST-kind event whose
|
|
3666
|
+
* `outcome` field reflects `outcomeKind` (SUCCESS → SUCCESS,
|
|
3667
|
+
* FAILURE → PROVIDER_ERROR) and whose `providerResponseMetadata` carries a
|
|
3668
|
+
* `{"error_message": ...}` envelope when `actualErrorMessage` is supplied.
|
|
3669
|
+
* Both events are acked individually; if either ack is non-ACCEPTED the
|
|
3670
|
+
* method raises `SpendGuardError`. See the JSDoc on
|
|
3671
|
+
* `CommitEstimatedRequest.outcomeKind` for the LLM_CALL_OUTCOME proto-kind
|
|
3672
|
+
* deviation note (Declared Deviation #1 in SLICE 5).
|
|
3673
|
+
*
|
|
3674
|
+
* When `req.outcomeKind` is ABSENT, behaviour is identical to SLICE 4 —
|
|
3675
|
+
* a single event is sent, a single ack is drained.
|
|
3676
|
+
*
|
|
3677
|
+
* @throws SidecarUnavailable on UNAVAILABLE / DEADLINE_EXCEEDED / CANCELLED.
|
|
3678
|
+
* @throws SpendGuardError on rejected ack or any other gRPC failure surface.
|
|
3679
|
+
*/
|
|
3680
|
+
async commitEstimated(req) {
|
|
3681
|
+
if (this.cfg.disabled) return;
|
|
3682
|
+
if (this.handshakeResult === null) {
|
|
3683
|
+
throw new HandshakeError(
|
|
3684
|
+
"commitEstimated() requires handshake(); call await client.handshake() before commitEstimated()"
|
|
3685
|
+
);
|
|
3686
|
+
}
|
|
3687
|
+
if (this.adapterClient === null) {
|
|
3688
|
+
await this.connect();
|
|
3689
|
+
}
|
|
3690
|
+
const adapter = this.adapterClient;
|
|
3691
|
+
if (adapter === null) {
|
|
3692
|
+
throw new SidecarUnavailable("transport not established for commitEstimated");
|
|
3693
|
+
}
|
|
3694
|
+
const events = [this.buildLlmCallPostEvent(req)];
|
|
3695
|
+
if (req.outcomeKind !== void 0) {
|
|
3696
|
+
events.push(this.buildLlmCallOutcomeEvent(req));
|
|
3697
|
+
}
|
|
3698
|
+
await this.withSpan(
|
|
3699
|
+
"commitEstimated",
|
|
3700
|
+
{
|
|
3701
|
+
[SPENDGUARD_OTEL_ATTR.TENANT_ID]: this.cfg.tenantId,
|
|
3702
|
+
[SPENDGUARD_OTEL_ATTR.DECISION_ID]: req.decisionId,
|
|
3703
|
+
[SPENDGUARD_OTEL_ATTR.SDK_VERSION]: this.cfg.sdkVersion
|
|
3704
|
+
},
|
|
3705
|
+
async () => {
|
|
3706
|
+
let call;
|
|
3707
|
+
try {
|
|
3708
|
+
call = adapter.emitTraceEvents({
|
|
3709
|
+
timeout: this.cfg.traceTimeoutMs
|
|
3710
|
+
});
|
|
3711
|
+
for (const event of events) {
|
|
3712
|
+
await call.requests.send(event);
|
|
3713
|
+
}
|
|
3714
|
+
await call.requests.complete();
|
|
3715
|
+
} catch (err) {
|
|
3716
|
+
throw mapGrpcStatusToError(err, { rpc: "commitEstimated" });
|
|
3717
|
+
}
|
|
3718
|
+
try {
|
|
3719
|
+
let acked = 0;
|
|
3720
|
+
for await (const ack of call.responses) {
|
|
3721
|
+
acked += 1;
|
|
3722
|
+
if (ack.status !== 1 /* ACCEPTED */) {
|
|
3723
|
+
throw new SpendGuardError(buildAckRejectMessage(ack));
|
|
3724
|
+
}
|
|
3725
|
+
}
|
|
3726
|
+
await call.status;
|
|
3727
|
+
await call.trailers;
|
|
3728
|
+
if (acked === 0) {
|
|
3729
|
+
throw new SpendGuardError("EmitTraceEvents closed without an ack from sidecar");
|
|
3730
|
+
}
|
|
3731
|
+
if (acked < events.length) {
|
|
3732
|
+
throw new SpendGuardError(
|
|
3733
|
+
`EmitTraceEvents acked ${acked} of ${events.length} events before closing`
|
|
3734
|
+
);
|
|
3735
|
+
}
|
|
3736
|
+
} catch (err) {
|
|
3737
|
+
if (err instanceof SpendGuardError) throw err;
|
|
3738
|
+
throw mapGrpcStatusToError(err, { rpc: "commitEstimated" });
|
|
3739
|
+
}
|
|
3740
|
+
}
|
|
3741
|
+
);
|
|
3742
|
+
}
|
|
3743
|
+
/**
|
|
3744
|
+
* Explicit release of a held reservation. Matches Agent Spend Protocol
|
|
3745
|
+
* Draft-01 §4 one-to-one (the proto wire's
|
|
3746
|
+
* `ReleaseReservationRequest` carries the canonical ASP fields at tags 1-3
|
|
3747
|
+
* and SpendGuard extensions at tag 100+).
|
|
3748
|
+
*
|
|
3749
|
+
* Behaviour:
|
|
3750
|
+
* - Disabled-mode short-circuit returns a synthetic
|
|
3751
|
+
* `makeDisabledReleaseOutcome(req)` — no UDS contact.
|
|
3752
|
+
* - Pre-handshake call throws `HandshakeError` via the `sessionId` getter
|
|
3753
|
+
* gate (the request envelope requires the negotiated session id).
|
|
3754
|
+
* - Wire envelope built by `buildReleaseRequest(req, sessionId)`.
|
|
3755
|
+
* - Response mapped by `mapReleaseResponse(res, decisionIdHint)`.
|
|
3756
|
+
* - Errors mapped centrally through `mapGrpcStatusToError`, with the
|
|
3757
|
+
* `release`-specific NOT_FOUND override (reservation lookup misses
|
|
3758
|
+
* surface as a plain `SpendGuardError("reservation not found")` so
|
|
3759
|
+
* adapters can distinguish "no such reservation" from the rich
|
|
3760
|
+
* FAILED_PRECONDITION cluster).
|
|
3761
|
+
*
|
|
3762
|
+
* @throws HandshakeError before `handshake()` completes.
|
|
3763
|
+
* @throws SidecarUnavailable on UNAVAILABLE / DEADLINE_EXCEEDED / CANCELLED.
|
|
3764
|
+
* @throws MutationApplyFailed on FAILED_PRECONDITION + IDEMPOTENCY_CONFLICT
|
|
3765
|
+
* or BUDGET_EXCEEDED — or an unknown FAILED_PRECONDITION reason (the
|
|
3766
|
+
* conservative default; never bare `SpendGuardError` for this cluster).
|
|
3767
|
+
* @throws ApprovalBundleHotReloadedError on FAILED_PRECONDITION +
|
|
3768
|
+
* BUNDLE_HOT_RELOADED.
|
|
3769
|
+
* @throws SpendGuardError on NOT_FOUND ("reservation not found") + any
|
|
3770
|
+
* other unmapped gRPC failure.
|
|
3771
|
+
*/
|
|
3772
|
+
async release(req) {
|
|
3773
|
+
if (this.cfg.disabled) return makeDisabledReleaseOutcome(req);
|
|
3774
|
+
if (this.handshakeResult === null) {
|
|
3775
|
+
throw new HandshakeError(
|
|
3776
|
+
"release() requires handshake(); call await client.handshake() before release()"
|
|
3777
|
+
);
|
|
3778
|
+
}
|
|
3779
|
+
if (this.adapterClient === null) {
|
|
3780
|
+
await this.connect();
|
|
3781
|
+
}
|
|
3782
|
+
const adapter = this.adapterClient;
|
|
3783
|
+
if (adapter === null) {
|
|
3784
|
+
throw new SidecarUnavailable("transport not established for release");
|
|
3785
|
+
}
|
|
3786
|
+
const grpcReq = buildReleaseRequest(req, this.handshakeResult.sessionId);
|
|
3787
|
+
return await this.withSpan(
|
|
3788
|
+
"release",
|
|
3789
|
+
{
|
|
3790
|
+
[SPENDGUARD_OTEL_ATTR.TENANT_ID]: this.cfg.tenantId,
|
|
3791
|
+
[SPENDGUARD_OTEL_ATTR.RESERVATION_ID]: req.reservationId,
|
|
3792
|
+
[SPENDGUARD_OTEL_ATTR.SDK_VERSION]: this.cfg.sdkVersion
|
|
3793
|
+
},
|
|
3794
|
+
async () => {
|
|
3795
|
+
let resp;
|
|
3796
|
+
try {
|
|
3797
|
+
resp = await adapter.releaseReservation(grpcReq, {
|
|
3798
|
+
timeout: this.cfg.publishTimeoutMs
|
|
3799
|
+
}).response;
|
|
3800
|
+
} catch (err) {
|
|
3801
|
+
throw mapGrpcStatusToError(err, { rpc: "release", releaseNotFoundAsPlain: true });
|
|
3802
|
+
}
|
|
3803
|
+
return mapReleaseResponse(resp);
|
|
3804
|
+
}
|
|
3805
|
+
);
|
|
3806
|
+
}
|
|
3807
|
+
/**
|
|
3808
|
+
* Reserve a session-scoped hold for a realtime voice session (D41 SR-V3).
|
|
3809
|
+
*
|
|
3810
|
+
* The public request shape mirrors `buildReserveSessionRequest`. When
|
|
3811
|
+
* `req.sessionId` is empty, the SDK fills it from the completed sidecar
|
|
3812
|
+
* handshake so adapter code can bind the session reservation to the active
|
|
3813
|
+
* UDS session without duplicating handshake plumbing.
|
|
3814
|
+
*
|
|
3815
|
+
* @throws HandshakeError before `handshake()` completes.
|
|
3816
|
+
* @throws SidecarUnavailable on UNAVAILABLE / DEADLINE_EXCEEDED / CANCELLED.
|
|
3817
|
+
* @throws SpendGuardError on proto error outcome or unmapped gRPC failure.
|
|
3818
|
+
*/
|
|
3819
|
+
async reserveSession(req) {
|
|
3820
|
+
if (this.cfg.disabled) {
|
|
3821
|
+
buildReserveSessionRequest(req);
|
|
3822
|
+
return makeDisabledReserveSessionOutcome(req);
|
|
3823
|
+
}
|
|
3824
|
+
if (this.handshakeResult === null) {
|
|
3825
|
+
throw new HandshakeError(
|
|
3826
|
+
"reserveSession() requires handshake(); call await client.handshake() before reserveSession()"
|
|
3827
|
+
);
|
|
3828
|
+
}
|
|
3829
|
+
if (this.adapterClient === null) {
|
|
3830
|
+
await this.connect();
|
|
3831
|
+
}
|
|
3832
|
+
const adapter = this.adapterClient;
|
|
3833
|
+
if (adapter === null) {
|
|
3834
|
+
throw new SidecarUnavailable("transport not established for reserveSession");
|
|
3835
|
+
}
|
|
3836
|
+
const grpcReq = buildReserveSessionRequest({
|
|
3837
|
+
...req,
|
|
3838
|
+
sessionId: req.sessionId || this.handshakeResult.sessionId
|
|
3839
|
+
});
|
|
3840
|
+
return await this.withSpan(
|
|
3841
|
+
"reserveSession",
|
|
3842
|
+
{
|
|
3843
|
+
[SPENDGUARD_OTEL_ATTR.TENANT_ID]: this.cfg.tenantId,
|
|
3844
|
+
[SPENDGUARD_OTEL_ATTR.SDK_VERSION]: this.cfg.sdkVersion
|
|
3845
|
+
},
|
|
3846
|
+
async () => {
|
|
3847
|
+
try {
|
|
3848
|
+
const resp = await adapter.reserveSession(grpcReq, {
|
|
3849
|
+
timeout: this.cfg.decisionTimeoutMs
|
|
3850
|
+
}).response;
|
|
3851
|
+
return mapReserveSessionOutcome(resp);
|
|
3852
|
+
} catch (err) {
|
|
3853
|
+
throw mapGrpcStatusToError(err, { rpc: "reserveSession" });
|
|
3854
|
+
}
|
|
3855
|
+
}
|
|
3856
|
+
);
|
|
3857
|
+
}
|
|
3858
|
+
/**
|
|
3859
|
+
* Commit one positive streaming spend delta against a session reservation.
|
|
3860
|
+
*
|
|
3861
|
+
* @throws HandshakeError before `handshake()` completes.
|
|
3862
|
+
* @throws SidecarUnavailable on UNAVAILABLE / DEADLINE_EXCEEDED / CANCELLED.
|
|
3863
|
+
* @throws SpendGuardError on proto error outcome or unmapped gRPC failure.
|
|
3864
|
+
*/
|
|
3865
|
+
async commitSessionDelta(req) {
|
|
3866
|
+
if (this.cfg.disabled) {
|
|
3867
|
+
buildCommitSessionDeltaRequest(req);
|
|
3868
|
+
return makeDisabledCommitSessionDeltaOutcome(req);
|
|
3869
|
+
}
|
|
3870
|
+
if (this.handshakeResult === null) {
|
|
3871
|
+
throw new HandshakeError(
|
|
3872
|
+
"commitSessionDelta() requires handshake(); call await client.handshake() before commitSessionDelta()"
|
|
3873
|
+
);
|
|
3874
|
+
}
|
|
3875
|
+
if (this.adapterClient === null) {
|
|
3876
|
+
await this.connect();
|
|
3877
|
+
}
|
|
3878
|
+
const adapter = this.adapterClient;
|
|
3879
|
+
if (adapter === null) {
|
|
3880
|
+
throw new SidecarUnavailable("transport not established for commitSessionDelta");
|
|
3881
|
+
}
|
|
3882
|
+
const grpcReq = buildCommitSessionDeltaRequest(req);
|
|
3883
|
+
return await this.withSpan(
|
|
3884
|
+
"commitSessionDelta",
|
|
3885
|
+
{
|
|
3886
|
+
[SPENDGUARD_OTEL_ATTR.TENANT_ID]: this.cfg.tenantId,
|
|
3887
|
+
[SPENDGUARD_OTEL_ATTR.SDK_VERSION]: this.cfg.sdkVersion
|
|
3888
|
+
},
|
|
3889
|
+
async () => {
|
|
3890
|
+
try {
|
|
3891
|
+
const resp = await adapter.commitSessionDelta(grpcReq, {
|
|
3892
|
+
timeout: this.cfg.traceTimeoutMs
|
|
3893
|
+
}).response;
|
|
3894
|
+
return mapCommitSessionDeltaOutcome(resp);
|
|
3895
|
+
} catch (err) {
|
|
3896
|
+
throw mapGrpcStatusToError(err, { rpc: "commitSessionDelta" });
|
|
3897
|
+
}
|
|
3898
|
+
}
|
|
3899
|
+
);
|
|
3900
|
+
}
|
|
3901
|
+
/**
|
|
3902
|
+
* Release the uncommitted remainder of a session reservation.
|
|
3903
|
+
*
|
|
3904
|
+
* @throws HandshakeError before `handshake()` completes.
|
|
3905
|
+
* @throws SidecarUnavailable on UNAVAILABLE / DEADLINE_EXCEEDED / CANCELLED.
|
|
3906
|
+
* @throws SpendGuardError on proto error outcome or unmapped gRPC failure.
|
|
3907
|
+
*/
|
|
3908
|
+
async releaseSession(req) {
|
|
3909
|
+
if (this.cfg.disabled) {
|
|
3910
|
+
buildReleaseSessionRequest(req);
|
|
3911
|
+
return makeDisabledReleaseSessionOutcome(req);
|
|
3912
|
+
}
|
|
3913
|
+
if (this.handshakeResult === null) {
|
|
3914
|
+
throw new HandshakeError(
|
|
3915
|
+
"releaseSession() requires handshake(); call await client.handshake() before releaseSession()"
|
|
3916
|
+
);
|
|
3917
|
+
}
|
|
3918
|
+
if (this.adapterClient === null) {
|
|
3919
|
+
await this.connect();
|
|
3920
|
+
}
|
|
3921
|
+
const adapter = this.adapterClient;
|
|
3922
|
+
if (adapter === null) {
|
|
3923
|
+
throw new SidecarUnavailable("transport not established for releaseSession");
|
|
3924
|
+
}
|
|
3925
|
+
const grpcReq = buildReleaseSessionRequest(req);
|
|
3926
|
+
return await this.withSpan(
|
|
3927
|
+
"releaseSession",
|
|
3928
|
+
{
|
|
3929
|
+
[SPENDGUARD_OTEL_ATTR.TENANT_ID]: this.cfg.tenantId,
|
|
3930
|
+
[SPENDGUARD_OTEL_ATTR.SDK_VERSION]: this.cfg.sdkVersion
|
|
3931
|
+
},
|
|
3932
|
+
async () => {
|
|
3933
|
+
try {
|
|
3934
|
+
const resp = await adapter.releaseSession(grpcReq, {
|
|
3935
|
+
timeout: this.cfg.publishTimeoutMs
|
|
3936
|
+
}).response;
|
|
3937
|
+
return mapReleaseSessionOutcome(resp);
|
|
3938
|
+
} catch (err) {
|
|
3939
|
+
throw mapGrpcStatusToError(err, { rpc: "releaseSession" });
|
|
3940
|
+
}
|
|
3941
|
+
}
|
|
3942
|
+
);
|
|
3943
|
+
}
|
|
3944
|
+
/**
|
|
3945
|
+
* Read-only budget snapshot. Locked decision #4 of design.md §9: in v0.1.x
|
|
3946
|
+
* the substrate ships the method signature but the sidecar wire is NOT yet
|
|
3947
|
+
* implemented. SLICE 5 wires the §9.4 placeholder body — adapters call this
|
|
3948
|
+
* method, catch the explicit `SpendGuardError`, and surface a clear "feature
|
|
3949
|
+
* not yet available" upstream rather than a stray NOT_FOUND from a missing
|
|
3950
|
+
* RPC route.
|
|
3951
|
+
*
|
|
3952
|
+
* Disabled-mode short-circuit returns a synthetic
|
|
3953
|
+
* `makeDisabledQueryBudgetResult(req)` so unit tests can program against
|
|
3954
|
+
* the method without a sidecar.
|
|
3955
|
+
*
|
|
3956
|
+
* @throws HandshakeError before `handshake()` completes.
|
|
3957
|
+
* @throws SpendGuardError carrying the tracking-issue URL otherwise.
|
|
3958
|
+
*/
|
|
3959
|
+
async queryBudget(req) {
|
|
3960
|
+
if (this.cfg.disabled) return makeDisabledQueryBudgetResult(req);
|
|
3961
|
+
if (this.handshakeResult === null) {
|
|
3962
|
+
throw new HandshakeError(
|
|
3963
|
+
"queryBudget() requires handshake(); call await client.handshake() before queryBudget()"
|
|
3964
|
+
);
|
|
3965
|
+
}
|
|
3966
|
+
return await this.withSpan(
|
|
3967
|
+
"queryBudget",
|
|
3968
|
+
{
|
|
3969
|
+
[SPENDGUARD_OTEL_ATTR.TENANT_ID]: this.cfg.tenantId,
|
|
3970
|
+
[SPENDGUARD_OTEL_ATTR.SCOPE_ID]: req.scopeId,
|
|
3971
|
+
[SPENDGUARD_OTEL_ATTR.SDK_VERSION]: this.cfg.sdkVersion
|
|
3972
|
+
},
|
|
3973
|
+
async () => {
|
|
3974
|
+
throw new SpendGuardError(QUERY_BUDGET_NOT_YET_WIRED);
|
|
3975
|
+
}
|
|
3976
|
+
);
|
|
3977
|
+
}
|
|
3978
|
+
// ── Lower-level surface (deferred to SLICE 7+) ──────────────────────────
|
|
3979
|
+
/**
|
|
3980
|
+
* Confirm `publish_effect` outcome. SLICE 7 wires body.
|
|
3981
|
+
* @throws SpendGuardError until SLICE 7 wires the body.
|
|
3982
|
+
*/
|
|
3983
|
+
async confirmPublishOutcome(req) {
|
|
3984
|
+
throw new SpendGuardError(`confirmPublishOutcome() ${SLICE_7_NOT_WIRED}`);
|
|
3985
|
+
}
|
|
3986
|
+
/**
|
|
3987
|
+
* Resume after a human approver acted on a `REQUIRE_APPROVAL` decision.
|
|
3988
|
+
* SLICE 7 wires the body; references this method from `ApprovalRequired.resume`.
|
|
3989
|
+
* @throws SpendGuardError until SLICE 7 wires the body.
|
|
3990
|
+
*/
|
|
3991
|
+
async resumeAfterApproval(req) {
|
|
3992
|
+
throw new SpendGuardError(`resumeAfterApproval() ${SLICE_7_NOT_WIRED}`);
|
|
3993
|
+
}
|
|
3994
|
+
/**
|
|
3995
|
+
* Safe-ack the `APPLY_FAILED` publish outcome — swallows transport errors
|
|
3996
|
+
* so the caller's original exception is never shadowed. SLICE 7 wires body.
|
|
3997
|
+
* @throws SpendGuardError until SLICE 7 wires the body.
|
|
3998
|
+
*/
|
|
3999
|
+
async safeConfirmApplyFailed(req) {
|
|
4000
|
+
throw new SpendGuardError(`safeConfirmApplyFailed() ${SLICE_7_NOT_WIRED}`);
|
|
4001
|
+
}
|
|
4002
|
+
/**
|
|
4003
|
+
* Lower-level entry point that `commitEstimated()` wraps. Provided so
|
|
4004
|
+
* adapters that need the raw trace-event surface have access. SLICE 7
|
|
4005
|
+
* wires body (the provider-report path).
|
|
4006
|
+
* @throws SpendGuardError until SLICE 7 wires the body.
|
|
4007
|
+
*/
|
|
4008
|
+
async emitLlmCallPost(req) {
|
|
4009
|
+
throw new SpendGuardError(`emitLlmCallPost() ${SLICE_7_NOT_WIRED}`);
|
|
4010
|
+
}
|
|
4011
|
+
// ── Internals ────────────────────────────────────────────────────────────
|
|
4012
|
+
/**
|
|
4013
|
+
* Build the gRPC channel credentials. Always insecure over UDS — the kernel
|
|
4014
|
+
* `SO_PEERCRED` check on the sidecar side is the trust anchor (Sidecar
|
|
4015
|
+
* Architecture §5). TLS over a Unix socket adds overhead with no security
|
|
4016
|
+
* benefit when the connection is implicitly local.
|
|
4017
|
+
*
|
|
4018
|
+
* Carved into its own method so a future slice can override under a
|
|
4019
|
+
* `runtime` flag once HTTP-gateway transport is added — `runtime: "fetch"`
|
|
4020
|
+
* would override to use TLS credentials. v0.1.x only supports `"uds-grpc"`.
|
|
4021
|
+
*/
|
|
4022
|
+
buildChannelCredentials() {
|
|
4023
|
+
return credentials.createInsecure();
|
|
4024
|
+
}
|
|
4025
|
+
/**
|
|
4026
|
+
* Translate the public `ReserveRequest` (camelCase, TS-idiomatic) into the
|
|
4027
|
+
* snake_case-on-wire `DecisionRequest` proto. Per implementation.md §4:
|
|
4028
|
+
*
|
|
4029
|
+
* 1. SessionId from the cached handshake (caller already gated above).
|
|
4030
|
+
* 2. Trigger enum mapping via `triggerEnumOf()`.
|
|
4031
|
+
* 3. W3C `traceparent` → `TraceContext` via `buildTraceContext()` (matches
|
|
4032
|
+
* Python `_build_trace_context`).
|
|
4033
|
+
* 4. `runtimeMetadata` carries the prompt hash (when caller supplied
|
|
4034
|
+
* `promptText`) and any `decisionContextJson` keys. The
|
|
4035
|
+
* `run_projection_policy` slot is filled from the caller's
|
|
4036
|
+
* `decisionContextJson.run_projection_policy` if present, otherwise
|
|
4037
|
+
* from `cfg.runProjectionDefault` when non-empty. **This is the
|
|
4038
|
+
* SLICE 4 consumption of MJ-1** — SLICE 3 stored the field on the
|
|
4039
|
+
* config; this method wires it onto the wire.
|
|
4040
|
+
* 5. `plannedStepsHint` is `plan.plannedCalls + plan.plannedTools` when
|
|
4041
|
+
* a `withRunPlan` scope is active (SLICE 7 R2), otherwise the proto3
|
|
4042
|
+
* default `0`.
|
|
4043
|
+
*
|
|
4044
|
+
* `runtime_metadata` is encoded as a hand-built `google.protobuf.Struct`
|
|
4045
|
+
* payload because the SDK does not yet ship `computePromptHash` (SLICE 6).
|
|
4046
|
+
* Until then this method ALWAYS sends an empty Struct body when no caller
|
|
4047
|
+
* decoration is requested — matching Python `runtime_metadata = None` which
|
|
4048
|
+
* is wire-equivalent to "field absent" under proto3 message optionality.
|
|
4049
|
+
*/
|
|
4050
|
+
buildDecisionRequest(req) {
|
|
4051
|
+
if (this.handshakeResult === null) {
|
|
4052
|
+
throw new HandshakeError("internal: buildDecisionRequest without handshake");
|
|
4053
|
+
}
|
|
4054
|
+
const plan = currentRunPlan();
|
|
4055
|
+
const plannedStepsHint = plan !== null ? plan.plannedCalls + plan.plannedTools : 0;
|
|
4056
|
+
const trigger = triggerEnumOf(req.trigger);
|
|
4057
|
+
const trace = buildTraceContext(req.traceparent ?? "", req.tracestate ?? "");
|
|
4058
|
+
const ids = {
|
|
4059
|
+
runId: req.runId,
|
|
4060
|
+
stepId: req.stepId,
|
|
4061
|
+
llmCallId: req.llmCallId,
|
|
4062
|
+
toolCallId: req.toolCallId ?? "",
|
|
4063
|
+
decisionId: req.decisionId,
|
|
4064
|
+
snapshotId: ""
|
|
4065
|
+
};
|
|
4066
|
+
const projectedClaims = req.projectedClaims.map((claim) => ({
|
|
4067
|
+
budgetId: claim.scopeId,
|
|
4068
|
+
unit: mapUnitRef2(claim.unit),
|
|
4069
|
+
amountAtomic: claim.amountAtomic,
|
|
4070
|
+
// direction: DEBIT (1) — SDK callers only project debits; credits are
|
|
4071
|
+
// generated server-side as compensating ledger entries (Stage 2 §4.6).
|
|
4072
|
+
direction: 1,
|
|
4073
|
+
// HARDEN_D05_WI — thread caller-supplied windowInstanceId onto the
|
|
4074
|
+
// wire claim. Omitted keeps the pre-HARDEN wire shape ("").
|
|
4075
|
+
windowInstanceId: claim.windowInstanceId ?? ""
|
|
4076
|
+
}));
|
|
4077
|
+
const runtimeMetadata = this.buildRuntimeMetadataStruct(req);
|
|
4078
|
+
const inputs = {
|
|
4079
|
+
projectedClaims,
|
|
4080
|
+
projectedP50Atomic: req.projectedP50Atomic ?? "",
|
|
4081
|
+
projectedP90Atomic: req.projectedP90Atomic ?? "",
|
|
4082
|
+
projectedP95Atomic: req.projectedP95Atomic ?? "",
|
|
4083
|
+
projectedP99Atomic: req.projectedP99Atomic ?? "",
|
|
4084
|
+
...req.projectedUnit !== void 0 ? { projectedUnit: mapUnitRef2(req.projectedUnit) } : {},
|
|
4085
|
+
...runtimeMetadata !== void 0 ? { runtimeMetadata } : {},
|
|
4086
|
+
...req.claimEstimate !== void 0 ? { claimEstimate: mapClaimEstimate(req.claimEstimate) } : {}
|
|
4087
|
+
};
|
|
4088
|
+
const idempotency = {
|
|
4089
|
+
key: req.idempotencyKey,
|
|
4090
|
+
// The sidecar/ledger own the canonical request hash; SDK leaves it empty
|
|
4091
|
+
// (matches Python parity at client.py:494).
|
|
4092
|
+
requestHash: new Uint8Array()
|
|
4093
|
+
};
|
|
4094
|
+
return {
|
|
4095
|
+
sessionId: this.handshakeResult.sessionId,
|
|
4096
|
+
trigger,
|
|
4097
|
+
trace,
|
|
4098
|
+
ids,
|
|
4099
|
+
route: req.route,
|
|
4100
|
+
inputs,
|
|
4101
|
+
parentRunId: req.parentRunId ?? "",
|
|
4102
|
+
budgetGrantJti: req.budgetGrantJti ?? "",
|
|
4103
|
+
idempotency,
|
|
4104
|
+
// SLICE 7 R2: Signal 3 — `plannedCalls + plannedTools` when an active
|
|
4105
|
+
// `withRunPlan` scope is in flight, otherwise proto3 default `0`. The
|
|
4106
|
+
// sidecar enforces the upper bound `[0, MAX_PLANNED_STEPS]` server-side
|
|
4107
|
+
// (`services/run_cost_projector/src/server.rs`) so the SDK doesn't gate
|
|
4108
|
+
// on a value the server may bump independently.
|
|
4109
|
+
plannedStepsHint,
|
|
4110
|
+
// D13 additive proto fields. These defaults preserve the pre-D13 BYOK
|
|
4111
|
+
// request-scoped path until an adapter explicitly opts into meter-only.
|
|
4112
|
+
reservationSource: 0 /* UNSPECIFIED */,
|
|
4113
|
+
meterOnlyEstimate: false
|
|
4114
|
+
};
|
|
4115
|
+
}
|
|
4116
|
+
/**
|
|
4117
|
+
* Build the `google.protobuf.Struct` payload that lands in
|
|
4118
|
+
* `DecisionRequest.inputs.runtime_metadata`. Returns `undefined` when there
|
|
4119
|
+
* is nothing to send (proto3 message optionality — wire equivalent to
|
|
4120
|
+
* "field absent").
|
|
4121
|
+
*
|
|
4122
|
+
* Two slots are populated here:
|
|
4123
|
+
* - `decision_context_json.*` keys from the caller (verbatim).
|
|
4124
|
+
* - `run_projection_policy` from the caller (if present in
|
|
4125
|
+
* `decisionContextJson`) OR `cfg.runProjectionDefault` (when set and
|
|
4126
|
+
* non-empty). The caller's value wins; the default only fills in when
|
|
4127
|
+
* the caller did not provide one — matches design.md §4.2 R2 semantics.
|
|
4128
|
+
*
|
|
4129
|
+
* SLICE 6 R1 closure of SLICE 4 M-3: when `req.promptText` is set,
|
|
4130
|
+
* `computePromptHash(req.promptText, this.cfg.tenantId)` populates
|
|
4131
|
+
* `runtime_metadata.prompt_hash` as a stringValue. Mirrors Python parity
|
|
4132
|
+
* at `sdk/python/.../client.py` (the `prompt_hash` field is the rules
|
|
4133
|
+
* dedup key per Cost Advisor P0.5 §5.1). The caller may pre-set
|
|
4134
|
+
* `decisionContextJson.prompt_hash` to override (e.g. when the prompt is
|
|
4135
|
+
* tokenised upstream and the hash is computed there); the caller-supplied
|
|
4136
|
+
* value wins.
|
|
4137
|
+
*/
|
|
4138
|
+
buildRuntimeMetadataStruct(req) {
|
|
4139
|
+
const fields = {};
|
|
4140
|
+
let hasField = false;
|
|
4141
|
+
if (req.decisionContextJson !== void 0) {
|
|
4142
|
+
for (const [k, v] of Object.entries(req.decisionContextJson)) {
|
|
4143
|
+
fields[k] = jsonValueToStructValue(v);
|
|
4144
|
+
hasField = true;
|
|
4145
|
+
}
|
|
4146
|
+
}
|
|
4147
|
+
if (this.cfg.runProjectionDefault !== "" && fields.run_projection_policy === void 0) {
|
|
4148
|
+
fields.run_projection_policy = jsonValueToStructValue(this.cfg.runProjectionDefault);
|
|
4149
|
+
hasField = true;
|
|
4150
|
+
}
|
|
4151
|
+
if (req.promptText !== void 0 && fields.prompt_hash === void 0) {
|
|
4152
|
+
const hash = computePromptHash(req.promptText, this.cfg.tenantId);
|
|
4153
|
+
fields.prompt_hash = jsonValueToStructValue(hash);
|
|
4154
|
+
hasField = true;
|
|
4155
|
+
}
|
|
4156
|
+
return hasField ? { fields } : void 0;
|
|
4157
|
+
}
|
|
4158
|
+
/**
|
|
4159
|
+
* Build the single LLM_CALL_POST trace event for `commitEstimated()`.
|
|
4160
|
+
* Mirrors Python `emit_llm_call_post` at client.py:818 with the difference
|
|
4161
|
+
* that `provider_reported_amount_atomic` is always empty here (the
|
|
4162
|
+
* provider-report path lives in SLICE 5+'s `emitLlmCallPost`).
|
|
4163
|
+
*/
|
|
4164
|
+
buildLlmCallPostEvent(req) {
|
|
4165
|
+
if (this.handshakeResult === null) {
|
|
4166
|
+
throw new HandshakeError("internal: buildLlmCallPostEvent without handshake");
|
|
4167
|
+
}
|
|
4168
|
+
const ts = wallClockToTimestamp(Date.now());
|
|
4169
|
+
return {
|
|
4170
|
+
sessionId: this.handshakeResult.sessionId,
|
|
4171
|
+
trace: buildTraceContext(req.traceparent ?? "", req.tracestate ?? ""),
|
|
4172
|
+
ids: {
|
|
4173
|
+
runId: req.runId,
|
|
4174
|
+
stepId: req.stepId,
|
|
4175
|
+
llmCallId: req.llmCallId,
|
|
4176
|
+
toolCallId: "",
|
|
4177
|
+
decisionId: req.decisionId,
|
|
4178
|
+
snapshotId: ""
|
|
4179
|
+
},
|
|
4180
|
+
kind: 4 /* LLM_CALL_POST */,
|
|
4181
|
+
eventTime: ts,
|
|
4182
|
+
payload: {
|
|
4183
|
+
oneofKind: "llmCallPost",
|
|
4184
|
+
llmCallPost: {
|
|
4185
|
+
reservationId: req.reservationId,
|
|
4186
|
+
providerReportedAmountAtomic: "",
|
|
4187
|
+
unit: mapUnitRef2(req.unit),
|
|
4188
|
+
pricing: {
|
|
4189
|
+
pricingVersion: req.pricing.pricingVersion,
|
|
4190
|
+
priceSnapshotHash: req.pricing.pricingHash,
|
|
4191
|
+
// HARDEN_D05_WI — thread the full freeze tuple (omitted → "").
|
|
4192
|
+
fxRateVersion: req.pricing.fxRateVersion ?? "",
|
|
4193
|
+
unitConversionVersion: req.pricing.unitConversionVersion ?? ""
|
|
4194
|
+
},
|
|
4195
|
+
providerEventId: req.providerEventId,
|
|
4196
|
+
outcome: llmOutcomeEnumOf(req.outcome),
|
|
4197
|
+
estimatedAmountAtomic: req.estimatedAmountAtomic,
|
|
4198
|
+
...req.actualInputTokens !== void 0 ? { actualInputTokens: String(req.actualInputTokens) } : {},
|
|
4199
|
+
...req.actualOutputTokens !== void 0 ? { actualOutputTokens: String(req.actualOutputTokens) } : {},
|
|
4200
|
+
...req.deltaBRatio !== void 0 ? { deltaBRatio: req.deltaBRatio } : {},
|
|
4201
|
+
...req.deltaCRatio !== void 0 ? { deltaCRatio: req.deltaCRatio } : {}
|
|
4202
|
+
}
|
|
4203
|
+
},
|
|
4204
|
+
providerResponseMetadata: req.providerResponseMetadata ?? ""
|
|
4205
|
+
};
|
|
4206
|
+
}
|
|
4207
|
+
/**
|
|
4208
|
+
* Build the SLICE 5 multi-event "outcome" companion event for
|
|
4209
|
+
* `commitEstimated()` when `req.outcomeKind` is set.
|
|
4210
|
+
*
|
|
4211
|
+
* The event reuses `TraceEvent_EventKind.LLM_CALL_POST` (per Declared
|
|
4212
|
+
* Deviation #1 — `LLM_CALL_OUTCOME` does not exist as a proto enum value
|
|
4213
|
+
* in `sidecar_adapter/v1/adapter.proto` yet).
|
|
4214
|
+
*
|
|
4215
|
+
* TODO(GH-issue-TBD): proto bump for `LLM_CALL_OUTCOME` +
|
|
4216
|
+
* sidecar `x-spendguard-reason-code` trailer extension. Both deferred to
|
|
4217
|
+
* the cross-component slice that touches `proto/` and
|
|
4218
|
+
* `services/sidecar/`. Track at
|
|
4219
|
+
* https://github.com/m24927605/agentic-spendguard/issues/TBD-proto-bump-llm-call-outcome
|
|
4220
|
+
* (R2 follow-up; not in scope for D05 SLICE 5).
|
|
4221
|
+
*
|
|
4222
|
+
* The `outcome` field on the inner `LlmCallPostPayload` carries the
|
|
4223
|
+
* semantic:
|
|
4224
|
+
*
|
|
4225
|
+
* - `outcomeKind === "SUCCESS"` → `LlmCallPostPayload_Outcome.SUCCESS`
|
|
4226
|
+
* - `outcomeKind === "FAILURE"` → `LlmCallPostPayload_Outcome.PROVIDER_ERROR`
|
|
4227
|
+
*
|
|
4228
|
+
* Actuals (`actualInputTokens` / `actualOutputTokens`) prefer the SLICE 5
|
|
4229
|
+
* `*Wire` fields when supplied (int64-as-string form), falling back to
|
|
4230
|
+
* the SLICE 4 numeric `actualInputTokens` / `actualOutputTokens` shape so
|
|
4231
|
+
* adapters do not need to double-specify. `actualErrorMessage` is threaded
|
|
4232
|
+
* onto `TraceEvent.providerResponseMetadata` as a JSON envelope
|
|
4233
|
+
* `{"error_message": "..."}` only when `outcomeKind === "FAILURE"`.
|
|
4234
|
+
*
|
|
4235
|
+
* `estimatedAmountAtomic` is intentionally set to an empty string on the
|
|
4236
|
+
* outcome event — the first event already booked the commit; the outcome
|
|
4237
|
+
* event only carries observation, not commit semantics. The sidecar will
|
|
4238
|
+
* surface a rejection ack if it requires the field (`mock-sidecar`'s tests
|
|
4239
|
+
* lock this in).
|
|
4240
|
+
*
|
|
4241
|
+
* @private
|
|
4242
|
+
*/
|
|
4243
|
+
buildLlmCallOutcomeEvent(req) {
|
|
4244
|
+
if (this.handshakeResult === null) {
|
|
4245
|
+
throw new HandshakeError("internal: buildLlmCallOutcomeEvent without handshake");
|
|
4246
|
+
}
|
|
4247
|
+
if (req.outcomeKind === void 0) {
|
|
4248
|
+
throw new SpendGuardError(
|
|
4249
|
+
"internal: buildLlmCallOutcomeEvent called without outcomeKind set"
|
|
4250
|
+
);
|
|
4251
|
+
}
|
|
4252
|
+
const ts = wallClockToTimestamp(Date.now());
|
|
4253
|
+
const inputWire = req.actualInputTokensWire ?? (req.actualInputTokens !== void 0 ? String(req.actualInputTokens) : void 0);
|
|
4254
|
+
const outputWire = req.actualOutputTokensWire ?? (req.actualOutputTokens !== void 0 ? String(req.actualOutputTokens) : void 0);
|
|
4255
|
+
const outcomeEnum = req.outcomeKind === "SUCCESS" ? 1 /* SUCCESS */ : 2 /* PROVIDER_ERROR */;
|
|
4256
|
+
const errorMessageEnvelope = req.outcomeKind === "FAILURE" && req.actualErrorMessage !== void 0 ? JSON.stringify({ error_message: req.actualErrorMessage }) : req.providerResponseMetadata ?? "";
|
|
4257
|
+
return {
|
|
4258
|
+
sessionId: this.handshakeResult.sessionId,
|
|
4259
|
+
trace: buildTraceContext(req.traceparent ?? "", req.tracestate ?? ""),
|
|
4260
|
+
ids: {
|
|
4261
|
+
runId: req.runId,
|
|
4262
|
+
stepId: req.stepId,
|
|
4263
|
+
llmCallId: req.llmCallId,
|
|
4264
|
+
toolCallId: "",
|
|
4265
|
+
decisionId: req.decisionId,
|
|
4266
|
+
snapshotId: ""
|
|
4267
|
+
},
|
|
4268
|
+
kind: 4 /* LLM_CALL_POST */,
|
|
4269
|
+
eventTime: ts,
|
|
4270
|
+
payload: {
|
|
4271
|
+
oneofKind: "llmCallPost",
|
|
4272
|
+
llmCallPost: {
|
|
4273
|
+
reservationId: req.reservationId,
|
|
4274
|
+
providerReportedAmountAtomic: "",
|
|
4275
|
+
unit: mapUnitRef2(req.unit),
|
|
4276
|
+
pricing: {
|
|
4277
|
+
pricingVersion: req.pricing.pricingVersion,
|
|
4278
|
+
priceSnapshotHash: req.pricing.pricingHash,
|
|
4279
|
+
// HARDEN_D05_WI — thread the full freeze tuple (omitted → "").
|
|
4280
|
+
fxRateVersion: req.pricing.fxRateVersion ?? "",
|
|
4281
|
+
unitConversionVersion: req.pricing.unitConversionVersion ?? ""
|
|
4282
|
+
},
|
|
4283
|
+
providerEventId: req.providerEventId,
|
|
4284
|
+
outcome: outcomeEnum,
|
|
4285
|
+
// The outcome companion event carries observation; the booking
|
|
4286
|
+
// amount stayed on the first event. Empty string is wire-equivalent
|
|
4287
|
+
// to "absent" for the proto3 string field.
|
|
4288
|
+
estimatedAmountAtomic: "",
|
|
4289
|
+
...inputWire !== void 0 ? { actualInputTokens: inputWire } : {},
|
|
4290
|
+
...outputWire !== void 0 ? { actualOutputTokens: outputWire } : {},
|
|
4291
|
+
...req.deltaBRatio !== void 0 ? { deltaBRatio: req.deltaBRatio } : {},
|
|
4292
|
+
...req.deltaCRatio !== void 0 ? { deltaCRatio: req.deltaCRatio } : {}
|
|
4293
|
+
}
|
|
4294
|
+
},
|
|
4295
|
+
providerResponseMetadata: errorMessageEnvelope
|
|
4296
|
+
};
|
|
4297
|
+
}
|
|
4298
|
+
};
|
|
4299
|
+
function errorMessage2(err) {
|
|
4300
|
+
if (err instanceof Error) return err.message;
|
|
4301
|
+
if (typeof err === "string") return err;
|
|
4302
|
+
try {
|
|
4303
|
+
return JSON.stringify(err);
|
|
4304
|
+
} catch {
|
|
4305
|
+
return String(err);
|
|
4306
|
+
}
|
|
4307
|
+
}
|
|
4308
|
+
function toHex(n) {
|
|
4309
|
+
return `0x${n.toString(16)}`;
|
|
4310
|
+
}
|
|
4311
|
+
function triggerEnumOf(name) {
|
|
4312
|
+
switch (name) {
|
|
4313
|
+
case "RUN_PRE":
|
|
4314
|
+
return 1 /* RUN_PRE */;
|
|
4315
|
+
case "AGENT_STEP_PRE":
|
|
4316
|
+
return 2 /* AGENT_STEP_PRE */;
|
|
4317
|
+
case "LLM_CALL_PRE":
|
|
4318
|
+
return 3 /* LLM_CALL_PRE */;
|
|
4319
|
+
case "TOOL_CALL_PRE":
|
|
4320
|
+
return 4 /* TOOL_CALL_PRE */;
|
|
4321
|
+
default: {
|
|
4322
|
+
throw new SpendGuardError(`unknown trigger: ${String(name)}`);
|
|
4323
|
+
}
|
|
4324
|
+
}
|
|
4325
|
+
}
|
|
4326
|
+
function llmOutcomeEnumOf(name) {
|
|
4327
|
+
switch (name) {
|
|
4328
|
+
case "SUCCESS":
|
|
4329
|
+
return 1 /* SUCCESS */;
|
|
4330
|
+
case "PROVIDER_ERROR":
|
|
4331
|
+
return 2 /* PROVIDER_ERROR */;
|
|
4332
|
+
case "CLIENT_TIMEOUT":
|
|
4333
|
+
return 3 /* CLIENT_TIMEOUT */;
|
|
4334
|
+
case "RUN_ABORTED":
|
|
4335
|
+
return 4 /* RUN_ABORTED */;
|
|
4336
|
+
default: {
|
|
4337
|
+
throw new SpendGuardError(`unknown llm outcome: ${String(name)}`);
|
|
4338
|
+
}
|
|
4339
|
+
}
|
|
4340
|
+
}
|
|
4341
|
+
function decisionEnumName(value) {
|
|
4342
|
+
switch (value) {
|
|
4343
|
+
case 1 /* CONTINUE */:
|
|
4344
|
+
return "CONTINUE";
|
|
4345
|
+
case 2 /* DEGRADE */:
|
|
4346
|
+
return "DEGRADE";
|
|
4347
|
+
case 3 /* SKIP */:
|
|
4348
|
+
return "SKIP";
|
|
4349
|
+
case 4 /* STOP */:
|
|
4350
|
+
return "STOP";
|
|
4351
|
+
case 5 /* REQUIRE_APPROVAL */:
|
|
4352
|
+
return "REQUIRE_APPROVAL";
|
|
4353
|
+
case 6 /* STOP_RUN_PROJECTION */:
|
|
4354
|
+
return "STOP_RUN_PROJECTION";
|
|
4355
|
+
default:
|
|
4356
|
+
return "UNKNOWN";
|
|
4357
|
+
}
|
|
4358
|
+
}
|
|
4359
|
+
function buildTraceContext(traceparent, tracestate) {
|
|
4360
|
+
if (traceparent === "") {
|
|
4361
|
+
return {
|
|
4362
|
+
traceId: "",
|
|
4363
|
+
spanId: "",
|
|
4364
|
+
parentSpanId: "",
|
|
4365
|
+
traceState: tracestate
|
|
4366
|
+
};
|
|
4367
|
+
}
|
|
4368
|
+
const parts = traceparent.split("-");
|
|
4369
|
+
if (parts.length !== 4 || parts[1]?.length !== 32 || parts[2]?.length !== 16) {
|
|
4370
|
+
return {
|
|
4371
|
+
traceId: "",
|
|
4372
|
+
spanId: "",
|
|
4373
|
+
parentSpanId: "",
|
|
4374
|
+
traceState: tracestate
|
|
4375
|
+
};
|
|
4376
|
+
}
|
|
4377
|
+
return {
|
|
4378
|
+
traceId: parts[1],
|
|
4379
|
+
spanId: parts[2],
|
|
4380
|
+
// Per Python parity, reuse upstream span_id as parent_span_id — the next
|
|
4381
|
+
// event is a child span from the sidecar's perspective.
|
|
4382
|
+
parentSpanId: parts[2],
|
|
4383
|
+
traceState: tracestate
|
|
4384
|
+
};
|
|
4385
|
+
}
|
|
4386
|
+
function mapUnitRef2(unit) {
|
|
4387
|
+
return {
|
|
4388
|
+
unitId: unit.unitId ?? "",
|
|
4389
|
+
kind: 0,
|
|
4390
|
+
currency: "",
|
|
4391
|
+
unitName: unit.unit,
|
|
4392
|
+
tokenKind: "",
|
|
4393
|
+
modelFamily: "",
|
|
4394
|
+
creditProgram: ""
|
|
4395
|
+
};
|
|
4396
|
+
}
|
|
4397
|
+
function mapClaimEstimate(estimate) {
|
|
4398
|
+
return {
|
|
4399
|
+
tokenizerTier: estimate.tokenizerTier ?? "",
|
|
4400
|
+
tokenizerVersionId: estimate.tokenizerVersionId ?? "",
|
|
4401
|
+
inputTokens: int64Field(estimate.inputTokens),
|
|
4402
|
+
predictedATokens: int64Field(estimate.predictedATokens),
|
|
4403
|
+
predictedBTokens: int64Field(estimate.predictedBTokens),
|
|
4404
|
+
predictedCTokens: int64Field(estimate.predictedCTokens),
|
|
4405
|
+
reservedStrategy: estimate.reservedStrategy ?? "",
|
|
4406
|
+
predictionStrategyUsed: estimate.predictionStrategyUsed ?? "",
|
|
4407
|
+
predictionPolicyUsed: estimate.predictionPolicyUsed ?? "",
|
|
4408
|
+
predictionConfidence: estimate.predictionConfidence ?? 0,
|
|
4409
|
+
predictionSampleSize: int64Field(estimate.predictionSampleSize),
|
|
4410
|
+
coldStartLayerUsed: estimate.coldStartLayerUsed ?? "",
|
|
4411
|
+
classifierVersion: estimate.classifierVersion ?? "",
|
|
4412
|
+
fingerprintVersion: estimate.fingerprintVersion ?? "",
|
|
4413
|
+
promptClassFingerprint: estimate.promptClassFingerprint ?? "",
|
|
4414
|
+
runProjectionAtDecisionAtomic: int64Field(estimate.runProjectionAtDecisionAtomic),
|
|
4415
|
+
runPredictedRemainingSteps: estimate.runPredictedRemainingSteps ?? 0,
|
|
4416
|
+
runStepsCompletedSoFar: int64Field(estimate.runStepsCompletedSoFar),
|
|
4417
|
+
runCodeTriggered: estimate.runCodeTriggered ?? "",
|
|
4418
|
+
model: estimate.model ?? "",
|
|
4419
|
+
promptClass: estimate.promptClass ?? ""
|
|
4420
|
+
};
|
|
4421
|
+
}
|
|
4422
|
+
function int64Field(v) {
|
|
4423
|
+
if (v === void 0) return "0";
|
|
4424
|
+
return typeof v === "bigint" ? v.toString() : Math.trunc(v).toString();
|
|
4425
|
+
}
|
|
4426
|
+
function wallClockToTimestamp(epochMs) {
|
|
4427
|
+
const seconds = Math.floor(epochMs / 1e3);
|
|
4428
|
+
const nanos = epochMs % 1e3 * 1e6;
|
|
4429
|
+
return { seconds: seconds.toString(), nanos };
|
|
4430
|
+
}
|
|
4431
|
+
function jsonValueToStructValue(value) {
|
|
4432
|
+
if (value === null || value === void 0) {
|
|
4433
|
+
return { kind: { oneofKind: "nullValue", nullValue: 0 } };
|
|
4434
|
+
}
|
|
4435
|
+
if (typeof value === "boolean") {
|
|
4436
|
+
return { kind: { oneofKind: "boolValue", boolValue: value } };
|
|
4437
|
+
}
|
|
4438
|
+
if (typeof value === "number") {
|
|
4439
|
+
return { kind: { oneofKind: "numberValue", numberValue: value } };
|
|
4440
|
+
}
|
|
4441
|
+
if (typeof value === "bigint") {
|
|
4442
|
+
return { kind: { oneofKind: "stringValue", stringValue: value.toString() } };
|
|
4443
|
+
}
|
|
4444
|
+
if (typeof value === "string") {
|
|
4445
|
+
return { kind: { oneofKind: "stringValue", stringValue: value } };
|
|
4446
|
+
}
|
|
4447
|
+
if (Array.isArray(value)) {
|
|
4448
|
+
return {
|
|
4449
|
+
kind: {
|
|
4450
|
+
oneofKind: "listValue",
|
|
4451
|
+
listValue: { values: value.map(jsonValueToStructValue) }
|
|
4452
|
+
}
|
|
4453
|
+
};
|
|
4454
|
+
}
|
|
4455
|
+
if (value instanceof Date) {
|
|
4456
|
+
return { kind: { oneofKind: "stringValue", stringValue: value.toISOString() } };
|
|
4457
|
+
}
|
|
4458
|
+
if (typeof value === "object") {
|
|
4459
|
+
const fields = {};
|
|
4460
|
+
for (const [k, v] of Object.entries(value)) {
|
|
4461
|
+
fields[k] = jsonValueToStructValue(v);
|
|
4462
|
+
}
|
|
4463
|
+
return {
|
|
4464
|
+
kind: { oneofKind: "structValue", structValue: { fields } }
|
|
4465
|
+
};
|
|
4466
|
+
}
|
|
4467
|
+
return { kind: { oneofKind: "stringValue", stringValue: String(value) } };
|
|
4468
|
+
}
|
|
4469
|
+
function mapDecisionResponse(resp, tenantId) {
|
|
4470
|
+
const name = decisionEnumName(resp.decision);
|
|
4471
|
+
if (name === "CONTINUE" || name === "DEGRADE") {
|
|
4472
|
+
return {
|
|
4473
|
+
decisionId: resp.decisionId,
|
|
4474
|
+
auditDecisionEventId: resp.auditDecisionEventId,
|
|
4475
|
+
decision: name,
|
|
4476
|
+
mutationPatchJson: resp.mutationPatchJson,
|
|
4477
|
+
effectHash: resp.effectHash ?? new Uint8Array(),
|
|
4478
|
+
ledgerTransactionId: resp.ledgerTransactionId,
|
|
4479
|
+
reservationIds: Object.freeze([...resp.reservationIds]),
|
|
4480
|
+
ttlExpiresAtSeconds: Number(resp.ttlExpiresAt?.seconds ?? 0),
|
|
4481
|
+
reasonCodes: Object.freeze([...resp.reasonCodes]),
|
|
4482
|
+
matchedRuleIds: Object.freeze([...resp.matchedRuleIds])
|
|
4483
|
+
};
|
|
4484
|
+
}
|
|
4485
|
+
if (name === "STOP" || name === "STOP_RUN_PROJECTION") {
|
|
4486
|
+
throw new DecisionStopped(
|
|
4487
|
+
`sidecar ${name} terminal=${resp.terminal} reasons=${JSON.stringify(resp.reasonCodes)}`,
|
|
4488
|
+
{
|
|
4489
|
+
decisionId: resp.decisionId,
|
|
4490
|
+
reasonCodes: [...resp.reasonCodes],
|
|
4491
|
+
...resp.auditDecisionEventId ? { auditDecisionEventId: resp.auditDecisionEventId } : {},
|
|
4492
|
+
matchedRuleIds: [...resp.matchedRuleIds]
|
|
4493
|
+
}
|
|
4494
|
+
);
|
|
4495
|
+
}
|
|
4496
|
+
if (name === "SKIP") {
|
|
4497
|
+
throw new DecisionSkipped(`sidecar SKIP reasons=${JSON.stringify(resp.reasonCodes)}`, {
|
|
4498
|
+
decisionId: resp.decisionId,
|
|
4499
|
+
reasonCodes: [...resp.reasonCodes],
|
|
4500
|
+
...resp.auditDecisionEventId ? { auditDecisionEventId: resp.auditDecisionEventId } : {},
|
|
4501
|
+
matchedRuleIds: [...resp.matchedRuleIds]
|
|
4502
|
+
});
|
|
4503
|
+
}
|
|
4504
|
+
if (name === "REQUIRE_APPROVAL") {
|
|
4505
|
+
throw new ApprovalRequired(
|
|
4506
|
+
`sidecar REQUIRE_APPROVAL approval_request_id=${resp.approvalRequestId}`,
|
|
4507
|
+
{
|
|
4508
|
+
decisionId: resp.decisionId,
|
|
4509
|
+
approvalRequestId: resp.approvalRequestId,
|
|
4510
|
+
...resp.approverRole ? { approverRole: resp.approverRole } : {},
|
|
4511
|
+
reasonCodes: [...resp.reasonCodes],
|
|
4512
|
+
...resp.auditDecisionEventId ? { auditDecisionEventId: resp.auditDecisionEventId } : {},
|
|
4513
|
+
matchedRuleIds: [...resp.matchedRuleIds],
|
|
4514
|
+
tenantId
|
|
4515
|
+
}
|
|
4516
|
+
);
|
|
4517
|
+
}
|
|
4518
|
+
throw new DecisionDenied(`sidecar returned unknown decision=${resp.decision}`, {
|
|
4519
|
+
decisionId: resp.decisionId,
|
|
4520
|
+
reasonCodes: [...resp.reasonCodes],
|
|
4521
|
+
...resp.auditDecisionEventId ? { auditDecisionEventId: resp.auditDecisionEventId } : {},
|
|
4522
|
+
matchedRuleIds: [...resp.matchedRuleIds]
|
|
4523
|
+
});
|
|
4524
|
+
}
|
|
4525
|
+
function computeReserveBodyHash(req) {
|
|
4526
|
+
const { idempotencyKey: _omit, ...identity } = req;
|
|
4527
|
+
return createHash("sha256").update(canonicalStableJson(identity), "utf8").digest("hex");
|
|
4528
|
+
}
|
|
4529
|
+
function canonicalStableJson(value) {
|
|
4530
|
+
if (value === null) return "null";
|
|
4531
|
+
if (typeof value === "bigint") return `"bigint:${value.toString()}"`;
|
|
4532
|
+
if (value instanceof Uint8Array) return `"bytes:${Buffer.from(value).toString("base64")}"`;
|
|
4533
|
+
if (Array.isArray(value)) {
|
|
4534
|
+
return `[${value.map((v) => canonicalStableJson(v)).join(",")}]`;
|
|
4535
|
+
}
|
|
4536
|
+
if (typeof value === "object") {
|
|
4537
|
+
const obj = value;
|
|
4538
|
+
const keys = Object.keys(obj).filter((k) => obj[k] !== void 0).sort();
|
|
4539
|
+
const parts = keys.map((k) => `${JSON.stringify(k)}:${canonicalStableJson(obj[k])}`);
|
|
4540
|
+
return `{${parts.join(",")}}`;
|
|
4541
|
+
}
|
|
4542
|
+
return JSON.stringify(value);
|
|
4543
|
+
}
|
|
4544
|
+
var REASON_CODE_HEADER = "x-spendguard-reason-code";
|
|
4545
|
+
var REASON_CODE_PREFIXES = [
|
|
4546
|
+
// Forward-compat: bracket-tagged emission from the resume path.
|
|
4547
|
+
["[bundle_hot_reloaded]", "BUNDLE_HOT_RELOADED"],
|
|
4548
|
+
// Defensive: matches the test fixture wording ("bundle hot-reloaded ...")
|
|
4549
|
+
// and any future un-bracketed sidecar emission without coupling to exact
|
|
4550
|
+
// detail text.
|
|
4551
|
+
["bundle hot-reload", "BUNDLE_HOT_RELOADED"],
|
|
4552
|
+
// DomainError::IdempotencyConflict (error.rs:44-45).
|
|
4553
|
+
["idempotency conflict", "IDEMPOTENCY_CONFLICT"],
|
|
4554
|
+
// FAILED_PRECONDITION cluster mapped to BUDGET_EXCEEDED — the five
|
|
4555
|
+
// variants from error.rs (lines 26-39) that to_status() routes to
|
|
4556
|
+
// Status::failed_precondition (excluding IdempotencyConflict above).
|
|
4557
|
+
["reservation state conflict", "BUDGET_EXCEEDED"],
|
|
4558
|
+
["reservation ttl expired", "BUDGET_EXCEEDED"],
|
|
4559
|
+
["pricing freeze mismatch", "BUDGET_EXCEEDED"],
|
|
4560
|
+
["overrun reservation", "BUDGET_EXCEEDED"],
|
|
4561
|
+
["multi-reservation commit deferred", "BUDGET_EXCEEDED"]
|
|
4562
|
+
];
|
|
4563
|
+
function mapGrpcStatusToError(err, ctx) {
|
|
4564
|
+
if (err instanceof SpendGuardError) return err;
|
|
4565
|
+
if (!(err instanceof RpcError)) {
|
|
4566
|
+
return new SpendGuardError(`${ctx.rpc} failed: ${errorMessage2(err)}`, { cause: err });
|
|
4567
|
+
}
|
|
4568
|
+
const code = err.code;
|
|
4569
|
+
const cause = err;
|
|
4570
|
+
if (code === "UNAVAILABLE" || code === "DEADLINE_EXCEEDED" || code === "CANCELLED") {
|
|
4571
|
+
return new SidecarUnavailable(
|
|
4572
|
+
`${ctx.rpc} failed: code=${code} detail=${JSON.stringify(err.message)}`,
|
|
4573
|
+
{ cause }
|
|
4574
|
+
);
|
|
4575
|
+
}
|
|
4576
|
+
if (code === "FAILED_PRECONDITION") {
|
|
4577
|
+
const reason = readReasonCode(err);
|
|
4578
|
+
if (reason === "BUNDLE_HOT_RELOADED") {
|
|
4579
|
+
return new ApprovalBundleHotReloadedError(
|
|
4580
|
+
`${ctx.rpc} failed: code=FAILED_PRECONDITION reason=BUNDLE_HOT_RELOADED detail=${JSON.stringify(err.message)}`,
|
|
4581
|
+
{ originalBundleHash: "", currentBundleHash: "" },
|
|
4582
|
+
{ cause }
|
|
4583
|
+
);
|
|
4584
|
+
}
|
|
4585
|
+
const reasonSuffix = reason !== void 0 ? ` reason=${reason}` : "";
|
|
4586
|
+
return new MutationApplyFailed(
|
|
4587
|
+
`${ctx.rpc} failed: code=FAILED_PRECONDITION${reasonSuffix} detail=${JSON.stringify(err.message)}`,
|
|
4588
|
+
{ cause }
|
|
4589
|
+
);
|
|
4590
|
+
}
|
|
4591
|
+
if (code === "NOT_FOUND") {
|
|
4592
|
+
if (ctx.releaseNotFoundAsPlain === true) {
|
|
4593
|
+
return new SpendGuardError("reservation not found", { cause });
|
|
4594
|
+
}
|
|
4595
|
+
return new SpendGuardError(
|
|
4596
|
+
`${ctx.rpc} failed: code=NOT_FOUND detail=${JSON.stringify(err.message)}`,
|
|
4597
|
+
{ cause }
|
|
4598
|
+
);
|
|
4599
|
+
}
|
|
4600
|
+
if (code === "ABORTED") {
|
|
4601
|
+
return new SpendGuardError(
|
|
4602
|
+
`${ctx.rpc} failed: code=ABORTED detail=${JSON.stringify(err.message)}`,
|
|
4603
|
+
{ cause }
|
|
4604
|
+
);
|
|
4605
|
+
}
|
|
4606
|
+
return new SpendGuardError(
|
|
4607
|
+
`${ctx.rpc} failed: code=${code} detail=${JSON.stringify(err.message)}`,
|
|
4608
|
+
{ cause }
|
|
4609
|
+
);
|
|
4610
|
+
}
|
|
4611
|
+
function readReasonCode(err) {
|
|
4612
|
+
const msg = err.message;
|
|
4613
|
+
if (typeof msg === "string" && msg.length > 0) {
|
|
4614
|
+
const lower = msg.toLowerCase();
|
|
4615
|
+
for (const [prefix, code] of REASON_CODE_PREFIXES) {
|
|
4616
|
+
if (lower.startsWith(prefix)) return code;
|
|
4617
|
+
}
|
|
4618
|
+
}
|
|
4619
|
+
const raw = err.meta?.[REASON_CODE_HEADER];
|
|
4620
|
+
if (raw === void 0) return void 0;
|
|
4621
|
+
if (typeof raw === "string") return raw;
|
|
4622
|
+
if (Array.isArray(raw) && raw.length > 0 && typeof raw[0] === "string") return raw[0];
|
|
4623
|
+
return void 0;
|
|
4624
|
+
}
|
|
4625
|
+
function buildAckRejectMessage(ack) {
|
|
4626
|
+
const statusName = ackStatusName(ack.status);
|
|
4627
|
+
const code = ack.error?.code ?? 0;
|
|
4628
|
+
const message = ack.error?.message ?? "";
|
|
4629
|
+
return `EmitTraceEvents rejected: status=${statusName} code=${code} message=${JSON.stringify(message)}`;
|
|
4630
|
+
}
|
|
4631
|
+
function ackStatusName(value) {
|
|
4632
|
+
switch (value) {
|
|
4633
|
+
case 1 /* ACCEPTED */:
|
|
4634
|
+
return "ACCEPTED";
|
|
4635
|
+
case 2 /* QUARANTINED */:
|
|
4636
|
+
return "QUARANTINED";
|
|
4637
|
+
case 3 /* REJECTED */:
|
|
4638
|
+
return "REJECTED";
|
|
4639
|
+
default:
|
|
4640
|
+
return `STATUS_${value}`;
|
|
4641
|
+
}
|
|
4642
|
+
}
|
|
4643
|
+
function makeDisabledHandshake() {
|
|
4644
|
+
return {
|
|
4645
|
+
sessionId: "disabled-noop-session",
|
|
4646
|
+
sidecarVersion: "disabled",
|
|
4647
|
+
schemaBundleId: "",
|
|
4648
|
+
schemaBundleHash: new Uint8Array(),
|
|
4649
|
+
contractBundleId: "",
|
|
4650
|
+
contractBundleHash: new Uint8Array(),
|
|
4651
|
+
capabilityRequired: 0,
|
|
4652
|
+
signingKeyId: "",
|
|
4653
|
+
announcementSignature: new Uint8Array()
|
|
4654
|
+
};
|
|
4655
|
+
}
|
|
4656
|
+
function makeDisabledDecision(req) {
|
|
4657
|
+
return {
|
|
4658
|
+
decisionId: req.decisionId,
|
|
4659
|
+
auditDecisionEventId: "",
|
|
4660
|
+
decision: "CONTINUE",
|
|
4661
|
+
mutationPatchJson: "",
|
|
4662
|
+
effectHash: new Uint8Array(),
|
|
4663
|
+
ledgerTransactionId: "",
|
|
4664
|
+
reservationIds: Object.freeze([]),
|
|
4665
|
+
ttlExpiresAtSeconds: 0,
|
|
4666
|
+
reasonCodes: Object.freeze(["disabled_mode"]),
|
|
4667
|
+
matchedRuleIds: Object.freeze([])
|
|
4668
|
+
};
|
|
4669
|
+
}
|
|
4670
|
+
function makeDisabledReleaseOutcome(req) {
|
|
4671
|
+
return {
|
|
4672
|
+
auditEventSignature: new Uint8Array(),
|
|
4673
|
+
ledgerTransactionId: "",
|
|
4674
|
+
releasedReservationIds: Object.freeze([req.reservationId])
|
|
4675
|
+
};
|
|
4676
|
+
}
|
|
4677
|
+
function makeDisabledReserveSessionOutcome(req) {
|
|
4678
|
+
return {
|
|
4679
|
+
kind: "accepted",
|
|
4680
|
+
sessionReservationId: `disabled:${req.sessionId || "session"}`,
|
|
4681
|
+
ledgerTransactionId: "",
|
|
4682
|
+
auditSessionEventId: "",
|
|
4683
|
+
ttlExpiresAt: null,
|
|
4684
|
+
reservedAmountAtomic: req.estimatedAmountAtomic,
|
|
4685
|
+
remainingAmountAtomic: req.estimatedAmountAtomic
|
|
4686
|
+
};
|
|
4687
|
+
}
|
|
4688
|
+
function makeDisabledCommitSessionDeltaOutcome(req) {
|
|
4689
|
+
return {
|
|
4690
|
+
sessionReservationId: req.sessionReservationId,
|
|
4691
|
+
streamingCommitId: req.streamingCommitId,
|
|
4692
|
+
ledgerTransactionId: "",
|
|
4693
|
+
auditSessionEventId: "",
|
|
4694
|
+
committedDeltaAtomic: req.amountAtomicDelta,
|
|
4695
|
+
cumulativeCommittedAtomic: req.amountAtomicDelta,
|
|
4696
|
+
remainingAmountAtomic: "0",
|
|
4697
|
+
recordedAt: null
|
|
4698
|
+
};
|
|
4699
|
+
}
|
|
4700
|
+
function makeDisabledReleaseSessionOutcome(req) {
|
|
4701
|
+
return {
|
|
4702
|
+
sessionReservationId: req.sessionReservationId,
|
|
4703
|
+
ledgerTransactionId: "",
|
|
4704
|
+
auditSessionEventId: "",
|
|
4705
|
+
releasedAmountAtomic: "0",
|
|
4706
|
+
committedAmountAtomic: "0",
|
|
4707
|
+
recordedAt: null
|
|
4708
|
+
};
|
|
4709
|
+
}
|
|
4710
|
+
function makeDisabledQueryBudgetResult(req) {
|
|
4711
|
+
return {
|
|
4712
|
+
availableAtomic: "0",
|
|
4713
|
+
reservedAtomic: "0",
|
|
4714
|
+
committedAtomic: "0",
|
|
4715
|
+
unit: { unit: "USD_MICROS", denomination: 1 },
|
|
4716
|
+
asOfSeconds: req.asOfSeconds ?? 0
|
|
4717
|
+
};
|
|
4718
|
+
}
|
|
4719
|
+
function buildReleaseRequest(req, sessionId) {
|
|
4720
|
+
return {
|
|
4721
|
+
reservationId: req.reservationId,
|
|
4722
|
+
idempotencyKey: req.idempotencyKey,
|
|
4723
|
+
reasonCodes: [...req.reasonCodes ?? []],
|
|
4724
|
+
tenantId: req.tenantId ?? "",
|
|
4725
|
+
workloadInstanceId: req.workloadInstanceId ?? "",
|
|
4726
|
+
sessionId
|
|
4727
|
+
};
|
|
4728
|
+
}
|
|
4729
|
+
function mapReserveSessionOutcome(resp) {
|
|
4730
|
+
switch (resp.outcome.oneofKind) {
|
|
4731
|
+
case "accepted": {
|
|
4732
|
+
const accepted = resp.outcome.accepted;
|
|
4733
|
+
return {
|
|
4734
|
+
kind: "accepted",
|
|
4735
|
+
sessionReservationId: accepted.sessionReservationId,
|
|
4736
|
+
ledgerTransactionId: accepted.ledgerTransactionId,
|
|
4737
|
+
auditSessionEventId: accepted.auditSessionEventId,
|
|
4738
|
+
ttlExpiresAt: timestampToDate(accepted.ttlExpiresAt),
|
|
4739
|
+
reservedAmountAtomic: accepted.reservedAmountAtomic,
|
|
4740
|
+
remainingAmountAtomic: accepted.remainingAmountAtomic
|
|
4741
|
+
};
|
|
4742
|
+
}
|
|
4743
|
+
case "denied": {
|
|
4744
|
+
const denied = resp.outcome.denied;
|
|
4745
|
+
return {
|
|
4746
|
+
kind: "denied",
|
|
4747
|
+
auditSessionEventId: denied.auditSessionEventId,
|
|
4748
|
+
reasonCodes: Object.freeze([...denied.reasonCodes]),
|
|
4749
|
+
matchedRuleIds: Object.freeze([...denied.matchedRuleIds]),
|
|
4750
|
+
...denied.error !== void 0 ? { error: denied.error } : {}
|
|
4751
|
+
};
|
|
4752
|
+
}
|
|
4753
|
+
case "error":
|
|
4754
|
+
throw new SpendGuardError(
|
|
4755
|
+
`sidecar reserveSession error code=${resp.outcome.error.code} message=${resp.outcome.error.message}`
|
|
4756
|
+
);
|
|
4757
|
+
default:
|
|
4758
|
+
throw new SpendGuardError("sidecar reserveSession returned empty outcome");
|
|
4759
|
+
}
|
|
4760
|
+
}
|
|
4761
|
+
function mapCommitSessionDeltaOutcome(resp) {
|
|
4762
|
+
switch (resp.outcome.oneofKind) {
|
|
4763
|
+
case "accepted": {
|
|
4764
|
+
const accepted = resp.outcome.accepted;
|
|
4765
|
+
return {
|
|
4766
|
+
sessionReservationId: accepted.sessionReservationId,
|
|
4767
|
+
streamingCommitId: accepted.streamingCommitId,
|
|
4768
|
+
ledgerTransactionId: accepted.ledgerTransactionId,
|
|
4769
|
+
auditSessionEventId: accepted.auditSessionEventId,
|
|
4770
|
+
committedDeltaAtomic: accepted.committedDeltaAtomic,
|
|
4771
|
+
cumulativeCommittedAtomic: accepted.cumulativeCommittedAtomic,
|
|
4772
|
+
remainingAmountAtomic: accepted.remainingAmountAtomic,
|
|
4773
|
+
recordedAt: timestampToDate(accepted.recordedAt)
|
|
4774
|
+
};
|
|
4775
|
+
}
|
|
4776
|
+
case "error":
|
|
4777
|
+
throw new SpendGuardError(
|
|
4778
|
+
`sidecar commitSessionDelta error code=${resp.outcome.error.code} message=${resp.outcome.error.message}`
|
|
4779
|
+
);
|
|
4780
|
+
default:
|
|
4781
|
+
throw new SpendGuardError("sidecar commitSessionDelta returned empty outcome");
|
|
4782
|
+
}
|
|
4783
|
+
}
|
|
4784
|
+
function mapReleaseSessionOutcome(resp) {
|
|
4785
|
+
switch (resp.outcome.oneofKind) {
|
|
4786
|
+
case "accepted": {
|
|
4787
|
+
const accepted = resp.outcome.accepted;
|
|
4788
|
+
return {
|
|
4789
|
+
sessionReservationId: accepted.sessionReservationId,
|
|
4790
|
+
ledgerTransactionId: accepted.ledgerTransactionId,
|
|
4791
|
+
auditSessionEventId: accepted.auditSessionEventId,
|
|
4792
|
+
releasedAmountAtomic: accepted.releasedAmountAtomic,
|
|
4793
|
+
committedAmountAtomic: accepted.committedAmountAtomic,
|
|
4794
|
+
recordedAt: timestampToDate(accepted.recordedAt)
|
|
4795
|
+
};
|
|
4796
|
+
}
|
|
4797
|
+
case "error":
|
|
4798
|
+
throw new SpendGuardError(
|
|
4799
|
+
`sidecar releaseSession error code=${resp.outcome.error.code} message=${resp.outcome.error.message}`
|
|
4800
|
+
);
|
|
4801
|
+
default:
|
|
4802
|
+
throw new SpendGuardError("sidecar releaseSession returned empty outcome");
|
|
4803
|
+
}
|
|
4804
|
+
}
|
|
4805
|
+
function mapReleaseResponse(resp) {
|
|
4806
|
+
return {
|
|
4807
|
+
auditEventSignature: resp.auditEventSignature ?? new Uint8Array(),
|
|
4808
|
+
ledgerTransactionId: resp.ledgerTransactionId,
|
|
4809
|
+
releasedReservationIds: Object.freeze([...resp.releasedReservationIds])
|
|
4810
|
+
};
|
|
4811
|
+
}
|
|
4812
|
+
|
|
4813
|
+
export { DEFAULT_CAPABILITY_LEVEL, DEFAULT_DECISION_TIMEOUT_MS, DEFAULT_HANDSHAKE_TIMEOUT_MS, DEFAULT_PROTOCOL_VERSION, DEFAULT_PUBLISH_TIMEOUT_MS, DEFAULT_TRACE_TIMEOUT_MS, REASON_CODE_PREFIXES, SpendGuardClient, computeReserveBodyHash };
|
|
4814
|
+
//# sourceMappingURL=client.js.map
|
|
4815
|
+
//# sourceMappingURL=client.js.map
|