@aglyn/plugins-ai 1.0.0-beta.270 → 1.0.0-beta.271
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/activity/ai-activity-actions.d.ts +1 -1
- package/src/lib/activity/ai-activity-actions.js +1 -0
- package/src/lib/activity/ai-activity-actions.js.map +1 -1
- package/src/lib/assets/site-styles/beauty.webp +0 -0
- package/src/lib/assets/site-styles/blog.webp +0 -0
- package/src/lib/assets/site-styles/business.webp +0 -0
- package/src/lib/assets/site-styles/coming-soon.webp +0 -0
- package/src/lib/assets/site-styles/education.webp +0 -0
- package/src/lib/assets/site-styles/events.webp +0 -0
- package/src/lib/assets/site-styles/fitness.webp +0 -0
- package/src/lib/assets/site-styles/landing.webp +0 -0
- package/src/lib/assets/site-styles/music.webp +0 -0
- package/src/lib/assets/site-styles/nonprofit.webp +0 -0
- package/src/lib/assets/site-styles/personal.webp +0 -0
- package/src/lib/assets/site-styles/photography.webp +0 -0
- package/src/lib/assets/site-styles/portfolio.webp +0 -0
- package/src/lib/assets/site-styles/professional.webp +0 -0
- package/src/lib/assets/site-styles/realestate.webp +0 -0
- package/src/lib/assets/site-styles/restaurant.webp +0 -0
- package/src/lib/assets/site-styles/store.webp +0 -0
- package/src/lib/assets/site-styles/studio.webp +0 -0
- package/src/lib/assets/site-styles/trades.webp +0 -0
- package/src/lib/assets/site-styles/wellness.webp +0 -0
- package/src/lib/assets/site-styles/yoga.webp +0 -0
- package/src/lib/components/ai-credits-card.component.d.ts +4 -3
- package/src/lib/components/ai-credits-card.component.js +15 -15
- package/src/lib/components/ai-credits-card.component.js.map +1 -1
- package/src/lib/components/ai-job-input-form.component.d.ts +36 -0
- package/src/lib/components/ai-job-input-form.component.js +100 -0
- package/src/lib/components/ai-job-input-form.component.js.map +1 -0
- package/src/lib/components/ai-job-requests.d.ts +4 -0
- package/src/lib/components/ai-job-requests.js +4 -0
- package/src/lib/components/ai-job-requests.js.map +1 -1
- package/src/lib/components/ai-site-start-card.component.d.ts +1 -1
- package/src/lib/components/ai-site-start-card.component.js +99 -31
- package/src/lib/components/ai-site-start-card.component.js.map +1 -1
- package/src/lib/components/ai-site-start-steps.component.d.ts +43 -2
- package/src/lib/components/ai-site-start-steps.component.js +651 -15
- package/src/lib/components/ai-site-start-steps.component.js.map +1 -1
- package/src/lib/components/ai-site-start-tracking.d.ts +10 -0
- package/src/lib/components/ai-site-start-tracking.js +14 -0
- package/src/lib/components/ai-site-start-tracking.js.map +1 -1
- package/src/lib/components/ai-site-style-previews.js +26 -22
- package/src/lib/components/ai-site-style-previews.js.map +1 -1
- package/src/lib/components/ai-upsell-dialog.component.d.ts +7 -5
- package/src/lib/components/ai-upsell-dialog.component.js +8 -6
- package/src/lib/components/ai-upsell-dialog.component.js.map +1 -1
- package/src/lib/components/assist-build-card.component.js +11 -1
- package/src/lib/components/assist-build-card.component.js.map +1 -1
- package/src/lib/components/assist-jobs-drawer.component.js +9 -1
- package/src/lib/components/assist-jobs-drawer.component.js.map +1 -1
- package/src/lib/components/assist-panel.component.js +8 -4
- package/src/lib/components/assist-panel.component.js.map +1 -1
- package/src/lib/components/staff-org-ai-card.component.js +4 -7
- package/src/lib/components/staff-org-ai-card.component.js.map +1 -1
- package/src/lib/declarations.d.ts +2 -2
- package/src/lib/declarations.js +9 -5
- package/src/lib/declarations.js.map +1 -1
- package/src/lib/jobs/ai-build-capabilities.js +3 -1
- package/src/lib/jobs/ai-build-capabilities.js.map +1 -1
- package/src/lib/jobs/ai-business-profile-prefill.d.ts +1 -1
- package/src/lib/jobs/ai-business-profile-prefill.js +14 -3
- package/src/lib/jobs/ai-business-profile-prefill.js.map +1 -1
- package/src/lib/jobs/ai-job-build-step.js +5 -3
- package/src/lib/jobs/ai-job-build-step.js.map +1 -1
- package/src/lib/jobs/ai-job-form-step.d.ts +15 -1
- package/src/lib/jobs/ai-job-form-step.js +75 -8
- package/src/lib/jobs/ai-job-form-step.js.map +1 -1
- package/src/lib/jobs/ai-job-page-language.d.ts +13 -0
- package/src/lib/jobs/ai-job-page-language.js +37 -1
- package/src/lib/jobs/ai-job-page-language.js.map +1 -1
- package/src/lib/jobs/ai-job-page-step.d.ts +17 -0
- package/src/lib/jobs/ai-job-page-step.js +37 -16
- package/src/lib/jobs/ai-job-page-step.js.map +1 -1
- package/src/lib/jobs/ai-job-plan-step.d.ts +25 -2
- package/src/lib/jobs/ai-job-plan-step.js +103 -29
- package/src/lib/jobs/ai-job-plan-step.js.map +1 -1
- package/src/lib/jobs/ai-job-settings-step.js +4 -3
- package/src/lib/jobs/ai-job-settings-step.js.map +1 -1
- package/src/lib/jobs/ai-job-site-datasets.d.ts +27 -0
- package/src/lib/jobs/ai-job-site-datasets.js +140 -14
- package/src/lib/jobs/ai-job-site-datasets.js.map +1 -1
- package/src/lib/jobs/ai-job-site-look.js +18 -5
- package/src/lib/jobs/ai-job-site-look.js.map +1 -1
- package/src/lib/jobs/ai-job-site-step.d.ts +16 -1
- package/src/lib/jobs/ai-job-site-step.js +95 -22
- package/src/lib/jobs/ai-job-site-step.js.map +1 -1
- package/src/lib/jobs/ai-job-text-step.d.ts +8 -1
- package/src/lib/jobs/ai-job-text-step.js.map +1 -1
- package/src/lib/jobs/ai-job-tracking-step.d.ts +14 -3
- package/src/lib/jobs/ai-job-tracking-step.js +28 -5
- package/src/lib/jobs/ai-job-tracking-step.js.map +1 -1
- package/src/lib/jobs/ai-jobs.d.ts +8 -1
- package/src/lib/jobs/ai-jobs.js +63 -8
- package/src/lib/jobs/ai-jobs.js.map +1 -1
- package/src/lib/jobs/ai-layout-stock-photos.d.ts +27 -2
- package/src/lib/jobs/ai-layout-stock-photos.js +190 -19
- package/src/lib/jobs/ai-layout-stock-photos.js.map +1 -1
- package/src/lib/jobs/ai-site-inspiration-signals.d.ts +98 -0
- package/src/lib/jobs/ai-site-inspiration-signals.js +585 -0
- package/src/lib/jobs/ai-site-inspiration-signals.js.map +1 -0
- package/src/lib/jobs/ai-site-inspiration.d.ts +157 -0
- package/src/lib/jobs/ai-site-inspiration.js +346 -0
- package/src/lib/jobs/ai-site-inspiration.js.map +1 -0
- package/src/lib/jobs/ai-site-publish.d.ts +26 -1
- package/src/lib/jobs/ai-site-publish.js +162 -13
- package/src/lib/jobs/ai-site-publish.js.map +1 -1
- package/src/lib/jobs/ai-theme-brand-inputs.d.ts +16 -0
- package/src/lib/jobs/ai-theme-brand-inputs.js +18 -4
- package/src/lib/jobs/ai-theme-brand-inputs.js.map +1 -1
- package/src/lib/jobs/fixtures/ai-candle-shop-free-plan-recording.d.ts +97 -0
- package/src/lib/jobs/fixtures/ai-candle-shop-free-plan-recording.js +137 -0
- package/src/lib/jobs/fixtures/ai-candle-shop-free-plan-recording.js.map +1 -0
- package/src/lib/jobs/fixtures/ai-site-inspiration-pages.d.ts +38 -0
- package/src/lib/jobs/fixtures/ai-site-inspiration-pages.js +103 -0
- package/src/lib/jobs/fixtures/ai-site-inspiration-pages.js.map +1 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl3988-recordings.d.ts +25 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl3988-recordings.js +174 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl3988-recordings.js.map +1 -0
- package/src/lib/layout-language/ai-layout-compiler.d.ts +1 -1
- package/src/lib/layout-language/ai-layout-compiler.js +438 -25
- package/src/lib/layout-language/ai-layout-compiler.js.map +1 -1
- package/src/lib/layout-language/ai-layout-contact.d.ts +57 -0
- package/src/lib/layout-language/ai-layout-contact.js +137 -0
- package/src/lib/layout-language/ai-layout-contact.js.map +1 -0
- package/src/lib/layout-language/ai-layout-copy.d.ts +12 -0
- package/src/lib/layout-language/ai-layout-copy.js +34 -2
- package/src/lib/layout-language/ai-layout-copy.js.map +1 -1
- package/src/lib/layout-language/ai-layout-design.d.ts +65 -8
- package/src/lib/layout-language/ai-layout-design.js +411 -97
- package/src/lib/layout-language/ai-layout-design.js.map +1 -1
- package/src/lib/layout-language/ai-layout-frame.js +23 -0
- package/src/lib/layout-language/ai-layout-frame.js.map +1 -1
- 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-language.d.ts +3 -2
- package/src/lib/layout-language/ai-layout-language.js +4 -3
- package/src/lib/layout-language/ai-layout-language.js.map +1 -1
- package/src/lib/layout-language/ai-layout-links.d.ts +13 -0
- package/src/lib/layout-language/ai-layout-links.js +30 -0
- package/src/lib/layout-language/ai-layout-links.js.map +1 -1
- package/src/lib/layout-language/ai-layout-pictures.d.ts +49 -6
- package/src/lib/layout-language/ai-layout-pictures.js +145 -22
- package/src/lib/layout-language/ai-layout-pictures.js.map +1 -1
- package/src/lib/model/ai-build-job.d.ts +16 -1
- package/src/lib/model/ai-build-job.js +40 -0
- package/src/lib/model/ai-build-job.js.map +1 -1
- package/src/lib/model/ai-job-input.d.ts +33 -0
- package/src/lib/model/ai-job-input.js +59 -0
- package/src/lib/model/ai-job-input.js.map +1 -0
- package/src/lib/model/ai-job-notice.d.ts +4 -0
- package/src/lib/model/ai-job-notice.js +11 -1
- package/src/lib/model/ai-job-notice.js.map +1 -1
- package/src/lib/model/ai-jobs.types.d.ts +40 -1
- package/src/lib/model/ai-jobs.types.js.map +1 -1
- package/src/lib/model/ai-site-details.d.ts +122 -0
- package/src/lib/model/ai-site-details.js +300 -0
- package/src/lib/model/ai-site-details.js.map +1 -0
- package/src/lib/model/ai-site-entity.d.ts +181 -0
- package/src/lib/model/ai-site-entity.js +390 -0
- package/src/lib/model/ai-site-entity.js.map +1 -0
- package/src/lib/model/ai-site-inspiration.d.ts +72 -0
- package/src/lib/model/ai-site-inspiration.js +109 -0
- package/src/lib/model/ai-site-inspiration.js.map +1 -0
- package/src/lib/model/ai-site-job.d.ts +13 -1
- package/src/lib/model/ai-site-job.js +15 -2
- package/src/lib/model/ai-site-job.js.map +1 -1
- package/src/lib/model/ai-site-kinds.js +109 -21
- package/src/lib/model/ai-site-kinds.js.map +1 -1
- package/src/lib/model/ai-site-look.d.ts +10 -0
- package/src/lib/model/ai-site-look.js +24 -0
- package/src/lib/model/ai-site-look.js.map +1 -1
- package/src/lib/model/ai-site-start-seo.d.ts +19 -5
- package/src/lib/model/ai-site-start-seo.js +25 -7
- package/src/lib/model/ai-site-start-seo.js.map +1 -1
- package/src/lib/model/ai-site-start-steps.d.ts +9 -3
- package/src/lib/model/ai-site-start-steps.js +67 -5
- package/src/lib/model/ai-site-start-steps.js.map +1 -1
- package/src/lib/model/ai-site-start.d.ts +68 -4
- package/src/lib/model/ai-site-start.js +166 -13
- package/src/lib/model/ai-site-start.js.map +1 -1
- package/src/lib/model/ai-upsell-copy.js +4 -1
- package/src/lib/model/ai-upsell-copy.js.map +1 -1
- package/src/lib/plan-entitlements.d.ts +4 -3
- package/src/lib/plan-entitlements.js +3 -8
- package/src/lib/plan-entitlements.js.map +1 -1
- package/src/lib/runtime/ai-dataset-generation.d.ts +8 -1
- package/src/lib/runtime/ai-dataset-generation.js +12 -2
- package/src/lib/runtime/ai-dataset-generation.js.map +1 -1
- package/src/lib/runtime/ai-doctrine-validators.d.ts +26 -33
- package/src/lib/runtime/ai-doctrine-validators.js +54 -44
- package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
- package/src/lib/runtime/ai-doctrine.js +1 -1
- package/src/lib/runtime/ai-doctrine.js.map +1 -1
- package/src/lib/runtime/ai-node-tree.d.ts +7 -0
- package/src/lib/runtime/ai-node-tree.js +9 -1
- package/src/lib/runtime/ai-node-tree.js.map +1 -1
- package/src/lib/server/ai-create-route.d.ts +1 -1
- package/src/lib/server/ai-create-route.js +3 -4
- package/src/lib/server/ai-create-route.js.map +1 -1
- package/src/lib/server/ai-jobs-resume.js +27 -3
- package/src/lib/server/ai-jobs-resume.js.map +1 -1
- package/src/lib/server/ai-jobs-route.js +7 -0
- package/src/lib/server/ai-jobs-route.js.map +1 -1
- package/src/lib/usage/assist-credits.d.ts +4 -4
- package/src/lib/usage/assist-credits.js +4 -4
- package/src/lib/usage/assist-credits.js.map +1 -1
- package/src/lib/usage/staff-org-ai-view.js +6 -3
- package/src/lib/usage/staff-org-ai-view.js.map +1 -1
- package/src/lib/usage/staff-org-ai.d.ts +4 -2
- package/src/lib/usage/staff-org-ai.js +7 -7
- package/src/lib/usage/staff-org-ai.js.map +1 -1
- package/src/lib/usage/staff-org-usage-ai.js +2 -2
- package/src/lib/usage/staff-org-usage-ai.js.map +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/components/staff-org-ai-card.component.tsx"],"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'use client'\n\nimport { aiAddonName } from '@aglyn/aglyn'\nimport { buildRoute, Route } from '@aglyn/aglyn/app-utils/console-routes'\nimport { pluginDocsHelp } from '@aglyn/aglyn/app-utils/docs-help'\nimport { mdiOpenInNew } from '@aglyn/shared-data-mdi'\nimport { AppLink, CardDisplay } from '@aglyn/shared-ui-jsx'\nimport {\n ListRowActions,\n ListTable,\n listActionsColumn,\n} from '@aglyn/shared-ui-jsx/components/list-table.component'\nimport { ScrollTable } from '@aglyn/shared-ui-jsx/components/scroll-table.component'\nimport { TABLE_ROW_HEIGHT } from '@aglyn/shared-ui-jsx/const/table-pagination'\nimport { useUser } from '@aglyn/tenant-feature-instance'\nimport { authorizedFetch } from '@aglyn/shared-util-http/authorized-token'\nimport {\n Alert,\n Chip,\n Stack,\n TableBody,\n TableCell,\n TableHead,\n TableRow,\n Typography,\n} from '@mui/material'\nimport type { GridColDef } from '@mui/x-data-grid'\nimport { useRouter } from 'next/navigation'\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport type {\n StaffOrgAiJob,\n StaffOrgAiJobs,\n StaffOrgAiRefusals,\n StaffOrgAiResponse,\n StaffOrgAiTokens,\n StaffOrgAiUser,\n} from '../usage/staff-org-ai'\nimport {\n allowanceSentence,\n credits,\n marginTone,\n overageStateSentence,\n poolPartsSentence,\n rate,\n refusalChips,\n tokenCount,\n usd,\n JOB_CHIP_STATUSES,\n} from '../usage/staff-org-ai-view'\nimport {\n StaffCreditReturnActions,\n StaffCreditReturnDialog,\n} from './staff-ai-credit-return.component'\n\n/**\n * THE STAFF AI CARD (AGL-2930): everything about one org's AI usage on the\n * page staff already open to look at that org.\n *\n * Read through `/api/ai/admin/org`, one request on mount. Every figure on it\n * is the route's, and every figure the route serves is composed from the\n * same helpers the meter refuses with — see `usage/staff-org-ai.ts`. This\n * file only lays them out.\n *\n * ## What each section is for\n *\n * - **Add-on** — is the org paying for AI, at what, since when.\n * - **Credit pool** — the band as three NAMED parts, because \"why does\n * this org have 13,000 credits\" has three answers (the plan, an override,\n * the add-on) and a single total cannot say which.\n * - **Overage** — what is past the band, what it is sold at, and the two\n * controls the org itself holds over it.\n * - **Refusals** — how often, and why, the gate said no this month.\n * - **Jobs** and **Top users** — the generative and per-person halves,\n * each of which says plainly when its rollup has nothing yet.\n * - **Tokens** — what each kind of request costs per request, what it\n * sends and generates, and how much of its prompt the cache served.\n * - **Margin** — spend against what AI brings in, red when it is over.\n * - **Actions** — where the override editor and the AI pause live.\n *\n * The header carries the card's two acts (AGL-3595): give credits back to\n * the band (and, on a Free workspace, to the owner's allowance), or reset\n * the month — and each recent job offers the same give-back, prefilled with\n * that job's spend.\n */\n\nconst when = (iso: string | null): string =>\n iso ? new Date(iso).toLocaleDateString() : '—'\n\nfunction RefusalsRow({ refusals }: { refusals: StaffOrgAiRefusals }) {\n return (\n <Stack direction=\"row\" spacing={1} useFlexGap sx={{ flexWrap: 'wrap' }}>\n {refusalChips(refusals).map((chip) => (\n <Chip\n key={chip.label}\n size=\"small\"\n variant={chip.count > 0 ? 'filled' : 'outlined'}\n color={chip.count > 0 ? 'warning' : 'default'}\n label={`${chip.label} ${chip.count.toLocaleString()}`}\n />\n ))}\n </Stack>\n )\n}\n\nfunction JobsSection({\n jobs,\n onGiveBack,\n}: {\n jobs: StaffOrgAiJobs | null\n onGiveBack: (job: StaffOrgAiJob) => void\n}) {\n const columns = useMemo(() => jobColumns(onGiveBack), [onGiveBack])\n if (jobs === null) {\n return (\n <Alert severity=\"warning\">\n {'Could not read the generation jobs — a failed read, not an idle org.'}\n </Alert>\n )\n }\n const total = Object.values(jobs.counts).reduce((sum, n) => sum + n, 0)\n if (total === 0) {\n return (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'No generation jobs yet.'}\n </Typography>\n )\n }\n return (\n <Stack spacing={1}>\n <Stack direction=\"row\" spacing={1} useFlexGap sx={{ flexWrap: 'wrap' }}>\n {JOB_CHIP_STATUSES.map((status) => (\n <Chip\n key={status}\n size=\"small\"\n color={\n status === 'failed' && jobs.counts[status] > 0\n ? 'error'\n : (status === 'needs_input' || status === 'needs_review') &&\n jobs.counts[status] > 0\n ? 'warning'\n : 'default'\n }\n label={`${status.replace('_', ' ')} ${jobs.counts[status]}`}\n />\n ))}\n <Chip size=\"small\" variant=\"outlined\" label={`done ${jobs.counts.done}`} />\n </Stack>\n {jobs.truncated ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'Counted from the newest jobs only — these counts are a floor.'}\n </Typography>\n ) : null}\n {/* A record list: the grid scrolls its own columns, so a job id and a\n starter's uid never push the card's content past its edge. */}\n <ListTable\n rows={jobs.recent}\n columns={columns}\n getRowId={(job: StaffOrgAiJob) => job.id}\n rowHeight={TABLE_ROW_HEIGHT}\n noRowsLabel=\"No recent jobs\"\n // The route's ten newest jobs: a bounded readout, so no filter over\n // the rows it holds (AGL-3321).\n disableColumnFilter\n quickFilter={false}\n />\n </Stack>\n )\n}\n\n/**\n * The recent jobs, one column per fact. Who started a job is a column of\n * its own rather than a link tucked beside the date, so it sorts like the\n * rest; the credits sort by what was SPENT, which is the figure the\n * pool was charged. The row's action gives that spend back (AGL-3595).\n */\nconst jobColumns = (\n onGiveBack: (job: StaffOrgAiJob) => void,\n): GridColDef<StaffOrgAiJob>[] => [\n {\n field: 'id',\n headerName: 'Job',\n flex: 1,\n minWidth: 200,\n renderCell: ({ row }) => (\n <Typography variant=\"body2\" noWrap title={row.id} sx={{ fontFamily: 'monospace' }}>\n {row.id}\n </Typography>\n ),\n },\n {\n field: 'kind',\n headerName: 'Kind',\n width: 120,\n valueFormatter: (value: string) => value || '—',\n },\n {\n field: 'status',\n headerName: 'Status',\n width: 130,\n valueFormatter: (value: string) => String(value ?? '').replace('_', ' '),\n },\n {\n field: 'creditsSpent',\n headerName: 'Credits',\n type: 'number',\n align: 'right',\n headerAlign: 'right',\n width: 140,\n valueFormatter: (value: number, row) =>\n `${credits(value)} / ${credits(row.creditsReserved)}`,\n },\n {\n field: 'createdAt',\n headerName: 'Started',\n width: 120,\n valueFormatter: (value: string | null) => when(value),\n },\n {\n field: 'createdBy',\n headerName: 'Started by',\n flex: 1,\n minWidth: 240,\n renderCell: ({ row }) =>\n row.createdBy ? (\n <AppLink\n href={buildRoute(Route.ADMIN_USER_DETAIL, { uid: row.createdBy })}\n variant=\"body2\"\n underline=\"hover\"\n noWrap\n sx={{ fontFamily: 'monospace' }}\n >\n {row.createdBy}\n </AppLink>\n ) : (\n '—'\n ),\n },\n listActionsColumn((row: StaffOrgAiJob) => (\n <ListRowActions\n label={row.id}\n items={[\n {\n key: 'give-back',\n label: 'Give back this job’s credits',\n disabled: row.creditsSpent <= 0,\n disabledReason: row.creditsSpent <= 0 ? 'This job spent no credits.' : undefined,\n onClick: () => onGiveBack(row),\n },\n ]}\n />\n )),\n]\n\n/** The month's tokens, and what each kind of request spends of them (AGL-2937). */\nfunction TokensSection({ tokens }: { tokens: StaffOrgAiTokens }) {\n const { total } = tokens\n return (\n <Stack spacing={1}>\n <Stack direction=\"row\" spacing={1} useFlexGap sx={{ alignItems: 'center', flexWrap: 'wrap' }}>\n <Typography variant=\"body2\">\n {`${tokenCount(total.input)} sent · ${tokenCount(total.cached)} read from cache · ${tokenCount(total.cacheWrite)} written to cache · ${tokenCount(total.output)} generated`}\n </Typography>\n <Chip\n size=\"small\"\n color={tokens.cacheHitRate != null && tokens.cacheHitRate >= 0.5 ? 'success' : 'default'}\n label={`cache hit rate ${rate(tokens.cacheHitRate)}`}\n />\n </Stack>\n {tokens.kinds.length === 0 ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'No model requests recorded by kind this month.'}\n </Typography>\n ) : (\n <ScrollTable size=\"small\">\n <TableHead>\n <TableRow>\n <TableCell>{'Kind'}</TableCell>\n <TableCell align=\"right\">{'Requests'}</TableCell>\n <TableCell align=\"right\">{'Per request'}</TableCell>\n <TableCell align=\"right\">{'Sent'}</TableCell>\n <TableCell align=\"right\">{'From cache'}</TableCell>\n <TableCell align=\"right\">{'Generated'}</TableCell>\n <TableCell align=\"right\">{'Cache hit'}</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {tokens.kinds.map((row) => (\n <TableRow key={row.kind}>\n <TableCell>{row.kind}</TableCell>\n <TableCell align=\"right\">{row.requests.toLocaleString()}</TableCell>\n <TableCell align=\"right\">{usd(row.costPerRequestUsd)}</TableCell>\n <TableCell align=\"right\">{tokenCount(row.tokens.input)}</TableCell>\n <TableCell align=\"right\">{tokenCount(row.tokens.cached)}</TableCell>\n <TableCell align=\"right\">{tokenCount(row.tokens.output)}</TableCell>\n <TableCell align=\"right\">{rate(row.cacheHitRate)}</TableCell>\n </TableRow>\n ))}\n </TableBody>\n </ScrollTable>\n )}\n </Stack>\n )\n}\n\n/**\n * The month's top spenders, one row per person. The row opens the account;\n * the uid rides beneath the roster's name because two people can share one.\n */\nfunction TopUsersSection({ users }: { users: StaffOrgAiUser[] }) {\n const router = useRouter()\n const columns = useMemo<GridColDef<StaffOrgAiUser>[]>(\n () => [\n {\n field: 'name',\n headerName: 'Person',\n flex: 1,\n minWidth: 220,\n renderCell: ({ row }) => (\n <Stack sx={{ minWidth: 0 }}>\n <Typography variant=\"body2\" noWrap title={row.name}>\n {row.name}\n </Typography>\n {row.name !== row.uid ? (\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n noWrap\n sx={{ fontFamily: 'monospace' }}\n >\n {row.uid}\n </Typography>\n ) : null}\n </Stack>\n ),\n },\n {\n field: 'credits',\n headerName: 'Credits',\n type: 'number',\n align: 'right',\n headerAlign: 'right',\n width: 110,\n valueFormatter: (value: number) => credits(value),\n },\n {\n field: 'share',\n headerName: 'Share',\n type: 'number',\n align: 'right',\n headerAlign: 'right',\n width: 90,\n valueFormatter: (value: number) => `${Math.round(value * 100)}%`,\n },\n {\n field: 'estCostUsd',\n headerName: 'Provider $',\n type: 'number',\n align: 'right',\n headerAlign: 'right',\n width: 120,\n valueFormatter: (value: number) => usd(value),\n },\n {\n field: 'requests',\n headerName: 'Requests',\n type: 'number',\n align: 'right',\n headerAlign: 'right',\n width: 110,\n valueFormatter: (value: number) => value.toLocaleString(),\n },\n {\n field: 'refusals',\n headerName: 'Refusals',\n type: 'number',\n align: 'right',\n headerAlign: 'right',\n width: 110,\n valueFormatter: (value: number) => value.toLocaleString(),\n },\n listActionsColumn((row: StaffOrgAiUser) => (\n <ListRowActions\n label={row.name}\n quick={{\n icon: mdiOpenInNew.path,\n label: 'View account',\n newTab: true,\n to: buildRoute(Route.ADMIN_USER_DETAIL, { uid: row.uid }),\n }}\n items={[]}\n />\n )),\n ],\n [],\n )\n return (\n <ListTable\n rows={users}\n columns={columns}\n getRowId={(row: StaffOrgAiUser) => row.uid}\n rowHeight={TABLE_ROW_HEIGHT}\n onOpen={(uid) => router.push(buildRoute(Route.ADMIN_USER_DETAIL, { uid }))}\n // The route's ten dearest members: a bounded readout, so no filter\n // over the rows it holds (AGL-3321).\n disableColumnFilter\n quickFilter={false}\n />\n )\n}\n\nconst StaffOrgAiCard = ({ orgId }: { orgId: string }) => {\n const { data: user } = useUser()\n // Keyed on who is signed in, not on the user object's identity.\n const signedInUid = user?.uid ?? null\n const userRef = useRef(user)\n userRef.current = user\n const [data, setData] = useState<StaffOrgAiResponse | null>(null)\n const [ready, setReady] = useState(false)\n const [error, setError] = useState<string | null>(null)\n // Bumped after a give-back, so the card re-reads the figures it changed.\n const [version, setVersion] = useState(0)\n const [notice, setNotice] = useState<string | null>(null)\n const [returning, setReturning] = useState<{\n mode: 'give' | 'reset'\n jobId?: string\n jobCredits?: number\n } | null>(null)\n const giveBackJob = useCallback(\n (job: StaffOrgAiJob) =>\n setReturning({ mode: 'give', jobId: job.id, jobCredits: job.creditsSpent }),\n [],\n )\n\n useEffect(() => {\n // Mounted only for a confirmed staff reader — the `staffOrg` zone sits\n // inside the page's `StaffOnly`, which renders nothing while the claim\n // loads — because the route records an access row on every successful\n // open, and an open the page did not mean to make would be an access\n // nobody made.\n const user = userRef.current\n if (!orgId || !signedInUid || !user) return undefined\n let active = true\n setReady(false)\n setError(null)\n void (async () => {\n try {\n const response = await authorizedFetch(\n user,\n `/api/ai/admin/org?orgId=${encodeURIComponent(orgId)}`,\n )\n const payload = await response.json().catch(() => null)\n if (!active) return\n if (!response.ok) {\n setError(payload?.error ?? 'AI lookup failed')\n setData(null)\n } else {\n setData(payload as StaffOrgAiResponse)\n }\n } catch {\n if (active) {\n setError('AI lookup failed')\n setData(null)\n }\n } finally {\n if (active) setReady(true)\n }\n })()\n return () => {\n active = false\n }\n }, [orgId, signedInUid, version])\n\n const name = aiAddonName()\n return (\n <CardDisplay\n header={name}\n help={pluginDocsHelp('aiMonitoring', {\n anchor: '#the-ai-card',\n excerpt:\n 'The add-on, the credit pool and its parts, this month’s overage and refusals, generation jobs, tokens and the cache hit rate by kind, the people spending the most, and the margin — for this organization.',\n })}\n HeaderProps={{\n action: (\n <StaffCreditReturnActions\n disabled={!data}\n onGive={() => setReturning({ mode: 'give' })}\n onReset={() => setReturning({ mode: 'reset' })}\n />\n ),\n }}\n contentGutterX\n contentGutterY\n >\n {data ? (\n <StaffCreditReturnDialog\n open={returning !== null}\n mode={returning?.mode ?? 'give'}\n target={{ orgId }}\n workspace={{ used: data.pool.usedCredits, limit: data.pool.totalCredits }}\n account={\n data.account\n ? { used: data.account.usedCredits, limit: data.account.limitCredits }\n : null\n }\n jobId={returning?.jobId ?? null}\n jobCredits={returning?.jobCredits ?? null}\n onClose={() => setReturning(null)}\n onReturned={(message) => {\n setReturning(null)\n setNotice(message)\n setVersion((current) => current + 1)\n }}\n />\n ) : null}\n {notice ? (\n <Alert severity=\"success\" onClose={() => setNotice(null)} sx={{ mb: 2 }}>\n {notice}\n </Alert>\n ) : null}\n {!ready ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Loading…'}\n </Typography>\n ) : error || !data ? (\n <Alert severity=\"warning\">\n {`Could not read this organization’s AI usage — ${error ?? 'a failed read'}, not zero usage.`}\n </Alert>\n ) : (\n <Stack spacing={2}>\n {/* Add-on */}\n <Stack spacing={0.5}>\n <Typography variant=\"overline\" color=\"text.secondary\">\n {'Add-on'}\n </Typography>\n <Stack useFlexGap direction=\"row\" spacing={1} sx={{ alignItems: 'center', flexWrap: 'wrap' }}>\n <Chip\n size=\"small\"\n color={data.addon.on ? 'primary' : 'default'}\n label={data.addon.on ? `${name} on` : `${name} off`}\n />\n {data.addon.priceUsd !== null ? (\n <Typography variant=\"body2\">\n {`${usd(data.addon.priceUsd)}/mo on this plan`}\n </Typography>\n ) : (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Not sold on this plan'}\n </Typography>\n )}\n {data.addon.on ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {data.addon.since\n ? `since ${when(data.addon.since)}`\n : data.addon.sinceSource === 'unavailable'\n ? 'since — (Stripe not reachable)'\n : 'since — (no subscription item)'}\n </Typography>\n ) : null}\n </Stack>\n </Stack>\n\n {/* Credit pool */}\n <Stack spacing={0.5}>\n <Typography variant=\"overline\" color=\"text.secondary\">\n {`Credit pool · ${data.month}`}\n </Typography>\n {data.pool.totalCredits === null && data.pool.uncapped ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Uncapped staff comp — no AI credit band. Bounded only by the message cap and an operator’s explicit spend ceiling.'}\n </Typography>\n ) : data.pool.totalCredits === null ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'No AI credit band on this plan — bounded by the message cap and the operator backstop.'}\n </Typography>\n ) : (\n <Typography variant=\"body2\">\n {`${credits(data.pool.totalCredits)} credits = ${poolPartsSentence(data.pool, name)}`}\n </Typography>\n )}\n <Typography variant=\"body2\">\n {`Used ${credits(data.pool.usedCredits)} credits (${usd(data.pool.providerUsd)} provider spend)`}\n {data.pool.remainingCredits !== null\n ? ` · ${credits(data.pool.remainingCredits)} remaining`\n : ''}\n </Typography>\n {data.pool.returnedCredits ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`${credits(data.pool.returnedCredits)} credits given back this month — already taken off the figure above.`}\n </Typography>\n ) : null}\n {data.account ? (\n <Typography variant=\"body2\">{allowanceSentence(data.account, 'org')}</Typography>\n ) : null}\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`Projected month-end at this pace: ${credits(data.pool.projectedCredits)} credits (${usd(data.pool.projectedUsd)}) · ${data.pool.messages.toLocaleString()} model turns, ${data.pool.deflected.toLocaleString()} answered from the docs`}\n </Typography>\n </Stack>\n\n {/* Overage */}\n <Stack spacing={0.5}>\n <Typography variant=\"overline\" color=\"text.secondary\">\n {'Overage'}\n </Typography>\n <Typography variant=\"body2\">\n {`${credits(data.overage.overageCredits)} credits over the band · ${usd(data.overage.accruedUsd)} accrued`}\n </Typography>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {overageStateSentence(data.overage, data.pool.uncapped === true)}\n </Typography>\n </Stack>\n\n {/* Refusals */}\n <Stack spacing={0.5}>\n <Typography variant=\"overline\" color=\"text.secondary\">\n {`Refusals this month · ${data.refusals.total.toLocaleString()}`}\n </Typography>\n <RefusalsRow refusals={data.refusals} />\n </Stack>\n\n {/* Jobs */}\n <Stack spacing={0.5}>\n <Typography variant=\"overline\" color=\"text.secondary\">\n {'Generation jobs'}\n </Typography>\n <JobsSection jobs={data.jobs} onGiveBack={giveBackJob} />\n </Stack>\n\n {/* Tokens — absent from a route older than the card */}\n {data.tokens ? (\n <Stack spacing={0.5}>\n <Typography variant=\"overline\" color=\"text.secondary\">\n {`Tokens · ${data.month}`}\n </Typography>\n <TokensSection tokens={data.tokens} />\n </Stack>\n ) : null}\n\n {/* Top users */}\n <Stack spacing={0.5}>\n <Typography variant=\"overline\" color=\"text.secondary\">\n {'Top users this month'}\n </Typography>\n {data.users.length === 0 ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'No AI usage attributed to a person this month.'}\n </Typography>\n ) : (\n <TopUsersSection users={data.users} />\n )}\n </Stack>\n\n {/* Margin */}\n <Stack spacing={0.5}>\n <Typography variant=\"overline\" color=\"text.secondary\">\n {'Margin'}\n </Typography>\n <Alert severity={marginTone(data.margin)}>\n {`Spend ${usd(data.margin.spendUsd)} against ${usd(data.margin.revenueUsd)} in — ` +\n `${usd(data.margin.addonRevenueUsd)} add-on, ${usd(data.margin.planAssistShareUsd)} plan assist share, ` +\n `${usd(data.margin.overageRevenueUsd)} overage.`}\n {data.margin.underwater\n ? ' Spend exceeds the add-on plus the plan’s assist share.'\n : ''}\n {data.margin.multiple >= 1\n ? ` ${data.margin.multiple}× the ${usd(data.margin.thresholdUsd)} staff review threshold.`\n : ''}\n </Alert>\n {data.margin.contribution.marginPct !== null ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`Whole-org contribution margin ${Math.round(data.margin.contribution.marginPct * 100)}% on the ${data.margin.contribution.month} rollup with this month’s AI spend.`}\n </Typography>\n ) : null}\n </Stack>\n\n {/* Actions */}\n <Stack spacing={0.5}>\n <Typography variant=\"overline\" color=\"text.secondary\">\n {'Actions'}\n </Typography>\n <Typography variant=\"body2\">\n {'Credit override and feature toggles: '}\n <AppLink href={buildRoute(Route.ADMIN_ORGS)} underline=\"hover\">\n {'the entitlement override editor'}\n </AppLink>\n {' (also under Staff actions above). Pause AI for this org: '}\n <AppLink href={buildRoute(Route.ADMIN_LOCKDOWN)} underline=\"hover\">\n {'Lockdown'}\n </AppLink>\n {', feature keys ai-assist and ai-generate scoped to the org.'}\n </Typography>\n </Stack>\n </Stack>\n )}\n </CardDisplay>\n )\n}\nStaffOrgAiCard.displayName = 'StaffOrgAiCard'\n\nexport default StaffOrgAiCard\n"],"names":["aiAddonName","buildRoute","Route","pluginDocsHelp","mdiOpenInNew","AppLink","CardDisplay","ListRowActions","ListTable","listActionsColumn","ScrollTable","TABLE_ROW_HEIGHT","useUser","authorizedFetch","Alert","Chip","Stack","TableBody","TableCell","TableHead","TableRow","Typography","useRouter","useCallback","useEffect","useMemo","useRef","useState","allowanceSentence","credits","marginTone","overageStateSentence","poolPartsSentence","rate","refusalChips","tokenCount","usd","JOB_CHIP_STATUSES","StaffCreditReturnActions","StaffCreditReturnDialog","when","iso","Date","toLocaleDateString","RefusalsRow","refusals","direction","spacing","useFlexGap","sx","flexWrap","map","chip","size","variant","count","color","label","toLocaleString","JobsSection","jobs","onGiveBack","columns","jobColumns","severity","total","Object","values","counts","reduce","sum","n","status","replace","done","truncated","rows","recent","getRowId","job","id","rowHeight","noRowsLabel","disableColumnFilter","quickFilter","field","headerName","flex","minWidth","renderCell","row","noWrap","title","fontFamily","width","valueFormatter","value","String","type","align","headerAlign","creditsReserved","createdBy","href","ADMIN_USER_DETAIL","uid","underline","items","key","disabled","creditsSpent","disabledReason","undefined","onClick","TokensSection","tokens","alignItems","input","cached","cacheWrite","output","cacheHitRate","kinds","length","kind","requests","costPerRequestUsd","TopUsersSection","users","router","name","Math","round","quick","icon","path","newTab","to","onOpen","push","StaffOrgAiCard","orgId","data","user","signedInUid","userRef","current","setData","ready","setReady","error","setError","version","setVersion","notice","setNotice","returning","setReturning","giveBackJob","mode","jobId","jobCredits","active","response","encodeURIComponent","payload","json","catch","ok","header","help","anchor","excerpt","HeaderProps","action","onGive","onReset","contentGutterX","contentGutterY","open","target","workspace","used","pool","usedCredits","limit","totalCredits","account","limitCredits","onClose","onReturned","message","mb","addon","on","priceUsd","since","sinceSource","month","uncapped","providerUsd","remainingCredits","returnedCredits","projectedCredits","projectedUsd","messages","deflected","overage","overageCredits","accruedUsd","margin","spendUsd","revenueUsd","addonRevenueUsd","planAssistShareUsd","overageRevenueUsd","underwater","multiple","thresholdUsd","contribution","marginPct","ADMIN_ORGS","ADMIN_LOCKDOWN","displayName"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/components/staff-org-ai-card.component.tsx"],"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'use client'\n\nimport { aiAddonName } from '@aglyn/aglyn'\nimport { AI_TIERS } from '@aglyn/aglyn/app-utils/plan-entitlements'\nimport { buildRoute, Route } from '@aglyn/aglyn/app-utils/console-routes'\nimport { pluginDocsHelp } from '@aglyn/aglyn/app-utils/docs-help'\nimport { mdiOpenInNew } from '@aglyn/shared-data-mdi'\nimport { AppLink, CardDisplay } from '@aglyn/shared-ui-jsx'\nimport {\n ListRowActions,\n ListTable,\n listActionsColumn,\n} from '@aglyn/shared-ui-jsx/components/list-table.component'\nimport { ScrollTable } from '@aglyn/shared-ui-jsx/components/scroll-table.component'\nimport { TABLE_ROW_HEIGHT } from '@aglyn/shared-ui-jsx/const/table-pagination'\nimport { useUser } from '@aglyn/tenant-feature-instance'\nimport { authorizedFetch } from '@aglyn/shared-util-http/authorized-token'\nimport {\n Alert,\n Chip,\n Stack,\n TableBody,\n TableCell,\n TableHead,\n TableRow,\n Typography,\n} from '@mui/material'\nimport type { GridColDef } from '@mui/x-data-grid'\nimport { useRouter } from 'next/navigation'\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport type {\n StaffOrgAiJob,\n StaffOrgAiJobs,\n StaffOrgAiRefusals,\n StaffOrgAiResponse,\n StaffOrgAiTokens,\n StaffOrgAiUser,\n} from '../usage/staff-org-ai'\nimport {\n allowanceSentence,\n credits,\n marginTone,\n overageStateSentence,\n poolPartsSentence,\n rate,\n refusalChips,\n tokenCount,\n usd,\n JOB_CHIP_STATUSES,\n} from '../usage/staff-org-ai-view'\nimport {\n StaffCreditReturnActions,\n StaffCreditReturnDialog,\n} from './staff-ai-credit-return.component'\n\n/**\n * THE STAFF AI CARD (AGL-2930): everything about one org's AI usage on the\n * page staff already open to look at that org.\n *\n * Read through `/api/ai/admin/org`, one request on mount. Every figure on it\n * is the route's, and every figure the route serves is composed from the\n * same helpers the meter refuses with — see `usage/staff-org-ai.ts`. This\n * file only lays them out.\n *\n * ## What each section is for\n *\n * - **Add-on** — is the org paying for AI, at what, since when.\n * - **Credit pool** — the band as three NAMED parts, because \"why does\n * this org have 13,000 credits\" has three answers (the plan, an override,\n * the add-on) and a single total cannot say which.\n * - **Overage** — what is past the band, what it is sold at, and the two\n * controls the org itself holds over it.\n * - **Refusals** — how often, and why, the gate said no this month.\n * - **Jobs** and **Top users** — the generative and per-person halves,\n * each of which says plainly when its rollup has nothing yet.\n * - **Tokens** — what each kind of request costs per request, what it\n * sends and generates, and how much of its prompt the cache served.\n * - **Margin** — spend against what AI brings in, red when it is over.\n * - **Actions** — where the override editor and the AI pause live.\n *\n * The header carries the card's two acts (AGL-3595): give credits back to\n * the band (and, on a Free workspace, to the owner's allowance), or reset\n * the month — and each recent job offers the same give-back, prefilled with\n * that job's spend.\n */\n\nconst when = (iso: string | null): string =>\n iso ? new Date(iso).toLocaleDateString() : '—'\n\nfunction RefusalsRow({ refusals }: { refusals: StaffOrgAiRefusals }) {\n return (\n <Stack direction=\"row\" spacing={1} useFlexGap sx={{ flexWrap: 'wrap' }}>\n {refusalChips(refusals).map((chip) => (\n <Chip\n key={chip.label}\n size=\"small\"\n variant={chip.count > 0 ? 'filled' : 'outlined'}\n color={chip.count > 0 ? 'warning' : 'default'}\n label={`${chip.label} ${chip.count.toLocaleString()}`}\n />\n ))}\n </Stack>\n )\n}\n\nfunction JobsSection({\n jobs,\n onGiveBack,\n}: {\n jobs: StaffOrgAiJobs | null\n onGiveBack: (job: StaffOrgAiJob) => void\n}) {\n const columns = useMemo(() => jobColumns(onGiveBack), [onGiveBack])\n if (jobs === null) {\n return (\n <Alert severity=\"warning\">\n {'Could not read the generation jobs — a failed read, not an idle org.'}\n </Alert>\n )\n }\n const total = Object.values(jobs.counts).reduce((sum, n) => sum + n, 0)\n if (total === 0) {\n return (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'No generation jobs yet.'}\n </Typography>\n )\n }\n return (\n <Stack spacing={1}>\n <Stack direction=\"row\" spacing={1} useFlexGap sx={{ flexWrap: 'wrap' }}>\n {JOB_CHIP_STATUSES.map((status) => (\n <Chip\n key={status}\n size=\"small\"\n color={\n status === 'failed' && jobs.counts[status] > 0\n ? 'error'\n : (status === 'needs_input' || status === 'needs_review') &&\n jobs.counts[status] > 0\n ? 'warning'\n : 'default'\n }\n label={`${status.replace('_', ' ')} ${jobs.counts[status]}`}\n />\n ))}\n <Chip size=\"small\" variant=\"outlined\" label={`done ${jobs.counts.done}`} />\n </Stack>\n {jobs.truncated ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {'Counted from the newest jobs only — these counts are a floor.'}\n </Typography>\n ) : null}\n {/* A record list: the grid scrolls its own columns, so a job id and a\n starter's uid never push the card's content past its edge. */}\n <ListTable\n rows={jobs.recent}\n columns={columns}\n getRowId={(job: StaffOrgAiJob) => job.id}\n rowHeight={TABLE_ROW_HEIGHT}\n noRowsLabel=\"No recent jobs\"\n // The route's ten newest jobs: a bounded readout, so no filter over\n // the rows it holds (AGL-3321).\n disableColumnFilter\n quickFilter={false}\n />\n </Stack>\n )\n}\n\n/**\n * The recent jobs, one column per fact. Who started a job is a column of\n * its own rather than a link tucked beside the date, so it sorts like the\n * rest; the credits sort by what was SPENT, which is the figure the\n * pool was charged. The row's action gives that spend back (AGL-3595).\n */\nconst jobColumns = (\n onGiveBack: (job: StaffOrgAiJob) => void,\n): GridColDef<StaffOrgAiJob>[] => [\n {\n field: 'id',\n headerName: 'Job',\n flex: 1,\n minWidth: 200,\n renderCell: ({ row }) => (\n <Typography variant=\"body2\" noWrap title={row.id} sx={{ fontFamily: 'monospace' }}>\n {row.id}\n </Typography>\n ),\n },\n {\n field: 'kind',\n headerName: 'Kind',\n width: 120,\n valueFormatter: (value: string) => value || '—',\n },\n {\n field: 'status',\n headerName: 'Status',\n width: 130,\n valueFormatter: (value: string) => String(value ?? '').replace('_', ' '),\n },\n {\n field: 'creditsSpent',\n headerName: 'Credits',\n type: 'number',\n align: 'right',\n headerAlign: 'right',\n width: 140,\n valueFormatter: (value: number, row) =>\n `${credits(value)} / ${credits(row.creditsReserved)}`,\n },\n {\n field: 'createdAt',\n headerName: 'Started',\n width: 120,\n valueFormatter: (value: string | null) => when(value),\n },\n {\n field: 'createdBy',\n headerName: 'Started by',\n flex: 1,\n minWidth: 240,\n renderCell: ({ row }) =>\n row.createdBy ? (\n <AppLink\n href={buildRoute(Route.ADMIN_USER_DETAIL, { uid: row.createdBy })}\n variant=\"body2\"\n underline=\"hover\"\n noWrap\n sx={{ fontFamily: 'monospace' }}\n >\n {row.createdBy}\n </AppLink>\n ) : (\n '—'\n ),\n },\n listActionsColumn((row: StaffOrgAiJob) => (\n <ListRowActions\n label={row.id}\n items={[\n {\n key: 'give-back',\n label: 'Give back this job’s credits',\n disabled: row.creditsSpent <= 0,\n disabledReason: row.creditsSpent <= 0 ? 'This job spent no credits.' : undefined,\n onClick: () => onGiveBack(row),\n },\n ]}\n />\n )),\n]\n\n/** The month's tokens, and what each kind of request spends of them (AGL-2937). */\nfunction TokensSection({ tokens }: { tokens: StaffOrgAiTokens }) {\n const { total } = tokens\n return (\n <Stack spacing={1}>\n <Stack direction=\"row\" spacing={1} useFlexGap sx={{ alignItems: 'center', flexWrap: 'wrap' }}>\n <Typography variant=\"body2\">\n {`${tokenCount(total.input)} sent · ${tokenCount(total.cached)} read from cache · ${tokenCount(total.cacheWrite)} written to cache · ${tokenCount(total.output)} generated`}\n </Typography>\n <Chip\n size=\"small\"\n color={tokens.cacheHitRate != null && tokens.cacheHitRate >= 0.5 ? 'success' : 'default'}\n label={`cache hit rate ${rate(tokens.cacheHitRate)}`}\n />\n </Stack>\n {tokens.kinds.length === 0 ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'No model requests recorded by kind this month.'}\n </Typography>\n ) : (\n <ScrollTable size=\"small\">\n <TableHead>\n <TableRow>\n <TableCell>{'Kind'}</TableCell>\n <TableCell align=\"right\">{'Requests'}</TableCell>\n <TableCell align=\"right\">{'Per request'}</TableCell>\n <TableCell align=\"right\">{'Sent'}</TableCell>\n <TableCell align=\"right\">{'From cache'}</TableCell>\n <TableCell align=\"right\">{'Generated'}</TableCell>\n <TableCell align=\"right\">{'Cache hit'}</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {tokens.kinds.map((row) => (\n <TableRow key={row.kind}>\n <TableCell>{row.kind}</TableCell>\n <TableCell align=\"right\">{row.requests.toLocaleString()}</TableCell>\n <TableCell align=\"right\">{usd(row.costPerRequestUsd)}</TableCell>\n <TableCell align=\"right\">{tokenCount(row.tokens.input)}</TableCell>\n <TableCell align=\"right\">{tokenCount(row.tokens.cached)}</TableCell>\n <TableCell align=\"right\">{tokenCount(row.tokens.output)}</TableCell>\n <TableCell align=\"right\">{rate(row.cacheHitRate)}</TableCell>\n </TableRow>\n ))}\n </TableBody>\n </ScrollTable>\n )}\n </Stack>\n )\n}\n\n/**\n * The month's top spenders, one row per person. The row opens the account;\n * the uid rides beneath the roster's name because two people can share one.\n */\nfunction TopUsersSection({ users }: { users: StaffOrgAiUser[] }) {\n const router = useRouter()\n const columns = useMemo<GridColDef<StaffOrgAiUser>[]>(\n () => [\n {\n field: 'name',\n headerName: 'Person',\n flex: 1,\n minWidth: 220,\n renderCell: ({ row }) => (\n <Stack sx={{ minWidth: 0 }}>\n <Typography variant=\"body2\" noWrap title={row.name}>\n {row.name}\n </Typography>\n {row.name !== row.uid ? (\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n noWrap\n sx={{ fontFamily: 'monospace' }}\n >\n {row.uid}\n </Typography>\n ) : null}\n </Stack>\n ),\n },\n {\n field: 'credits',\n headerName: 'Credits',\n type: 'number',\n align: 'right',\n headerAlign: 'right',\n width: 110,\n valueFormatter: (value: number) => credits(value),\n },\n {\n field: 'share',\n headerName: 'Share',\n type: 'number',\n align: 'right',\n headerAlign: 'right',\n width: 90,\n valueFormatter: (value: number) => `${Math.round(value * 100)}%`,\n },\n {\n field: 'estCostUsd',\n headerName: 'Provider $',\n type: 'number',\n align: 'right',\n headerAlign: 'right',\n width: 120,\n valueFormatter: (value: number) => usd(value),\n },\n {\n field: 'requests',\n headerName: 'Requests',\n type: 'number',\n align: 'right',\n headerAlign: 'right',\n width: 110,\n valueFormatter: (value: number) => value.toLocaleString(),\n },\n {\n field: 'refusals',\n headerName: 'Refusals',\n type: 'number',\n align: 'right',\n headerAlign: 'right',\n width: 110,\n valueFormatter: (value: number) => value.toLocaleString(),\n },\n listActionsColumn((row: StaffOrgAiUser) => (\n <ListRowActions\n label={row.name}\n quick={{\n icon: mdiOpenInNew.path,\n label: 'View account',\n newTab: true,\n to: buildRoute(Route.ADMIN_USER_DETAIL, { uid: row.uid }),\n }}\n items={[]}\n />\n )),\n ],\n [],\n )\n return (\n <ListTable\n rows={users}\n columns={columns}\n getRowId={(row: StaffOrgAiUser) => row.uid}\n rowHeight={TABLE_ROW_HEIGHT}\n onOpen={(uid) => router.push(buildRoute(Route.ADMIN_USER_DETAIL, { uid }))}\n // The route's ten dearest members: a bounded readout, so no filter\n // over the rows it holds (AGL-3321).\n disableColumnFilter\n quickFilter={false}\n />\n )\n}\n\nconst StaffOrgAiCard = ({ orgId }: { orgId: string }) => {\n const { data: user } = useUser()\n // Keyed on who is signed in, not on the user object's identity.\n const signedInUid = user?.uid ?? null\n const userRef = useRef(user)\n userRef.current = user\n const [data, setData] = useState<StaffOrgAiResponse | null>(null)\n const [ready, setReady] = useState(false)\n const [error, setError] = useState<string | null>(null)\n // Bumped after a give-back, so the card re-reads the figures it changed.\n const [version, setVersion] = useState(0)\n const [notice, setNotice] = useState<string | null>(null)\n const [returning, setReturning] = useState<{\n mode: 'give' | 'reset'\n jobId?: string\n jobCredits?: number\n } | null>(null)\n const giveBackJob = useCallback(\n (job: StaffOrgAiJob) =>\n setReturning({ mode: 'give', jobId: job.id, jobCredits: job.creditsSpent }),\n [],\n )\n\n useEffect(() => {\n // Mounted only for a confirmed staff reader — the `staffOrg` zone sits\n // inside the page's `StaffOnly`, which renders nothing while the claim\n // loads — because the route records an access row on every successful\n // open, and an open the page did not mean to make would be an access\n // nobody made.\n const user = userRef.current\n if (!orgId || !signedInUid || !user) return undefined\n let active = true\n setReady(false)\n setError(null)\n void (async () => {\n try {\n const response = await authorizedFetch(\n user,\n `/api/ai/admin/org?orgId=${encodeURIComponent(orgId)}`,\n )\n const payload = await response.json().catch(() => null)\n if (!active) return\n if (!response.ok) {\n setError(payload?.error ?? 'AI lookup failed')\n setData(null)\n } else {\n setData(payload as StaffOrgAiResponse)\n }\n } catch {\n if (active) {\n setError('AI lookup failed')\n setData(null)\n }\n } finally {\n if (active) setReady(true)\n }\n })()\n return () => {\n active = false\n }\n }, [orgId, signedInUid, version])\n\n const name = aiAddonName()\n return (\n <CardDisplay\n header={name}\n help={pluginDocsHelp('aiMonitoring', {\n anchor: '#the-ai-card',\n excerpt:\n 'The add-on, the credit pool and its parts, this month’s overage and refusals, generation jobs, tokens and the cache hit rate by kind, the people spending the most, and the margin — for this organization.',\n })}\n HeaderProps={{\n action: (\n <StaffCreditReturnActions\n disabled={!data}\n onGive={() => setReturning({ mode: 'give' })}\n onReset={() => setReturning({ mode: 'reset' })}\n />\n ),\n }}\n contentGutterX\n contentGutterY\n >\n {data ? (\n <StaffCreditReturnDialog\n open={returning !== null}\n mode={returning?.mode ?? 'give'}\n target={{ orgId }}\n workspace={{ used: data.pool.usedCredits, limit: data.pool.totalCredits }}\n account={\n data.account\n ? { used: data.account.usedCredits, limit: data.account.limitCredits }\n : null\n }\n jobId={returning?.jobId ?? null}\n jobCredits={returning?.jobCredits ?? null}\n onClose={() => setReturning(null)}\n onReturned={(message) => {\n setReturning(null)\n setNotice(message)\n setVersion((current) => current + 1)\n }}\n />\n ) : null}\n {notice ? (\n <Alert severity=\"success\" onClose={() => setNotice(null)} sx={{ mb: 2 }}>\n {notice}\n </Alert>\n ) : null}\n {!ready ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Loading…'}\n </Typography>\n ) : error || !data ? (\n <Alert severity=\"warning\">\n {`Could not read this organization’s AI usage — ${error ?? 'a failed read'}, not zero usage.`}\n </Alert>\n ) : (\n <Stack spacing={2}>\n {/* Add-on */}\n <Stack spacing={0.5}>\n <Typography variant=\"overline\" color=\"text.secondary\">\n {'Add-on'}\n </Typography>\n <Stack useFlexGap direction=\"row\" spacing={1} sx={{ alignItems: 'center', flexWrap: 'wrap' }}>\n <Chip\n size=\"small\"\n color={data.addon.on ? 'primary' : 'default'}\n label={\n data.addon.on\n ? `${name}${data.addon.tier ? ` ${AI_TIERS[data.addon.tier].label}` : ''} on`\n : `${name} off`\n }\n />\n {data.addon.priceUsd !== null ? (\n <Typography variant=\"body2\">\n {`${usd(data.addon.priceUsd)}/mo`}\n </Typography>\n ) : null}\n {data.addon.on ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {data.addon.since\n ? `since ${when(data.addon.since)}`\n : data.addon.sinceSource === 'unavailable'\n ? 'since — (Stripe not reachable)'\n : 'since — (no subscription item)'}\n </Typography>\n ) : null}\n </Stack>\n </Stack>\n\n {/* Credit pool */}\n <Stack spacing={0.5}>\n <Typography variant=\"overline\" color=\"text.secondary\">\n {`Credit pool · ${data.month}`}\n </Typography>\n {data.pool.totalCredits === null && data.pool.uncapped ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Uncapped staff comp — no AI credit band. Bounded only by the message cap and an operator’s explicit spend ceiling.'}\n </Typography>\n ) : data.pool.totalCredits === null ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'No AI credit band on this plan — bounded by the message cap and the operator backstop.'}\n </Typography>\n ) : (\n <Typography variant=\"body2\">\n {`${credits(data.pool.totalCredits)} credits = ${poolPartsSentence(data.pool, name)}`}\n </Typography>\n )}\n <Typography variant=\"body2\">\n {`Used ${credits(data.pool.usedCredits)} credits (${usd(data.pool.providerUsd)} provider spend)`}\n {data.pool.remainingCredits !== null\n ? ` · ${credits(data.pool.remainingCredits)} remaining`\n : ''}\n </Typography>\n {data.pool.returnedCredits ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`${credits(data.pool.returnedCredits)} credits given back this month — already taken off the figure above.`}\n </Typography>\n ) : null}\n {data.account ? (\n <Typography variant=\"body2\">{allowanceSentence(data.account, 'org')}</Typography>\n ) : null}\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`Projected month-end at this pace: ${credits(data.pool.projectedCredits)} credits (${usd(data.pool.projectedUsd)}) · ${data.pool.messages.toLocaleString()} model turns, ${data.pool.deflected.toLocaleString()} answered from the docs`}\n </Typography>\n </Stack>\n\n {/* Overage */}\n <Stack spacing={0.5}>\n <Typography variant=\"overline\" color=\"text.secondary\">\n {'Overage'}\n </Typography>\n <Typography variant=\"body2\">\n {`${credits(data.overage.overageCredits)} credits over the band · ${usd(data.overage.accruedUsd)} accrued`}\n </Typography>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {overageStateSentence(data.overage, data.pool.uncapped === true)}\n </Typography>\n </Stack>\n\n {/* Refusals */}\n <Stack spacing={0.5}>\n <Typography variant=\"overline\" color=\"text.secondary\">\n {`Refusals this month · ${data.refusals.total.toLocaleString()}`}\n </Typography>\n <RefusalsRow refusals={data.refusals} />\n </Stack>\n\n {/* Jobs */}\n <Stack spacing={0.5}>\n <Typography variant=\"overline\" color=\"text.secondary\">\n {'Generation jobs'}\n </Typography>\n <JobsSection jobs={data.jobs} onGiveBack={giveBackJob} />\n </Stack>\n\n {/* Tokens — absent from a route older than the card */}\n {data.tokens ? (\n <Stack spacing={0.5}>\n <Typography variant=\"overline\" color=\"text.secondary\">\n {`Tokens · ${data.month}`}\n </Typography>\n <TokensSection tokens={data.tokens} />\n </Stack>\n ) : null}\n\n {/* Top users */}\n <Stack spacing={0.5}>\n <Typography variant=\"overline\" color=\"text.secondary\">\n {'Top users this month'}\n </Typography>\n {data.users.length === 0 ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'No AI usage attributed to a person this month.'}\n </Typography>\n ) : (\n <TopUsersSection users={data.users} />\n )}\n </Stack>\n\n {/* Margin */}\n <Stack spacing={0.5}>\n <Typography variant=\"overline\" color=\"text.secondary\">\n {'Margin'}\n </Typography>\n <Alert severity={marginTone(data.margin)}>\n {`Spend ${usd(data.margin.spendUsd)} against ${usd(data.margin.revenueUsd)} in — ` +\n `${usd(data.margin.addonRevenueUsd)} add-on, ${usd(data.margin.planAssistShareUsd)} plan assist share, ` +\n `${usd(data.margin.overageRevenueUsd)} overage.`}\n {data.margin.underwater\n ? ' Spend exceeds the add-on plus the plan’s assist share.'\n : ''}\n {data.margin.multiple >= 1\n ? ` ${data.margin.multiple}× the ${usd(data.margin.thresholdUsd)} staff review threshold.`\n : ''}\n </Alert>\n {data.margin.contribution.marginPct !== null ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {`Whole-org contribution margin ${Math.round(data.margin.contribution.marginPct * 100)}% on the ${data.margin.contribution.month} rollup with this month’s AI spend.`}\n </Typography>\n ) : null}\n </Stack>\n\n {/* Actions */}\n <Stack spacing={0.5}>\n <Typography variant=\"overline\" color=\"text.secondary\">\n {'Actions'}\n </Typography>\n <Typography variant=\"body2\">\n {'Credit override and feature toggles: '}\n <AppLink href={buildRoute(Route.ADMIN_ORGS)} underline=\"hover\">\n {'the entitlement override editor'}\n </AppLink>\n {' (also under Staff actions above). Pause AI for this org: '}\n <AppLink href={buildRoute(Route.ADMIN_LOCKDOWN)} underline=\"hover\">\n {'Lockdown'}\n </AppLink>\n {', feature keys ai-assist and ai-generate scoped to the org.'}\n </Typography>\n </Stack>\n </Stack>\n )}\n </CardDisplay>\n )\n}\nStaffOrgAiCard.displayName = 'StaffOrgAiCard'\n\nexport default StaffOrgAiCard\n"],"names":["aiAddonName","AI_TIERS","buildRoute","Route","pluginDocsHelp","mdiOpenInNew","AppLink","CardDisplay","ListRowActions","ListTable","listActionsColumn","ScrollTable","TABLE_ROW_HEIGHT","useUser","authorizedFetch","Alert","Chip","Stack","TableBody","TableCell","TableHead","TableRow","Typography","useRouter","useCallback","useEffect","useMemo","useRef","useState","allowanceSentence","credits","marginTone","overageStateSentence","poolPartsSentence","rate","refusalChips","tokenCount","usd","JOB_CHIP_STATUSES","StaffCreditReturnActions","StaffCreditReturnDialog","when","iso","Date","toLocaleDateString","RefusalsRow","refusals","direction","spacing","useFlexGap","sx","flexWrap","map","chip","size","variant","count","color","label","toLocaleString","JobsSection","jobs","onGiveBack","columns","jobColumns","severity","total","Object","values","counts","reduce","sum","n","status","replace","done","truncated","rows","recent","getRowId","job","id","rowHeight","noRowsLabel","disableColumnFilter","quickFilter","field","headerName","flex","minWidth","renderCell","row","noWrap","title","fontFamily","width","valueFormatter","value","String","type","align","headerAlign","creditsReserved","createdBy","href","ADMIN_USER_DETAIL","uid","underline","items","key","disabled","creditsSpent","disabledReason","undefined","onClick","TokensSection","tokens","alignItems","input","cached","cacheWrite","output","cacheHitRate","kinds","length","kind","requests","costPerRequestUsd","TopUsersSection","users","router","name","Math","round","quick","icon","path","newTab","to","onOpen","push","StaffOrgAiCard","orgId","data","user","signedInUid","userRef","current","setData","ready","setReady","error","setError","version","setVersion","notice","setNotice","returning","setReturning","giveBackJob","mode","jobId","jobCredits","active","response","encodeURIComponent","payload","json","catch","ok","header","help","anchor","excerpt","HeaderProps","action","onGive","onReset","contentGutterX","contentGutterY","open","target","workspace","used","pool","usedCredits","limit","totalCredits","account","limitCredits","onClose","onReturned","message","mb","addon","on","tier","priceUsd","since","sinceSource","month","uncapped","providerUsd","remainingCredits","returnedCredits","projectedCredits","projectedUsd","messages","deflected","overage","overageCredits","accruedUsd","margin","spendUsd","revenueUsd","addonRevenueUsd","planAssistShareUsd","overageRevenueUsd","underwater","multiple","thresholdUsd","contribution","marginPct","ADMIN_ORGS","ADMIN_LOCKDOWN","displayName"],"mappings":"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"}
|
|
@@ -27,8 +27,8 @@ import { type PluginEntitlementRegistration } from '@aglyn/aglyn/plugin-manager/
|
|
|
27
27
|
* reaches a provider, Firestore or React.
|
|
28
28
|
*
|
|
29
29
|
* The plan tables keep the per-plan defaults for `aiGenerative` and
|
|
30
|
-
* `aiAssist`, and `
|
|
31
|
-
* keys and
|
|
30
|
+
* `aiAssist`, and `AI_TIERS` keeps each tier's price and credits, so this
|
|
31
|
+
* names keys and restates no figure.
|
|
32
32
|
*
|
|
33
33
|
* `ai-assist` and `ai-generate` are separate levers because the two doors
|
|
34
34
|
* spend at different rates and an incident on one need not stop the other
|
package/src/lib/declarations.js
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
*/ // Named modules rather than the `@aglyn/aglyn` barrel: both apps load this
|
|
17
17
|
// on the server at boot, and the full barrel carries client-only contexts
|
|
18
18
|
// (AGL-405).
|
|
19
|
-
import {
|
|
19
|
+
import { aiTierQuotaPerUnit, planSellsAiTiers } from "@aglyn/aglyn/app-utils/plan-entitlements";
|
|
20
20
|
import { registerPluginConfigSchema } from "@aglyn/aglyn/plugin-manager/plugin-config";
|
|
21
21
|
import { registerPluginEntitlements } from "@aglyn/aglyn/plugin-manager/plugin-entitlements";
|
|
22
22
|
import { AI_PLUGIN_ID } from "./constants.js";
|
|
@@ -35,8 +35,8 @@ import { registerAiActivityActions } from "./activity/ai-activity-actions.js";
|
|
|
35
35
|
* reaches a provider, Firestore or React.
|
|
36
36
|
*
|
|
37
37
|
* The plan tables keep the per-plan defaults for `aiGenerative` and
|
|
38
|
-
* `aiAssist`, and `
|
|
39
|
-
* keys and
|
|
38
|
+
* `aiAssist`, and `AI_TIERS` keeps each tier's price and credits, so this
|
|
39
|
+
* names keys and restates no figure.
|
|
40
40
|
*
|
|
41
41
|
* `ai-assist` and `ai-generate` are separate levers because the two doors
|
|
42
42
|
* spend at different rates and an incident on one need not stop the other
|
|
@@ -50,14 +50,18 @@ import { registerAiActivityActions } from "./activity/ai-activity-actions.js";
|
|
|
50
50
|
key: 'aiAddon',
|
|
51
51
|
label: 'AI add-on',
|
|
52
52
|
maxUnits: 1,
|
|
53
|
+
// The purchased tier's credits on top of the plan's included band
|
|
54
|
+
// (AGL-3965): one pool, widened by what was bought rather than by
|
|
55
|
+
// which plan bought it.
|
|
53
56
|
quota: {
|
|
54
57
|
key: 'assistCreditsPerMonth',
|
|
55
|
-
|
|
58
|
+
perUnit: aiTierQuotaPerUnit
|
|
56
59
|
},
|
|
57
60
|
features: [
|
|
58
61
|
'aiGenerative',
|
|
59
62
|
'aiAssist'
|
|
60
|
-
]
|
|
63
|
+
],
|
|
64
|
+
soldOn: planSellsAiTiers
|
|
61
65
|
}
|
|
62
66
|
],
|
|
63
67
|
features: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../libs/plugins/ai/src/lib/declarations.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// Named modules rather than the `@aglyn/aglyn` barrel: both apps load this\n// on the server at boot, and the full barrel carries client-only contexts\n// (AGL-405).\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/plugins/ai/src/lib/declarations.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// Named modules rather than the `@aglyn/aglyn` barrel: both apps load this\n// on the server at boot, and the full barrel carries client-only contexts\n// (AGL-405).\nimport {\n aiTierQuotaPerUnit,\n planSellsAiTiers,\n} from '@aglyn/aglyn/app-utils/plan-entitlements'\nimport { registerPluginConfigSchema } from '@aglyn/aglyn/plugin-manager/plugin-config'\nimport {\n registerPluginEntitlements,\n type PluginEntitlementRegistration,\n} from '@aglyn/aglyn/plugin-manager/plugin-entitlements'\nimport { AI_PLUGIN_ID } from './constants'\nimport { AI_ORG_PERMISSIONS } from './model/ai-permissions'\nimport { AI_CONFIG_SCHEMA } from './plugin-config'\nimport { registerAiActivityActions } from './activity/ai-activity-actions'\n\n/**\n * The plugin's DECLARATIONS (AGL-2939): what core must know about this\n * plugin before any of its surfaces load — its billing and access keys,\n * the AI permission keys it adds to the org catalog (AGL-2984), its\n * activity codes, its settings schema. Loaded eagerly by both apps\n * through the generated declarations manifest, at boot on the server and\n * with the plugin loader on the client, so a core billing route folds the\n * add-on and the staff lockdown page lists the levers whether or not a\n * request has touched the plugin yet. Light by construction: nothing here\n * reaches a provider, Firestore or React.\n *\n * The plan tables keep the per-plan defaults for `aiGenerative` and\n * `aiAssist`, and `AI_TIERS` keeps each tier's price and credits, so this\n * names keys and restates no figure.\n *\n * `ai-assist` and `ai-generate` are separate levers because the two doors\n * spend at different rates and an incident on one need not stop the other\n * (AGL-2903). Both grant the staff bypass: a provider incident is verified\n * recovered by staff making one real call, not by lifting the lock and\n * watching customers find out.\n */\nexport const AI_PLUGIN_ENTITLEMENTS: PluginEntitlementRegistration = {\n pluginId: AI_PLUGIN_ID,\n seatAddons: [\n {\n key: 'aiAddon',\n label: 'AI add-on',\n maxUnits: 1,\n // The purchased tier's credits on top of the plan's included band\n // (AGL-3965): one pool, widened by what was bought rather than by\n // which plan bought it.\n quota: {\n key: 'assistCreditsPerMonth',\n perUnit: aiTierQuotaPerUnit,\n },\n features: ['aiGenerative', 'aiAssist'],\n soldOn: planSellsAiTiers,\n },\n ],\n features: [\n { key: 'aiAssist', label: 'AI assist' },\n { key: 'aiGenerative', label: 'AI generation' },\n ],\n lockdownFeatures: [\n {\n key: 'ai-assist',\n label: 'AI assist',\n customerName: 'AI assist',\n staffBypass: true,\n notice: {\n title: 'AI assist is temporarily unavailable',\n body: 'AI assist is temporarily unavailable. Your content is unaffected — please try again shortly.',\n },\n // Gated even while the route 501s without a provider key — the switch\n // predates the key on purpose.\n apiPaths: { exact: ['ai/assist', 'assist/chat'] },\n },\n {\n key: 'ai-generate',\n label: 'AI generation',\n customerName: 'AI generation',\n staffBypass: true,\n notice: {\n title: 'AI generation is temporarily unavailable',\n body: 'Generating sections, pages and automations with AI is temporarily unavailable. Everything already built is unaffected — please try again shortly.',\n },\n // `ai/seo` (AGL-2910) applies a finished audit's drafts; it spends\n // nothing, and it is still a generative door the switch stops.\n apiPaths: { prefixes: ['ai/generate', 'ai/jobs', 'ai/seo'] },\n },\n ],\n orgPermissions: AI_ORG_PERMISSIONS,\n}\n\nlet declared = false\n\n/**\n * Registers everything above, and the activity codes. Idempotent: the\n * declarations manifest runs it once per process, and a surface's register\n * fn may call it again. The codes are a call rather than an import made\n * for what the module does as it loads, because the browser's manifest\n * reaches that module through nothing else, and a bundler honoring this\n * package's `sideEffects` deletes such an import (AGL-3025).\n */\nexport function registerAiDeclarations(): void {\n if (declared) return\n declared = true\n registerPluginEntitlements(AI_PLUGIN_ENTITLEMENTS)\n registerPluginConfigSchema(AI_CONFIG_SCHEMA)\n registerAiActivityActions()\n}\n\nregisterAiDeclarations()\n"],"names":["aiTierQuotaPerUnit","planSellsAiTiers","registerPluginConfigSchema","registerPluginEntitlements","AI_PLUGIN_ID","AI_ORG_PERMISSIONS","AI_CONFIG_SCHEMA","registerAiActivityActions","AI_PLUGIN_ENTITLEMENTS","pluginId","seatAddons","key","label","maxUnits","quota","perUnit","features","soldOn","lockdownFeatures","customerName","staffBypass","notice","title","body","apiPaths","exact","prefixes","orgPermissions","declared","registerAiDeclarations"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED,2EAA2E;AAC3E,0EAA0E;AAC1E,aAAa;AACb,SACEA,kBAAkB,EAClBC,gBAAgB,QACX,2CAA0C;AACjD,SAASC,0BAA0B,QAAQ,4CAA2C;AACtF,SACEC,0BAA0B,QAErB,kDAAiD;AACxD,SAASC,YAAY,QAAQ,iBAAa;AAC1C,SAASC,kBAAkB,QAAQ,4BAAwB;AAC3D,SAASC,gBAAgB,QAAQ,qBAAiB;AAClD,SAASC,yBAAyB,QAAQ,oCAAgC;AAE1E;;;;;;;;;;;;;;;;;;;;CAoBC,GACD,OAAO,MAAMC,yBAAwD;IACnEC,UAAUL;IACVM,YAAY;QACV;YACEC,KAAK;YACLC,OAAO;YACPC,UAAU;YACV,kEAAkE;YAClE,kEAAkE;YAClE,wBAAwB;YACxBC,OAAO;gBACLH,KAAK;gBACLI,SAASf;YACX;YACAgB,UAAU;gBAAC;gBAAgB;aAAW;YACtCC,QAAQhB;QACV;KACD;IACDe,UAAU;QACR;YAAEL,KAAK;YAAYC,OAAO;QAAY;QACtC;YAAED,KAAK;YAAgBC,OAAO;QAAgB;KAC/C;IACDM,kBAAkB;QAChB;YACEP,KAAK;YACLC,OAAO;YACPO,cAAc;YACdC,aAAa;YACbC,QAAQ;gBACNC,OAAO;gBACPC,MAAM;YACR;YACA,sEAAsE;YACtE,+BAA+B;YAC/BC,UAAU;gBAAEC,OAAO;oBAAC;oBAAa;iBAAc;YAAC;QAClD;QACA;YACEd,KAAK;YACLC,OAAO;YACPO,cAAc;YACdC,aAAa;YACbC,QAAQ;gBACNC,OAAO;gBACPC,MAAM;YACR;YACA,mEAAmE;YACnE,+DAA+D;YAC/DC,UAAU;gBAAEE,UAAU;oBAAC;oBAAe;oBAAW;iBAAS;YAAC;QAC7D;KACD;IACDC,gBAAgBtB;AAClB,EAAC;AAED,IAAIuB,WAAW;AAEf;;;;;;;CAOC,GACD,OAAO,SAASC;IACd,IAAID,UAAU;IACdA,WAAW;IACXzB,2BAA2BK;IAC3BN,2BAA2BI;IAC3BC;AACF;AAEAsB"}
|
|
@@ -28,7 +28,7 @@ import { aiPluginDraftOwner } from "./ai-job-plugin-drafts.js";
|
|
|
28
28
|
import { aiJobStepRunnerFor } from "./ai-jobs.js";
|
|
29
29
|
import { AI_SETTINGS_ARGS_SCHEMA, AI_SETTINGS_WHERE } from "./ai-job-settings-step.js";
|
|
30
30
|
import { AI_MEDIA_ARGS_SCHEMA, AI_MEDIA_LIMITS, AI_MEDIA_WHERE } from "./ai-job-media-step.js";
|
|
31
|
-
import { AI_TRACKING_ARGS_SCHEMA, AI_TRACKING_WHERE, aiTrackingMissingInput } from "./ai-job-tracking-step.js";
|
|
31
|
+
import { AI_TRACKING_ARGS_SCHEMA, AI_TRACKING_WHERE, aiTrackingInputFields, aiTrackingMissingInput } from "./ai-job-tracking-step.js";
|
|
32
32
|
/**
|
|
33
33
|
* What THIS plugin lets a build make (AGL-3616), registered on the core's
|
|
34
34
|
* capability contract exactly as any other plugin registers its own, so the
|
|
@@ -453,6 +453,8 @@ const passes = (count)=>()=>count * AI_SITE_PASS_CREDITS;
|
|
|
453
453
|
live: true,
|
|
454
454
|
// An item with no usable id asks for it instead of being built (AGL-3751).
|
|
455
455
|
missingInput: aiTrackingMissingInput,
|
|
456
|
+
// …and waits for it in `needs_input`, with a field naming the provider (AGL-3978).
|
|
457
|
+
inputFields: aiTrackingInputFields,
|
|
456
458
|
// Written by code from the plan's values: no model pass.
|
|
457
459
|
estimateCredits: ()=>0,
|
|
458
460
|
degrade: 'omit'
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/jobs/ai-build-capabilities.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 { DUPLICABLE_HOST_RESOURCE_KINDS, DUPLICATE_NAME_MAX } from '@aglyn/aglyn/app-utils/duplicate-resource'\nimport { checkEntitlement } from '@aglyn/aglyn/app-utils/plan-entitlements'\nimport type { AglynOrgBilling } from '@aglyn/aglyn/foundation/definitions/org-billing.types'\nimport { isHostPluginEnabled } from '@aglyn/aglyn/plugin-manager/enabled-plugins'\nimport {\n pluginAiCapabilities,\n registerPluginAiCapability,\n type PluginAiCapability,\n type ResolvedPluginAiCapability,\n} from '@aglyn/aglyn/plugin-manager/plugin-ai-capabilities'\nimport { filterEnabledPluginsByReleaseFlags } from '@aglyn/tenant-data-admin/server/release-flags'\nimport { AI_TEMPLATE_SUBJECTS } from '../model/ai-template-subjects'\nimport { AI_SITE_PASS_CREDITS } from '../model/ai-site-job'\nimport type { AiBuildOps } from '../model/ai-build-job'\nimport { AI_LOGIC_FUNCTION_RESOURCE } from '../model/ai-logic-job'\nimport { AI_AUTOMATION_RESOURCE } from '../model/ai-workflow-job'\nimport { AI_EDIT_TARGET_KINDS } from '../model/ai-edit-job'\nimport { AI_CAMPAIGN_RESOURCE } from './ai-job-campaign-step'\nimport { aiPluginDraftOwner, type AiPluginDraftOwnerLookup } from './ai-job-plugin-drafts'\nimport { aiJobStepRunnerFor } from './ai-jobs'\nimport { AI_SETTINGS_ARGS_SCHEMA, AI_SETTINGS_WHERE } from './ai-job-settings-step'\nimport { AI_MEDIA_ARGS_SCHEMA, AI_MEDIA_LIMITS, AI_MEDIA_WHERE } from './ai-job-media-step'\nimport { AI_TRACKING_ARGS_SCHEMA, AI_TRACKING_WHERE, aiTrackingMissingInput } from './ai-job-tracking-step'\n\n/**\n * What THIS plugin lets a build make (AGL-3616), registered on the core's\n * capability contract exactly as any other plugin registers its own, so the\n * planner, the gates and the estimate read one list and name no plugin.\n *\n * Every one is built by a runner this plugin already has (`runnerKind`):\n * pages, layouts, forms, components and email designs are the plan's\n * creations and screens; templates, campaigns and automations are items with\n * arguments. A campaign and an automation are still WRITTEN by the marketing\n * and workflows plugins, through the writers their runners already call, and\n * a site function by the logic plugin's `function` writer, which the `logic`\n * runner calls when its job is a build's unit. A change to a page or layout\n * the site already has is the `edit` runner's, and a change to its header or\n * footer menu the `navigation` runner's (AGL-3728), a copy of something\n * it has the `duplicate` runner's (AGL-3740), a change to its settings\n * the `settings` runner's (AGL-3748), organizing its media library the\n * `media` runner's (AGL-3752), and a change to its analytics and\n * advertising tags the `tracking` runner's (AGL-3751).\n */\n\n/** This plugin's id, as its registrations name their owner. */\nconst AI_PLUGIN_ID = 'ai'\n\nconst NO_ARGS = { type: 'object', properties: {}, additionalProperties: false } as const\n\nconst passes = (count: number) => () => count * AI_SITE_PASS_CREDITS\n\n/** The operations this plugin owns, as it registers them. */\nexport const AI_OWNED_CAPABILITIES: readonly PluginAiCapability[] = [\n {\n op: 'page',\n noun: 'page',\n where: 'Pages',\n intents: ['new pages: home, about, services, contact, pricing, a landing page'],\n argsSchema: NO_ARGS,\n maxPerPlan: 8,\n freeAllowed: true,\n runnerKind: 'page',\n estimateCredits: passes(6),\n degrade: 'omit',\n },\n {\n op: 'layout',\n noun: 'layout',\n where: 'Layouts',\n intents: ['a header and footer shared by pages'],\n argsSchema: NO_ARGS,\n maxPerPlan: 1,\n freeAllowed: true,\n runnerKind: 'layout',\n estimateCredits: passes(1),\n degrade: 'fallback',\n },\n {\n op: 'form',\n noun: 'form',\n where: 'Forms',\n intents: ['a contact form, a quote request, a sign-up form'],\n argsSchema: NO_ARGS,\n maxPerPlan: 3,\n freeAllowed: true,\n runnerKind: 'form',\n estimateCredits: passes(1),\n degrade: 'omit',\n },\n {\n op: 'component',\n noun: 'component',\n where: 'Components',\n intents: ['a reusable card or block placed on several pages'],\n argsSchema: NO_ARGS,\n maxPerPlan: 4,\n freeAllowed: false,\n runnerKind: 'component',\n estimateCredits: passes(1),\n degrade: 'omit',\n },\n {\n op: 'email',\n noun: 'email design',\n where: 'Emails → Templates',\n intents: ['an email design: a welcome, a reply, an announcement'],\n argsSchema: NO_ARGS,\n maxPerPlan: 2,\n freeAllowed: false,\n runnerKind: 'email',\n estimateCredits: passes(1),\n degrade: 'omit',\n },\n {\n op: 'template',\n noun: 'page template',\n where: 'Templates',\n intents: ['a page template for blog posts, products or authors'],\n argsSchema: {\n type: 'object',\n properties: {\n subject: {\n type: 'string',\n description: 'What each page shows: entry (a collection entry), product or author.',\n enum: AI_TEMPLATE_SUBJECTS,\n },\n collectionId: {\n type: 'string',\n description: 'For entry: the collection id from the site inventory.',\n maxLength: 100,\n },\n },\n required: ['subject'],\n additionalProperties: false,\n },\n maxPerPlan: 2,\n freeAllowed: false,\n runnerKind: 'template',\n estimateCredits: passes(6),\n degrade: 'omit',\n },\n {\n op: 'campaign',\n noun: 'email campaign',\n where: 'Marketing → Campaigns',\n intents: ['an email campaign drafted and left unsent'],\n argsSchema: {\n type: 'object',\n properties: {\n name: { type: 'string', description: 'What the campaign is called.', maxLength: 120 },\n },\n additionalProperties: false,\n },\n maxPerPlan: 2,\n freeAllowed: false,\n runnerKind: 'campaign',\n estimateCredits: passes(2),\n degrade: 'omit',\n },\n {\n op: 'workflow',\n noun: 'automation',\n where: 'Automations',\n intents: ['an automation: when a form is sent, do something'],\n argsSchema: NO_ARGS,\n maxPerPlan: 2,\n freeAllowed: false,\n runnerKind: 'workflow',\n estimateCredits: passes(1),\n degrade: 'omit',\n },\n {\n // A function needs a model, so it is this plugin's operation; the logic\n // plugin owns the record and writes it (AGL-3616). New functions only: a\n // build never changes one the site already has.\n op: 'function',\n noun: 'site function',\n where: 'Logic → Functions',\n intents: ['a site function that works a value out from what it is given: a price, a total, a quote'],\n argsSchema: NO_ARGS,\n maxPerPlan: 2,\n // Free includes one function (`functionsPerHost: 1`), and Logic no feature.\n freeAllowed: true,\n quota: 'functionsPerHost',\n runnerKind: 'logic',\n estimateCredits: passes(1),\n degrade: 'omit',\n },\n {\n // A change to something the site already has (AGL-3616), made by the\n // `edit` runner: the Assist edit rung's protocol against the stored\n // document, saved as a version visitors do not see. Not on the Free\n // taste: without version history only an unpublished page can take a\n // change, which is rarely the page a request means, and its admission\n // would refuse the item after the plan was confirmed.\n op: 'edit',\n noun: 'page change',\n where: 'the page’s or layout’s versions',\n intents: [\n 'a change to a page or layout the site already has — shorter copy, a new section, different wording — saved as a version visitors do not see until it is published',\n ],\n argsSchema: {\n type: 'object',\n properties: {\n target: {\n type: 'string',\n description: 'The id of an existing page or layout from the site inventory.',\n maxLength: 64,\n },\n targetKind: {\n type: 'string',\n description: 'screen when target is a page, layout when it is a layout.',\n enum: AI_EDIT_TARGET_KINDS,\n },\n },\n required: ['target'],\n additionalProperties: false,\n },\n maxPerPlan: 3,\n freeAllowed: false,\n runnerKind: 'edit',\n estimateCredits: passes(1),\n degrade: 'omit',\n },\n {\n // The site's header and footer menus (AGL-3728): the Besigner's own Page\n // Links and Dropdown Menus in the site's layout, changed by code from the\n // words the planner wrote, saved as a version beside the live one. No\n // model, so no credits. Not on the Free taste, as `edit`: a layout is\n // always served, so without version history there is nowhere to land.\n op: 'navigation',\n noun: 'menu change',\n where: 'the layout’s versions',\n intents: [\n 'changing the site’s header or footer menu — add, remove, rename, reorder or relink its items, or put items under a dropdown — saved as a layout version visitors do not see until it is published',\n ],\n argsSchema: {\n type: 'object',\n properties: {\n menu: {\n type: 'string',\n description: 'Which menu: header (the default), footer, or both.',\n enum: ['header', 'footer', 'both'],\n },\n layout: {\n type: 'string',\n description: 'The layout id from the site inventory, or new:<name> of a layout this plan makes; leave it out for the layout the site’s pages use.',\n maxLength: 64,\n },\n add: {\n type: 'array',\n description:\n 'Items to add, each \"Label => destination\", or \"Parent > Label => destination\" to put it under the dropdown Parent. A destination is a page id from the site inventory, new:<page title> of a page this plan makes, a path such as /contact, or an https:// address.',\n items: { type: 'string', maxLength: 160 },\n maxItems: 12,\n },\n remove: {\n type: 'array',\n description: 'Labels of items to take out, as \"Label\" or \"Parent > Label\".',\n items: { type: 'string', maxLength: 100 },\n maxItems: 12,\n },\n rename: {\n type: 'array',\n description: 'Items to rename, each \"Old label => New label\".',\n items: { type: 'string', maxLength: 100 },\n maxItems: 12,\n },\n relink: {\n type: 'array',\n description: 'Items to point somewhere else, each \"Label => destination\", destinations as in add.',\n items: { type: 'string', maxLength: 160 },\n maxItems: 12,\n },\n order: {\n type: 'array',\n description: 'Top-level labels in the order wanted; items not named keep their order after them.',\n items: { type: 'string', maxLength: 60 },\n maxItems: 12,\n },\n },\n additionalProperties: false,\n },\n maxPerPlan: 1,\n freeAllowed: false,\n // Offered only where the change has somewhere to land: a plan with version history.\n feature: 'versioning',\n runnerKind: 'navigation',\n // Written by code from the plan's words: no model pass.\n estimateCredits: () => 0,\n degrade: 'omit',\n },\n {\n // A copy of something the site already has (AGL-3740), made by core's\n // `duplicateResource` — the console's own Duplicate… — so \"another page\n // like Services\" is copied rather than generated again. No model, so no\n // credits; the copy meets the plan's own counters as a create does,\n // which is why the Free taste may ask for one.\n op: 'duplicate',\n noun: 'copy',\n where: 'the list the original is on',\n intents: [\n 'a copy of a page, component, layout, template, form, email design or workflow the site already has, as an unpublished draft to change — rather than making it again',\n ],\n argsSchema: {\n type: 'object',\n properties: {\n kind: {\n type: 'string',\n description: 'What to copy: screen (a page), component, layout, template, form, emailDesign or workflow.',\n enum: DUPLICABLE_HOST_RESOURCE_KINDS,\n },\n source: {\n type: 'string',\n description: 'The id of the thing to copy from the site inventory, or its exact name where the inventory does not list it.',\n maxLength: 64,\n },\n name: {\n type: 'string',\n description: 'What the copy is called; leave it out for \"Copy of\" the original’s name.',\n maxLength: DUPLICATE_NAME_MAX,\n },\n },\n required: ['kind', 'source'],\n additionalProperties: false,\n },\n maxPerPlan: 3,\n freeAllowed: true,\n runnerKind: 'duplicate',\n // Copied by code: no model pass.\n estimateCredits: () => 0,\n degrade: 'omit',\n },\n {\n // The site's settings (AGL-3748): the fields the console's settings\n // cards write — name, search defaults, favicon, logo and social image\n // from the media library, language, time zone, contact details and the\n // cookie banner's mode — held to the same limits and saved live when the\n // plan is confirmed, as a settings save is. No model, so no credits; every\n // plan may change its own settings, so the Free taste may too. Domains,\n // members, billing, plugins, indexing and anything with a credential are\n // not arguments, so they cannot be asked for.\n op: 'settings',\n noun: 'settings change',\n where: AI_SETTINGS_WHERE,\n intents: [\n 'changing the site’s settings — its name, search title and description, title pattern, favicon, logo or social image (from images already in the media library), language, time zone, business name, description (tagline), phone, contact email or address, or the cookie banner’s mode — saved to the live site when the plan is confirmed',\n ],\n argsSchema: AI_SETTINGS_ARGS_SCHEMA,\n maxPerPlan: 1,\n freeAllowed: true,\n runnerKind: 'settings',\n // A setting has no draft state: saved, it is what the live site renders.\n live: true,\n // Written by code from the plan's values: no model pass.\n estimateCredits: () => 0,\n degrade: 'omit',\n },\n {\n // Organizing files already in the site's own media library (AGL-3752):\n // the folder each is filed in, its tags, its alt text and its name, as\n // the library's Details drawer and bulk actions write them, saved live\n // when the plan is confirmed. Never an upload, a copy, a replacement or a\n // deletion, and never the organization's shared library. No model, so no\n // credits; every plan has a media library, so the Free taste may too.\n op: 'media',\n noun: 'media library change',\n where: AI_MEDIA_WHERE,\n intents: [\n `organizing files already in the site’s media library — filing them in a folder (made if missing), adding or removing tags, renaming one, or writing alt text for an image the request describes or from the caption the library already holds — up to ${AI_MEDIA_LIMITS.files} files a change, saved live when the plan is confirmed; never uploading, copying or deleting a file`,\n ],\n argsSchema: AI_MEDIA_ARGS_SCHEMA,\n maxPerPlan: 4,\n freeAllowed: true,\n runnerKind: 'media',\n // A library file's details have no draft state: saved, they are what the library shows.\n live: true,\n // Written by code from the plan's values: no model pass.\n estimateCredits: () => 0,\n degrade: 'omit',\n },\n {\n // The site's analytics and advertising tags (AGL-3751): the ids the\n // console's Setup → Tracking card sets — Google Analytics, Tag Manager,\n // and the Meta, Google Ads, LinkedIn, TikTok and Pinterest tags — each\n // held to the card's own pattern, set or removed, saved live on confirm.\n // Only public ids the person states: never a credential (Ad conversions'\n // tokens, Zapier, webhook secrets), and never the consent banner, which\n // still decides where every tag loads. No model, so no credits; the card\n // is on every plan, so the Free taste may ask too.\n op: 'tracking',\n noun: 'tracking change',\n where: AI_TRACKING_WHERE,\n intents: [\n 'connecting or removing the site’s Google Analytics, Google Tag Manager, Meta pixel, Google Ads, LinkedIn Insight, TikTok pixel or Pinterest tag by the ID the person gives (never one it makes up; ask for the ID when the request has none) — saved to the live site when the plan is confirmed, loading only where a visitor’s cookie consent allows',\n ],\n argsSchema: AI_TRACKING_ARGS_SCHEMA,\n maxPerPlan: 1,\n freeAllowed: true,\n runnerKind: 'tracking',\n // A tag has no draft state: saved, it is on every live page.\n live: true,\n // An item with no usable id asks for it instead of being built (AGL-3751).\n missingInput: aiTrackingMissingInput,\n // Written by code from the plan's values: no model pass.\n estimateCredits: () => 0,\n degrade: 'omit',\n },\n]\n\n/**\n * The resource another plugin writes for each operation of this plugin's that\n * cannot be built without it. The operation runs where that writer's owner\n * runs — registered, switched on for the workspace and the site, and past its\n * release flag — exactly as an operation that owner registered would.\n */\nexport const AI_OWNED_OP_WRITERS: Readonly<Partial<Record<string, string>>> = {\n function: AI_LOGIC_FUNCTION_RESOURCE,\n // A campaign is written by the marketing plugin's campaign writer, an\n // automation by the workflows plugin's: neither is offered where its\n // writer's plugin is off, rather than planned and then skipped.\n campaign: AI_CAMPAIGN_RESOURCE,\n workflow: AI_AUTOMATION_RESOURCE,\n}\n\n/** Registers this plugin's build operations; the console surface calls it. */\nexport function registerAiBuildCapabilities(): void {\n for (const capability of AI_OWNED_CAPABILITIES) {\n registerPluginAiCapability(capability, { pluginId: AI_PLUGIN_ID })\n }\n}\n\n/** What decides which operations a build may use here. */\nexport interface AiBuildOpsContext {\n orgId: string\n hostId: string | null\n org: Partial<AglynOrgBilling> | null\n /** The site document, for the plugins switched on and off on it. */\n host: Readonly<Record<string, unknown>> | null\n freeTaste: boolean\n}\n\nexport interface AiBuildOpsDeps {\n /** The registered capabilities; the core registry's otherwise. */\n capabilities?: () => ResolvedPluginAiCapability[]\n /** The release-flag read; the platform's otherwise. */\n releasedPlugins?: (pluginIds: string[], orgId: string) => Promise<string[]>\n /** Whether a runner is registered for a kind; the machine's otherwise. */\n hasRunner?: (kind: string) => boolean\n /** Which plugin writes a resource; the core's registry otherwise. */\n writerOwner?: AiPluginDraftOwnerLookup\n}\n\n/**\n * The operations a build may plan on this site, by op (AGL-3616): every\n * registered capability whose owner runs here — switched on for the\n * workspace and the site, past its release flag; for one of this plugin's\n * operations another plugin writes (`AI_OWNED_OP_WRITERS`), that writer's\n * owner, and a writer registered at all — whose entitlement the plan\n * holds, which the Free taste may use where the workspace is on it, and,\n * for an AI-run operation, whose runner this process loaded. One release-flag\n * read for every owner at once. What a member may do and what an allowance\n * has left are the owner's to say when the item runs (`refusal`).\n */\nexport async function aiBuildOps(context: AiBuildOpsContext, deps: AiBuildOpsDeps = {}): Promise<AiBuildOps> {\n const all = (deps.capabilities ?? pluginAiCapabilities)()\n const hasRunner = deps.hasRunner ?? ((kind: string) => aiJobStepRunnerFor(kind as never) !== null)\n const writerOwner = deps.writerOwner ?? aiPluginDraftOwner\n // The plugin each of this plugin's operations depends on, by op; `null` where its writer is not registered.\n const writtenBy = new Map<string, string | null>()\n for (const { pluginId, capability } of all) {\n const resource = pluginId === AI_PLUGIN_ID ? AI_OWNED_OP_WRITERS[capability.op] : undefined\n if (resource) writtenBy.set(capability.op, writerOwner(resource))\n }\n const owners = [\n ...new Set(\n [...all.map((one) => one.pluginId), ...writtenBy.values()].filter(\n (id): id is string => !!id && id !== AI_PLUGIN_ID,\n ),\n ),\n ]\n const released = new Set(\n owners.length\n ? await (deps.releasedPlugins ??\n ((ids, orgId) => filterEnabledPluginsByReleaseFlags(ids, { orgId, authorization: null })))(owners, context.orgId)\n : [],\n )\n const ops = new Map<string, PluginAiCapability>()\n for (const { pluginId, capability } of all) {\n // The plugin that must run here: the owner, or for one of this plugin's\n // operations, the plugin that writes what it makes.\n const runsOn = pluginId === AI_PLUGIN_ID ? writtenBy.get(capability.op) : pluginId\n if (runsOn === null) continue\n if (runsOn !== undefined && runsOn !== AI_PLUGIN_ID) {\n if (!released.has(runsOn)) continue\n if (!isHostPluginEnabled(context.org as { enabledPlugins?: string[] } | null, context.host, runsOn)) continue\n }\n if (capability.feature && !checkEntitlement(context.org, capability.feature)) continue\n if (context.freeTaste && !capability.freeAllowed) continue\n if (capability.runnerKind && !hasRunner(capability.runnerKind)) continue\n ops.set(capability.op, capability)\n }\n return ops\n}\n\n/**\n * The lines the plan step's request lists the item operations in: each op\n * with what it makes, its arguments and their meaning. Per site, so they ride\n * the job's own turn and never a cached system block.\n */\nexport function aiBuildOpLines(ops: AiBuildOps, structural: readonly string[]): string[] {\n const items = [...ops.values()].filter((one) => !structural.includes(one.op))\n if (!items.length) return ['Operations for items: none on this site. Leave items empty.']\n const lines = ['Operations for items (anything else goes in create or screens):']\n for (const one of items) {\n const args = Object.entries(one.argsSchema.properties).map(([name, property]) => {\n const required = one.argsSchema.required?.includes(name) ? '' : ' (optional)'\n // An array's values are named too (AGL-3616): told only \"days: array\",\n // the live canonical plan wrote \"monday\" for the enum's \"mon\".\n const choices = property.enum\n ? ` one of ${property.enum.join('|')}`\n : property.items?.enum\n ? ` of ${property.items.enum.join('|')}`\n : ''\n return `${name}: ${property.type}${choices}${required} — ${property.description}`\n })\n lines.push(\n `- ${one.op}: ${aiNounWithArticle(one.noun)}, at most ${one.maxPerPlan}; for ${one.intents.join('; ')}.${\n one.pageBlocks?.length ? ` A page section that uses it places the ${one.pageBlocks.join(' or ')} block: put new:<name> in that section's uses.` : ''\n } Args: ${args.length ? `{ ${args.join('; ')} }` : '{}'}.`,\n )\n }\n // Measured live on the canonical request (AGL-3616): asked for \"forms for\n // bookings\", the planner made a plain form rather than the operation that\n // takes bookings. An operation does the job; a form that imitates it does not.\n lines.push(\n 'When the request asks for what one of these operations makes, plan that operation as an item, and place it on the page that offers it. Never stand in for it with a form, page or component that only imitates it: a form that collects what the operation would handle does not do its job. A form is for what no operation here makes, such as general inquiries.',\n )\n return lines\n}\n\nfunction aiNounWithArticle(noun: string): string {\n return `${/^[aeiou]/i.test(noun) ? 'an' : 'a'} ${noun}`\n}\n\n/** What a build can make here, in the owner's words, for the chat's instructions. */\nexport function aiBuildIntents(ops: AiBuildOps): string[] {\n return [...ops.values()].flatMap((one) => one.intents)\n}\n"],"names":["DUPLICABLE_HOST_RESOURCE_KINDS","DUPLICATE_NAME_MAX","checkEntitlement","isHostPluginEnabled","pluginAiCapabilities","registerPluginAiCapability","filterEnabledPluginsByReleaseFlags","AI_TEMPLATE_SUBJECTS","AI_SITE_PASS_CREDITS","AI_LOGIC_FUNCTION_RESOURCE","AI_AUTOMATION_RESOURCE","AI_EDIT_TARGET_KINDS","AI_CAMPAIGN_RESOURCE","aiPluginDraftOwner","aiJobStepRunnerFor","AI_SETTINGS_ARGS_SCHEMA","AI_SETTINGS_WHERE","AI_MEDIA_ARGS_SCHEMA","AI_MEDIA_LIMITS","AI_MEDIA_WHERE","AI_TRACKING_ARGS_SCHEMA","AI_TRACKING_WHERE","aiTrackingMissingInput","AI_PLUGIN_ID","NO_ARGS","type","properties","additionalProperties","passes","count","AI_OWNED_CAPABILITIES","op","noun","where","intents","argsSchema","maxPerPlan","freeAllowed","runnerKind","estimateCredits","degrade","subject","description","enum","collectionId","maxLength","required","name","quota","target","targetKind","menu","layout","add","items","maxItems","remove","rename","relink","order","feature","kind","source","live","files","missingInput","AI_OWNED_OP_WRITERS","function","campaign","workflow","registerAiBuildCapabilities","capability","pluginId","aiBuildOps","context","deps","all","capabilities","hasRunner","writerOwner","writtenBy","Map","resource","undefined","set","owners","Set","map","one","values","filter","id","released","length","releasedPlugins","ids","orgId","authorization","ops","runsOn","get","has","org","host","freeTaste","aiBuildOpLines","structural","includes","lines","args","Object","entries","property","choices","join","push","aiNounWithArticle","pageBlocks","test","aiBuildIntents","flatMap"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/jobs/ai-build-capabilities.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 { DUPLICABLE_HOST_RESOURCE_KINDS, DUPLICATE_NAME_MAX } from '@aglyn/aglyn/app-utils/duplicate-resource'\nimport { checkEntitlement } from '@aglyn/aglyn/app-utils/plan-entitlements'\nimport type { AglynOrgBilling } from '@aglyn/aglyn/foundation/definitions/org-billing.types'\nimport { isHostPluginEnabled } from '@aglyn/aglyn/plugin-manager/enabled-plugins'\nimport {\n pluginAiCapabilities,\n registerPluginAiCapability,\n type PluginAiCapability,\n type ResolvedPluginAiCapability,\n} from '@aglyn/aglyn/plugin-manager/plugin-ai-capabilities'\nimport { filterEnabledPluginsByReleaseFlags } from '@aglyn/tenant-data-admin/server/release-flags'\nimport { AI_TEMPLATE_SUBJECTS } from '../model/ai-template-subjects'\nimport { AI_SITE_PASS_CREDITS } from '../model/ai-site-job'\nimport type { AiBuildOps } from '../model/ai-build-job'\nimport { AI_LOGIC_FUNCTION_RESOURCE } from '../model/ai-logic-job'\nimport { AI_AUTOMATION_RESOURCE } from '../model/ai-workflow-job'\nimport { AI_EDIT_TARGET_KINDS } from '../model/ai-edit-job'\nimport { AI_CAMPAIGN_RESOURCE } from './ai-job-campaign-step'\nimport { aiPluginDraftOwner, type AiPluginDraftOwnerLookup } from './ai-job-plugin-drafts'\nimport { aiJobStepRunnerFor } from './ai-jobs'\nimport { AI_SETTINGS_ARGS_SCHEMA, AI_SETTINGS_WHERE } from './ai-job-settings-step'\nimport { AI_MEDIA_ARGS_SCHEMA, AI_MEDIA_LIMITS, AI_MEDIA_WHERE } from './ai-job-media-step'\nimport { AI_TRACKING_ARGS_SCHEMA, AI_TRACKING_WHERE, aiTrackingInputFields, aiTrackingMissingInput } from './ai-job-tracking-step'\n\n/**\n * What THIS plugin lets a build make (AGL-3616), registered on the core's\n * capability contract exactly as any other plugin registers its own, so the\n * planner, the gates and the estimate read one list and name no plugin.\n *\n * Every one is built by a runner this plugin already has (`runnerKind`):\n * pages, layouts, forms, components and email designs are the plan's\n * creations and screens; templates, campaigns and automations are items with\n * arguments. A campaign and an automation are still WRITTEN by the marketing\n * and workflows plugins, through the writers their runners already call, and\n * a site function by the logic plugin's `function` writer, which the `logic`\n * runner calls when its job is a build's unit. A change to a page or layout\n * the site already has is the `edit` runner's, and a change to its header or\n * footer menu the `navigation` runner's (AGL-3728), a copy of something\n * it has the `duplicate` runner's (AGL-3740), a change to its settings\n * the `settings` runner's (AGL-3748), organizing its media library the\n * `media` runner's (AGL-3752), and a change to its analytics and\n * advertising tags the `tracking` runner's (AGL-3751).\n */\n\n/** This plugin's id, as its registrations name their owner. */\nconst AI_PLUGIN_ID = 'ai'\n\nconst NO_ARGS = { type: 'object', properties: {}, additionalProperties: false } as const\n\nconst passes = (count: number) => () => count * AI_SITE_PASS_CREDITS\n\n/** The operations this plugin owns, as it registers them. */\nexport const AI_OWNED_CAPABILITIES: readonly PluginAiCapability[] = [\n {\n op: 'page',\n noun: 'page',\n where: 'Pages',\n intents: ['new pages: home, about, services, contact, pricing, a landing page'],\n argsSchema: NO_ARGS,\n maxPerPlan: 8,\n freeAllowed: true,\n runnerKind: 'page',\n estimateCredits: passes(6),\n degrade: 'omit',\n },\n {\n op: 'layout',\n noun: 'layout',\n where: 'Layouts',\n intents: ['a header and footer shared by pages'],\n argsSchema: NO_ARGS,\n maxPerPlan: 1,\n freeAllowed: true,\n runnerKind: 'layout',\n estimateCredits: passes(1),\n degrade: 'fallback',\n },\n {\n op: 'form',\n noun: 'form',\n where: 'Forms',\n intents: ['a contact form, a quote request, a sign-up form'],\n argsSchema: NO_ARGS,\n maxPerPlan: 3,\n freeAllowed: true,\n runnerKind: 'form',\n estimateCredits: passes(1),\n degrade: 'omit',\n },\n {\n op: 'component',\n noun: 'component',\n where: 'Components',\n intents: ['a reusable card or block placed on several pages'],\n argsSchema: NO_ARGS,\n maxPerPlan: 4,\n freeAllowed: false,\n runnerKind: 'component',\n estimateCredits: passes(1),\n degrade: 'omit',\n },\n {\n op: 'email',\n noun: 'email design',\n where: 'Emails → Templates',\n intents: ['an email design: a welcome, a reply, an announcement'],\n argsSchema: NO_ARGS,\n maxPerPlan: 2,\n freeAllowed: false,\n runnerKind: 'email',\n estimateCredits: passes(1),\n degrade: 'omit',\n },\n {\n op: 'template',\n noun: 'page template',\n where: 'Templates',\n intents: ['a page template for blog posts, products or authors'],\n argsSchema: {\n type: 'object',\n properties: {\n subject: {\n type: 'string',\n description: 'What each page shows: entry (a collection entry), product or author.',\n enum: AI_TEMPLATE_SUBJECTS,\n },\n collectionId: {\n type: 'string',\n description: 'For entry: the collection id from the site inventory.',\n maxLength: 100,\n },\n },\n required: ['subject'],\n additionalProperties: false,\n },\n maxPerPlan: 2,\n freeAllowed: false,\n runnerKind: 'template',\n estimateCredits: passes(6),\n degrade: 'omit',\n },\n {\n op: 'campaign',\n noun: 'email campaign',\n where: 'Marketing → Campaigns',\n intents: ['an email campaign drafted and left unsent'],\n argsSchema: {\n type: 'object',\n properties: {\n name: { type: 'string', description: 'What the campaign is called.', maxLength: 120 },\n },\n additionalProperties: false,\n },\n maxPerPlan: 2,\n freeAllowed: false,\n runnerKind: 'campaign',\n estimateCredits: passes(2),\n degrade: 'omit',\n },\n {\n op: 'workflow',\n noun: 'automation',\n where: 'Automations',\n intents: ['an automation: when a form is sent, do something'],\n argsSchema: NO_ARGS,\n maxPerPlan: 2,\n freeAllowed: false,\n runnerKind: 'workflow',\n estimateCredits: passes(1),\n degrade: 'omit',\n },\n {\n // A function needs a model, so it is this plugin's operation; the logic\n // plugin owns the record and writes it (AGL-3616). New functions only: a\n // build never changes one the site already has.\n op: 'function',\n noun: 'site function',\n where: 'Logic → Functions',\n intents: ['a site function that works a value out from what it is given: a price, a total, a quote'],\n argsSchema: NO_ARGS,\n maxPerPlan: 2,\n // Free includes one function (`functionsPerHost: 1`), and Logic no feature.\n freeAllowed: true,\n quota: 'functionsPerHost',\n runnerKind: 'logic',\n estimateCredits: passes(1),\n degrade: 'omit',\n },\n {\n // A change to something the site already has (AGL-3616), made by the\n // `edit` runner: the Assist edit rung's protocol against the stored\n // document, saved as a version visitors do not see. Not on the Free\n // taste: without version history only an unpublished page can take a\n // change, which is rarely the page a request means, and its admission\n // would refuse the item after the plan was confirmed.\n op: 'edit',\n noun: 'page change',\n where: 'the page’s or layout’s versions',\n intents: [\n 'a change to a page or layout the site already has — shorter copy, a new section, different wording — saved as a version visitors do not see until it is published',\n ],\n argsSchema: {\n type: 'object',\n properties: {\n target: {\n type: 'string',\n description: 'The id of an existing page or layout from the site inventory.',\n maxLength: 64,\n },\n targetKind: {\n type: 'string',\n description: 'screen when target is a page, layout when it is a layout.',\n enum: AI_EDIT_TARGET_KINDS,\n },\n },\n required: ['target'],\n additionalProperties: false,\n },\n maxPerPlan: 3,\n freeAllowed: false,\n runnerKind: 'edit',\n estimateCredits: passes(1),\n degrade: 'omit',\n },\n {\n // The site's header and footer menus (AGL-3728): the Besigner's own Page\n // Links and Dropdown Menus in the site's layout, changed by code from the\n // words the planner wrote, saved as a version beside the live one. No\n // model, so no credits. Not on the Free taste, as `edit`: a layout is\n // always served, so without version history there is nowhere to land.\n op: 'navigation',\n noun: 'menu change',\n where: 'the layout’s versions',\n intents: [\n 'changing the site’s header or footer menu — add, remove, rename, reorder or relink its items, or put items under a dropdown — saved as a layout version visitors do not see until it is published',\n ],\n argsSchema: {\n type: 'object',\n properties: {\n menu: {\n type: 'string',\n description: 'Which menu: header (the default), footer, or both.',\n enum: ['header', 'footer', 'both'],\n },\n layout: {\n type: 'string',\n description: 'The layout id from the site inventory, or new:<name> of a layout this plan makes; leave it out for the layout the site’s pages use.',\n maxLength: 64,\n },\n add: {\n type: 'array',\n description:\n 'Items to add, each \"Label => destination\", or \"Parent > Label => destination\" to put it under the dropdown Parent. A destination is a page id from the site inventory, new:<page title> of a page this plan makes, a path such as /contact, or an https:// address.',\n items: { type: 'string', maxLength: 160 },\n maxItems: 12,\n },\n remove: {\n type: 'array',\n description: 'Labels of items to take out, as \"Label\" or \"Parent > Label\".',\n items: { type: 'string', maxLength: 100 },\n maxItems: 12,\n },\n rename: {\n type: 'array',\n description: 'Items to rename, each \"Old label => New label\".',\n items: { type: 'string', maxLength: 100 },\n maxItems: 12,\n },\n relink: {\n type: 'array',\n description: 'Items to point somewhere else, each \"Label => destination\", destinations as in add.',\n items: { type: 'string', maxLength: 160 },\n maxItems: 12,\n },\n order: {\n type: 'array',\n description: 'Top-level labels in the order wanted; items not named keep their order after them.',\n items: { type: 'string', maxLength: 60 },\n maxItems: 12,\n },\n },\n additionalProperties: false,\n },\n maxPerPlan: 1,\n freeAllowed: false,\n // Offered only where the change has somewhere to land: a plan with version history.\n feature: 'versioning',\n runnerKind: 'navigation',\n // Written by code from the plan's words: no model pass.\n estimateCredits: () => 0,\n degrade: 'omit',\n },\n {\n // A copy of something the site already has (AGL-3740), made by core's\n // `duplicateResource` — the console's own Duplicate… — so \"another page\n // like Services\" is copied rather than generated again. No model, so no\n // credits; the copy meets the plan's own counters as a create does,\n // which is why the Free taste may ask for one.\n op: 'duplicate',\n noun: 'copy',\n where: 'the list the original is on',\n intents: [\n 'a copy of a page, component, layout, template, form, email design or workflow the site already has, as an unpublished draft to change — rather than making it again',\n ],\n argsSchema: {\n type: 'object',\n properties: {\n kind: {\n type: 'string',\n description: 'What to copy: screen (a page), component, layout, template, form, emailDesign or workflow.',\n enum: DUPLICABLE_HOST_RESOURCE_KINDS,\n },\n source: {\n type: 'string',\n description: 'The id of the thing to copy from the site inventory, or its exact name where the inventory does not list it.',\n maxLength: 64,\n },\n name: {\n type: 'string',\n description: 'What the copy is called; leave it out for \"Copy of\" the original’s name.',\n maxLength: DUPLICATE_NAME_MAX,\n },\n },\n required: ['kind', 'source'],\n additionalProperties: false,\n },\n maxPerPlan: 3,\n freeAllowed: true,\n runnerKind: 'duplicate',\n // Copied by code: no model pass.\n estimateCredits: () => 0,\n degrade: 'omit',\n },\n {\n // The site's settings (AGL-3748): the fields the console's settings\n // cards write — name, search defaults, favicon, logo and social image\n // from the media library, language, time zone, contact details and the\n // cookie banner's mode — held to the same limits and saved live when the\n // plan is confirmed, as a settings save is. No model, so no credits; every\n // plan may change its own settings, so the Free taste may too. Domains,\n // members, billing, plugins, indexing and anything with a credential are\n // not arguments, so they cannot be asked for.\n op: 'settings',\n noun: 'settings change',\n where: AI_SETTINGS_WHERE,\n intents: [\n 'changing the site’s settings — its name, search title and description, title pattern, favicon, logo or social image (from images already in the media library), language, time zone, business name, description (tagline), phone, contact email or address, or the cookie banner’s mode — saved to the live site when the plan is confirmed',\n ],\n argsSchema: AI_SETTINGS_ARGS_SCHEMA,\n maxPerPlan: 1,\n freeAllowed: true,\n runnerKind: 'settings',\n // A setting has no draft state: saved, it is what the live site renders.\n live: true,\n // Written by code from the plan's values: no model pass.\n estimateCredits: () => 0,\n degrade: 'omit',\n },\n {\n // Organizing files already in the site's own media library (AGL-3752):\n // the folder each is filed in, its tags, its alt text and its name, as\n // the library's Details drawer and bulk actions write them, saved live\n // when the plan is confirmed. Never an upload, a copy, a replacement or a\n // deletion, and never the organization's shared library. No model, so no\n // credits; every plan has a media library, so the Free taste may too.\n op: 'media',\n noun: 'media library change',\n where: AI_MEDIA_WHERE,\n intents: [\n `organizing files already in the site’s media library — filing them in a folder (made if missing), adding or removing tags, renaming one, or writing alt text for an image the request describes or from the caption the library already holds — up to ${AI_MEDIA_LIMITS.files} files a change, saved live when the plan is confirmed; never uploading, copying or deleting a file`,\n ],\n argsSchema: AI_MEDIA_ARGS_SCHEMA,\n maxPerPlan: 4,\n freeAllowed: true,\n runnerKind: 'media',\n // A library file's details have no draft state: saved, they are what the library shows.\n live: true,\n // Written by code from the plan's values: no model pass.\n estimateCredits: () => 0,\n degrade: 'omit',\n },\n {\n // The site's analytics and advertising tags (AGL-3751): the ids the\n // console's Setup → Tracking card sets — Google Analytics, Tag Manager,\n // and the Meta, Google Ads, LinkedIn, TikTok and Pinterest tags — each\n // held to the card's own pattern, set or removed, saved live on confirm.\n // Only public ids the person states: never a credential (Ad conversions'\n // tokens, Zapier, webhook secrets), and never the consent banner, which\n // still decides where every tag loads. No model, so no credits; the card\n // is on every plan, so the Free taste may ask too.\n op: 'tracking',\n noun: 'tracking change',\n where: AI_TRACKING_WHERE,\n intents: [\n 'connecting or removing the site’s Google Analytics, Google Tag Manager, Meta pixel, Google Ads, LinkedIn Insight, TikTok pixel or Pinterest tag by the ID the person gives (never one it makes up; ask for the ID when the request has none) — saved to the live site when the plan is confirmed, loading only where a visitor’s cookie consent allows',\n ],\n argsSchema: AI_TRACKING_ARGS_SCHEMA,\n maxPerPlan: 1,\n freeAllowed: true,\n runnerKind: 'tracking',\n // A tag has no draft state: saved, it is on every live page.\n live: true,\n // An item with no usable id asks for it instead of being built (AGL-3751).\n missingInput: aiTrackingMissingInput,\n // …and waits for it in `needs_input`, with a field naming the provider (AGL-3978).\n inputFields: aiTrackingInputFields,\n // Written by code from the plan's values: no model pass.\n estimateCredits: () => 0,\n degrade: 'omit',\n },\n]\n\n/**\n * The resource another plugin writes for each operation of this plugin's that\n * cannot be built without it. The operation runs where that writer's owner\n * runs — registered, switched on for the workspace and the site, and past its\n * release flag — exactly as an operation that owner registered would.\n */\nexport const AI_OWNED_OP_WRITERS: Readonly<Partial<Record<string, string>>> = {\n function: AI_LOGIC_FUNCTION_RESOURCE,\n // A campaign is written by the marketing plugin's campaign writer, an\n // automation by the workflows plugin's: neither is offered where its\n // writer's plugin is off, rather than planned and then skipped.\n campaign: AI_CAMPAIGN_RESOURCE,\n workflow: AI_AUTOMATION_RESOURCE,\n}\n\n/** Registers this plugin's build operations; the console surface calls it. */\nexport function registerAiBuildCapabilities(): void {\n for (const capability of AI_OWNED_CAPABILITIES) {\n registerPluginAiCapability(capability, { pluginId: AI_PLUGIN_ID })\n }\n}\n\n/** What decides which operations a build may use here. */\nexport interface AiBuildOpsContext {\n orgId: string\n hostId: string | null\n org: Partial<AglynOrgBilling> | null\n /** The site document, for the plugins switched on and off on it. */\n host: Readonly<Record<string, unknown>> | null\n freeTaste: boolean\n}\n\nexport interface AiBuildOpsDeps {\n /** The registered capabilities; the core registry's otherwise. */\n capabilities?: () => ResolvedPluginAiCapability[]\n /** The release-flag read; the platform's otherwise. */\n releasedPlugins?: (pluginIds: string[], orgId: string) => Promise<string[]>\n /** Whether a runner is registered for a kind; the machine's otherwise. */\n hasRunner?: (kind: string) => boolean\n /** Which plugin writes a resource; the core's registry otherwise. */\n writerOwner?: AiPluginDraftOwnerLookup\n}\n\n/**\n * The operations a build may plan on this site, by op (AGL-3616): every\n * registered capability whose owner runs here — switched on for the\n * workspace and the site, past its release flag; for one of this plugin's\n * operations another plugin writes (`AI_OWNED_OP_WRITERS`), that writer's\n * owner, and a writer registered at all — whose entitlement the plan\n * holds, which the Free taste may use where the workspace is on it, and,\n * for an AI-run operation, whose runner this process loaded. One release-flag\n * read for every owner at once. What a member may do and what an allowance\n * has left are the owner's to say when the item runs (`refusal`).\n */\nexport async function aiBuildOps(context: AiBuildOpsContext, deps: AiBuildOpsDeps = {}): Promise<AiBuildOps> {\n const all = (deps.capabilities ?? pluginAiCapabilities)()\n const hasRunner = deps.hasRunner ?? ((kind: string) => aiJobStepRunnerFor(kind as never) !== null)\n const writerOwner = deps.writerOwner ?? aiPluginDraftOwner\n // The plugin each of this plugin's operations depends on, by op; `null` where its writer is not registered.\n const writtenBy = new Map<string, string | null>()\n for (const { pluginId, capability } of all) {\n const resource = pluginId === AI_PLUGIN_ID ? AI_OWNED_OP_WRITERS[capability.op] : undefined\n if (resource) writtenBy.set(capability.op, writerOwner(resource))\n }\n const owners = [\n ...new Set(\n [...all.map((one) => one.pluginId), ...writtenBy.values()].filter(\n (id): id is string => !!id && id !== AI_PLUGIN_ID,\n ),\n ),\n ]\n const released = new Set(\n owners.length\n ? await (deps.releasedPlugins ??\n ((ids, orgId) => filterEnabledPluginsByReleaseFlags(ids, { orgId, authorization: null })))(owners, context.orgId)\n : [],\n )\n const ops = new Map<string, PluginAiCapability>()\n for (const { pluginId, capability } of all) {\n // The plugin that must run here: the owner, or for one of this plugin's\n // operations, the plugin that writes what it makes.\n const runsOn = pluginId === AI_PLUGIN_ID ? writtenBy.get(capability.op) : pluginId\n if (runsOn === null) continue\n if (runsOn !== undefined && runsOn !== AI_PLUGIN_ID) {\n if (!released.has(runsOn)) continue\n if (!isHostPluginEnabled(context.org as { enabledPlugins?: string[] } | null, context.host, runsOn)) continue\n }\n if (capability.feature && !checkEntitlement(context.org, capability.feature)) continue\n if (context.freeTaste && !capability.freeAllowed) continue\n if (capability.runnerKind && !hasRunner(capability.runnerKind)) continue\n ops.set(capability.op, capability)\n }\n return ops\n}\n\n/**\n * The lines the plan step's request lists the item operations in: each op\n * with what it makes, its arguments and their meaning. Per site, so they ride\n * the job's own turn and never a cached system block.\n */\nexport function aiBuildOpLines(ops: AiBuildOps, structural: readonly string[]): string[] {\n const items = [...ops.values()].filter((one) => !structural.includes(one.op))\n if (!items.length) return ['Operations for items: none on this site. Leave items empty.']\n const lines = ['Operations for items (anything else goes in create or screens):']\n for (const one of items) {\n const args = Object.entries(one.argsSchema.properties).map(([name, property]) => {\n const required = one.argsSchema.required?.includes(name) ? '' : ' (optional)'\n // An array's values are named too (AGL-3616): told only \"days: array\",\n // the live canonical plan wrote \"monday\" for the enum's \"mon\".\n const choices = property.enum\n ? ` one of ${property.enum.join('|')}`\n : property.items?.enum\n ? ` of ${property.items.enum.join('|')}`\n : ''\n return `${name}: ${property.type}${choices}${required} — ${property.description}`\n })\n lines.push(\n `- ${one.op}: ${aiNounWithArticle(one.noun)}, at most ${one.maxPerPlan}; for ${one.intents.join('; ')}.${\n one.pageBlocks?.length ? ` A page section that uses it places the ${one.pageBlocks.join(' or ')} block: put new:<name> in that section's uses.` : ''\n } Args: ${args.length ? `{ ${args.join('; ')} }` : '{}'}.`,\n )\n }\n // Measured live on the canonical request (AGL-3616): asked for \"forms for\n // bookings\", the planner made a plain form rather than the operation that\n // takes bookings. An operation does the job; a form that imitates it does not.\n lines.push(\n 'When the request asks for what one of these operations makes, plan that operation as an item, and place it on the page that offers it. Never stand in for it with a form, page or component that only imitates it: a form that collects what the operation would handle does not do its job. A form is for what no operation here makes, such as general inquiries.',\n )\n return lines\n}\n\nfunction aiNounWithArticle(noun: string): string {\n return `${/^[aeiou]/i.test(noun) ? 'an' : 'a'} ${noun}`\n}\n\n/** What a build can make here, in the owner's words, for the chat's instructions. */\nexport function aiBuildIntents(ops: AiBuildOps): string[] {\n return [...ops.values()].flatMap((one) => one.intents)\n}\n"],"names":["DUPLICABLE_HOST_RESOURCE_KINDS","DUPLICATE_NAME_MAX","checkEntitlement","isHostPluginEnabled","pluginAiCapabilities","registerPluginAiCapability","filterEnabledPluginsByReleaseFlags","AI_TEMPLATE_SUBJECTS","AI_SITE_PASS_CREDITS","AI_LOGIC_FUNCTION_RESOURCE","AI_AUTOMATION_RESOURCE","AI_EDIT_TARGET_KINDS","AI_CAMPAIGN_RESOURCE","aiPluginDraftOwner","aiJobStepRunnerFor","AI_SETTINGS_ARGS_SCHEMA","AI_SETTINGS_WHERE","AI_MEDIA_ARGS_SCHEMA","AI_MEDIA_LIMITS","AI_MEDIA_WHERE","AI_TRACKING_ARGS_SCHEMA","AI_TRACKING_WHERE","aiTrackingInputFields","aiTrackingMissingInput","AI_PLUGIN_ID","NO_ARGS","type","properties","additionalProperties","passes","count","AI_OWNED_CAPABILITIES","op","noun","where","intents","argsSchema","maxPerPlan","freeAllowed","runnerKind","estimateCredits","degrade","subject","description","enum","collectionId","maxLength","required","name","quota","target","targetKind","menu","layout","add","items","maxItems","remove","rename","relink","order","feature","kind","source","live","files","missingInput","inputFields","AI_OWNED_OP_WRITERS","function","campaign","workflow","registerAiBuildCapabilities","capability","pluginId","aiBuildOps","context","deps","all","capabilities","hasRunner","writerOwner","writtenBy","Map","resource","undefined","set","owners","Set","map","one","values","filter","id","released","length","releasedPlugins","ids","orgId","authorization","ops","runsOn","get","has","org","host","freeTaste","aiBuildOpLines","structural","includes","lines","args","Object","entries","property","choices","join","push","aiNounWithArticle","pageBlocks","test","aiBuildIntents","flatMap"],"mappings":"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"}
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* See the License for the specific language governing permissions and
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
|
-
import type
|
|
17
|
+
import { type BusinessProfileValues } from '@aglyn/aglyn/app-utils/business-profile';
|
|
18
18
|
import type { AiJob } from '../model/ai-jobs.types';
|
|
19
19
|
import type { AiJobTransitionListener } from './ai-jobs';
|
|
20
20
|
/** The guided start's answers, as profile values; `null` when it gave none. */
|
|
@@ -13,7 +13,9 @@
|
|
|
13
13
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
14
|
* See the License for the specific language governing permissions and
|
|
15
15
|
* limitations under the License.
|
|
16
|
-
*/ import {
|
|
16
|
+
*/ import { BUSINESS_PROFILE_MAX_CHARS } from "@aglyn/aglyn/app-utils/business-profile";
|
|
17
|
+
import { aiSiteDetailsOf, aiSiteServiceAreas } from "../model/ai-site-details.js";
|
|
18
|
+
import { prefillAiBusinessProfile } from "../runtime/site-context.js";
|
|
17
19
|
/**
|
|
18
20
|
* A site job fills in the site's business profile (AGL-3661), so the next job
|
|
19
21
|
* — and the owner, on Setup → Business profile — starts from what the guided
|
|
@@ -21,7 +23,8 @@
|
|
|
21
23
|
*
|
|
22
24
|
* Two sources, each recorded as itself:
|
|
23
25
|
* - `start`: the answers the owner gave the guided start — what the business
|
|
24
|
-
* is, who it is for, its city. Their words,
|
|
26
|
+
* is, who it is for, the areas it serves (else its city). Their words,
|
|
27
|
+
* given in another place.
|
|
25
28
|
* - `ai`: what the plan wrote for the home page's search description, used
|
|
26
29
|
* only where the start said nothing about what the business does.
|
|
27
30
|
*
|
|
@@ -39,7 +42,15 @@
|
|
|
39
42
|
const city = text(inputs['city']);
|
|
40
43
|
if (businessType) values.whatYouDo = sentence(businessType);
|
|
41
44
|
if (audience) values.audience = audience;
|
|
42
|
-
|
|
45
|
+
// The areas "More details" names (AGL-3979), as many whole ones as the field holds; else the city.
|
|
46
|
+
const max = BUSINESS_PROFILE_MAX_CHARS.serviceArea;
|
|
47
|
+
let serviceArea = '';
|
|
48
|
+
for (const area of aiSiteServiceAreas(aiSiteDetailsOf(inputs).serviceArea)){
|
|
49
|
+
const next = serviceArea ? `${serviceArea}, ${area}` : area;
|
|
50
|
+
if (next.length > max) break;
|
|
51
|
+
serviceArea = next;
|
|
52
|
+
}
|
|
53
|
+
if (serviceArea || city) values.serviceArea = (serviceArea || city).slice(0, max);
|
|
43
54
|
return Object.keys(values).length ? values : null;
|
|
44
55
|
}
|
|
45
56
|
/** The plan's home page description, as a line about the business; `null` when it has none. */ export function aiBusinessProfilePlanValues(job) {
|