@aglyn/plugins-ai 1.0.0-beta.254 → 1.0.0-beta.256
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/components/assist-signals-page.component.js +5 -6
- package/src/lib/components/assist-signals-page.component.js.map +1 -1
- package/src/lib/components/staff-org-ai-card.component.d.ts +0 -10
- package/src/lib/components/staff-org-ai-card.component.js +10 -79
- package/src/lib/components/staff-org-ai-card.component.js.map +1 -1
- package/src/lib/components/staff-org-ai-conversations.component.js +8 -41
- package/src/lib/components/staff-org-ai-conversations.component.js.map +1 -1
- package/src/lib/components/staff-user-ai-usage-card.component.js +2 -1
- package/src/lib/components/staff-user-ai-usage-card.component.js.map +1 -1
- package/src/lib/jobs/ai-job-page-language.d.ts +14 -1
- package/src/lib/jobs/ai-job-page-language.js +18 -3
- package/src/lib/jobs/ai-job-page-language.js.map +1 -1
- package/src/lib/jobs/ai-job-page-step.js +17 -3
- package/src/lib/jobs/ai-job-page-step.js.map +1 -1
- package/src/lib/jobs/ai-job-plan-step.js +4 -0
- package/src/lib/jobs/ai-job-plan-step.js.map +1 -1
- package/src/lib/jobs/ai-layout-stock-photos.d.ts +30 -0
- package/src/lib/jobs/ai-layout-stock-photos.js +76 -8
- package/src/lib/jobs/ai-layout-stock-photos.js.map +1 -1
- package/src/lib/jobs/fixtures/ai-dental-site-plan-recording.d.ts +95 -0
- package/src/lib/jobs/fixtures/ai-dental-site-plan-recording.js +137 -0
- package/src/lib/jobs/fixtures/ai-dental-site-plan-recording.js.map +1 -0
- package/src/lib/layout-language/ai-layout-labels.d.ts +2 -0
- package/src/lib/layout-language/ai-layout-labels.js +12 -6
- package/src/lib/layout-language/ai-layout-labels.js.map +1 -1
- package/src/lib/layout-language/ai-layout-pictures.d.ts +12 -3
- package/src/lib/layout-language/ai-layout-pictures.js +6 -3
- package/src/lib/layout-language/ai-layout-pictures.js.map +1 -1
- package/src/lib/model/ai-products-bulk.d.ts +48 -0
- package/src/lib/model/ai-products-bulk.js +56 -0
- package/src/lib/model/ai-products-bulk.js.map +1 -0
- package/src/lib/model/ai-products.d.ts +2 -4
- package/src/lib/model/ai-products.js +4 -9
- package/src/lib/model/ai-products.js.map +1 -1
- package/src/lib/providers/anthropic.js +26 -5
- package/src/lib/providers/anthropic.js.map +1 -1
- package/src/lib/providers/contract.d.ts +10 -0
- package/src/lib/providers/contract.js.map +1 -1
- package/src/lib/runtime/ai-doctrine-validators.d.ts +20 -0
- package/src/lib/runtime/ai-doctrine-validators.js +50 -0
- package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
- package/src/lib/runtime/ai-doctrine.d.ts +11 -0
- package/src/lib/runtime/ai-doctrine.js +9 -4
- package/src/lib/runtime/ai-doctrine.js.map +1 -1
- package/src/lib/runtime/ai-runtime.d.ts +6 -0
- package/src/lib/runtime/ai-runtime.js +10 -0
- package/src/lib/runtime/ai-runtime.js.map +1 -1
- package/src/lib/server/ai-admin-conversations.d.ts +2 -0
- package/src/lib/server/ai-admin-conversations.js +40 -7
- package/src/lib/server/ai-admin-conversations.js.map +1 -1
- package/src/lib/server/ai-admin-org.js +28 -2
- package/src/lib/server/ai-admin-org.js.map +1 -1
- package/src/lib/server/ai-admin-orgs-spend.js +19 -1
- package/src/lib/server/ai-admin-orgs-spend.js.map +1 -1
- package/src/lib/server/ai-admin-signals.js +11 -3
- package/src/lib/server/ai-admin-signals.js.map +1 -1
- package/src/lib/server/ai-admin-user.js +11 -1
- package/src/lib/server/ai-admin-user.js.map +1 -1
- package/src/lib/usage/ai-usage-wire.d.ts +5 -2
- package/src/lib/usage/ai-usage-wire.js +5 -2
- package/src/lib/usage/ai-usage-wire.js.map +1 -1
- package/src/lib/usage/assist-signals-view.d.ts +123 -0
- package/src/lib/usage/assist-signals-view.js +151 -0
- package/src/lib/usage/assist-signals-view.js.map +1 -0
- package/src/lib/usage/staff-org-ai-conversations-view.d.ts +51 -0
- package/src/lib/usage/staff-org-ai-conversations-view.js +127 -0
- package/src/lib/usage/staff-org-ai-conversations-view.js.map +1 -0
- package/src/lib/usage/staff-org-ai-view.d.ts +181 -0
- package/src/lib/usage/staff-org-ai-view.js +263 -0
- package/src/lib/usage/staff-org-ai-view.js.map +1 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ // Imported by the staff card (client) and by the App Route that serves it, so it
|
|
17
|
+
// imports neither entry barrel (see `staff-org-ai.ts`).
|
|
18
|
+
import { aiUsageMonthLabel } from "./ai-usage-wire.js";
|
|
19
|
+
import { aiCreditsCell, aiOverageCell, assistCostCell, assistPoolSentence } from "./staff-org-usage-ai.js";
|
|
20
|
+
/*
|
|
21
|
+
* THE STAFF AI CARD, AS IT PRINTS (AGL-3667).
|
|
22
|
+
*
|
|
23
|
+
* `/admin/orgs/:orgId` draws the card in the browser: whole credits, dollars to
|
|
24
|
+
* four places under a dollar, the pool as the parts that make it up, the
|
|
25
|
+
* overage's state in one sentence, a red or amber or green margin. The staff
|
|
26
|
+
* apps read the same figures through `/api/ai/admin/org?view=prepared`, which
|
|
27
|
+
* sends each sentence the card prints, so a figure or a sentence on the card is
|
|
28
|
+
* decided once. The card imports the helpers below for the same reason.
|
|
29
|
+
*/ export const credits = (value)=>value == null ? '—' : Math.round(value).toLocaleString('en-US');
|
|
30
|
+
/**
|
|
31
|
+
* Four decimals under a dollar, two above (the assist-signals page's rule):
|
|
32
|
+
* a month that really cost eight cents must not read as `$0.00`.
|
|
33
|
+
*/ export const usd = (value)=>{
|
|
34
|
+
if (value == null) return '—';
|
|
35
|
+
const amount = Number(value) || 0;
|
|
36
|
+
return `$${amount.toFixed(Math.abs(amount) < 1 ? 4 : 2)}`;
|
|
37
|
+
};
|
|
38
|
+
export const tokenCount = (value)=>Math.round(value).toLocaleString('en-US');
|
|
39
|
+
export const rate = (value)=>value == null ? '—' : `${Math.round(value * 100)}%`;
|
|
40
|
+
/** The pool as one sentence naming every part that is non-zero. */ export function poolPartsSentence(pool, addonName) {
|
|
41
|
+
const parts = [];
|
|
42
|
+
if (pool.overrideCredits !== null) {
|
|
43
|
+
parts.push(`${credits(pool.overrideCredits)} staff override`);
|
|
44
|
+
} else {
|
|
45
|
+
parts.push(`${credits(pool.planCredits)} plan band`);
|
|
46
|
+
}
|
|
47
|
+
if (pool.addonCredits > 0) {
|
|
48
|
+
parts.push(`${credits(pool.addonCredits)} ${addonName} add-on`);
|
|
49
|
+
}
|
|
50
|
+
return parts.join(' + ');
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The overage's state as one line: sold, walled, or capped — or, for an
|
|
54
|
+
* uncapped staff comp (AGL-3049), nothing to sell past at all.
|
|
55
|
+
*/ export function overageStateSentence(overage, uncapped = false) {
|
|
56
|
+
if (uncapped) {
|
|
57
|
+
return 'Nothing is sold past a band: an uncapped staff comp has none, and bills nothing.';
|
|
58
|
+
}
|
|
59
|
+
if (overage.hardCap) return 'Stopped at the band — the org’s band switch is on.';
|
|
60
|
+
if (!overage.sellsOverage) return 'Not sold past the band on this plan.';
|
|
61
|
+
const per = overage.rateUsdPer1k === null ? '' : ` at ${usd(overage.rateUsdPer1k)} per 1,000`;
|
|
62
|
+
if (overage.capUsd !== null) {
|
|
63
|
+
return overage.capReached ? `Stopped — the org’s ${usd(overage.capUsd)} overage ceiling is reached.` : `Sold${per}, up to the org’s ${usd(overage.capUsd)} ceiling.`;
|
|
64
|
+
}
|
|
65
|
+
return `Sold${per}, no ceiling set.`;
|
|
66
|
+
}
|
|
67
|
+
/** Whether the margin section renders red. */ export function marginTone(margin) {
|
|
68
|
+
if (margin.underwater) return 'error';
|
|
69
|
+
if (margin.multiple >= 1) return 'warning';
|
|
70
|
+
return 'success';
|
|
71
|
+
}
|
|
72
|
+
/** The words for each reason the gate refused, in the order the card lists them. */ export const REFUSAL_LABELS = {
|
|
73
|
+
band: 'band',
|
|
74
|
+
cap: 'ceiling',
|
|
75
|
+
messages: 'messages',
|
|
76
|
+
budget: 'operator backstop',
|
|
77
|
+
// A hard allotment a manager set on a member, a collaborator or a site
|
|
78
|
+
// (AGL-2942).
|
|
79
|
+
allotment: 'allotments',
|
|
80
|
+
// The Free taste's rungs (AGL-2925): only a Free workspace collects these.
|
|
81
|
+
account: 'free account',
|
|
82
|
+
requests: 'free requests/day',
|
|
83
|
+
refusals: 'free refusals/day',
|
|
84
|
+
platform: 'platform ceiling'
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* Each reason as the chip the card draws: `band 3`. A reason the answering
|
|
88
|
+
* server does not yet count reads as zero.
|
|
89
|
+
*/ export function refusalChips(refusals) {
|
|
90
|
+
return Object.keys(REFUSAL_LABELS).map((reason)=>{
|
|
91
|
+
var _refusals_reason;
|
|
92
|
+
return {
|
|
93
|
+
label: REFUSAL_LABELS[reason],
|
|
94
|
+
count: Number((_refusals_reason = refusals[reason]) != null ? _refusals_reason : 0)
|
|
95
|
+
};
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
/** The statuses the jobs row names, and the ones that turn it amber or red. */ export const JOB_CHIP_STATUSES = [
|
|
99
|
+
'queued',
|
|
100
|
+
'running',
|
|
101
|
+
'needs_input',
|
|
102
|
+
'needs_review',
|
|
103
|
+
'failed'
|
|
104
|
+
];
|
|
105
|
+
/** What the add-on row says about when it was bought. */ export function addonSinceNote(addon) {
|
|
106
|
+
if (addon.since) return '';
|
|
107
|
+
return addon.sinceSource === 'unavailable' ? 'Stripe not reachable' : 'no subscription item';
|
|
108
|
+
}
|
|
109
|
+
/** Which meters a give-back may go to, as the dialog offers them, and the one it starts on. */ export function creditReturnMeters(hasWorkspace, hasAccount) {
|
|
110
|
+
const labels = {
|
|
111
|
+
both: 'Both',
|
|
112
|
+
workspace: 'Workspace band',
|
|
113
|
+
account: 'Owner’s Free allowance'
|
|
114
|
+
};
|
|
115
|
+
return [
|
|
116
|
+
'both',
|
|
117
|
+
'workspace',
|
|
118
|
+
'account'
|
|
119
|
+
].filter((meter)=>meter === 'both' ? hasWorkspace && hasAccount : meter === 'workspace' ? hasWorkspace : hasAccount).map((value)=>({
|
|
120
|
+
value,
|
|
121
|
+
label: labels[value]
|
|
122
|
+
}));
|
|
123
|
+
}
|
|
124
|
+
/** The most one give-back may return to the meter(s) chosen: the lower of the two for both. */ export function creditReturnable(meter, workspaceUsed, accountUsed) {
|
|
125
|
+
const figures = meter === 'both' ? [
|
|
126
|
+
workspaceUsed,
|
|
127
|
+
accountUsed
|
|
128
|
+
] : meter === 'workspace' ? [
|
|
129
|
+
workspaceUsed
|
|
130
|
+
] : [
|
|
131
|
+
accountUsed
|
|
132
|
+
];
|
|
133
|
+
if (figures.some((figure)=>figure == null)) return 0;
|
|
134
|
+
return Math.max(0, Math.min(...figures.map((figure)=>Math.floor(figure != null ? figure : 0))));
|
|
135
|
+
}
|
|
136
|
+
/** The sentence under the give-back form: what each meter used, which is all it can return. */ export function creditReturnSummary(workspaceUsed, accountUsed) {
|
|
137
|
+
const parts = [];
|
|
138
|
+
if (workspaceUsed != null) parts.push(`workspace band ${credits(workspaceUsed)}`);
|
|
139
|
+
if (accountUsed != null) parts.push(`owner’s Free allowance ${credits(accountUsed)}`);
|
|
140
|
+
return parts.length ? `Used this month, and so the most to give back: ${parts.join(', ')}.` : 'Nothing is metered here.';
|
|
141
|
+
}
|
|
142
|
+
/** One line of the allowance, as the org card and the user card print it. */ export function allowanceSentence(account, scope) {
|
|
143
|
+
const given = account.returnedCredits ? ` (${credits(account.returnedCredits)} given back)` : '';
|
|
144
|
+
return scope === 'org' ? `Owner’s Free allowance: ${credits(account.usedCredits)} of ${credits(account.limitCredits)} used across their free workspaces${given}` : `Free AI allowance this month: ${credits(account.usedCredits)} of ${credits(account.limitCredits)} credits used across the free workspaces this account owns${given}.`;
|
|
145
|
+
}
|
|
146
|
+
/** The card's figures as the sentences it prints. */ export function staffOrgAiView(data, addonName, usage) {
|
|
147
|
+
var _ref, _ref1, _ref2, _ref3;
|
|
148
|
+
var _meters_, _data_account, _data_account1;
|
|
149
|
+
const { addon, pool, overage, refusals, jobs, margin } = data;
|
|
150
|
+
const uncapped = pool.uncapped === true;
|
|
151
|
+
const sentence = pool.totalCredits === null && uncapped ? 'Uncapped staff comp — no AI credit band. Bounded only by the message cap and an operator’s explicit spend ceiling.' : pool.totalCredits === null ? 'No AI credit band on this plan — bounded by the message cap and the operator backstop.' : `${credits(pool.totalCredits)} credits = ${poolPartsSentence(pool, addonName)}`;
|
|
152
|
+
const hasAccount = Boolean(data.account);
|
|
153
|
+
const meters = creditReturnMeters(true, hasAccount);
|
|
154
|
+
const defaultMeter = (_ref = (_meters_ = meters[0]) == null ? void 0 : _meters_.value) != null ? _ref : 'workspace';
|
|
155
|
+
const returnable = creditReturnable(defaultMeter, pool.usedCredits, (_ref1 = (_data_account = data.account) == null ? void 0 : _data_account.usedCredits) != null ? _ref1 : null);
|
|
156
|
+
return {
|
|
157
|
+
month: data.month,
|
|
158
|
+
addon: {
|
|
159
|
+
on: addon.on,
|
|
160
|
+
status: addon.on ? `${addonName} on` : `${addonName} off`,
|
|
161
|
+
price: addon.priceUsd !== null ? `${usd(addon.priceUsd)}/mo on this plan` : 'Not sold on this plan',
|
|
162
|
+
since: addon.on ? addon.since : null,
|
|
163
|
+
sinceNote: addon.on ? addonSinceNote(addon) : ''
|
|
164
|
+
},
|
|
165
|
+
pool: {
|
|
166
|
+
band: sentence,
|
|
167
|
+
used: `Used ${credits(pool.usedCredits)} credits (${usd(pool.providerUsd)} provider spend)` + (pool.remainingCredits !== null ? ` · ${credits(pool.remainingCredits)} remaining` : ''),
|
|
168
|
+
returned: pool.returnedCredits ? `${credits(pool.returnedCredits)} credits given back this month — already taken off the figure above.` : '',
|
|
169
|
+
allowance: data.account ? allowanceSentence(data.account, 'org') : '',
|
|
170
|
+
projected: `Projected month-end at this pace: ${credits(pool.projectedCredits)} credits (${usd(pool.projectedUsd)}) · ${pool.messages.toLocaleString('en-US')} model turns, ${pool.deflected.toLocaleString('en-US')} answered from the docs`
|
|
171
|
+
},
|
|
172
|
+
overage: {
|
|
173
|
+
line: `${credits(overage.overageCredits)} credits over the band · ${usd(overage.accruedUsd)} accrued`,
|
|
174
|
+
state: overageStateSentence(overage, uncapped)
|
|
175
|
+
},
|
|
176
|
+
refusals: {
|
|
177
|
+
heading: `Refusals this month · ${refusals.total.toLocaleString('en-US')}`,
|
|
178
|
+
chips: refusalChips(refusals).map((chip)=>`${chip.label} ${chip.count.toLocaleString('en-US')}`)
|
|
179
|
+
},
|
|
180
|
+
jobs: {
|
|
181
|
+
failedRead: jobs === null,
|
|
182
|
+
empty: jobs !== null && Object.values(jobs.counts).reduce((sum, n)=>sum + n, 0) === 0,
|
|
183
|
+
chips: jobs ? [
|
|
184
|
+
...JOB_CHIP_STATUSES.map((status)=>`${status.replace('_', ' ')} ${jobs.counts[status]}`),
|
|
185
|
+
`done ${jobs.counts.done}`
|
|
186
|
+
] : [],
|
|
187
|
+
floor: (jobs == null ? void 0 : jobs.truncated) ? 'Counted from the newest jobs only — these counts are a floor.' : '',
|
|
188
|
+
recent: ((_ref2 = jobs == null ? void 0 : jobs.recent) != null ? _ref2 : []).map((job)=>{
|
|
189
|
+
var _job_status;
|
|
190
|
+
return {
|
|
191
|
+
id: job.id,
|
|
192
|
+
kind: job.kind || '—',
|
|
193
|
+
status: String((_job_status = job.status) != null ? _job_status : '').replace('_', ' '),
|
|
194
|
+
credits: `${credits(job.creditsSpent)} / ${credits(job.creditsReserved)}`,
|
|
195
|
+
startedAt: job.createdAt,
|
|
196
|
+
startedBy: job.createdBy,
|
|
197
|
+
// What a give-back of this job starts at: its spend, never more than the month used.
|
|
198
|
+
giveBack: job.creditsSpent > 0 ? Math.min(Math.ceil(job.creditsSpent), returnable) : 0
|
|
199
|
+
};
|
|
200
|
+
})
|
|
201
|
+
},
|
|
202
|
+
tokens: data.tokens ? {
|
|
203
|
+
totals: `${tokenCount(data.tokens.total.input)} sent · ${tokenCount(data.tokens.total.cached)} read from cache · ${tokenCount(data.tokens.total.cacheWrite)} written to cache · ${tokenCount(data.tokens.total.output)} generated`,
|
|
204
|
+
cacheHit: `cache hit rate ${rate(data.tokens.cacheHitRate)}`,
|
|
205
|
+
empty: data.tokens.kinds.length === 0,
|
|
206
|
+
kinds: data.tokens.kinds.map((row)=>({
|
|
207
|
+
kind: row.kind,
|
|
208
|
+
headline: `${row.requests.toLocaleString('en-US')} requests · ${usd(row.costPerRequestUsd)} per request`,
|
|
209
|
+
detail: `${tokenCount(row.tokens.input)} sent · ${tokenCount(row.tokens.cached)} from cache · ${tokenCount(row.tokens.output)} generated · cache hit ${rate(row.cacheHitRate)}`
|
|
210
|
+
}))
|
|
211
|
+
} : null,
|
|
212
|
+
users: data.users.map((user)=>({
|
|
213
|
+
uid: user.uid,
|
|
214
|
+
name: user.name,
|
|
215
|
+
headline: `${credits(user.credits)} credits · ${Math.round(user.share * 100)}% · ${usd(user.estCostUsd)} provider`,
|
|
216
|
+
detail: `${user.requests.toLocaleString('en-US')} requests · ${user.refusals.toLocaleString('en-US')} refusals`
|
|
217
|
+
})),
|
|
218
|
+
margin: {
|
|
219
|
+
tone: marginTone(margin),
|
|
220
|
+
text: `Spend ${usd(margin.spendUsd)} against ${usd(margin.revenueUsd)} in — ` + `${usd(margin.addonRevenueUsd)} add-on, ${usd(margin.planAssistShareUsd)} plan assist share, ` + `${usd(margin.overageRevenueUsd)} overage.` + (margin.underwater ? ' Spend exceeds the add-on plus the plan’s assist share.' : '') + (margin.multiple >= 1 ? ` ${margin.multiple}× the ${usd(margin.thresholdUsd)} staff review threshold.` : ''),
|
|
221
|
+
contribution: margin.contribution.marginPct !== null ? `Whole-org contribution margin ${Math.round(margin.contribution.marginPct * 100)}% on the ${margin.contribution.month} rollup with this month’s AI spend.` : ''
|
|
222
|
+
},
|
|
223
|
+
giveBack: {
|
|
224
|
+
meters,
|
|
225
|
+
defaultMeter,
|
|
226
|
+
summary: creditReturnSummary(pool.usedCredits, (_ref3 = (_data_account1 = data.account) == null ? void 0 : _data_account1.usedCredits) != null ? _ref3 : null),
|
|
227
|
+
returnable
|
|
228
|
+
},
|
|
229
|
+
usage: usage ? {
|
|
230
|
+
pool: assistPoolSentence(usage.pool),
|
|
231
|
+
months: usage.months.map((row)=>({
|
|
232
|
+
month: row.month,
|
|
233
|
+
headline: `Assist ${assistCostCell(row.assistCostUsd)}`,
|
|
234
|
+
detail: `AI credits used ${aiCreditsCell(row.assistCredits)} \u00b7 AI overage billed ${aiOverageCell(row.assistOverageUsd)}`
|
|
235
|
+
}))
|
|
236
|
+
} : null
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
/** The account card as it prints: the Free allowance, and a row per workspace per month kept. */ export function staffUserAiView(data) {
|
|
240
|
+
var _ref;
|
|
241
|
+
var _data_allowance;
|
|
242
|
+
const used = (_ref = (_data_allowance = data.allowance) == null ? void 0 : _data_allowance.usedCredits) != null ? _ref : null;
|
|
243
|
+
return {
|
|
244
|
+
allowance: data.allowance ? allowanceSentence(data.allowance, 'user') : '',
|
|
245
|
+
giveBack: {
|
|
246
|
+
summary: creditReturnSummary(null, used),
|
|
247
|
+
returnable: creditReturnable('account', null, used)
|
|
248
|
+
},
|
|
249
|
+
empty: data.rows.length ? '' : 'No AI usage attributed to this account in any workspace it belongs to.',
|
|
250
|
+
rows: data.rows.map((row)=>{
|
|
251
|
+
var _row_orgName;
|
|
252
|
+
return {
|
|
253
|
+
orgId: row.orgId,
|
|
254
|
+
workspace: (_row_orgName = row.orgName) != null ? _row_orgName : row.orgId,
|
|
255
|
+
month: aiUsageMonthLabel(row.month, 'en-US'),
|
|
256
|
+
headline: `${credits(row.credits)} credits`,
|
|
257
|
+
detail: `${row.requests.toLocaleString('en-US')} requests \u00b7 ${row.refusals.toLocaleString('en-US')} refusals`
|
|
258
|
+
};
|
|
259
|
+
})
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
//# sourceMappingURL=staff-org-ai-view.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/usage/staff-org-ai-view.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\n// Imported by the staff card (client) and by the App Route that serves it, so it\n// imports neither entry barrel (see `staff-org-ai.ts`).\nimport { aiUsageMonthLabel } from './ai-usage-wire'\nimport {\n aiCreditsCell,\n aiOverageCell,\n assistCostCell,\n assistPoolSentence,\n type StaffAssistPool,\n type StaffOrgUsageAiMonth,\n} from './staff-org-usage-ai'\nimport type {\n StaffAiAccountAllowance,\n StaffOrgAiMargin,\n StaffOrgAiOverage,\n StaffOrgAiPool,\n StaffOrgAiRefusals,\n StaffOrgAiResponse,\n} from './staff-org-ai'\n\n/*\n * THE STAFF AI CARD, AS IT PRINTS (AGL-3667).\n *\n * `/admin/orgs/:orgId` draws the card in the browser: whole credits, dollars to\n * four places under a dollar, the pool as the parts that make it up, the\n * overage's state in one sentence, a red or amber or green margin. The staff\n * apps read the same figures through `/api/ai/admin/org?view=prepared`, which\n * sends each sentence the card prints, so a figure or a sentence on the card is\n * decided once. The card imports the helpers below for the same reason.\n */\n\nexport const credits = (value: number | null | undefined): string =>\n value == null ? '—' : Math.round(value).toLocaleString('en-US')\n\n/**\n * Four decimals under a dollar, two above (the assist-signals page's rule):\n * a month that really cost eight cents must not read as `$0.00`.\n */\nexport const usd = (value: number | null | undefined): string => {\n if (value == null) return '—'\n const amount = Number(value) || 0\n return `$${amount.toFixed(Math.abs(amount) < 1 ? 4 : 2)}`\n}\n\nexport const tokenCount = (value: number): string => Math.round(value).toLocaleString('en-US')\n\nexport const rate = (value: number | null): string => (value == null ? '—' : `${Math.round(value * 100)}%`)\n\n/** The pool as one sentence naming every part that is non-zero. */\nexport function poolPartsSentence(pool: StaffOrgAiPool, addonName: string): string {\n const parts: string[] = []\n if (pool.overrideCredits !== null) {\n parts.push(`${credits(pool.overrideCredits)} staff override`)\n } else {\n parts.push(`${credits(pool.planCredits)} plan band`)\n }\n if (pool.addonCredits > 0) {\n parts.push(`${credits(pool.addonCredits)} ${addonName} add-on`)\n }\n return parts.join(' + ')\n}\n\n/**\n * The overage's state as one line: sold, walled, or capped — or, for an\n * uncapped staff comp (AGL-3049), nothing to sell past at all.\n */\nexport function overageStateSentence(overage: StaffOrgAiOverage, uncapped = false): string {\n if (uncapped) {\n return 'Nothing is sold past a band: an uncapped staff comp has none, and bills nothing.'\n }\n if (overage.hardCap) return 'Stopped at the band — the org’s band switch is on.'\n if (!overage.sellsOverage) return 'Not sold past the band on this plan.'\n const per = overage.rateUsdPer1k === null ? '' : ` at ${usd(overage.rateUsdPer1k)} per 1,000`\n if (overage.capUsd !== null) {\n return overage.capReached\n ? `Stopped — the org’s ${usd(overage.capUsd)} overage ceiling is reached.`\n : `Sold${per}, up to the org’s ${usd(overage.capUsd)} ceiling.`\n }\n return `Sold${per}, no ceiling set.`\n}\n\n/** Whether the margin section renders red. */\nexport function marginTone(margin: StaffOrgAiMargin): 'error' | 'warning' | 'success' {\n if (margin.underwater) return 'error'\n if (margin.multiple >= 1) return 'warning'\n return 'success'\n}\n\n/** The words for each reason the gate refused, in the order the card lists them. */\nexport const REFUSAL_LABELS: Record<keyof Omit<StaffOrgAiRefusals, 'total'>, string> = {\n band: 'band',\n cap: 'ceiling',\n messages: 'messages',\n budget: 'operator backstop',\n // A hard allotment a manager set on a member, a collaborator or a site\n // (AGL-2942).\n allotment: 'allotments',\n // The Free taste's rungs (AGL-2925): only a Free workspace collects these.\n account: 'free account',\n requests: 'free requests/day',\n refusals: 'free refusals/day',\n platform: 'platform ceiling',\n}\n\n/**\n * Each reason as the chip the card draws: `band 3`. A reason the answering\n * server does not yet count reads as zero.\n */\nexport function refusalChips(refusals: StaffOrgAiRefusals): Array<{ label: string; count: number }> {\n return (Object.keys(REFUSAL_LABELS) as Array<keyof typeof REFUSAL_LABELS>).map((reason) => ({\n label: REFUSAL_LABELS[reason],\n count: Number(refusals[reason] ?? 0),\n }))\n}\n\n/** The statuses the jobs row names, and the ones that turn it amber or red. */\nexport const JOB_CHIP_STATUSES = ['queued', 'running', 'needs_input', 'needs_review', 'failed'] as const\n\n/** What the add-on row says about when it was bought. */\nexport function addonSinceNote(addon: StaffOrgAiResponse['addon']): string {\n if (addon.since) return ''\n return addon.sinceSource === 'unavailable' ? 'Stripe not reachable' : 'no subscription item'\n}\n\n/** Which meters a give-back may go to, as the dialog offers them, and the one it starts on. */\nexport function creditReturnMeters(\n hasWorkspace: boolean,\n hasAccount: boolean,\n): Array<{ value: 'both' | 'workspace' | 'account'; label: string }> {\n const labels = { both: 'Both', workspace: 'Workspace band', account: 'Owner’s Free allowance' } as const\n return (['both', 'workspace', 'account'] as const)\n .filter((meter) => (meter === 'both' ? hasWorkspace && hasAccount : meter === 'workspace' ? hasWorkspace : hasAccount))\n .map((value) => ({ value, label: labels[value] }))\n}\n\n/** The most one give-back may return to the meter(s) chosen: the lower of the two for both. */\nexport function creditReturnable(\n meter: 'both' | 'workspace' | 'account',\n workspaceUsed: number | null,\n accountUsed: number | null,\n): number {\n const figures = meter === 'both' ? [workspaceUsed, accountUsed] : meter === 'workspace' ? [workspaceUsed] : [accountUsed]\n if (figures.some((figure) => figure == null)) return 0\n return Math.max(0, Math.min(...figures.map((figure) => Math.floor(figure ?? 0))))\n}\n\n/** The sentence under the give-back form: what each meter used, which is all it can return. */\nexport function creditReturnSummary(workspaceUsed: number | null, accountUsed: number | null): string {\n const parts: string[] = []\n if (workspaceUsed != null) parts.push(`workspace band ${credits(workspaceUsed)}`)\n if (accountUsed != null) parts.push(`owner’s Free allowance ${credits(accountUsed)}`)\n return parts.length ? `Used this month, and so the most to give back: ${parts.join(', ')}.` : 'Nothing is metered here.'\n}\n\n/** One line of the allowance, as the org card and the user card print it. */\nexport function allowanceSentence(account: StaffAiAccountAllowance, scope: 'org' | 'user'): string {\n const given = account.returnedCredits ? ` (${credits(account.returnedCredits)} given back)` : ''\n return scope === 'org'\n ? `Owner’s Free allowance: ${credits(account.usedCredits)} of ${credits(account.limitCredits)} used across their free workspaces${given}`\n : `Free AI allowance this month: ${credits(account.usedCredits)} of ${credits(account.limitCredits)} credits used across the free workspaces this account owns${given}.`\n}\n\nexport interface StaffOrgAiView {\n month: string\n addon: { status: string; price: string; since: string | null; sinceNote: string; on: boolean }\n pool: {\n band: string\n used: string\n returned: string\n allowance: string\n projected: string\n }\n overage: { line: string; state: string }\n refusals: { heading: string; chips: string[] }\n jobs: {\n failedRead: boolean\n empty: boolean\n chips: string[]\n floor: string\n recent: Array<{\n id: string\n kind: string\n status: string\n credits: string\n startedAt: string | null\n startedBy: string | null\n giveBack: number\n }>\n }\n tokens: {\n totals: string\n cacheHit: string\n empty: boolean\n kinds: Array<{ kind: string; headline: string; detail: string }>\n } | null\n users: Array<{ uid: string; name: string; headline: string; detail: string }>\n margin: { tone: 'error' | 'warning' | 'success'; text: string; contribution: string }\n giveBack: {\n meters: Array<{ value: string; label: string }>\n defaultMeter: string\n summary: string\n returnable: number\n }\n /**\n * The AI columns of the org page's monthly usage table, and the pool line it draws above them\n * (`staffOrgUsageColumn`); null where the reader did not hand the rollups over.\n */\n usage: { pool: string; months: Array<{ month: string; headline: string; detail: string }> } | null\n}\n\n/** The AI fields of one monthly rollup, with the month they belong to. */\nexport type StaffOrgAiUsageRollup = StaffOrgUsageAiMonth & { month: string }\n\n/** The card's figures as the sentences it prints. */\nexport function staffOrgAiView(\n data: StaffOrgAiResponse,\n addonName: string,\n usage?: { pool: StaffAssistPool; months: readonly StaffOrgAiUsageRollup[] },\n): StaffOrgAiView {\n const { addon, pool, overage, refusals, jobs, margin } = data\n const uncapped = pool.uncapped === true\n const sentence =\n pool.totalCredits === null && uncapped\n ? 'Uncapped staff comp — no AI credit band. Bounded only by the message cap and an operator’s explicit spend ceiling.'\n : pool.totalCredits === null\n ? 'No AI credit band on this plan — bounded by the message cap and the operator backstop.'\n : `${credits(pool.totalCredits)} credits = ${poolPartsSentence(pool, addonName)}`\n\n const hasAccount = Boolean(data.account)\n const meters = creditReturnMeters(true, hasAccount)\n const defaultMeter = meters[0]?.value ?? 'workspace'\n const returnable = creditReturnable(defaultMeter, pool.usedCredits, data.account?.usedCredits ?? null)\n\n return {\n month: data.month,\n addon: {\n on: addon.on,\n status: addon.on ? `${addonName} on` : `${addonName} off`,\n price: addon.priceUsd !== null ? `${usd(addon.priceUsd)}/mo on this plan` : 'Not sold on this plan',\n since: addon.on ? addon.since : null,\n sinceNote: addon.on ? addonSinceNote(addon) : '',\n },\n pool: {\n band: sentence,\n used:\n `Used ${credits(pool.usedCredits)} credits (${usd(pool.providerUsd)} provider spend)` +\n (pool.remainingCredits !== null ? ` · ${credits(pool.remainingCredits)} remaining` : ''),\n returned: pool.returnedCredits\n ? `${credits(pool.returnedCredits)} credits given back this month — already taken off the figure above.`\n : '',\n allowance: data.account ? allowanceSentence(data.account, 'org') : '',\n projected: `Projected month-end at this pace: ${credits(pool.projectedCredits)} credits (${usd(pool.projectedUsd)}) · ${pool.messages.toLocaleString('en-US')} model turns, ${pool.deflected.toLocaleString('en-US')} answered from the docs`,\n },\n overage: {\n line: `${credits(overage.overageCredits)} credits over the band · ${usd(overage.accruedUsd)} accrued`,\n state: overageStateSentence(overage, uncapped),\n },\n refusals: {\n heading: `Refusals this month · ${refusals.total.toLocaleString('en-US')}`,\n chips: refusalChips(refusals).map((chip) => `${chip.label} ${chip.count.toLocaleString('en-US')}`),\n },\n jobs: {\n failedRead: jobs === null,\n empty: jobs !== null && Object.values(jobs.counts).reduce((sum, n) => sum + n, 0) === 0,\n chips: jobs\n ? [\n ...JOB_CHIP_STATUSES.map((status) => `${status.replace('_', ' ')} ${jobs.counts[status]}`),\n `done ${jobs.counts.done}`,\n ]\n : [],\n floor: jobs?.truncated ? 'Counted from the newest jobs only — these counts are a floor.' : '',\n recent: (jobs?.recent ?? []).map((job) => ({\n id: job.id,\n kind: job.kind || '—',\n status: String(job.status ?? '').replace('_', ' '),\n credits: `${credits(job.creditsSpent)} / ${credits(job.creditsReserved)}`,\n startedAt: job.createdAt,\n startedBy: job.createdBy,\n // What a give-back of this job starts at: its spend, never more than the month used.\n giveBack: job.creditsSpent > 0 ? Math.min(Math.ceil(job.creditsSpent), returnable) : 0,\n })),\n },\n tokens: data.tokens\n ? {\n totals: `${tokenCount(data.tokens.total.input)} sent · ${tokenCount(data.tokens.total.cached)} read from cache · ${tokenCount(data.tokens.total.cacheWrite)} written to cache · ${tokenCount(data.tokens.total.output)} generated`,\n cacheHit: `cache hit rate ${rate(data.tokens.cacheHitRate)}`,\n empty: data.tokens.kinds.length === 0,\n kinds: data.tokens.kinds.map((row) => ({\n kind: row.kind,\n headline: `${row.requests.toLocaleString('en-US')} requests · ${usd(row.costPerRequestUsd)} per request`,\n detail: `${tokenCount(row.tokens.input)} sent · ${tokenCount(row.tokens.cached)} from cache · ${tokenCount(row.tokens.output)} generated · cache hit ${rate(row.cacheHitRate)}`,\n })),\n }\n : null,\n users: data.users.map((user) => ({\n uid: user.uid,\n name: user.name,\n headline: `${credits(user.credits)} credits · ${Math.round(user.share * 100)}% · ${usd(user.estCostUsd)} provider`,\n detail: `${user.requests.toLocaleString('en-US')} requests · ${user.refusals.toLocaleString('en-US')} refusals`,\n })),\n margin: {\n tone: marginTone(margin),\n text:\n `Spend ${usd(margin.spendUsd)} against ${usd(margin.revenueUsd)} in — ` +\n `${usd(margin.addonRevenueUsd)} add-on, ${usd(margin.planAssistShareUsd)} plan assist share, ` +\n `${usd(margin.overageRevenueUsd)} overage.` +\n (margin.underwater ? ' Spend exceeds the add-on plus the plan’s assist share.' : '') +\n (margin.multiple >= 1 ? ` ${margin.multiple}× the ${usd(margin.thresholdUsd)} staff review threshold.` : ''),\n contribution:\n margin.contribution.marginPct !== null\n ? `Whole-org contribution margin ${Math.round(margin.contribution.marginPct * 100)}% on the ${margin.contribution.month} rollup with this month’s AI spend.`\n : '',\n },\n giveBack: {\n meters,\n defaultMeter,\n summary: creditReturnSummary(pool.usedCredits, data.account?.usedCredits ?? null),\n returnable,\n },\n usage: usage\n ? {\n pool: assistPoolSentence(usage.pool),\n months: usage.months.map((row) => ({\n month: row.month,\n headline: `Assist ${assistCostCell(row.assistCostUsd)}`,\n detail: `AI credits used ${aiCreditsCell(row.assistCredits)} \\u00b7 AI overage billed ${aiOverageCell(row.assistOverageUsd)}`,\n })),\n }\n : null,\n }\n}\n\n/** One row of `/api/ai/admin/user`: a workspace's month for the account. */\nexport interface StaffUserAiRow {\n orgId: string\n orgName: string | null\n slug: string | null\n month: string\n credits: number\n requests: number\n refusals: number\n}\n\nexport interface StaffUserAiView {\n allowance: string\n giveBack: { summary: string; returnable: number }\n empty: string\n rows: Array<{ orgId: string; workspace: string; month: string; headline: string; detail: string }>\n}\n\n/** The account card as it prints: the Free allowance, and a row per workspace per month kept. */\nexport function staffUserAiView(data: {\n rows: StaffUserAiRow[]\n allowance: StaffAiAccountAllowance | null\n}): StaffUserAiView {\n const used = data.allowance?.usedCredits ?? null\n return {\n allowance: data.allowance ? allowanceSentence(data.allowance, 'user') : '',\n giveBack: {\n summary: creditReturnSummary(null, used),\n returnable: creditReturnable('account', null, used),\n },\n empty: data.rows.length ? '' : 'No AI usage attributed to this account in any workspace it belongs to.',\n rows: data.rows.map((row) => ({\n orgId: row.orgId,\n workspace: row.orgName ?? row.orgId,\n month: aiUsageMonthLabel(row.month, 'en-US'),\n headline: `${credits(row.credits)} credits`,\n detail: `${row.requests.toLocaleString('en-US')} requests \\u00b7 ${row.refusals.toLocaleString('en-US')} refusals`,\n })),\n }\n}\n"],"names":["aiUsageMonthLabel","aiCreditsCell","aiOverageCell","assistCostCell","assistPoolSentence","credits","value","Math","round","toLocaleString","usd","amount","Number","toFixed","abs","tokenCount","rate","poolPartsSentence","pool","addonName","parts","overrideCredits","push","planCredits","addonCredits","join","overageStateSentence","overage","uncapped","hardCap","sellsOverage","per","rateUsdPer1k","capUsd","capReached","marginTone","margin","underwater","multiple","REFUSAL_LABELS","band","cap","messages","budget","allotment","account","requests","refusals","platform","refusalChips","Object","keys","map","reason","label","count","JOB_CHIP_STATUSES","addonSinceNote","addon","since","sinceSource","creditReturnMeters","hasWorkspace","hasAccount","labels","both","workspace","filter","meter","creditReturnable","workspaceUsed","accountUsed","figures","some","figure","max","min","floor","creditReturnSummary","length","allowanceSentence","scope","given","returnedCredits","usedCredits","limitCredits","staffOrgAiView","data","usage","meters","jobs","sentence","totalCredits","Boolean","defaultMeter","returnable","month","on","status","price","priceUsd","sinceNote","used","providerUsd","remainingCredits","returned","allowance","projected","projectedCredits","projectedUsd","deflected","line","overageCredits","accruedUsd","state","heading","total","chips","chip","failedRead","empty","values","counts","reduce","sum","n","replace","done","truncated","recent","job","id","kind","String","creditsSpent","creditsReserved","startedAt","createdAt","startedBy","createdBy","giveBack","ceil","tokens","totals","input","cached","cacheWrite","output","cacheHit","cacheHitRate","kinds","row","headline","costPerRequestUsd","detail","users","user","uid","name","share","estCostUsd","tone","text","spendUsd","revenueUsd","addonRevenueUsd","planAssistShareUsd","overageRevenueUsd","thresholdUsd","contribution","marginPct","summary","months","assistCostUsd","assistCredits","assistOverageUsd","staffUserAiView","rows","orgId","orgName"],"mappings":"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"}
|