@carrierllc/mcp 0.8.0 → 0.9.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/dist/{chunk-JROD4YAU.js → chunk-VACB3Z5V.js} +3 -2
- package/dist/chunk-VACB3Z5V.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/index.js +414 -165
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
- package/dist/chunk-JROD4YAU.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
subscriberIdParams,
|
|
38
38
|
usageOverPeriodParams,
|
|
39
39
|
verifyStorefront
|
|
40
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-VACB3Z5V.js";
|
|
41
41
|
import "./chunk-SHKKVIIA.js";
|
|
42
42
|
|
|
43
43
|
// src/index.ts
|
|
@@ -69,11 +69,11 @@ var OcsClient = class {
|
|
|
69
69
|
async call(method, params = {}) {
|
|
70
70
|
await acquireEndpointSlot(this.token, method, "interactive");
|
|
71
71
|
const url = `${this.baseUrl}/v1?token=${this.token}`;
|
|
72
|
-
const
|
|
72
|
+
const body2 = JSON.stringify({ [method]: params });
|
|
73
73
|
const res = await fetch(url, {
|
|
74
74
|
method: "POST",
|
|
75
75
|
headers: { "Content-Type": "application/json" },
|
|
76
|
-
body
|
|
76
|
+
body: body2
|
|
77
77
|
});
|
|
78
78
|
if (!res.ok) {
|
|
79
79
|
throw new OcsApiError(res.status, `HTTP ${res.status} ${res.statusText}`, method);
|
|
@@ -109,6 +109,17 @@ function getBillingPrimary(env) {
|
|
|
109
109
|
const raw = env.BILLING_PRIMARY;
|
|
110
110
|
return raw === "clerk" ? "clerk" : "stripe";
|
|
111
111
|
}
|
|
112
|
+
function platformOrgId(env) {
|
|
113
|
+
const raw = env.CARRIER_PLATFORM_ORG_ID;
|
|
114
|
+
if (typeof raw !== "string") return null;
|
|
115
|
+
const trimmed = raw.trim();
|
|
116
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
117
|
+
}
|
|
118
|
+
function isPlatformOperator(env, orgId) {
|
|
119
|
+
const platform = platformOrgId(env);
|
|
120
|
+
if (!platform) return false;
|
|
121
|
+
return Boolean(orgId) && orgId === platform;
|
|
122
|
+
}
|
|
112
123
|
async function checkCallQuota(env, sub, tier) {
|
|
113
124
|
const limit = TIER_CALL_LIMITS[tier];
|
|
114
125
|
const resetAt = firstDayNextMonth();
|
|
@@ -155,7 +166,7 @@ async function pushStripeUsageRecord(env, sub, quantity) {
|
|
|
155
166
|
if (!env.CARRIER_USERS) return;
|
|
156
167
|
const subItemId = await env.CARRIER_USERS.get(`stripe_sub_item_id:${sub}`);
|
|
157
168
|
if (!subItemId) return;
|
|
158
|
-
const
|
|
169
|
+
const body2 = new URLSearchParams({
|
|
159
170
|
quantity: String(quantity),
|
|
160
171
|
timestamp: String(Math.floor(Date.now() / 1e3)),
|
|
161
172
|
action: "increment"
|
|
@@ -168,7 +179,7 @@ async function pushStripeUsageRecord(env, sub, quantity) {
|
|
|
168
179
|
Authorization: `Bearer ${stripeKey}`,
|
|
169
180
|
"Content-Type": "application/x-www-form-urlencoded"
|
|
170
181
|
},
|
|
171
|
-
body:
|
|
182
|
+
body: body2.toString()
|
|
172
183
|
}
|
|
173
184
|
);
|
|
174
185
|
}
|
|
@@ -589,8 +600,8 @@ function wrapHandler(toolName, ocsMethod, requiredScope, ctx, handler) {
|
|
|
589
600
|
};
|
|
590
601
|
}
|
|
591
602
|
async function ocsCall(env, token2, method, params = {}) {
|
|
592
|
-
const
|
|
593
|
-
const result2 = await
|
|
603
|
+
const client2 = new OcsClient(env.CARRIER_OCS_BASE_URL, token2);
|
|
604
|
+
const result2 = await client2.call(method, params);
|
|
594
605
|
return {
|
|
595
606
|
content: [{ type: "text", text: JSON.stringify(result2, null, 2) }]
|
|
596
607
|
};
|
|
@@ -598,14 +609,14 @@ async function ocsCall(env, token2, method, params = {}) {
|
|
|
598
609
|
async function resolveSubscriberByIccid(env, token2, iccid, cache) {
|
|
599
610
|
const hit = cache.get(iccid);
|
|
600
611
|
if (hit) return hit;
|
|
601
|
-
const
|
|
602
|
-
const record = await
|
|
612
|
+
const client2 = new OcsClient(env.CARRIER_OCS_BASE_URL, token2);
|
|
613
|
+
const record = await client2.call("getSingleSubscriber", { iccid });
|
|
603
614
|
cache.set(iccid, record);
|
|
604
615
|
return record;
|
|
605
616
|
}
|
|
606
617
|
async function getDefaultResellerId(env, token2) {
|
|
607
|
-
const
|
|
608
|
-
const info = await
|
|
618
|
+
const client2 = new OcsClient(env.CARRIER_OCS_BASE_URL, token2);
|
|
619
|
+
const info = await client2.call("getResellerInfo", {});
|
|
609
620
|
const id = info?.id;
|
|
610
621
|
if (typeof id !== "number") {
|
|
611
622
|
throw new Error("Could not determine resellerId from getResellerInfo");
|
|
@@ -809,8 +820,8 @@ function registerAllTools(server2, ctx) {
|
|
|
809
820
|
ctx,
|
|
810
821
|
async (args, token2) => {
|
|
811
822
|
const params = buildListSubscriberParams(args);
|
|
812
|
-
const
|
|
813
|
-
const raw = await
|
|
823
|
+
const client2 = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
|
|
824
|
+
const raw = await client2.call("listSubscriber", params);
|
|
814
825
|
const payload = applySubscriberFilters(raw, args);
|
|
815
826
|
return {
|
|
816
827
|
content: [{ type: "text", text: JSON.stringify(payload, null, 2) }]
|
|
@@ -3286,8 +3297,8 @@ var ocsAppMethods = ocsSpec.v1_app_methods;
|
|
|
3286
3297
|
// src/intelligence.ts
|
|
3287
3298
|
async function safeCall(env, token2, method, params = {}) {
|
|
3288
3299
|
try {
|
|
3289
|
-
const
|
|
3290
|
-
const data = await
|
|
3300
|
+
const client2 = new OcsClient(env.CARRIER_OCS_BASE_URL, token2);
|
|
3301
|
+
const data = await client2.call(method, params);
|
|
3291
3302
|
return { data, error: null };
|
|
3292
3303
|
} catch (err7) {
|
|
3293
3304
|
return { data: null, error: err7 instanceof Error ? err7.message : String(err7) };
|
|
@@ -4304,8 +4315,8 @@ function registerAllBacklogTools(server2, ctx) {
|
|
|
4304
4315
|
ctx,
|
|
4305
4316
|
async ({ iccid, phone_number, phone_type }, token2) => {
|
|
4306
4317
|
const ocsMethod = phone_type === "fake" ? "affectSubscriberFakePhoneNumber" : "affectSubscriberRealPhoneNumber";
|
|
4307
|
-
const
|
|
4308
|
-
const result2 = await
|
|
4318
|
+
const client2 = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
|
|
4319
|
+
const result2 = await client2.call(ocsMethod, { subscriber: iccid, phoneNumber: phone_number });
|
|
4309
4320
|
return {
|
|
4310
4321
|
content: [{ type: "text", text: JSON.stringify(result2, null, 2) }]
|
|
4311
4322
|
};
|
|
@@ -4342,11 +4353,11 @@ function registerAllBacklogTools(server2, ctx) {
|
|
|
4342
4353
|
cell_id,
|
|
4343
4354
|
signal_strength
|
|
4344
4355
|
}, token2) => {
|
|
4345
|
-
const
|
|
4356
|
+
const client2 = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
|
|
4346
4357
|
const params = { radioType: radio_type, mcc, mnc, lac };
|
|
4347
4358
|
if (cell_id !== void 0) params.cellId = cell_id;
|
|
4348
4359
|
if (signal_strength !== void 0) params.signalStrength = signal_strength;
|
|
4349
|
-
const result2 = await
|
|
4360
|
+
const result2 = await client2.call("getSubscriberLocationByCellId", params);
|
|
4350
4361
|
return {
|
|
4351
4362
|
content: [{ type: "text", text: JSON.stringify(result2, null, 2) }]
|
|
4352
4363
|
};
|
|
@@ -4370,16 +4381,16 @@ function registerAllBacklogTools(server2, ctx) {
|
|
|
4370
4381
|
ctx,
|
|
4371
4382
|
async ({ resellerId }, token2) => {
|
|
4372
4383
|
const id = resellerId ?? await (async () => {
|
|
4373
|
-
const
|
|
4374
|
-
const info = await
|
|
4384
|
+
const client3 = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
|
|
4385
|
+
const info = await client3.call("getResellerInfo", {});
|
|
4375
4386
|
const resolvedId = info?.id;
|
|
4376
4387
|
if (typeof resolvedId !== "number") {
|
|
4377
4388
|
throw new Error("Could not determine resellerId from getResellerInfo");
|
|
4378
4389
|
}
|
|
4379
4390
|
return resolvedId;
|
|
4380
4391
|
})();
|
|
4381
|
-
const
|
|
4382
|
-
const result2 = await
|
|
4392
|
+
const client2 = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
|
|
4393
|
+
const result2 = await client2.call("listDetailedDestinationList", id);
|
|
4383
4394
|
return {
|
|
4384
4395
|
content: [{ type: "text", text: JSON.stringify(result2, null, 2) }]
|
|
4385
4396
|
};
|
|
@@ -4404,8 +4415,8 @@ function registerAllBacklogTools(server2, ctx) {
|
|
|
4404
4415
|
BACKLOG_TOOL_SCOPES["modify_subscriber_mobile_plan"],
|
|
4405
4416
|
ctx,
|
|
4406
4417
|
async ({ iccid, mobile_plan_id }, token2) => {
|
|
4407
|
-
const
|
|
4408
|
-
const result2 = await
|
|
4418
|
+
const client2 = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
|
|
4419
|
+
const result2 = await client2.call(
|
|
4409
4420
|
"modifySubscriberMobilePlan",
|
|
4410
4421
|
{ subscriber: iccid, mobilePlanId: mobile_plan_id }
|
|
4411
4422
|
);
|
|
@@ -4438,8 +4449,8 @@ function registerAllBacklogTools(server2, ctx) {
|
|
|
4438
4449
|
const params = { subscriber: iccid, packageId: package_id };
|
|
4439
4450
|
if (start_date !== void 0) params.startDate = start_date;
|
|
4440
4451
|
if (end_date !== void 0) params.endDate = end_date;
|
|
4441
|
-
const
|
|
4442
|
-
const result2 = await
|
|
4452
|
+
const client2 = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
|
|
4453
|
+
const result2 = await client2.call(
|
|
4443
4454
|
"modifySubscriberPrepaidPackageActivePeriod",
|
|
4444
4455
|
params
|
|
4445
4456
|
);
|
|
@@ -4467,8 +4478,8 @@ function registerAllBacklogTools(server2, ctx) {
|
|
|
4467
4478
|
BACKLOG_TOOL_SCOPES["modify_subscriber_voip_plan"],
|
|
4468
4479
|
ctx,
|
|
4469
4480
|
async ({ iccid, voip_plan_id }, token2) => {
|
|
4470
|
-
const
|
|
4471
|
-
const result2 = await
|
|
4481
|
+
const client2 = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
|
|
4482
|
+
const result2 = await client2.call(
|
|
4472
4483
|
"modifySubscriberVoipPlan",
|
|
4473
4484
|
{ subscriber: iccid, voipPlanId: voip_plan_id }
|
|
4474
4485
|
);
|
|
@@ -4498,8 +4509,8 @@ function registerAllBacklogTools(server2, ctx) {
|
|
|
4498
4509
|
const cache = /* @__PURE__ */ new Map();
|
|
4499
4510
|
const sub = await resolveSubscriberByIccid(ctx.env, token2, iccid, cache);
|
|
4500
4511
|
const subscriberId = sub.id ?? sub.subscriberId ?? iccid;
|
|
4501
|
-
const
|
|
4502
|
-
const result2 = await
|
|
4512
|
+
const client2 = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
|
|
4513
|
+
const result2 = await client2.call(
|
|
4503
4514
|
"pushSteeringToSubs",
|
|
4504
4515
|
{ subscriber: subscriberId }
|
|
4505
4516
|
);
|
|
@@ -4526,8 +4537,8 @@ function registerAllBacklogTools(server2, ctx) {
|
|
|
4526
4537
|
BACKLOG_TOOL_SCOPES["reset_subscriber_gz_counter"],
|
|
4527
4538
|
ctx,
|
|
4528
4539
|
async ({ iccid }, token2) => {
|
|
4529
|
-
const
|
|
4530
|
-
const result2 = await
|
|
4540
|
+
const client2 = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
|
|
4541
|
+
const result2 = await client2.call("resetSubsGzCounter", { subscriber: iccid });
|
|
4531
4542
|
return {
|
|
4532
4543
|
content: [{ type: "text", text: JSON.stringify(result2, null, 2) }]
|
|
4533
4544
|
};
|
|
@@ -4550,14 +4561,14 @@ function registerAllBacklogTools(server2, ctx) {
|
|
|
4550
4561
|
BACKLOG_TOOL_SCOPES["carrier_webhook_config"],
|
|
4551
4562
|
ctx,
|
|
4552
4563
|
async ({ reseller_id }, token2) => {
|
|
4553
|
-
const
|
|
4564
|
+
const client2 = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
|
|
4554
4565
|
let resellerId = reseller_id;
|
|
4555
4566
|
if (resellerId === void 0) {
|
|
4556
4567
|
resellerId = await getDefaultResellerId(ctx.env, token2);
|
|
4557
4568
|
}
|
|
4558
4569
|
const params = {};
|
|
4559
4570
|
if (resellerId !== void 0) params.id = resellerId;
|
|
4560
|
-
const raw = await
|
|
4571
|
+
const raw = await client2.call("getResellerInfo", params);
|
|
4561
4572
|
const traffic = raw.trafficInfo ?? {};
|
|
4562
4573
|
const notification = raw.notificationInfo ?? {};
|
|
4563
4574
|
const result2 = {
|
|
@@ -4592,12 +4603,12 @@ function registerAllBacklogTools(server2, ctx) {
|
|
|
4592
4603
|
BACKLOG_TOOL_SCOPES["list_subscriber_voip_tariff"],
|
|
4593
4604
|
ctx,
|
|
4594
4605
|
async ({ reseller_id }, token2) => {
|
|
4595
|
-
const
|
|
4606
|
+
const client2 = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
|
|
4596
4607
|
const params = {};
|
|
4597
4608
|
if (reseller_id !== void 0) {
|
|
4598
4609
|
params.resellerId = reseller_id;
|
|
4599
4610
|
}
|
|
4600
|
-
const result2 = await
|
|
4611
|
+
const result2 = await client2.call("listSubscriberVoipTariff", params);
|
|
4601
4612
|
return {
|
|
4602
4613
|
content: [{ type: "text", text: JSON.stringify(result2, null, 2) }]
|
|
4603
4614
|
};
|
|
@@ -4622,8 +4633,8 @@ function registerAllBacklogTools(server2, ctx) {
|
|
|
4622
4633
|
BACKLOG_TOOL_SCOPES["list_voip_tariff_rule"],
|
|
4623
4634
|
ctx,
|
|
4624
4635
|
async ({ voip_plan_id }, token2) => {
|
|
4625
|
-
const
|
|
4626
|
-
const result2 = await
|
|
4636
|
+
const client2 = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
|
|
4637
|
+
const result2 = await client2.call("listVoipTariffRule", voip_plan_id);
|
|
4627
4638
|
return {
|
|
4628
4639
|
content: [{ type: "text", text: JSON.stringify(result2, null, 2) }]
|
|
4629
4640
|
};
|
|
@@ -4651,8 +4662,8 @@ function registerAllBacklogTools(server2, ctx) {
|
|
|
4651
4662
|
location_zone_id,
|
|
4652
4663
|
network_profile_id
|
|
4653
4664
|
}, token2) => {
|
|
4654
|
-
const
|
|
4655
|
-
const result2 = await
|
|
4665
|
+
const client2 = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
|
|
4666
|
+
const result2 = await client2.call("changeNetworkProfileOfLocationZone", {
|
|
4656
4667
|
locationZoneId: location_zone_id,
|
|
4657
4668
|
networkProfileId: network_profile_id
|
|
4658
4669
|
});
|
|
@@ -4664,8 +4675,197 @@ function registerAllBacklogTools(server2, ctx) {
|
|
|
4664
4675
|
);
|
|
4665
4676
|
}
|
|
4666
4677
|
|
|
4667
|
-
//
|
|
4678
|
+
// ../../packages/carrier-ai/dist/index.js
|
|
4668
4679
|
import { AwsClient } from "aws4fetch";
|
|
4680
|
+
var AI_TIER_POLICY = {
|
|
4681
|
+
free: { limit: 5, window: "day" },
|
|
4682
|
+
pro: { limit: 1e3, window: "month" },
|
|
4683
|
+
enterprise: { limit: 1e4, window: "month" },
|
|
4684
|
+
// Finite, deliberately. This was `Infinity` when the tier was introduced in
|
|
4685
|
+
// #762, and Infinity breaks in two ways that both hide themselves:
|
|
4686
|
+
//
|
|
4687
|
+
// 1. JSON.stringify(Infinity) is "null". The quota endpoint returned
|
|
4688
|
+
// {"limit":null,"remaining":null} and the console badge rendered
|
|
4689
|
+
// "1 of null used". That is the whole reason this was investigated.
|
|
4690
|
+
// 2. An infinite allowance is unmetered Bedrock. A staff account could
|
|
4691
|
+
// spend without bound and nothing would refuse it or show a number.
|
|
4692
|
+
//
|
|
4693
|
+
// 100,000 is roughly $580 of Haiku at the measured $0.0058/call. Nobody on
|
|
4694
|
+
// staff will reach it by using the product, and a runaway loop stops.
|
|
4695
|
+
superadmin: { limit: 1e5, window: "month" }
|
|
4696
|
+
};
|
|
4697
|
+
for (const [tier, policy] of Object.entries(AI_TIER_POLICY)) {
|
|
4698
|
+
if (!Number.isFinite(policy.limit) || policy.limit <= 0) {
|
|
4699
|
+
throw new Error(
|
|
4700
|
+
`AI_TIER_POLICY.${tier}.limit must be a positive finite number, got ${policy.limit}. A non-finite limit serialises to null in JSON and leaves spend unmetered.`
|
|
4701
|
+
);
|
|
4702
|
+
}
|
|
4703
|
+
}
|
|
4704
|
+
var PRELUDE_BYTES = 12;
|
|
4705
|
+
var MESSAGE_CRC_BYTES = 4;
|
|
4706
|
+
var MIN_FRAME_BYTES = PRELUDE_BYTES + MESSAGE_CRC_BYTES;
|
|
4707
|
+
var MAX_FRAME_BYTES = 16 * 1024 * 1024;
|
|
4708
|
+
var MAX_ENTRIES = 16;
|
|
4709
|
+
var MAX_KEY_LEN = 256;
|
|
4710
|
+
var MAX_VALUE_LEN = 256;
|
|
4711
|
+
var ALLOWED = /[^a-zA-Z0-9\s:_@$#=/+,\-.]/g;
|
|
4712
|
+
function clean(value, max) {
|
|
4713
|
+
return value.replace(ALLOWED, "").slice(0, max);
|
|
4714
|
+
}
|
|
4715
|
+
var REQUEST_METADATA_HEADER = "X-Amzn-Bedrock-Request-Metadata";
|
|
4716
|
+
function requestMetadata(attr2) {
|
|
4717
|
+
const out = {};
|
|
4718
|
+
const pairs = [
|
|
4719
|
+
["product", "carrier"],
|
|
4720
|
+
["org", attr2.orgId],
|
|
4721
|
+
["subaccount", attr2.subAccountId],
|
|
4722
|
+
["surface", attr2.surface],
|
|
4723
|
+
["tier", attr2.tier]
|
|
4724
|
+
];
|
|
4725
|
+
for (const [k, v] of pairs) {
|
|
4726
|
+
if (v === void 0 || v === "") continue;
|
|
4727
|
+
const key = clean(k, MAX_KEY_LEN);
|
|
4728
|
+
const value = clean(v, MAX_VALUE_LEN);
|
|
4729
|
+
if (key && value && Object.keys(out).length < MAX_ENTRIES) out[key] = value;
|
|
4730
|
+
}
|
|
4731
|
+
return Object.keys(out).length > 0 ? out : null;
|
|
4732
|
+
}
|
|
4733
|
+
var ZERO_USAGE = {
|
|
4734
|
+
inputTokens: 0,
|
|
4735
|
+
outputTokens: 0,
|
|
4736
|
+
cacheReadTokens: 0,
|
|
4737
|
+
cacheWriteTokens: 0
|
|
4738
|
+
};
|
|
4739
|
+
function extractUsage(payload) {
|
|
4740
|
+
if (!payload || typeof payload !== "object") return ZERO_USAGE;
|
|
4741
|
+
const root = payload;
|
|
4742
|
+
const holder = root.usage ?? root.message?.usage;
|
|
4743
|
+
if (!holder) return ZERO_USAGE;
|
|
4744
|
+
const num = (v) => {
|
|
4745
|
+
const n = Number(v);
|
|
4746
|
+
return Number.isFinite(n) && n > 0 ? n : 0;
|
|
4747
|
+
};
|
|
4748
|
+
return {
|
|
4749
|
+
inputTokens: num(holder.input_tokens),
|
|
4750
|
+
outputTokens: num(holder.output_tokens),
|
|
4751
|
+
cacheReadTokens: num(holder.cache_read_input_tokens),
|
|
4752
|
+
cacheWriteTokens: num(holder.cache_creation_input_tokens)
|
|
4753
|
+
};
|
|
4754
|
+
}
|
|
4755
|
+
var HAIKU_RATES = {
|
|
4756
|
+
inputPerMTok: 1,
|
|
4757
|
+
outputPerMTok: 5,
|
|
4758
|
+
cacheReadPerMTok: 0.1,
|
|
4759
|
+
cacheWritePerMTok: 1.25,
|
|
4760
|
+
asOf: "2026-08-22"
|
|
4761
|
+
};
|
|
4762
|
+
function estimateCostUsd(u, rates = HAIKU_RATES) {
|
|
4763
|
+
const perTok = (mtok) => mtok / 1e6;
|
|
4764
|
+
return u.inputTokens * perTok(rates.inputPerMTok) + u.outputTokens * perTok(rates.outputPerMTok) + u.cacheReadTokens * perTok(rates.cacheReadPerMTok) + u.cacheWriteTokens * perTok(rates.cacheWritePerMTok);
|
|
4765
|
+
}
|
|
4766
|
+
var DEFAULT_BEDROCK_REGION = "us-east-1";
|
|
4767
|
+
var DEFAULT_MODEL_ID = "us.anthropic.claude-haiku-4-5-20251001-v1:0";
|
|
4768
|
+
var BEDROCK_TIMEOUT_MS = 3e4;
|
|
4769
|
+
var BedrockRateLimitError = class extends Error {
|
|
4770
|
+
isRateLimit = true;
|
|
4771
|
+
/**
|
|
4772
|
+
* The raw `retry-after` header, when Bedrock sent one. Callers surface it as
|
|
4773
|
+
* the delay they tell the user to wait; without it they have to guess.
|
|
4774
|
+
*/
|
|
4775
|
+
retryAfter;
|
|
4776
|
+
constructor(message, retryAfter = null) {
|
|
4777
|
+
super(message);
|
|
4778
|
+
this.name = "BedrockRateLimitError";
|
|
4779
|
+
this.retryAfter = retryAfter;
|
|
4780
|
+
}
|
|
4781
|
+
};
|
|
4782
|
+
var BedrockError = class extends Error {
|
|
4783
|
+
constructor(message, status) {
|
|
4784
|
+
super(message);
|
|
4785
|
+
this.status = status;
|
|
4786
|
+
this.name = "BedrockError";
|
|
4787
|
+
}
|
|
4788
|
+
status;
|
|
4789
|
+
};
|
|
4790
|
+
function client(creds) {
|
|
4791
|
+
const region = creds.region ?? DEFAULT_BEDROCK_REGION;
|
|
4792
|
+
return {
|
|
4793
|
+
aws: new AwsClient({
|
|
4794
|
+
accessKeyId: creds.accessKeyId,
|
|
4795
|
+
secretAccessKey: creds.secretAccessKey,
|
|
4796
|
+
...creds.sessionToken ? { sessionToken: creds.sessionToken } : {},
|
|
4797
|
+
region,
|
|
4798
|
+
service: "bedrock"
|
|
4799
|
+
}),
|
|
4800
|
+
region,
|
|
4801
|
+
modelId: creds.modelId ?? DEFAULT_MODEL_ID
|
|
4802
|
+
};
|
|
4803
|
+
}
|
|
4804
|
+
function body(req) {
|
|
4805
|
+
return {
|
|
4806
|
+
anthropic_version: "bedrock-2023-05-31",
|
|
4807
|
+
max_tokens: req.maxTokens,
|
|
4808
|
+
...req.temperature !== void 0 ? { temperature: req.temperature } : {},
|
|
4809
|
+
system: [{ type: "text", text: req.system, cache_control: { type: "ephemeral" } }],
|
|
4810
|
+
messages: req.messages.map((m) => ({ role: m.role, content: m.content })),
|
|
4811
|
+
...req.tools ? { tools: req.tools, tool_choice: { type: "any" } } : {}
|
|
4812
|
+
};
|
|
4813
|
+
}
|
|
4814
|
+
function headersFor(req, accept) {
|
|
4815
|
+
const headers = {
|
|
4816
|
+
"Content-Type": "application/json",
|
|
4817
|
+
Accept: accept
|
|
4818
|
+
};
|
|
4819
|
+
const meta = req.attribution ? requestMetadata(req.attribution) : null;
|
|
4820
|
+
if (meta) headers[REQUEST_METADATA_HEADER] = JSON.stringify(meta);
|
|
4821
|
+
return headers;
|
|
4822
|
+
}
|
|
4823
|
+
function reportUsage(req, usage) {
|
|
4824
|
+
if (!req.onUsage) return;
|
|
4825
|
+
try {
|
|
4826
|
+
req.onUsage(usage);
|
|
4827
|
+
} catch {
|
|
4828
|
+
}
|
|
4829
|
+
}
|
|
4830
|
+
async function fail(resp) {
|
|
4831
|
+
const text = await resp.text().catch(() => "");
|
|
4832
|
+
if (resp.status === 429 || /throttl/i.test(text)) {
|
|
4833
|
+
throw new BedrockRateLimitError(
|
|
4834
|
+
text || "Bedrock throttled the request",
|
|
4835
|
+
resp.headers.get("retry-after")
|
|
4836
|
+
);
|
|
4837
|
+
}
|
|
4838
|
+
throw new BedrockError(text || `Bedrock returned HTTP ${resp.status}`, resp.status);
|
|
4839
|
+
}
|
|
4840
|
+
async function invokeTool(creds, req, signal) {
|
|
4841
|
+
const { aws, region, modelId } = client(creds);
|
|
4842
|
+
const controller = new AbortController();
|
|
4843
|
+
const timer = setTimeout(() => controller.abort(), req.timeoutMs ?? BEDROCK_TIMEOUT_MS);
|
|
4844
|
+
const onAbort = () => controller.abort();
|
|
4845
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
4846
|
+
try {
|
|
4847
|
+
const headers = headersFor(req, "application/json");
|
|
4848
|
+
const resp = await aws.fetch(
|
|
4849
|
+
`https://bedrock-runtime.${region}.amazonaws.com/model/${encodeURIComponent(modelId)}/invoke`,
|
|
4850
|
+
{
|
|
4851
|
+
method: "POST",
|
|
4852
|
+
headers,
|
|
4853
|
+
body: JSON.stringify(body(req)),
|
|
4854
|
+
signal: controller.signal
|
|
4855
|
+
}
|
|
4856
|
+
);
|
|
4857
|
+
if (!resp.ok) await fail(resp);
|
|
4858
|
+
const json = await resp.json();
|
|
4859
|
+
reportUsage(req, extractUsage(json));
|
|
4860
|
+
const block = json.content?.find((b) => b.type === "tool_use");
|
|
4861
|
+
return block?.name ? { name: block.name, input: block.input ?? {} } : null;
|
|
4862
|
+
} finally {
|
|
4863
|
+
clearTimeout(timer);
|
|
4864
|
+
signal?.removeEventListener("abort", onAbort);
|
|
4865
|
+
}
|
|
4866
|
+
}
|
|
4867
|
+
|
|
4868
|
+
// src/tools-carrier-ask.ts
|
|
4669
4869
|
import { z as z11 } from "zod";
|
|
4670
4870
|
|
|
4671
4871
|
// src/tools-ui-agent.ts
|
|
@@ -4711,7 +4911,7 @@ var MANUS_API_BASE = "https://api.manus.ai/v2";
|
|
|
4711
4911
|
|
|
4712
4912
|
// src/tools-ui-agent.ts
|
|
4713
4913
|
async function createManusTask(apiKey, prompt, title, outputSchema) {
|
|
4714
|
-
const
|
|
4914
|
+
const body2 = {
|
|
4715
4915
|
message: { content: prompt },
|
|
4716
4916
|
agent_profile: "manus-1.6-lite",
|
|
4717
4917
|
hide_in_task_list: true,
|
|
@@ -4719,7 +4919,7 @@ async function createManusTask(apiKey, prompt, title, outputSchema) {
|
|
|
4719
4919
|
title
|
|
4720
4920
|
};
|
|
4721
4921
|
if (outputSchema) {
|
|
4722
|
-
|
|
4922
|
+
body2.structured_output_schema = outputSchema;
|
|
4723
4923
|
}
|
|
4724
4924
|
const res = await fetch(`${MANUS_API_BASE}/task.create`, {
|
|
4725
4925
|
method: "POST",
|
|
@@ -4727,7 +4927,7 @@ async function createManusTask(apiKey, prompt, title, outputSchema) {
|
|
|
4727
4927
|
"x-manus-api-key": apiKey,
|
|
4728
4928
|
"Content-Type": "application/json"
|
|
4729
4929
|
},
|
|
4730
|
-
body: JSON.stringify(
|
|
4930
|
+
body: JSON.stringify(body2)
|
|
4731
4931
|
});
|
|
4732
4932
|
return await res.json();
|
|
4733
4933
|
}
|
|
@@ -5252,14 +5452,14 @@ async function withFallback(fn, keys) {
|
|
|
5252
5452
|
true
|
|
5253
5453
|
);
|
|
5254
5454
|
}
|
|
5255
|
-
async function manusPost(path, apiKey,
|
|
5455
|
+
async function manusPost(path, apiKey, body2) {
|
|
5256
5456
|
const res = await fetch(`${MANUS_API_BASE2}/${path}`, {
|
|
5257
5457
|
method: "POST",
|
|
5258
5458
|
headers: {
|
|
5259
5459
|
"x-manus-api-key": apiKey,
|
|
5260
5460
|
"Content-Type": "application/json"
|
|
5261
5461
|
},
|
|
5262
|
-
body: JSON.stringify(
|
|
5462
|
+
body: JSON.stringify(body2)
|
|
5263
5463
|
});
|
|
5264
5464
|
const data = await res.json();
|
|
5265
5465
|
return { _httpStatus: res.status, data, key_used: "primary" };
|
|
@@ -5269,14 +5469,14 @@ async function sendMessage(keys, taskId, content, opts) {
|
|
|
5269
5469
|
if (opts?.connectors?.length) message.connectors = opts.connectors;
|
|
5270
5470
|
if (opts?.enableSkills?.length) message.enable_skills = opts.enableSkills;
|
|
5271
5471
|
if (opts?.forceSkills?.length) message.force_skills = opts.forceSkills;
|
|
5272
|
-
const
|
|
5472
|
+
const body2 = {
|
|
5273
5473
|
task_id: taskId,
|
|
5274
5474
|
message
|
|
5275
5475
|
};
|
|
5276
|
-
if (opts?.agentProfile)
|
|
5277
|
-
if (opts?.outputSchema)
|
|
5476
|
+
if (opts?.agentProfile) body2.agent_profile = opts.agentProfile;
|
|
5477
|
+
if (opts?.outputSchema) body2.structured_output_schema = opts.outputSchema;
|
|
5278
5478
|
return withFallback(
|
|
5279
|
-
(apiKey) => manusPost("task.sendMessage", apiKey,
|
|
5479
|
+
(apiKey) => manusPost("task.sendMessage", apiKey, body2),
|
|
5280
5480
|
keys
|
|
5281
5481
|
);
|
|
5282
5482
|
}
|
|
@@ -5601,7 +5801,7 @@ function validateCron(cron) {
|
|
|
5601
5801
|
return minuteFieldViolatesFiveMinuteRule(minuteField ?? "", cron);
|
|
5602
5802
|
}
|
|
5603
5803
|
async function createSchedule(apiKey, params) {
|
|
5604
|
-
const
|
|
5804
|
+
const body2 = {
|
|
5605
5805
|
name: params.name,
|
|
5606
5806
|
cron: params.cron,
|
|
5607
5807
|
prompt_template: params.prompt_template,
|
|
@@ -5615,7 +5815,7 @@ async function createSchedule(apiKey, params) {
|
|
|
5615
5815
|
"x-manus-api-key": apiKey,
|
|
5616
5816
|
"Content-Type": "application/json"
|
|
5617
5817
|
},
|
|
5618
|
-
body: JSON.stringify(
|
|
5818
|
+
body: JSON.stringify(body2)
|
|
5619
5819
|
});
|
|
5620
5820
|
if (!res.ok) {
|
|
5621
5821
|
throw new ManusScheduleError(
|
|
@@ -6245,19 +6445,33 @@ function registerScheduleAndUsageTools(server2, ctx) {
|
|
|
6245
6445
|
import { z as z7 } from "zod";
|
|
6246
6446
|
import * as Sentry2 from "@sentry/cloudflare";
|
|
6247
6447
|
|
|
6448
|
+
// src/audit-schema.ts
|
|
6449
|
+
var MARKER_INDEX = 11;
|
|
6450
|
+
var SCHEMA_GENERIC = "v1-generic";
|
|
6451
|
+
var SCHEMA_CARRIER_ASK = "v1-carrier-ask";
|
|
6452
|
+
function withSchemaMarker(blobs, marker) {
|
|
6453
|
+
const out = [...blobs];
|
|
6454
|
+
while (out.length < MARKER_INDEX) out.push("");
|
|
6455
|
+
out.push(marker);
|
|
6456
|
+
return out;
|
|
6457
|
+
}
|
|
6458
|
+
|
|
6248
6459
|
// src/audit.ts
|
|
6249
6460
|
function writeAudit(env, row) {
|
|
6250
6461
|
env.AUDIT_LOG.writeDataPoint({
|
|
6251
|
-
blobs:
|
|
6252
|
-
|
|
6253
|
-
|
|
6254
|
-
|
|
6255
|
-
|
|
6256
|
-
|
|
6257
|
-
|
|
6258
|
-
|
|
6259
|
-
|
|
6260
|
-
|
|
6462
|
+
blobs: withSchemaMarker(
|
|
6463
|
+
[
|
|
6464
|
+
row.tool_name,
|
|
6465
|
+
row.ocs_method,
|
|
6466
|
+
row.status,
|
|
6467
|
+
row.dry_run ? "1" : "0",
|
|
6468
|
+
row.sub,
|
|
6469
|
+
row.manus_task_id ?? "",
|
|
6470
|
+
row.manus_profile ?? "",
|
|
6471
|
+
row.manus_key_used ?? ""
|
|
6472
|
+
],
|
|
6473
|
+
SCHEMA_GENERIC
|
|
6474
|
+
),
|
|
6261
6475
|
doubles: [row.duration_ms, row.ocs_status_code ?? 0],
|
|
6262
6476
|
indexes: [String(row.reseller_id)]
|
|
6263
6477
|
});
|
|
@@ -6396,14 +6610,14 @@ function resolveConfig(env) {
|
|
|
6396
6610
|
async function atlasFetch(env, path, init) {
|
|
6397
6611
|
const { baseUrl: baseUrl2, key } = resolveConfig(env);
|
|
6398
6612
|
const headers = { "X-Carrier-Internal-Key": key };
|
|
6399
|
-
let
|
|
6613
|
+
let body2;
|
|
6400
6614
|
if (init.body !== void 0) {
|
|
6401
6615
|
headers["Content-Type"] = "application/json";
|
|
6402
|
-
|
|
6616
|
+
body2 = JSON.stringify(init.body);
|
|
6403
6617
|
}
|
|
6404
6618
|
let res;
|
|
6405
6619
|
try {
|
|
6406
|
-
res = await fetch(`${baseUrl2}${path}`, { method: init.method, headers, body });
|
|
6620
|
+
res = await fetch(`${baseUrl2}${path}`, { method: init.method, headers, body: body2 });
|
|
6407
6621
|
} catch (e) {
|
|
6408
6622
|
throw new WalletClientError(
|
|
6409
6623
|
`ATLAS wallet request failed: ${e instanceof Error ? e.message : "network error"}`,
|
|
@@ -6564,7 +6778,7 @@ async function runAutoTopup(env, args) {
|
|
|
6564
6778
|
return { charged: false, creditedCents: 0, reason: "no_payment_method" };
|
|
6565
6779
|
}
|
|
6566
6780
|
const bonusCents = bonusCentsFor(pack);
|
|
6567
|
-
const
|
|
6781
|
+
const body2 = new URLSearchParams({
|
|
6568
6782
|
amount: String(pack.eurCents),
|
|
6569
6783
|
currency: "eur",
|
|
6570
6784
|
customer: customerId,
|
|
@@ -6581,7 +6795,7 @@ async function runAutoTopup(env, args) {
|
|
|
6581
6795
|
const resp = await stripePostForm(
|
|
6582
6796
|
stripeKey,
|
|
6583
6797
|
"/v1/payment_intents",
|
|
6584
|
-
|
|
6798
|
+
body2
|
|
6585
6799
|
);
|
|
6586
6800
|
if (!resp.ok) {
|
|
6587
6801
|
return {
|
|
@@ -6855,6 +7069,13 @@ function registerStripeConnectTools(server2, ctx) {
|
|
|
6855
7069
|
annotations: annotationsFor("stripe_connect_status", "read")
|
|
6856
7070
|
},
|
|
6857
7071
|
async ({ operator_id }) => {
|
|
7072
|
+
if (operator_id !== void 0 && operator_id !== operatorId) {
|
|
7073
|
+
if (!isPlatformOperator(env, props2.org_id)) {
|
|
7074
|
+
return err2(
|
|
7075
|
+
"operator_id may only be overridden by Carrier's own organization. Omit it to read your own Stripe Connect status."
|
|
7076
|
+
);
|
|
7077
|
+
}
|
|
7078
|
+
}
|
|
6858
7079
|
const opId = operator_id ?? operatorId;
|
|
6859
7080
|
const opKvKey = operator_id ? `stripe_account:${operator_id}` : kvKey;
|
|
6860
7081
|
const start = Date.now();
|
|
@@ -7593,7 +7814,7 @@ async function triggerBillingThreshold(env, sub, amountCents) {
|
|
|
7593
7814
|
if (!stripeKey) return;
|
|
7594
7815
|
const customerId = await env.CARRIER_USERS.get(`stripe_customer_id:${sub}`);
|
|
7595
7816
|
if (!customerId) return;
|
|
7596
|
-
const
|
|
7817
|
+
const body2 = new URLSearchParams({
|
|
7597
7818
|
customer: customerId,
|
|
7598
7819
|
amount: String(Math.round(amountCents)),
|
|
7599
7820
|
currency: "usd",
|
|
@@ -7605,7 +7826,7 @@ async function triggerBillingThreshold(env, sub, amountCents) {
|
|
|
7605
7826
|
Authorization: `Bearer ${stripeKey}`,
|
|
7606
7827
|
"Content-Type": "application/x-www-form-urlencoded"
|
|
7607
7828
|
},
|
|
7608
|
-
body:
|
|
7829
|
+
body: body2.toString()
|
|
7609
7830
|
});
|
|
7610
7831
|
if (!resp.ok) return;
|
|
7611
7832
|
const invoiceBody = new URLSearchParams({
|
|
@@ -7629,7 +7850,7 @@ async function pushOverageToStripe(env, sub, quantity, ratePerCredit) {
|
|
|
7629
7850
|
if (!stripeKey) return;
|
|
7630
7851
|
const subItemId = await env.CARRIER_USERS.get(`stripe_sub_item_id:${sub}`);
|
|
7631
7852
|
if (!subItemId) return;
|
|
7632
|
-
const
|
|
7853
|
+
const body2 = new URLSearchParams({
|
|
7633
7854
|
quantity: String(quantity),
|
|
7634
7855
|
timestamp: String(Math.floor(Date.now() / 1e3)),
|
|
7635
7856
|
action: "increment"
|
|
@@ -7642,7 +7863,7 @@ async function pushOverageToStripe(env, sub, quantity, ratePerCredit) {
|
|
|
7642
7863
|
Authorization: `Bearer ${stripeKey}`,
|
|
7643
7864
|
"Content-Type": "application/x-www-form-urlencoded"
|
|
7644
7865
|
},
|
|
7645
|
-
body:
|
|
7866
|
+
body: body2.toString()
|
|
7646
7867
|
}
|
|
7647
7868
|
);
|
|
7648
7869
|
await env.CARRIER_USERS.put(
|
|
@@ -9316,37 +9537,9 @@ function routerTools() {
|
|
|
9316
9537
|
var ROUTER_SYSTEM_PROMPT = `You are a carrier fleet operations router. Your job is to map a user's natural-language intent to exactly ONE tool from the Carrier MCP tool registry.
|
|
9317
9538
|
|
|
9318
9539
|
${ROUTER_RULES}`;
|
|
9319
|
-
var
|
|
9320
|
-
|
|
9321
|
-
|
|
9322
|
-
const region = env.AWS_REGION ?? DEFAULT_REGION;
|
|
9323
|
-
const modelId = env.BEDROCK_MODEL_ID ?? DEFAULT_MODEL_ID;
|
|
9324
|
-
const aws = new AwsClient({
|
|
9325
|
-
accessKeyId: env.AWS_ACCESS_KEY_ID,
|
|
9326
|
-
secretAccessKey: env.AWS_SECRET_ACCESS_KEY,
|
|
9327
|
-
region,
|
|
9328
|
-
service: "bedrock"
|
|
9329
|
-
});
|
|
9330
|
-
const url = `https://bedrock-runtime.${region}.amazonaws.com/model/${encodeURIComponent(modelId)}/invoke`;
|
|
9331
|
-
const resp = await aws.fetch(url, {
|
|
9332
|
-
method: "POST",
|
|
9333
|
-
headers: { "Content-Type": "application/json", Accept: "application/json" },
|
|
9334
|
-
body: JSON.stringify(payload)
|
|
9335
|
-
});
|
|
9336
|
-
if (!resp.ok) {
|
|
9337
|
-
const body = await resp.text();
|
|
9338
|
-
if (resp.status === 429) {
|
|
9339
|
-
const retryAfter = resp.headers.get("retry-after");
|
|
9340
|
-
const err7 = new Error(`Bedrock rate limit: ${body}`);
|
|
9341
|
-
err7.isRateLimit = true;
|
|
9342
|
-
err7.retryAfter = retryAfter;
|
|
9343
|
-
throw err7;
|
|
9344
|
-
}
|
|
9345
|
-
throw new Error(`Bedrock invoke failed: ${resp.status} ${body}`);
|
|
9346
|
-
}
|
|
9347
|
-
return await resp.json();
|
|
9348
|
-
}
|
|
9349
|
-
async function _routeIntent(intent, context, env) {
|
|
9540
|
+
var ROUTER_TIMEOUT_MS = 12e3;
|
|
9541
|
+
async function _routeIntent(intent, context, env, opts = {}) {
|
|
9542
|
+
const { attribution, onUsage } = opts;
|
|
9350
9543
|
if (env.CARRIER_ASK_ENABLED !== "true" || !env.AWS_ACCESS_KEY_ID || !env.AWS_SECRET_ACCESS_KEY) {
|
|
9351
9544
|
return {
|
|
9352
9545
|
match: "routing_pending",
|
|
@@ -9362,26 +9555,32 @@ async function _routeIntent(intent, context, env) {
|
|
|
9362
9555
|
|
|
9363
9556
|
Pre-resolved context: ${JSON.stringify(definedContext)}` : "";
|
|
9364
9557
|
const userMessage = `${intent}${contextNote}`;
|
|
9365
|
-
const
|
|
9366
|
-
|
|
9367
|
-
|
|
9368
|
-
|
|
9369
|
-
|
|
9370
|
-
tools: routerTools(),
|
|
9371
|
-
tool_choice: { type: "any" }
|
|
9372
|
-
};
|
|
9373
|
-
let response;
|
|
9558
|
+
const routerToolList = routerTools();
|
|
9559
|
+
const tools = routerToolList.map(
|
|
9560
|
+
(tool, idx) => idx === routerToolList.length - 1 ? { ...tool, cache_control: { type: "ephemeral" } } : tool
|
|
9561
|
+
);
|
|
9562
|
+
let toolCall;
|
|
9374
9563
|
try {
|
|
9375
|
-
|
|
9376
|
-
|
|
9377
|
-
|
|
9378
|
-
|
|
9379
|
-
|
|
9380
|
-
|
|
9564
|
+
toolCall = await invokeTool(
|
|
9565
|
+
{
|
|
9566
|
+
accessKeyId: env.AWS_ACCESS_KEY_ID,
|
|
9567
|
+
secretAccessKey: env.AWS_SECRET_ACCESS_KEY,
|
|
9568
|
+
...env.AWS_REGION ? { region: env.AWS_REGION } : {},
|
|
9569
|
+
...env.BEDROCK_MODEL_ID ? { modelId: env.BEDROCK_MODEL_ID } : {}
|
|
9570
|
+
},
|
|
9571
|
+
{
|
|
9572
|
+
system: ROUTER_SYSTEM_PROMPT,
|
|
9573
|
+
messages: [{ role: "user", content: userMessage }],
|
|
9574
|
+
maxTokens: 512,
|
|
9575
|
+
tools,
|
|
9576
|
+
timeoutMs: ROUTER_TIMEOUT_MS,
|
|
9577
|
+
...attribution ? { attribution } : {},
|
|
9578
|
+
...onUsage ? { onUsage } : {}
|
|
9579
|
+
}
|
|
9580
|
+
);
|
|
9381
9581
|
} catch (err7) {
|
|
9382
|
-
if (err7 instanceof
|
|
9383
|
-
const
|
|
9384
|
-
const parsedSeconds = retryAfter ? parseInt(retryAfter, 10) : 60;
|
|
9582
|
+
if (err7 instanceof BedrockRateLimitError) {
|
|
9583
|
+
const parsedSeconds = err7.retryAfter ? parseInt(err7.retryAfter, 10) : 60;
|
|
9385
9584
|
return {
|
|
9386
9585
|
match: "rate_limited",
|
|
9387
9586
|
retry_after_seconds: Number.isFinite(parsedSeconds) ? parsedSeconds : 60,
|
|
@@ -9390,17 +9589,14 @@ Pre-resolved context: ${JSON.stringify(definedContext)}` : "";
|
|
|
9390
9589
|
}
|
|
9391
9590
|
throw err7;
|
|
9392
9591
|
}
|
|
9393
|
-
|
|
9394
|
-
(block) => block.type === "tool_use"
|
|
9395
|
-
);
|
|
9396
|
-
if (!toolUseBlock) {
|
|
9592
|
+
if (!toolCall) {
|
|
9397
9593
|
return {
|
|
9398
9594
|
match: "none",
|
|
9399
9595
|
closest: [],
|
|
9400
9596
|
suggestion: "Could not determine the right tool for this intent. Try rephrasing or use carrier_ask_describe to explore available tools."
|
|
9401
9597
|
};
|
|
9402
9598
|
}
|
|
9403
|
-
const { name: resolvedTool, input } =
|
|
9599
|
+
const { name: resolvedTool, input } = toolCall;
|
|
9404
9600
|
const resolvedParams = input ?? {};
|
|
9405
9601
|
if (resolvedTool === "carrier_clarify") {
|
|
9406
9602
|
const candidates = resolvedParams.candidates ?? [];
|
|
@@ -9443,23 +9639,47 @@ Pre-resolved context: ${JSON.stringify(definedContext)}` : "";
|
|
|
9443
9639
|
function writeCarrierAskAudit(env, row) {
|
|
9444
9640
|
try {
|
|
9445
9641
|
env.AUDIT_LOG.writeDataPoint({
|
|
9446
|
-
|
|
9447
|
-
|
|
9448
|
-
|
|
9449
|
-
|
|
9450
|
-
|
|
9451
|
-
|
|
9452
|
-
|
|
9453
|
-
|
|
9454
|
-
|
|
9455
|
-
|
|
9456
|
-
|
|
9457
|
-
|
|
9458
|
-
|
|
9459
|
-
|
|
9460
|
-
|
|
9642
|
+
// The marker at blob[11] is what separates these rows from writeAudit's,
|
|
9643
|
+
// which writes a different layout to this same dataset — its blob[4] is
|
|
9644
|
+
// `sub` where this one's is an intent hash. Filter on it before reading
|
|
9645
|
+
// any other position.
|
|
9646
|
+
blobs: withSchemaMarker(
|
|
9647
|
+
[
|
|
9648
|
+
"carrier_ask",
|
|
9649
|
+
// blob[0] tool_name
|
|
9650
|
+
row.resolved_tool,
|
|
9651
|
+
// blob[1] resolved tool (or "none")
|
|
9652
|
+
row.status,
|
|
9653
|
+
// blob[2] ok | error
|
|
9654
|
+
row.match,
|
|
9655
|
+
// blob[3] match type
|
|
9656
|
+
row.intent_hash,
|
|
9657
|
+
// blob[4] SHA-256 of intent
|
|
9658
|
+
row.confirm_token_state,
|
|
9659
|
+
// blob[5] confirm token state
|
|
9660
|
+
row.sub,
|
|
9661
|
+
// blob[6] user subject
|
|
9662
|
+
// Appended, never reordered: blob positions are the query contract and
|
|
9663
|
+
// an existing dashboard reading blob[3] must keep reading match.
|
|
9664
|
+
row.model_id,
|
|
9665
|
+
// blob[7] model id, or "none"
|
|
9666
|
+
row.tier
|
|
9667
|
+
// blob[8] tier at call time
|
|
9668
|
+
],
|
|
9669
|
+
SCHEMA_CARRIER_ASK
|
|
9670
|
+
),
|
|
9671
|
+
// Same rule for doubles. latency stays at [0].
|
|
9672
|
+
doubles: [
|
|
9673
|
+
row.latency_ms,
|
|
9674
|
+
row.usage.inputTokens,
|
|
9675
|
+
row.usage.outputTokens,
|
|
9676
|
+
row.usage.cacheReadTokens,
|
|
9677
|
+
row.usage.cacheWriteTokens,
|
|
9678
|
+
// An estimate from a rate card we maintain, not a billed figure. It is
|
|
9679
|
+
// here so a per-tenant cost query is one SQL statement rather than a
|
|
9680
|
+
// join against a rate table that lives in another package.
|
|
9681
|
+
estimateCostUsd(row.usage)
|
|
9461
9682
|
],
|
|
9462
|
-
doubles: [row.latency_ms],
|
|
9463
9683
|
indexes: [String(row.reseller_id)]
|
|
9464
9684
|
});
|
|
9465
9685
|
} catch {
|
|
@@ -9505,7 +9725,10 @@ function registerAllCarrierAskTools(server2, ctx) {
|
|
|
9505
9725
|
status: "error",
|
|
9506
9726
|
latency_ms: Date.now() - start,
|
|
9507
9727
|
sub: ctx.props.sub,
|
|
9508
|
-
reseller_id: ctx.props.reseller_id
|
|
9728
|
+
reseller_id: ctx.props.reseller_id,
|
|
9729
|
+
model_id: "none",
|
|
9730
|
+
tier: ctx.props.tier,
|
|
9731
|
+
usage: ZERO_USAGE
|
|
9509
9732
|
});
|
|
9510
9733
|
return {
|
|
9511
9734
|
content: [
|
|
@@ -9543,7 +9766,10 @@ function registerAllCarrierAskTools(server2, ctx) {
|
|
|
9543
9766
|
status: "ok",
|
|
9544
9767
|
latency_ms: Date.now() - start,
|
|
9545
9768
|
sub: ctx.props.sub,
|
|
9546
|
-
reseller_id: ctx.props.reseller_id
|
|
9769
|
+
reseller_id: ctx.props.reseller_id,
|
|
9770
|
+
model_id: "none",
|
|
9771
|
+
tier: ctx.props.tier,
|
|
9772
|
+
usage: ZERO_USAGE
|
|
9547
9773
|
});
|
|
9548
9774
|
return {
|
|
9549
9775
|
content: [
|
|
@@ -9560,8 +9786,21 @@ function registerAllCarrierAskTools(server2, ctx) {
|
|
|
9560
9786
|
};
|
|
9561
9787
|
}
|
|
9562
9788
|
let route;
|
|
9789
|
+
let routeUsage = ZERO_USAGE;
|
|
9790
|
+
let modelRan = false;
|
|
9563
9791
|
try {
|
|
9564
|
-
route = await _routeIntent(intent, context, ctx.env
|
|
9792
|
+
route = await _routeIntent(intent, context, ctx.env, {
|
|
9793
|
+
attribution: {
|
|
9794
|
+
...ctx.props.org_id ? { orgId: ctx.props.org_id } : {},
|
|
9795
|
+
...ctx.props.reseller_id ? { subAccountId: String(ctx.props.reseller_id) } : {},
|
|
9796
|
+
surface: "carrier_ask",
|
|
9797
|
+
tier: ctx.props.tier
|
|
9798
|
+
},
|
|
9799
|
+
onUsage: (u) => {
|
|
9800
|
+
routeUsage = u;
|
|
9801
|
+
modelRan = true;
|
|
9802
|
+
}
|
|
9803
|
+
});
|
|
9565
9804
|
} catch (err7) {
|
|
9566
9805
|
writeCarrierAskAudit(ctx.env, {
|
|
9567
9806
|
intent_hash: intentHash,
|
|
@@ -9571,7 +9810,14 @@ function registerAllCarrierAskTools(server2, ctx) {
|
|
|
9571
9810
|
status: "error",
|
|
9572
9811
|
latency_ms: Date.now() - start,
|
|
9573
9812
|
sub: ctx.props.sub,
|
|
9574
|
-
reseller_id: ctx.props.reseller_id
|
|
9813
|
+
reseller_id: ctx.props.reseller_id,
|
|
9814
|
+
model_id: modelRan ? ctx.env.BEDROCK_MODEL_ID ?? DEFAULT_MODEL_ID : "none",
|
|
9815
|
+
tier: ctx.props.tier,
|
|
9816
|
+
// Not ZERO_USAGE: a call can throw AFTER the model answered, and
|
|
9817
|
+
// those tokens were billed regardless. Recording zero here is how
|
|
9818
|
+
// measured spend drifts below real spend in exactly the rows used
|
|
9819
|
+
// to check it.
|
|
9820
|
+
usage: routeUsage
|
|
9575
9821
|
});
|
|
9576
9822
|
return {
|
|
9577
9823
|
content: [
|
|
@@ -9608,7 +9854,10 @@ function registerAllCarrierAskTools(server2, ctx) {
|
|
|
9608
9854
|
status: "ok",
|
|
9609
9855
|
latency_ms: Date.now() - start,
|
|
9610
9856
|
sub: ctx.props.sub,
|
|
9611
|
-
reseller_id: ctx.props.reseller_id
|
|
9857
|
+
reseller_id: ctx.props.reseller_id,
|
|
9858
|
+
model_id: modelRan ? ctx.env.BEDROCK_MODEL_ID ?? DEFAULT_MODEL_ID : "none",
|
|
9859
|
+
tier: ctx.props.tier,
|
|
9860
|
+
usage: routeUsage
|
|
9612
9861
|
});
|
|
9613
9862
|
return {
|
|
9614
9863
|
content: [
|
|
@@ -10150,22 +10399,22 @@ function toFleetInput(raw) {
|
|
|
10150
10399
|
|
|
10151
10400
|
// src/apps/fleet-health-app.ts
|
|
10152
10401
|
var FLEET_APP_RESOURCE_URI = "ui://fleet-health-dashboard";
|
|
10153
|
-
async function safeCall2(
|
|
10402
|
+
async function safeCall2(client2, method, params) {
|
|
10154
10403
|
try {
|
|
10155
|
-
return { data: await
|
|
10404
|
+
return { data: await client2.call(method, params), error: null };
|
|
10156
10405
|
} catch (err7) {
|
|
10157
10406
|
return { data: null, error: err7 instanceof Error ? err7.message : String(err7) };
|
|
10158
10407
|
}
|
|
10159
10408
|
}
|
|
10160
10409
|
async function loadFleet(ctx, accountId) {
|
|
10161
10410
|
const token2 = await ctx.getUserToken(ctx.props.sub);
|
|
10162
|
-
const
|
|
10411
|
+
const client2 = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
|
|
10163
10412
|
const resellerId = await getDefaultResellerId(ctx.env, token2).catch(() => void 0);
|
|
10164
10413
|
const statusParams = accountId !== void 0 ? { accountId } : resellerId !== void 0 ? { resellerId } : {};
|
|
10165
10414
|
const accountParams = resellerId !== void 0 ? { resellerId } : {};
|
|
10166
10415
|
const [status, accounts] = await Promise.all([
|
|
10167
|
-
safeCall2(
|
|
10168
|
-
safeCall2(
|
|
10416
|
+
safeCall2(client2, "esimStatusPerAccount", statusParams),
|
|
10417
|
+
safeCall2(client2, "listResellerAccount", accountParams)
|
|
10169
10418
|
]);
|
|
10170
10419
|
return toFleetInput({
|
|
10171
10420
|
status: status.data,
|
|
@@ -10311,9 +10560,9 @@ async function deleteWizardSession(env, sub, wizardId) {
|
|
|
10311
10560
|
}
|
|
10312
10561
|
|
|
10313
10562
|
// src/apps/provisioning-wizard.ts
|
|
10314
|
-
async function safeCallWithToken(
|
|
10563
|
+
async function safeCallWithToken(client2, _token, method, params = {}) {
|
|
10315
10564
|
try {
|
|
10316
|
-
return { data: await
|
|
10565
|
+
return { data: await client2.call(method, params), error: null };
|
|
10317
10566
|
} catch (err7) {
|
|
10318
10567
|
return {
|
|
10319
10568
|
data: null,
|
|
@@ -10380,11 +10629,11 @@ function registerProvisioningWizard(server2, ctx) {
|
|
|
10380
10629
|
},
|
|
10381
10630
|
async ({ step, wizardId, subscriber_iccid, package_template_id }) => {
|
|
10382
10631
|
const token2 = await ctx.getUserToken(ctx.props.sub);
|
|
10383
|
-
const
|
|
10632
|
+
const client2 = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
|
|
10384
10633
|
if (step === "init") {
|
|
10385
10634
|
const newWizardId = generateWizardId();
|
|
10386
10635
|
const subscribersResult = await safeCallWithToken(
|
|
10387
|
-
|
|
10636
|
+
client2,
|
|
10388
10637
|
token2,
|
|
10389
10638
|
"listResellerAccount",
|
|
10390
10639
|
{}
|
|
@@ -10462,7 +10711,7 @@ function registerProvisioningWizard(server2, ctx) {
|
|
|
10462
10711
|
}
|
|
10463
10712
|
const resellerIdForTemplates = await getDefaultResellerId(ctx.env, token2);
|
|
10464
10713
|
const packagesResult = await safeCallWithToken(
|
|
10465
|
-
|
|
10714
|
+
client2,
|
|
10466
10715
|
token2,
|
|
10467
10716
|
"listPrepaidPackageTemplate",
|
|
10468
10717
|
{ resellerId: resellerIdForTemplates }
|
|
@@ -10529,7 +10778,7 @@ function registerProvisioningWizard(server2, ctx) {
|
|
|
10529
10778
|
};
|
|
10530
10779
|
}
|
|
10531
10780
|
const previewResult = await safeCallWithToken(
|
|
10532
|
-
|
|
10781
|
+
client2,
|
|
10533
10782
|
token2,
|
|
10534
10783
|
"listPrepaidPackageTemplate",
|
|
10535
10784
|
{}
|
|
@@ -10601,7 +10850,7 @@ function registerProvisioningWizard(server2, ctx) {
|
|
|
10601
10850
|
};
|
|
10602
10851
|
}
|
|
10603
10852
|
const subRecord = await safeCallWithToken(
|
|
10604
|
-
|
|
10853
|
+
client2,
|
|
10605
10854
|
token2,
|
|
10606
10855
|
"getSingleSubscriber",
|
|
10607
10856
|
{ iccid: session.subscriber_iccid }
|
|
@@ -10630,7 +10879,7 @@ function registerProvisioningWizard(server2, ctx) {
|
|
|
10630
10879
|
};
|
|
10631
10880
|
}
|
|
10632
10881
|
const result2 = await safeCallWithToken(
|
|
10633
|
-
|
|
10882
|
+
client2,
|
|
10634
10883
|
token2,
|
|
10635
10884
|
"affectPackageToSubscriber",
|
|
10636
10885
|
{
|
|
@@ -10674,9 +10923,9 @@ import {
|
|
|
10674
10923
|
registerAppResource as registerAppResource3,
|
|
10675
10924
|
RESOURCE_MIME_TYPE as RESOURCE_MIME_TYPE3
|
|
10676
10925
|
} from "@modelcontextprotocol/ext-apps/server";
|
|
10677
|
-
async function safeCallWithToken2(
|
|
10926
|
+
async function safeCallWithToken2(client2, _token, method, params = {}) {
|
|
10678
10927
|
try {
|
|
10679
|
-
return { data: await
|
|
10928
|
+
return { data: await client2.call(method, params), error: null };
|
|
10680
10929
|
} catch (err7) {
|
|
10681
10930
|
return {
|
|
10682
10931
|
data: null,
|
|
@@ -10740,10 +10989,10 @@ function registerBalanceTopupApp(server2, ctx) {
|
|
|
10740
10989
|
ctx,
|
|
10741
10990
|
async ({ iccid, delta, preview }) => {
|
|
10742
10991
|
const token2 = await ctx.getUserToken(ctx.props.sub);
|
|
10743
|
-
const
|
|
10992
|
+
const client2 = new OcsClient(ctx.env.CARRIER_OCS_BASE_URL, token2);
|
|
10744
10993
|
if (preview === true) {
|
|
10745
10994
|
const result2 = await safeCallWithToken2(
|
|
10746
|
-
|
|
10995
|
+
client2,
|
|
10747
10996
|
token2,
|
|
10748
10997
|
"getSingleSubscriber",
|
|
10749
10998
|
{ iccid }
|
|
@@ -10768,7 +11017,7 @@ function registerBalanceTopupApp(server2, ctx) {
|
|
|
10768
11017
|
};
|
|
10769
11018
|
}
|
|
10770
11019
|
const execResult = await safeCallWithToken2(
|
|
10771
|
-
|
|
11020
|
+
client2,
|
|
10772
11021
|
token2,
|
|
10773
11022
|
// CAR-78: subscriber top-up uses modifySubscriberBalance with { subscriber, amount }
|
|
10774
11023
|
// (delta). modifyAccountBalance is account-level and expects { accountId, amount, mode }.
|