@aglyn/plugins-ai 1.0.0-beta.242 → 1.0.0-beta.244
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/package.json +17 -17
- package/src/lib/jobs/ai-job-layout-language.js +11 -6
- package/src/lib/jobs/ai-job-layout-language.js.map +1 -1
- package/src/lib/jobs/ai-job-page-language.d.ts +3 -1
- package/src/lib/jobs/ai-job-page-language.js +17 -5
- package/src/lib/jobs/ai-job-page-language.js.map +1 -1
- package/src/lib/jobs/ai-job-page-step.js +11 -4
- package/src/lib/jobs/ai-job-page-step.js.map +1 -1
- package/src/lib/jobs/ai-job-site-step.js +22 -8
- package/src/lib/jobs/ai-job-site-step.js.map +1 -1
- package/src/lib/jobs/ai-layout-stock-photos.d.ts +52 -8
- package/src/lib/jobs/ai-layout-stock-photos.js +351 -72
- package/src/lib/jobs/ai-layout-stock-photos.js.map +1 -1
- package/src/lib/jobs/ai-site-publish.d.ts +14 -0
- package/src/lib/jobs/ai-site-publish.js +28 -3
- package/src/lib/jobs/ai-site-publish.js.map +1 -1
- package/src/lib/jobs/fixtures/ai-stock-photo-tidewater-recordings.d.ts +27 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-tidewater-recordings.js +261 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-tidewater-recordings.js.map +1 -0
- package/src/lib/layout-language/ai-layout-links.js +5 -2
- package/src/lib/layout-language/ai-layout-links.js.map +1 -1
- package/src/lib/runtime/ai-doctrine-validators.d.ts +42 -1
- package/src/lib/runtime/ai-doctrine-validators.js +98 -11
- package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
- package/src/lib/usage/ai-quota-checks.d.ts +13 -3
- package/src/lib/usage/ai-quota-checks.js +46 -8
- package/src/lib/usage/ai-quota-checks.js.map +1 -1
|
@@ -22,9 +22,14 @@ export declare const AI_CREDITS_QUOTA_KEY = "assistCredits";
|
|
|
22
22
|
* check the usage-alerts sweep runs beside its own.
|
|
23
23
|
*
|
|
24
24
|
* Measured in CREDITS — the unit the customer was sold and the meter shows —
|
|
25
|
-
* from
|
|
26
|
-
*
|
|
27
|
-
*
|
|
25
|
+
* from the workspace's month (`orgs/{orgId}/assistUsage/{month}`) NET OF
|
|
26
|
+
* CREDITS GIVEN BACK (`assistSpendAfterReturnsUsd`, AGL-3595), through the one
|
|
27
|
+
* conversion, so this alert, the Billing meter, the Assist usage strip and
|
|
28
|
+
* the reservation cannot disagree about how far into the band the org is.
|
|
29
|
+
* The month's spend line is gross — `estCostUsd` alone — and read off it, a
|
|
30
|
+
* Free workspace whose test resets and refunded failures had handed 252 of
|
|
31
|
+
* 442 credits back was told it had used "442 — more than the 300 your plan
|
|
32
|
+
* includes". A plan with no band
|
|
28
33
|
* resolves `null` and reads as a limit of 0, which the sweep skips the way it
|
|
29
34
|
* skips Free's zero-quota dimensions.
|
|
30
35
|
*
|
|
@@ -35,3 +40,8 @@ export declare const AI_CREDITS_QUOTA_KEY = "assistCredits";
|
|
|
35
40
|
* can never incur would be the surprise bill in reverse.
|
|
36
41
|
*/
|
|
37
42
|
export declare function aiQuotaChecks(context: UsageQuotaContext): Promise<readonly UsageQuotaCheck[]>;
|
|
43
|
+
/**
|
|
44
|
+
* The checks, given the workspace's month spend in billed USD, already net
|
|
45
|
+
* of give-backs.
|
|
46
|
+
*/
|
|
47
|
+
export declare function aiQuotaChecksFrom(context: Pick<UsageQuotaContext, 'org' | 'month'>, spentUsd: number): readonly UsageQuotaCheck[];
|
|
@@ -14,16 +14,24 @@
|
|
|
14
14
|
* See the License for the specific language governing permissions and
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/ import { ASSIST_HARD_CAP_CONTROL_LABEL, ASSIST_HARD_CAP_CONTROL_LOCATION, assistBandRefuses, assistCreditsFromUsd, resolveAssistCreditBudget, resolveAssistHardCap, resolveAssistOverageRateUsdPer1k } from "./assist-credits.js";
|
|
17
|
-
import {
|
|
17
|
+
import { resolveEffectivePlan } from "@aglyn/aglyn/app-utils/plan-entitlements";
|
|
18
|
+
import { firebaseAdmin } from "@aglyn/tenant-data-admin";
|
|
19
|
+
import { ASSIST_RETURNED_USD_FIELD, assistSpendAfterReturnsUsd } from "./assist-credit-returns.js";
|
|
20
|
+
import { aiFreeCreditsResetLabel, aiFreeCreditsResetOn } from "../model/ai-site-job.js";
|
|
18
21
|
/** The guard key the credits band is warned under. */ export const AI_CREDITS_QUOTA_KEY = 'assistCredits';
|
|
19
22
|
/**
|
|
20
23
|
* The AI credits band the WORKSPACE is warned about (AGL-2898), as a quota
|
|
21
24
|
* check the usage-alerts sweep runs beside its own.
|
|
22
25
|
*
|
|
23
26
|
* Measured in CREDITS — the unit the customer was sold and the meter shows —
|
|
24
|
-
* from
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
+
* from the workspace's month (`orgs/{orgId}/assistUsage/{month}`) NET OF
|
|
28
|
+
* CREDITS GIVEN BACK (`assistSpendAfterReturnsUsd`, AGL-3595), through the one
|
|
29
|
+
* conversion, so this alert, the Billing meter, the Assist usage strip and
|
|
30
|
+
* the reservation cannot disagree about how far into the band the org is.
|
|
31
|
+
* The month's spend line is gross — `estCostUsd` alone — and read off it, a
|
|
32
|
+
* Free workspace whose test resets and refunded failures had handed 252 of
|
|
33
|
+
* 442 credits back was told it had used "442 — more than the 300 your plan
|
|
34
|
+
* includes". A plan with no band
|
|
27
35
|
* resolves `null` and reads as a limit of 0, which the sweep skips the way it
|
|
28
36
|
* skips Free's zero-quota dimensions.
|
|
29
37
|
*
|
|
@@ -33,11 +41,41 @@ import { AI_ASSIST_SPEND_LINE_ID } from "../usage-axes.js";
|
|
|
33
41
|
* ever billed — and telling a Free org to "set a monthly cap" on a charge it
|
|
34
42
|
* can never incur would be the surprise bill in reverse.
|
|
35
43
|
*/ export async function aiQuotaChecks(context) {
|
|
36
|
-
|
|
37
|
-
|
|
44
|
+
const monthDoc = await firebaseAdmin.app().firestore().collection('orgs').doc(context.orgId).collection('assistUsage').doc(context.month).get();
|
|
45
|
+
// Net of credits given back (AGL-3595) — the figure the gate admits on.
|
|
46
|
+
const spentUsd = assistSpendAfterReturnsUsd(monthDoc.get('estCostUsd'), monthDoc.get(ASSIST_RETURNED_USD_FIELD));
|
|
47
|
+
return aiQuotaChecksFrom(context, spentUsd);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The checks, given the workspace's month spend in billed USD, already net
|
|
51
|
+
* of give-backs.
|
|
52
|
+
*/ export function aiQuotaChecksFrom(context, spentUsd) {
|
|
38
53
|
const org = context.org;
|
|
39
54
|
const bandCredits = resolveAssistCreditBudget(org);
|
|
40
|
-
const
|
|
55
|
+
const used = assistCreditsFromUsd(spentUsd);
|
|
56
|
+
// FREE IS AN ALLOWANCE, NOT A BAND SOLD PAST. Nothing past it is ever
|
|
57
|
+
// billed, so the notice says the credits are used for the month, when they
|
|
58
|
+
// renew, and that an upgrade adds more — never "more than your plan
|
|
59
|
+
// includes", which reads like the start of a charge.
|
|
60
|
+
if (resolveEffectivePlan(org) === 'free') {
|
|
61
|
+
const renews = aiFreeCreditsResetLabel(aiFreeCreditsResetOn(new Date(`${context.month}-01T00:00:00.000Z`)));
|
|
62
|
+
return [
|
|
63
|
+
{
|
|
64
|
+
key: AI_CREDITS_QUOTA_KEY,
|
|
65
|
+
label: 'free AI credits',
|
|
66
|
+
noun: 'free AI credits',
|
|
67
|
+
used,
|
|
68
|
+
limit: bandCredits != null ? bandCredits : 0,
|
|
69
|
+
cadence: 'monthly',
|
|
70
|
+
outcome: 'stops',
|
|
71
|
+
reachedTitle: "You've used your free AI credits for this month",
|
|
72
|
+
reachedLead: 'has used its free AI credits for this month.',
|
|
73
|
+
reached: `They renew on ${renews}. Upgrade for more.`,
|
|
74
|
+
reachedLinksUpgrade: true,
|
|
75
|
+
approach: 'Nothing is ever charged on Free. When they are used, AI assist ' + `pauses until your credits renew on ${renews}, or upgrade for more.`
|
|
76
|
+
}
|
|
77
|
+
];
|
|
78
|
+
}
|
|
41
79
|
// Whether crossing the band produces an invoice line or a stop. The same
|
|
42
80
|
// predicate the reservation refuses on, so the words and the behavior
|
|
43
81
|
// cannot drift: a band that refuses — the org's own switch, or a plan with
|
|
@@ -55,7 +93,7 @@ import { AI_ASSIST_SPEND_LINE_ID } from "../usage-axes.js";
|
|
|
55
93
|
key: AI_CREDITS_QUOTA_KEY,
|
|
56
94
|
label: 'AI assist credits',
|
|
57
95
|
noun: 'AI assist credits',
|
|
58
|
-
used
|
|
96
|
+
used,
|
|
59
97
|
limit: bandCredits != null ? bandCredits : 0,
|
|
60
98
|
cadence: 'monthly',
|
|
61
99
|
outcome: bandIsWall ? 'stops' : 'bills',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/usage/ai-quota-checks.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ASSIST_HARD_CAP_CONTROL_LABEL,\n ASSIST_HARD_CAP_CONTROL_LOCATION,\n assistBandRefuses,\n assistCreditsFromUsd,\n resolveAssistCreditBudget,\n resolveAssistHardCap,\n resolveAssistOverageRateUsdPer1k,\n} from './assist-credits'\nimport type {\n UsageQuotaCheck,\n UsageQuotaContext,\n} from '@aglyn/aglyn/plugin-manager/usage-alert-contributors'\nimport { AI_ASSIST_SPEND_LINE_ID } from '../usage-axes'\n\n/** The guard key the credits band is warned under. */\nexport const AI_CREDITS_QUOTA_KEY = 'assistCredits'\n\n/**\n * The AI credits band the WORKSPACE is warned about (AGL-2898), as a quota\n * check the usage-alerts sweep runs beside its own.\n *\n * Measured in CREDITS — the unit the customer was sold and the meter shows —\n * from this plugin's line of the month's spend (the billed `estCostUsd`)\n * through the one conversion, so this alert and the Billing meter cannot\n * disagree about how far into the band the org is. A plan with no band\n * resolves `null` and reads as a limit of 0, which the sweep skips the way it\n * skips Free's zero-quota dimensions.\n *\n * Approaching the band is the sweep's generic warning; REACHING it says what\n * happens next, which differs by plan and by the org's own controls — metered\n * at a rate unless a stop is set, or stopped until next month with nothing\n * ever billed — and telling a Free org to \"set a monthly cap\" on a charge it\n * can never incur would be the surprise bill in reverse.\n */\nexport async function aiQuotaChecks(\n context: UsageQuotaContext,\n): Promise<readonly UsageQuotaCheck[]> {\n const org = context.org as never\n const bandCredits = resolveAssistCreditBudget(org)\n const spentUsd =\n context.spend.lines.find((line) => line.id === AI_ASSIST_SPEND_LINE_ID)\n ?.usd ?? 0\n // Whether crossing the band produces an invoice line or a stop. The same\n // predicate the reservation refuses on, so the words and the behavior\n // cannot drift: a band that refuses — the org's own switch, or a plan with\n // no rate — is a wall, and everything else is sold past.\n const bandIsWall = assistBandRefuses(org)\n // Through the same resolver `assistBandRefuses` asks, so the alert's rate\n // and its wall/sold verdict cannot disagree about one org. Read straight off\n // `PLAN_PRICING` they did: Starter's listed rate is null and the add-on's is\n // added by the resolver, so a Starter workspace with the add-on was told\n // \"sold past the band\" at \"$0.00 per 1,000\" in the same sentence (AGL-3014).\n const rateUsdPer1k = resolveAssistOverageRateUsdPer1k(org)\n const rate = `$${(rateUsdPer1k ?? 0).toFixed(2)} per 1,000`\n return [\n {\n key: AI_CREDITS_QUOTA_KEY,\n label: 'AI assist credits',\n noun: 'AI assist credits',\n used: assistCreditsFromUsd(spentUsd),\n limit: bandCredits ?? 0,\n cadence: 'monthly',\n outcome: bandIsWall ? 'stops' : 'bills',\n reachedTitle: bandIsWall\n ? \"You've used your included AI assist credits\"\n : \"You've used your included AI assist credits — extra credits \" +\n 'are now billed',\n reached: bandIsWall\n ? 'AI assist stops here until next month — nothing past the band ' +\n 'is ever billed. Upgrade in Billing to add credits' +\n (resolveAssistHardCap(org) && rateUsdPer1k !== null\n ? `, or turn off \"${ASSIST_HARD_CAP_CONTROL_LABEL}\" ` +\n `under ${ASSIST_HARD_CAP_CONTROL_LOCATION} to keep ` +\n `going at your plan’s rate.`\n : '.')\n : 'The assistant keeps answering, and the extra credits are ' +\n `metered on your monthly invoice at ${rate} — unless you set a ` +\n `stop under ${ASSIST_HARD_CAP_CONTROL_LOCATION}: stop at the ` +\n 'included band, or stop once this month’s overage reaches a ' +\n 'figure you choose.',\n approach: bandIsWall\n ? 'Nothing changes and nothing is charged — at the included band, ' +\n 'AI assist stops until next month, and nothing past it is ever ' +\n 'billed.'\n : 'Nothing is charged yet — past the included band, extra credits ' +\n `are metered on your monthly invoice at ${rate} unless you set a ` +\n `stop under ${ASSIST_HARD_CAP_CONTROL_LOCATION}.`,\n },\n ]\n}\n"],"names":["ASSIST_HARD_CAP_CONTROL_LABEL","ASSIST_HARD_CAP_CONTROL_LOCATION","assistBandRefuses","assistCreditsFromUsd","resolveAssistCreditBudget","resolveAssistHardCap","resolveAssistOverageRateUsdPer1k","AI_ASSIST_SPEND_LINE_ID","AI_CREDITS_QUOTA_KEY","aiQuotaChecks","context","org","bandCredits","spentUsd","spend","lines","find","line","id","usd","bandIsWall","rateUsdPer1k","rate","toFixed","key","label","noun","used","limit","cadence","outcome","reachedTitle","reached","approach"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,SACEA,6BAA6B,EAC7BC,gCAAgC,EAChCC,iBAAiB,EACjBC,oBAAoB,EACpBC,yBAAyB,EACzBC,oBAAoB,EACpBC,gCAAgC,QAC3B,sBAAkB;AAKzB,SAASC,uBAAuB,QAAQ,mBAAe;AAEvD,oDAAoD,GACpD,OAAO,MAAMC,uBAAuB,gBAAe;AAEnD;;;;;;;;;;;;;;;;CAgBC,GACD,OAAO,eAAeC,cACpBC,OAA0B;;QAKxBA;IAHF,MAAMC,MAAMD,QAAQC,GAAG;IACvB,MAAMC,cAAcR,0BAA0BO;IAC9C,MAAME,oBACJH,4BAAAA,QAAQI,KAAK,CAACC,KAAK,CAACC,IAAI,CAAC,CAACC,OAASA,KAAKC,EAAE,KAAKX,6CAA/CG,0BACIS,GAAG,mBAAI;IACb,yEAAyE;IACzE,sEAAsE;IACtE,2EAA2E;IAC3E,yDAAyD;IACzD,MAAMC,aAAalB,kBAAkBS;IACrC,0EAA0E;IAC1E,6EAA6E;IAC7E,6EAA6E;IAC7E,yEAAyE;IACzE,6EAA6E;IAC7E,MAAMU,eAAef,iCAAiCK;IACtD,MAAMW,OAAO,CAAC,CAAC,EAAE,CAACD,uBAAAA,eAAgB,GAAGE,OAAO,CAAC,GAAG,UAAU,CAAC;IAC3D,OAAO;QACL;YACEC,KAAKhB;YACLiB,OAAO;YACPC,MAAM;YACNC,MAAMxB,qBAAqBU;YAC3Be,KAAK,EAAEhB,sBAAAA,cAAe;YACtBiB,SAAS;YACTC,SAASV,aAAa,UAAU;YAChCW,cAAcX,aACV,gDACA,iEACA;YACJY,SAASZ,aACL,mEACA,sDACCf,CAAAA,qBAAqBM,QAAQU,iBAAiB,OAC3C,CAAC,eAAe,EAAErB,8BAA8B,EAAE,CAAC,GACnD,CAAC,MAAM,EAAEC,iCAAiC,SAAS,CAAC,GACpD,CAAC,0BAA0B,CAAC,GAC5B,GAAE,IACN,8DACA,CAAC,mCAAmC,EAAEqB,KAAK,oBAAoB,CAAC,GAChE,CAAC,WAAW,EAAErB,iCAAiC,cAAc,CAAC,GAC9D,gEACA;YACJgC,UAAUb,aACN,oEACA,mEACA,YACA,oEACA,CAAC,uCAAuC,EAAEE,KAAK,kBAAkB,CAAC,GAClE,CAAC,WAAW,EAAErB,iCAAiC,CAAC,CAAC;QACvD;KACD;AACH"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/usage/ai-quota-checks.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ASSIST_HARD_CAP_CONTROL_LABEL,\n ASSIST_HARD_CAP_CONTROL_LOCATION,\n assistBandRefuses,\n assistCreditsFromUsd,\n resolveAssistCreditBudget,\n resolveAssistHardCap,\n resolveAssistOverageRateUsdPer1k,\n} from './assist-credits'\nimport type {\n UsageQuotaCheck,\n UsageQuotaContext,\n} from '@aglyn/aglyn/plugin-manager/usage-alert-contributors'\nimport { resolveEffectivePlan } from '@aglyn/aglyn/app-utils/plan-entitlements'\nimport { firebaseAdmin } from '@aglyn/tenant-data-admin'\nimport {\n ASSIST_RETURNED_USD_FIELD,\n assistSpendAfterReturnsUsd,\n} from './assist-credit-returns'\nimport {\n aiFreeCreditsResetLabel,\n aiFreeCreditsResetOn,\n} from '../model/ai-site-job'\n\n/** The guard key the credits band is warned under. */\nexport const AI_CREDITS_QUOTA_KEY = 'assistCredits'\n\n/**\n * The AI credits band the WORKSPACE is warned about (AGL-2898), as a quota\n * check the usage-alerts sweep runs beside its own.\n *\n * Measured in CREDITS — the unit the customer was sold and the meter shows —\n * from the workspace's month (`orgs/{orgId}/assistUsage/{month}`) NET OF\n * CREDITS GIVEN BACK (`assistSpendAfterReturnsUsd`, AGL-3595), through the one\n * conversion, so this alert, the Billing meter, the Assist usage strip and\n * the reservation cannot disagree about how far into the band the org is.\n * The month's spend line is gross — `estCostUsd` alone — and read off it, a\n * Free workspace whose test resets and refunded failures had handed 252 of\n * 442 credits back was told it had used \"442 — more than the 300 your plan\n * includes\". A plan with no band\n * resolves `null` and reads as a limit of 0, which the sweep skips the way it\n * skips Free's zero-quota dimensions.\n *\n * Approaching the band is the sweep's generic warning; REACHING it says what\n * happens next, which differs by plan and by the org's own controls — metered\n * at a rate unless a stop is set, or stopped until next month with nothing\n * ever billed — and telling a Free org to \"set a monthly cap\" on a charge it\n * can never incur would be the surprise bill in reverse.\n */\nexport async function aiQuotaChecks(\n context: UsageQuotaContext,\n): Promise<readonly UsageQuotaCheck[]> {\n const monthDoc = await firebaseAdmin\n .app()\n .firestore()\n .collection('orgs')\n .doc(context.orgId)\n .collection('assistUsage')\n .doc(context.month)\n .get()\n // Net of credits given back (AGL-3595) — the figure the gate admits on.\n const spentUsd = assistSpendAfterReturnsUsd(\n monthDoc.get('estCostUsd'),\n monthDoc.get(ASSIST_RETURNED_USD_FIELD),\n )\n return aiQuotaChecksFrom(context, spentUsd)\n}\n\n/**\n * The checks, given the workspace's month spend in billed USD, already net\n * of give-backs.\n */\nexport function aiQuotaChecksFrom(\n context: Pick<UsageQuotaContext, 'org' | 'month'>,\n spentUsd: number,\n): readonly UsageQuotaCheck[] {\n const org = context.org as never\n const bandCredits = resolveAssistCreditBudget(org)\n const used = assistCreditsFromUsd(spentUsd)\n // FREE IS AN ALLOWANCE, NOT A BAND SOLD PAST. Nothing past it is ever\n // billed, so the notice says the credits are used for the month, when they\n // renew, and that an upgrade adds more — never \"more than your plan\n // includes\", which reads like the start of a charge.\n if (resolveEffectivePlan(org) === 'free') {\n const renews = aiFreeCreditsResetLabel(\n aiFreeCreditsResetOn(new Date(`${context.month}-01T00:00:00.000Z`)),\n )\n return [\n {\n key: AI_CREDITS_QUOTA_KEY,\n label: 'free AI credits',\n noun: 'free AI credits',\n used,\n limit: bandCredits ?? 0,\n cadence: 'monthly',\n outcome: 'stops',\n reachedTitle: \"You've used your free AI credits for this month\",\n reachedLead: 'has used its free AI credits for this month.',\n reached: `They renew on ${renews}. Upgrade for more.`,\n reachedLinksUpgrade: true,\n approach:\n 'Nothing is ever charged on Free. When they are used, AI assist ' +\n `pauses until your credits renew on ${renews}, or upgrade for more.`,\n },\n ]\n }\n // Whether crossing the band produces an invoice line or a stop. The same\n // predicate the reservation refuses on, so the words and the behavior\n // cannot drift: a band that refuses — the org's own switch, or a plan with\n // no rate — is a wall, and everything else is sold past.\n const bandIsWall = assistBandRefuses(org)\n // Through the same resolver `assistBandRefuses` asks, so the alert's rate\n // and its wall/sold verdict cannot disagree about one org. Read straight off\n // `PLAN_PRICING` they did: Starter's listed rate is null and the add-on's is\n // added by the resolver, so a Starter workspace with the add-on was told\n // \"sold past the band\" at \"$0.00 per 1,000\" in the same sentence (AGL-3014).\n const rateUsdPer1k = resolveAssistOverageRateUsdPer1k(org)\n const rate = `$${(rateUsdPer1k ?? 0).toFixed(2)} per 1,000`\n return [\n {\n key: AI_CREDITS_QUOTA_KEY,\n label: 'AI assist credits',\n noun: 'AI assist credits',\n used,\n limit: bandCredits ?? 0,\n cadence: 'monthly',\n outcome: bandIsWall ? 'stops' : 'bills',\n reachedTitle: bandIsWall\n ? \"You've used your included AI assist credits\"\n : \"You've used your included AI assist credits — extra credits \" +\n 'are now billed',\n reached: bandIsWall\n ? 'AI assist stops here until next month — nothing past the band ' +\n 'is ever billed. Upgrade in Billing to add credits' +\n (resolveAssistHardCap(org) && rateUsdPer1k !== null\n ? `, or turn off \"${ASSIST_HARD_CAP_CONTROL_LABEL}\" ` +\n `under ${ASSIST_HARD_CAP_CONTROL_LOCATION} to keep ` +\n `going at your plan’s rate.`\n : '.')\n : 'The assistant keeps answering, and the extra credits are ' +\n `metered on your monthly invoice at ${rate} — unless you set a ` +\n `stop under ${ASSIST_HARD_CAP_CONTROL_LOCATION}: stop at the ` +\n 'included band, or stop once this month’s overage reaches a ' +\n 'figure you choose.',\n approach: bandIsWall\n ? 'Nothing changes and nothing is charged — at the included band, ' +\n 'AI assist stops until next month, and nothing past it is ever ' +\n 'billed.'\n : 'Nothing is charged yet — past the included band, extra credits ' +\n `are metered on your monthly invoice at ${rate} unless you set a ` +\n `stop under ${ASSIST_HARD_CAP_CONTROL_LOCATION}.`,\n },\n ]\n}\n"],"names":["ASSIST_HARD_CAP_CONTROL_LABEL","ASSIST_HARD_CAP_CONTROL_LOCATION","assistBandRefuses","assistCreditsFromUsd","resolveAssistCreditBudget","resolveAssistHardCap","resolveAssistOverageRateUsdPer1k","resolveEffectivePlan","firebaseAdmin","ASSIST_RETURNED_USD_FIELD","assistSpendAfterReturnsUsd","aiFreeCreditsResetLabel","aiFreeCreditsResetOn","AI_CREDITS_QUOTA_KEY","aiQuotaChecks","context","monthDoc","app","firestore","collection","doc","orgId","month","get","spentUsd","aiQuotaChecksFrom","org","bandCredits","used","renews","Date","key","label","noun","limit","cadence","outcome","reachedTitle","reachedLead","reached","reachedLinksUpgrade","approach","bandIsWall","rateUsdPer1k","rate","toFixed"],"mappings":"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"}
|