@aglyn/plugins-ai 1.0.0-beta.231 → 1.0.0-beta.233
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.js +8 -4
- package/src/lib/activity/ai-activity-actions.js.map +1 -1
- package/src/lib/components/ai-job-follow.component.js +1 -0
- package/src/lib/components/ai-job-follow.component.js.map +1 -1
- package/src/lib/components/ai-job-links.js +13 -0
- package/src/lib/components/ai-job-links.js.map +1 -1
- package/src/lib/components/ai-jobs-list-page.component.js +1 -0
- package/src/lib/components/ai-jobs-list-page.component.js.map +1 -1
- package/src/lib/components/ai-media-create.component.d.ts +20 -7
- package/src/lib/components/ai-media-create.component.js +107 -55
- package/src/lib/components/ai-media-create.component.js.map +1 -1
- package/src/lib/components/ai-seo-fields-card.component.js +1 -0
- package/src/lib/components/ai-seo-fields-card.component.js.map +1 -1
- package/src/lib/components/ai-site-memory-card.component.d.ts +32 -0
- package/src/lib/components/ai-site-memory-card.component.js +187 -0
- package/src/lib/components/ai-site-memory-card.component.js.map +1 -0
- package/src/lib/components/ai-site-start-card.component.js +80 -77
- package/src/lib/components/ai-site-start-card.component.js.map +1 -1
- package/src/lib/components/ai-theme-proposal-card.component.js +4 -0
- package/src/lib/components/ai-theme-proposal-card.component.js.map +1 -1
- package/src/lib/components/ai-usage-strip.component.js +1 -0
- package/src/lib/components/ai-usage-strip.component.js.map +1 -1
- package/src/lib/components/assist-panel.component.d.ts +10 -0
- package/src/lib/components/assist-panel.component.js +119 -9
- package/src/lib/components/assist-panel.component.js.map +1 -1
- package/src/lib/components/assist-signals-page.component.js +2 -0
- package/src/lib/components/assist-signals-page.component.js.map +1 -1
- package/src/lib/components/billing-ai-allotments.component.js +3 -0
- package/src/lib/components/billing-ai-allotments.component.js.map +1 -1
- package/src/lib/components/billing-ai-top-users.component.js +1 -0
- package/src/lib/components/billing-ai-top-users.component.js.map +1 -1
- package/src/lib/components/billing-assist-overage-card.component.js +2 -0
- package/src/lib/components/billing-assist-overage-card.component.js.map +1 -1
- package/src/lib/components/member-ai-usage-card.component.js +10 -0
- package/src/lib/components/member-ai-usage-card.component.js.map +1 -1
- package/src/lib/components/staff-org-ai-card.component.js +1 -0
- package/src/lib/components/staff-org-ai-card.component.js.map +1 -1
- package/src/lib/components/staff-org-ai-conversations.component.d.ts +23 -0
- package/src/lib/components/staff-org-ai-conversations.component.js +346 -0
- package/src/lib/components/staff-org-ai-conversations.component.js.map +1 -0
- package/src/lib/declarations.server.js +7 -4
- package/src/lib/declarations.server.js.map +1 -1
- package/src/lib/jobs/ai-build-capabilities.d.ts +13 -1
- package/src/lib/jobs/ai-build-capabilities.js +109 -9
- package/src/lib/jobs/ai-build-capabilities.js.map +1 -1
- package/src/lib/jobs/ai-business-profile-prefill.d.ts +29 -0
- package/src/lib/jobs/ai-business-profile-prefill.js +85 -0
- package/src/lib/jobs/ai-business-profile-prefill.js.map +1 -0
- package/src/lib/jobs/ai-job-build-step.js +3 -1
- package/src/lib/jobs/ai-job-build-step.js.map +1 -1
- package/src/lib/jobs/ai-job-edit-step.d.ts +225 -0
- package/src/lib/jobs/ai-job-edit-step.js +631 -0
- package/src/lib/jobs/ai-job-edit-step.js.map +1 -0
- package/src/lib/jobs/ai-job-insight-step.js +21 -4
- package/src/lib/jobs/ai-job-insight-step.js.map +1 -1
- package/src/lib/jobs/ai-job-layout-language.d.ts +8 -3
- package/src/lib/jobs/ai-job-layout-language.js +8 -2
- package/src/lib/jobs/ai-job-layout-language.js.map +1 -1
- package/src/lib/jobs/ai-job-layout-step.js +7 -6
- package/src/lib/jobs/ai-job-layout-step.js.map +1 -1
- package/src/lib/jobs/ai-job-logic-step.d.ts +20 -0
- package/src/lib/jobs/ai-job-logic-step.js +87 -6
- package/src/lib/jobs/ai-job-logic-step.js.map +1 -1
- package/src/lib/jobs/ai-job-page-language.d.ts +52 -7
- package/src/lib/jobs/ai-job-page-language.js +72 -9
- package/src/lib/jobs/ai-job-page-language.js.map +1 -1
- package/src/lib/jobs/ai-job-page-step.js +12 -2
- package/src/lib/jobs/ai-job-page-step.js.map +1 -1
- package/src/lib/jobs/ai-job-plan-step.d.ts +24 -5
- package/src/lib/jobs/ai-job-plan-step.js +68 -21
- package/src/lib/jobs/ai-job-plan-step.js.map +1 -1
- package/src/lib/jobs/ai-job-site-content.d.ts +163 -0
- package/src/lib/jobs/ai-job-site-content.js +443 -0
- package/src/lib/jobs/ai-job-site-content.js.map +1 -0
- package/src/lib/jobs/ai-job-site-look.d.ts +112 -0
- package/src/lib/jobs/ai-job-site-look.js +322 -0
- package/src/lib/jobs/ai-job-site-look.js.map +1 -0
- package/src/lib/jobs/ai-job-site-step.d.ts +26 -5
- package/src/lib/jobs/ai-job-site-step.js +163 -24
- package/src/lib/jobs/ai-job-site-step.js.map +1 -1
- package/src/lib/jobs/ai-jobs-notify.d.ts +16 -1
- package/src/lib/jobs/ai-jobs-notify.js +81 -3
- package/src/lib/jobs/ai-jobs-notify.js.map +1 -1
- package/src/lib/jobs/ai-jobs.d.ts +14 -0
- package/src/lib/jobs/ai-jobs.js +28 -10
- package/src/lib/jobs/ai-jobs.js.map +1 -1
- package/src/lib/layout-language/ai-layout-compiler.d.ts +9 -0
- package/src/lib/layout-language/ai-layout-compiler.js +120 -33
- package/src/lib/layout-language/ai-layout-compiler.js.map +1 -1
- package/src/lib/layout-language/ai-layout-frame.js +5 -4
- package/src/lib/layout-language/ai-layout-frame.js.map +1 -1
- package/src/lib/layout-language/ai-layout-language.d.ts +12 -5
- package/src/lib/layout-language/ai-layout-language.js +92 -9
- package/src/lib/layout-language/ai-layout-language.js.map +1 -1
- package/src/lib/layout-language/ai-layout-pictures.d.ts +144 -0
- package/src/lib/layout-language/ai-layout-pictures.js +214 -0
- package/src/lib/layout-language/ai-layout-pictures.js.map +1 -0
- package/src/lib/layout-language/ai-layout-store.d.ts +2 -0
- package/src/lib/layout-language/ai-layout-store.js +7 -1
- package/src/lib/layout-language/ai-layout-store.js.map +1 -1
- package/src/lib/model/ai-build-progress.js +4 -1
- package/src/lib/model/ai-build-progress.js.map +1 -1
- package/src/lib/model/ai-edit-job.d.ts +109 -0
- package/src/lib/model/ai-edit-job.js +157 -0
- package/src/lib/model/ai-edit-job.js.map +1 -0
- package/src/lib/model/ai-job-activity.js +1 -0
- package/src/lib/model/ai-job-activity.js.map +1 -1
- package/src/lib/model/ai-jobs.types.d.ts +3 -1
- package/src/lib/model/ai-jobs.types.js.map +1 -1
- package/src/lib/model/ai-logic-job.d.ts +18 -1
- package/src/lib/model/ai-logic-job.js +24 -3
- package/src/lib/model/ai-logic-job.js.map +1 -1
- package/src/lib/model/ai-media-credits.d.ts +8 -4
- package/src/lib/model/ai-media-credits.js +11 -4
- package/src/lib/model/ai-media-credits.js.map +1 -1
- package/src/lib/model/ai-media-kinds.d.ts +68 -0
- package/src/lib/model/ai-media-kinds.js +98 -0
- package/src/lib/model/ai-media-kinds.js.map +1 -0
- package/src/lib/model/ai-plan-capabilities.d.ts +16 -0
- package/src/lib/model/ai-plan-capabilities.js +5 -0
- package/src/lib/model/ai-plan-capabilities.js.map +1 -1
- package/src/lib/model/ai-site-build-progress.d.ts +4 -0
- package/src/lib/model/ai-site-build-progress.js +28 -11
- package/src/lib/model/ai-site-build-progress.js.map +1 -1
- package/src/lib/model/ai-site-context.d.ts +111 -0
- package/src/lib/model/ai-site-context.js +222 -0
- package/src/lib/model/ai-site-context.js.map +1 -0
- package/src/lib/model/ai-site-job.d.ts +10 -2
- package/src/lib/model/ai-site-job.js +12 -5
- package/src/lib/model/ai-site-job.js.map +1 -1
- package/src/lib/model/ai-site-kinds.d.ts +164 -0
- package/src/lib/model/ai-site-kinds.js +1942 -0
- package/src/lib/model/ai-site-kinds.js.map +1 -0
- package/src/lib/model/ai-site-look.d.ts +150 -0
- package/src/lib/model/ai-site-look.js +1236 -0
- package/src/lib/model/ai-site-look.js.map +1 -0
- package/src/lib/model/ai-site-memory.d.ts +80 -0
- package/src/lib/model/ai-site-memory.js +171 -0
- package/src/lib/model/ai-site-memory.js.map +1 -0
- package/src/lib/model/ai-site-start.d.ts +10 -1
- package/src/lib/model/ai-site-start.js +16 -2
- package/src/lib/model/ai-site-start.js.map +1 -1
- package/src/lib/model/assist-follow-up.d.ts +92 -0
- package/src/lib/model/assist-follow-up.js +128 -0
- package/src/lib/model/assist-follow-up.js.map +1 -0
- package/src/lib/operator-alerts.d.ts +18 -0
- package/src/lib/operator-alerts.js +42 -0
- package/src/lib/operator-alerts.js.map +1 -1
- package/src/lib/plugin-config.js +2 -0
- package/src/lib/plugin-config.js.map +1 -1
- package/src/lib/plugin.js +20 -1
- package/src/lib/plugin.js.map +1 -1
- package/src/lib/providers/anthropic.d.ts +9 -1
- package/src/lib/providers/anthropic.js +143 -9
- package/src/lib/providers/anthropic.js.map +1 -1
- package/src/lib/providers/catalog.d.ts +37 -7
- package/src/lib/providers/catalog.js +103 -11
- package/src/lib/providers/catalog.js.map +1 -1
- package/src/lib/providers/contract.d.ts +29 -0
- package/src/lib/providers/contract.js.map +1 -1
- package/src/lib/providers/image-contract.d.ts +22 -1
- package/src/lib/providers/image-contract.js +40 -1
- package/src/lib/providers/image-contract.js.map +1 -1
- package/src/lib/providers/image-endpoints.d.ts +24 -0
- package/src/lib/providers/image-endpoints.js +28 -0
- package/src/lib/providers/image-endpoints.js.map +1 -0
- package/src/lib/providers/model-choice.js +23 -2
- package/src/lib/providers/model-choice.js.map +1 -1
- package/src/lib/providers/routing.js +18 -0
- package/src/lib/providers/routing.js.map +1 -1
- package/src/lib/providers/vertex-image-endpoint.d.ts +48 -0
- package/src/lib/providers/vertex-image-endpoint.js +80 -0
- package/src/lib/providers/vertex-image-endpoint.js.map +1 -0
- package/src/lib/providers/vertex-image.d.ts +13 -27
- package/src/lib/providers/vertex-image.js +15 -42
- package/src/lib/providers/vertex-image.js.map +1 -1
- package/src/lib/runtime/ai-blog-post-generation.d.ts +62 -0
- package/src/lib/runtime/ai-blog-post-generation.js +89 -0
- package/src/lib/runtime/ai-blog-post-generation.js.map +1 -0
- package/src/lib/runtime/ai-dev-env.d.ts +53 -0
- package/src/lib/runtime/ai-dev-env.js +72 -0
- package/src/lib/runtime/ai-dev-env.js.map +1 -0
- package/src/lib/runtime/ai-dev-replay.d.ts +116 -0
- package/src/lib/runtime/ai-dev-replay.js +313 -0
- package/src/lib/runtime/ai-dev-replay.js.map +1 -0
- package/src/lib/runtime/ai-doctrine-validators.d.ts +7 -0
- package/src/lib/runtime/ai-doctrine-validators.js +9 -2
- package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
- package/src/lib/runtime/ai-doctrine.js +5 -1
- package/src/lib/runtime/ai-doctrine.js.map +1 -1
- package/src/lib/runtime/ai-eval-live.js +4 -0
- package/src/lib/runtime/ai-eval-live.js.map +1 -1
- package/src/lib/runtime/ai-eval.d.ts +13 -1
- package/src/lib/runtime/ai-eval.js +84 -1
- package/src/lib/runtime/ai-eval.js.map +1 -1
- package/src/lib/runtime/ai-live-batch.d.ts +45 -0
- package/src/lib/runtime/ai-live-batch.js +89 -0
- package/src/lib/runtime/ai-live-batch.js.map +1 -0
- package/src/lib/runtime/ai-runtime.js +46 -2
- package/src/lib/runtime/ai-runtime.js.map +1 -1
- package/src/lib/runtime/site-context.d.ts +58 -0
- package/src/lib/runtime/site-context.js +127 -0
- package/src/lib/runtime/site-context.js.map +1 -0
- package/src/lib/server/ai-admin-conversations.d.ts +22 -0
- package/src/lib/server/ai-admin-conversations.js +197 -0
- package/src/lib/server/ai-admin-conversations.js.map +1 -0
- package/src/lib/server/ai-media-image.d.ts +5 -5
- package/src/lib/server/ai-media-image.js +25 -11
- package/src/lib/server/ai-media-image.js.map +1 -1
- package/src/lib/server/ai-media-raster-prompt.d.ts +34 -0
- package/src/lib/server/ai-media-raster-prompt.js +53 -0
- package/src/lib/server/ai-media-raster-prompt.js.map +1 -0
- package/src/lib/server/assist-chat.d.ts +11 -0
- package/src/lib/server/assist-chat.js +57 -18
- package/src/lib/server/assist-chat.js.map +1 -1
- package/src/lib/server/assist-edit-applied.js +16 -3
- package/src/lib/server/assist-edit-applied.js.map +1 -1
- package/src/lib/server/assist-view-context.d.ts +19 -1
- package/src/lib/server/assist-view-context.js +38 -1
- package/src/lib/server/assist-view-context.js.map +1 -1
- package/src/lib/server.js +10 -0
- package/src/lib/server.js.map +1 -1
- package/src/lib/subprocessors.js +17 -1
- package/src/lib/subprocessors.js.map +1 -1
- package/src/lib/tools/ai-blog-post-tool.d.ts +60 -0
- package/src/lib/tools/ai-blog-post-tool.js +175 -0
- package/src/lib/tools/ai-blog-post-tool.js.map +1 -0
- package/src/lib/usage/assist-usage.d.ts +3 -0
- package/src/lib/usage/assist-usage.js +4 -2
- package/src/lib/usage/assist-usage.js.map +1 -1
- package/src/lib/usage/staff-org-ai-conversations.d.ts +103 -0
- package/src/lib/usage/staff-org-ai-conversations.js +152 -0
- package/src/lib/usage/staff-org-ai-conversations.js.map +1 -0
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ 'use client';
|
|
17
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
18
|
+
import { PLATFORM_BRAND_NAME } from "@aglyn/aglyn";
|
|
19
|
+
import { pluginDocsHelp } from "@aglyn/aglyn/app-utils/docs-help";
|
|
20
|
+
import { CardDisplay } from "@aglyn/shared-ui-jsx";
|
|
21
|
+
import { ListPagination } from "@aglyn/shared-ui-jsx/components/list-pagination.component";
|
|
22
|
+
import { authorizedFetch } from "@aglyn/shared-util-http/authorized-token";
|
|
23
|
+
import { useUser } from "@aglyn/tenant-feature-instance";
|
|
24
|
+
import { Alert, Box, Button, Chip, Divider, Stack, ToggleButton, ToggleButtonGroup, Typography } from "@mui/material";
|
|
25
|
+
import { useCallback, useRef, useState } from "react";
|
|
26
|
+
import { STAFF_AI_CONVERSATIONS_PAGE } from "../usage/staff-org-ai-conversations.js";
|
|
27
|
+
/**
|
|
28
|
+
* What an organization asked Aglyn AI and what it answered (AGL-3675): the
|
|
29
|
+
* Assist chat's questions and answers, and each AI job's brief and result,
|
|
30
|
+
* newest first, on the staff org page.
|
|
31
|
+
*
|
|
32
|
+
* Nothing is read until staff ask: the route writes an audited access row
|
|
33
|
+
* for every page it returns, so a card that loaded with the page would log
|
|
34
|
+
* reads nobody chose to make.
|
|
35
|
+
*/ const when = (iso)=>iso ? new Date(iso).toLocaleString() : 'Unknown time';
|
|
36
|
+
const who = (person)=>{
|
|
37
|
+
var _ref, _person_email;
|
|
38
|
+
return (_ref = (_person_email = person.email) != null ? _person_email : person.name) != null ? _ref : person.uid ? `uid ${person.uid}` : 'Unknown member';
|
|
39
|
+
};
|
|
40
|
+
const money = (value)=>value === null ? null : `$${value.toFixed(value < 1 ? 4 : 2)}`;
|
|
41
|
+
/** A block of what someone typed or what came back, kept as written. */ const Words = ({ label, children })=>/*#__PURE__*/ _jsxs(Box, {
|
|
42
|
+
children: [
|
|
43
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
44
|
+
variant: "overline",
|
|
45
|
+
color: "text.secondary",
|
|
46
|
+
children: label
|
|
47
|
+
}),
|
|
48
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
49
|
+
variant: "body2",
|
|
50
|
+
sx: {
|
|
51
|
+
whiteSpace: 'pre-wrap',
|
|
52
|
+
overflowWrap: 'anywhere'
|
|
53
|
+
},
|
|
54
|
+
children: children || '—'
|
|
55
|
+
})
|
|
56
|
+
]
|
|
57
|
+
});
|
|
58
|
+
const Meta = ({ children })=>/*#__PURE__*/ _jsx(Stack, {
|
|
59
|
+
direction: "row",
|
|
60
|
+
useFlexGap: true,
|
|
61
|
+
sx: {
|
|
62
|
+
flexWrap: 'wrap',
|
|
63
|
+
gap: 1,
|
|
64
|
+
alignItems: 'center'
|
|
65
|
+
},
|
|
66
|
+
children: children
|
|
67
|
+
});
|
|
68
|
+
const AssistRow = ({ row })=>/*#__PURE__*/ _jsxs(Stack, {
|
|
69
|
+
spacing: 1,
|
|
70
|
+
children: [
|
|
71
|
+
/*#__PURE__*/ _jsxs(Meta, {
|
|
72
|
+
children: [
|
|
73
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
74
|
+
variant: "body2",
|
|
75
|
+
sx: {
|
|
76
|
+
fontWeight: 600
|
|
77
|
+
},
|
|
78
|
+
children: who(row.by)
|
|
79
|
+
}),
|
|
80
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
81
|
+
variant: "body2",
|
|
82
|
+
color: "text.secondary",
|
|
83
|
+
children: when(row.at)
|
|
84
|
+
}),
|
|
85
|
+
row.route ? /*#__PURE__*/ _jsx(Chip, {
|
|
86
|
+
size: "small",
|
|
87
|
+
variant: "outlined",
|
|
88
|
+
label: row.route
|
|
89
|
+
}) : null,
|
|
90
|
+
row.model ? /*#__PURE__*/ _jsx(Chip, {
|
|
91
|
+
size: "small",
|
|
92
|
+
variant: "outlined",
|
|
93
|
+
label: row.model
|
|
94
|
+
}) : null,
|
|
95
|
+
money(row.estCostUsd) ? /*#__PURE__*/ _jsx(Chip, {
|
|
96
|
+
size: "small",
|
|
97
|
+
variant: "outlined",
|
|
98
|
+
label: money(row.estCostUsd)
|
|
99
|
+
}) : null,
|
|
100
|
+
row.feedback ? /*#__PURE__*/ _jsx(Chip, {
|
|
101
|
+
size: "small",
|
|
102
|
+
color: row.feedback === 'up' ? 'success' : 'warning',
|
|
103
|
+
label: `Rated ${row.feedback}`
|
|
104
|
+
}) : null
|
|
105
|
+
]
|
|
106
|
+
}),
|
|
107
|
+
/*#__PURE__*/ _jsx(Words, {
|
|
108
|
+
label: "Question",
|
|
109
|
+
children: row.question
|
|
110
|
+
}),
|
|
111
|
+
/*#__PURE__*/ _jsx(Words, {
|
|
112
|
+
label: "Answer",
|
|
113
|
+
children: row.answer
|
|
114
|
+
})
|
|
115
|
+
]
|
|
116
|
+
});
|
|
117
|
+
const Result = ({ result })=>{
|
|
118
|
+
switch(result.kind){
|
|
119
|
+
case 'insight':
|
|
120
|
+
return /*#__PURE__*/ _jsx(Words, {
|
|
121
|
+
label: "Answer",
|
|
122
|
+
children: [
|
|
123
|
+
...result.insights,
|
|
124
|
+
...result.gap ? [
|
|
125
|
+
`Not answered: ${result.gap}`
|
|
126
|
+
] : []
|
|
127
|
+
].join('\n\n')
|
|
128
|
+
});
|
|
129
|
+
case 'crm-record':
|
|
130
|
+
return /*#__PURE__*/ _jsx(Words, {
|
|
131
|
+
label: "Summary",
|
|
132
|
+
children: [
|
|
133
|
+
result.summary,
|
|
134
|
+
result.standing,
|
|
135
|
+
result.nextStep ? `Next step: ${result.nextStep}` : null
|
|
136
|
+
].filter(Boolean).join('\n\n')
|
|
137
|
+
});
|
|
138
|
+
case 'crm-email':
|
|
139
|
+
return /*#__PURE__*/ _jsx(Words, {
|
|
140
|
+
label: "Email draft",
|
|
141
|
+
children: `Subject: ${result.subject}\n\n${result.body}`
|
|
142
|
+
});
|
|
143
|
+
case 'crm-mapping':
|
|
144
|
+
return /*#__PURE__*/ _jsx(Words, {
|
|
145
|
+
label: "Column matches",
|
|
146
|
+
children: result.matches.join('\n')
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
const JobRow = ({ row })=>/*#__PURE__*/ _jsxs(Stack, {
|
|
151
|
+
spacing: 1,
|
|
152
|
+
children: [
|
|
153
|
+
/*#__PURE__*/ _jsxs(Meta, {
|
|
154
|
+
children: [
|
|
155
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
156
|
+
variant: "body2",
|
|
157
|
+
sx: {
|
|
158
|
+
fontWeight: 600
|
|
159
|
+
},
|
|
160
|
+
children: who(row.by)
|
|
161
|
+
}),
|
|
162
|
+
/*#__PURE__*/ _jsx(Typography, {
|
|
163
|
+
variant: "body2",
|
|
164
|
+
color: "text.secondary",
|
|
165
|
+
children: when(row.at)
|
|
166
|
+
}),
|
|
167
|
+
/*#__PURE__*/ _jsx(Chip, {
|
|
168
|
+
size: "small",
|
|
169
|
+
variant: "outlined",
|
|
170
|
+
label: row.kind
|
|
171
|
+
}),
|
|
172
|
+
/*#__PURE__*/ _jsx(Chip, {
|
|
173
|
+
size: "small",
|
|
174
|
+
color: row.status === 'done' ? 'success' : row.status === 'failed' ? 'error' : 'default',
|
|
175
|
+
label: row.status
|
|
176
|
+
}),
|
|
177
|
+
/*#__PURE__*/ _jsx(Chip, {
|
|
178
|
+
size: "small",
|
|
179
|
+
variant: "outlined",
|
|
180
|
+
label: `${row.credits.toLocaleString()} credits`
|
|
181
|
+
})
|
|
182
|
+
]
|
|
183
|
+
}),
|
|
184
|
+
/*#__PURE__*/ _jsx(Words, {
|
|
185
|
+
label: "Brief",
|
|
186
|
+
children: row.brief
|
|
187
|
+
}),
|
|
188
|
+
row.result ? /*#__PURE__*/ _jsx(Result, {
|
|
189
|
+
result: row.result
|
|
190
|
+
}) : null,
|
|
191
|
+
row.outputs.length ? /*#__PURE__*/ _jsx(Words, {
|
|
192
|
+
label: "Made",
|
|
193
|
+
children: row.outputs.map((output)=>[
|
|
194
|
+
output.label,
|
|
195
|
+
output.note
|
|
196
|
+
].filter(Boolean).join(' — ')).join('\n')
|
|
197
|
+
}) : null,
|
|
198
|
+
row.error ? /*#__PURE__*/ _jsx(Alert, {
|
|
199
|
+
severity: "error",
|
|
200
|
+
children: row.error
|
|
201
|
+
}) : null
|
|
202
|
+
]
|
|
203
|
+
});
|
|
204
|
+
const StaffOrgAiConversations = ({ orgId })=>{
|
|
205
|
+
const { data: user } = useUser();
|
|
206
|
+
const userRef = useRef(user);
|
|
207
|
+
userRef.current = user;
|
|
208
|
+
const [kind, setKind] = useState(null);
|
|
209
|
+
const [rows, setRows] = useState([]);
|
|
210
|
+
// The cursor that opens each page: `cursors[page]` is the `after` its
|
|
211
|
+
// request carries, so Previous re-reads a page rather than keeping every
|
|
212
|
+
// page read so far in memory.
|
|
213
|
+
const [cursors, setCursors] = useState([
|
|
214
|
+
null
|
|
215
|
+
]);
|
|
216
|
+
const [page, setPage] = useState(0);
|
|
217
|
+
const [next, setNext] = useState(null);
|
|
218
|
+
const [loading, setLoading] = useState(false);
|
|
219
|
+
const [error, setError] = useState(null);
|
|
220
|
+
const load = useCallback(async (target, targetPage, after)=>{
|
|
221
|
+
const current = userRef.current;
|
|
222
|
+
if (!current || !orgId) return;
|
|
223
|
+
setLoading(true);
|
|
224
|
+
setError(null);
|
|
225
|
+
try {
|
|
226
|
+
const params = new URLSearchParams({
|
|
227
|
+
orgId,
|
|
228
|
+
kind: target
|
|
229
|
+
});
|
|
230
|
+
if (after) params.set('after', after);
|
|
231
|
+
const response = await authorizedFetch(current, `/api/ai/admin/conversations?${params}`);
|
|
232
|
+
const payload = await response.json().catch(()=>null);
|
|
233
|
+
if (!response.ok || !payload) {
|
|
234
|
+
var _ref;
|
|
235
|
+
setError((_ref = payload == null ? void 0 : payload.error) != null ? _ref : 'The conversations could not be read.');
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
setRows(payload.rows);
|
|
239
|
+
setPage(targetPage);
|
|
240
|
+
setNext(payload.next);
|
|
241
|
+
setCursors((existing)=>{
|
|
242
|
+
const kept = existing.slice(0, targetPage + 1);
|
|
243
|
+
return payload.next ? [
|
|
244
|
+
...kept,
|
|
245
|
+
payload.next
|
|
246
|
+
] : kept;
|
|
247
|
+
});
|
|
248
|
+
} catch (unused) {
|
|
249
|
+
setError('The conversations could not be read.');
|
|
250
|
+
} finally{
|
|
251
|
+
setLoading(false);
|
|
252
|
+
}
|
|
253
|
+
}, [
|
|
254
|
+
orgId
|
|
255
|
+
]);
|
|
256
|
+
const show = useCallback((target)=>{
|
|
257
|
+
setKind(target);
|
|
258
|
+
setRows([]);
|
|
259
|
+
setNext(null);
|
|
260
|
+
setPage(0);
|
|
261
|
+
setCursors([
|
|
262
|
+
null
|
|
263
|
+
]);
|
|
264
|
+
void load(target, 0, null);
|
|
265
|
+
}, [
|
|
266
|
+
load
|
|
267
|
+
]);
|
|
268
|
+
return /*#__PURE__*/ _jsx(CardDisplay, {
|
|
269
|
+
header: "AI conversations",
|
|
270
|
+
help: pluginDocsHelp('aiMonitoring', {
|
|
271
|
+
anchor: '#ai-conversations',
|
|
272
|
+
excerpt: `What this organization asked ${PLATFORM_BRAND_NAME} AI and what it answered: Assist chat questions and answers, and each AI job’s brief and result. Each page staff read is recorded in the audit log, without the text.`
|
|
273
|
+
}),
|
|
274
|
+
HeaderProps: {
|
|
275
|
+
action: kind === null ? /*#__PURE__*/ _jsx(Button, {
|
|
276
|
+
size: "small",
|
|
277
|
+
onClick: ()=>show('assist'),
|
|
278
|
+
children: 'Show conversations'
|
|
279
|
+
}) : /*#__PURE__*/ _jsxs(ToggleButtonGroup, {
|
|
280
|
+
size: "small",
|
|
281
|
+
exclusive: true,
|
|
282
|
+
value: kind,
|
|
283
|
+
onChange: (_, value)=>value && show(value),
|
|
284
|
+
"aria-label": "Which conversations",
|
|
285
|
+
children: [
|
|
286
|
+
/*#__PURE__*/ _jsx(ToggleButton, {
|
|
287
|
+
value: "assist",
|
|
288
|
+
children: 'Assist chat'
|
|
289
|
+
}),
|
|
290
|
+
/*#__PURE__*/ _jsx(ToggleButton, {
|
|
291
|
+
value: "jobs",
|
|
292
|
+
children: 'AI jobs'
|
|
293
|
+
})
|
|
294
|
+
]
|
|
295
|
+
})
|
|
296
|
+
},
|
|
297
|
+
contentGutterX: true,
|
|
298
|
+
contentGutterY: true,
|
|
299
|
+
children: kind === null ? /*#__PURE__*/ _jsx(Typography, {
|
|
300
|
+
variant: "body2",
|
|
301
|
+
color: "text.secondary",
|
|
302
|
+
children: `What people in this organization typed to ${PLATFORM_BRAND_NAME} AI, and what it answered. Opening it is recorded in the audit log.`
|
|
303
|
+
}) : /*#__PURE__*/ _jsxs(Stack, {
|
|
304
|
+
spacing: 2,
|
|
305
|
+
divider: /*#__PURE__*/ _jsx(Divider, {
|
|
306
|
+
flexItem: true
|
|
307
|
+
}),
|
|
308
|
+
children: [
|
|
309
|
+
error ? /*#__PURE__*/ _jsx(Alert, {
|
|
310
|
+
severity: "warning",
|
|
311
|
+
children: error
|
|
312
|
+
}) : null,
|
|
313
|
+
!loading && !error && !rows.length ? /*#__PURE__*/ _jsx(Typography, {
|
|
314
|
+
variant: "body2",
|
|
315
|
+
color: "text.secondary",
|
|
316
|
+
children: kind === 'assist' ? 'No Assist chat in the last 180 days.' : 'No AI jobs yet.'
|
|
317
|
+
}) : null,
|
|
318
|
+
rows.map((row)=>kind === 'assist' ? /*#__PURE__*/ _jsx(AssistRow, {
|
|
319
|
+
row: row
|
|
320
|
+
}, row.id) : /*#__PURE__*/ _jsx(JobRow, {
|
|
321
|
+
row: row
|
|
322
|
+
}, row.id)),
|
|
323
|
+
loading ? /*#__PURE__*/ _jsx(Typography, {
|
|
324
|
+
variant: "body2",
|
|
325
|
+
color: "text.secondary",
|
|
326
|
+
children: 'Loading…'
|
|
327
|
+
}) : null,
|
|
328
|
+
rows.length || page > 0 ? /*#__PURE__*/ _jsx(ListPagination, {
|
|
329
|
+
page: page,
|
|
330
|
+
pageSize: STAFF_AI_CONVERSATIONS_PAGE,
|
|
331
|
+
rowCount: rows.length,
|
|
332
|
+
hasMore: Boolean(next),
|
|
333
|
+
disabled: loading,
|
|
334
|
+
onPageChange: (target)=>{
|
|
335
|
+
var _cursors_target;
|
|
336
|
+
return void load(kind, target, (_cursors_target = cursors[target]) != null ? _cursors_target : null);
|
|
337
|
+
}
|
|
338
|
+
}) : null
|
|
339
|
+
]
|
|
340
|
+
})
|
|
341
|
+
});
|
|
342
|
+
};
|
|
343
|
+
StaffOrgAiConversations.displayName = 'StaffOrgAiConversations';
|
|
344
|
+
export default StaffOrgAiConversations;
|
|
345
|
+
|
|
346
|
+
//# sourceMappingURL=staff-org-ai-conversations.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/components/staff-org-ai-conversations.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\n'use client'\n\nimport { PLATFORM_BRAND_NAME } from '@aglyn/aglyn'\nimport { pluginDocsHelp } from '@aglyn/aglyn/app-utils/docs-help'\nimport { CardDisplay } from '@aglyn/shared-ui-jsx'\nimport { ListPagination } from '@aglyn/shared-ui-jsx/components/list-pagination.component'\nimport { authorizedFetch } from '@aglyn/shared-util-http/authorized-token'\nimport { useUser } from '@aglyn/tenant-feature-instance'\nimport {\n Alert,\n Box,\n Button,\n Chip,\n Divider,\n Stack,\n ToggleButton,\n ToggleButtonGroup,\n Typography,\n} from '@mui/material'\nimport { useCallback, useRef, useState, type ReactNode } from 'react'\nimport {\n STAFF_AI_CONVERSATIONS_PAGE,\n type StaffAiAssistRow,\n type StaffAiConversationKind,\n type StaffAiConversationPerson,\n type StaffAiConversationsResponse,\n type StaffAiJobResult,\n type StaffAiJobRow,\n} from '../usage/staff-org-ai-conversations'\n\n/**\n * What an organization asked Aglyn AI and what it answered (AGL-3675): the\n * Assist chat's questions and answers, and each AI job's brief and result,\n * newest first, on the staff org page.\n *\n * Nothing is read until staff ask: the route writes an audited access row\n * for every page it returns, so a card that loaded with the page would log\n * reads nobody chose to make.\n */\n\nconst when = (iso: string | null) => (iso ? new Date(iso).toLocaleString() : 'Unknown time')\n\nconst who = (person: StaffAiConversationPerson) =>\n person.email ?? person.name ?? (person.uid ? `uid ${person.uid}` : 'Unknown member')\n\nconst money = (value: number | null) => (value === null ? null : `$${value.toFixed(value < 1 ? 4 : 2)}`)\n\n/** A block of what someone typed or what came back, kept as written. */\nconst Words = ({ label, children }: { label: string; children: string }) => (\n <Box>\n <Typography variant=\"overline\" color=\"text.secondary\">\n {label}\n </Typography>\n <Typography variant=\"body2\" sx={{ whiteSpace: 'pre-wrap', overflowWrap: 'anywhere' }}>\n {children || '—'}\n </Typography>\n </Box>\n)\n\nconst Meta = ({ children }: { children: ReactNode }) => (\n <Stack direction=\"row\" useFlexGap sx={{ flexWrap: 'wrap', gap: 1, alignItems: 'center' }}>\n {children}\n </Stack>\n)\n\nconst AssistRow = ({ row }: { row: StaffAiAssistRow }) => (\n <Stack spacing={1}>\n <Meta>\n <Typography variant=\"body2\" sx={{ fontWeight: 600 }}>\n {who(row.by)}\n </Typography>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {when(row.at)}\n </Typography>\n {row.route ? <Chip size=\"small\" variant=\"outlined\" label={row.route} /> : null}\n {row.model ? <Chip size=\"small\" variant=\"outlined\" label={row.model} /> : null}\n {money(row.estCostUsd) ? <Chip size=\"small\" variant=\"outlined\" label={money(row.estCostUsd)} /> : null}\n {row.feedback ? (\n <Chip size=\"small\" color={row.feedback === 'up' ? 'success' : 'warning'} label={`Rated ${row.feedback}`} />\n ) : null}\n </Meta>\n <Words label=\"Question\">{row.question}</Words>\n <Words label=\"Answer\">{row.answer}</Words>\n </Stack>\n)\n\nconst Result = ({ result }: { result: StaffAiJobResult }) => {\n switch (result.kind) {\n case 'insight':\n return (\n <Words label=\"Answer\">\n {[...result.insights, ...(result.gap ? [`Not answered: ${result.gap}`] : [])].join('\\n\\n')}\n </Words>\n )\n case 'crm-record':\n return (\n <Words label=\"Summary\">\n {[result.summary, result.standing, result.nextStep ? `Next step: ${result.nextStep}` : null]\n .filter(Boolean)\n .join('\\n\\n')}\n </Words>\n )\n case 'crm-email':\n return <Words label=\"Email draft\">{`Subject: ${result.subject}\\n\\n${result.body}`}</Words>\n case 'crm-mapping':\n return <Words label=\"Column matches\">{result.matches.join('\\n')}</Words>\n }\n}\n\nconst JobRow = ({ row }: { row: StaffAiJobRow }) => (\n <Stack spacing={1}>\n <Meta>\n <Typography variant=\"body2\" sx={{ fontWeight: 600 }}>\n {who(row.by)}\n </Typography>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {when(row.at)}\n </Typography>\n <Chip size=\"small\" variant=\"outlined\" label={row.kind} />\n <Chip\n size=\"small\"\n color={row.status === 'done' ? 'success' : row.status === 'failed' ? 'error' : 'default'}\n label={row.status}\n />\n <Chip size=\"small\" variant=\"outlined\" label={`${row.credits.toLocaleString()} credits`} />\n </Meta>\n <Words label=\"Brief\">{row.brief}</Words>\n {row.result ? <Result result={row.result} /> : null}\n {row.outputs.length ? (\n <Words label=\"Made\">\n {row.outputs\n .map((output) => [output.label, output.note].filter(Boolean).join(' — '))\n .join('\\n')}\n </Words>\n ) : null}\n {row.error ? <Alert severity=\"error\">{row.error}</Alert> : null}\n </Stack>\n)\n\nconst StaffOrgAiConversations = ({ orgId }: { orgId: string }) => {\n const { data: user } = useUser()\n const userRef = useRef(user)\n userRef.current = user\n const [kind, setKind] = useState<StaffAiConversationKind | null>(null)\n const [rows, setRows] = useState<Array<StaffAiAssistRow | StaffAiJobRow>>([])\n // The cursor that opens each page: `cursors[page]` is the `after` its\n // request carries, so Previous re-reads a page rather than keeping every\n // page read so far in memory.\n const [cursors, setCursors] = useState<Array<string | null>>([null])\n const [page, setPage] = useState(0)\n const [next, setNext] = useState<string | null>(null)\n const [loading, setLoading] = useState(false)\n const [error, setError] = useState<string | null>(null)\n\n const load = useCallback(\n async (target: StaffAiConversationKind, targetPage: number, after: string | null) => {\n const current = userRef.current\n if (!current || !orgId) return\n setLoading(true)\n setError(null)\n try {\n const params = new URLSearchParams({ orgId, kind: target })\n if (after) params.set('after', after)\n const response = await authorizedFetch(current, `/api/ai/admin/conversations?${params}`)\n const payload = (await response.json().catch(() => null)) as\n | (StaffAiConversationsResponse & { error?: string })\n | null\n if (!response.ok || !payload) {\n setError(payload?.error ?? 'The conversations could not be read.')\n return\n }\n setRows(payload.rows)\n setPage(targetPage)\n setNext(payload.next)\n setCursors((existing) => {\n const kept = existing.slice(0, targetPage + 1)\n return payload.next ? [...kept, payload.next] : kept\n })\n } catch {\n setError('The conversations could not be read.')\n } finally {\n setLoading(false)\n }\n },\n [orgId],\n )\n\n const show = useCallback(\n (target: StaffAiConversationKind) => {\n setKind(target)\n setRows([])\n setNext(null)\n setPage(0)\n setCursors([null])\n void load(target, 0, null)\n },\n [load],\n )\n\n return (\n <CardDisplay\n header=\"AI conversations\"\n help={pluginDocsHelp('aiMonitoring', {\n anchor: '#ai-conversations',\n excerpt:\n `What this organization asked ${PLATFORM_BRAND_NAME} AI and what it answered: Assist chat questions and answers, and each AI job’s brief and result. Each page staff read is recorded in the audit log, without the text.`,\n })}\n HeaderProps={{\n action:\n kind === null ? (\n <Button size=\"small\" onClick={() => show('assist')}>\n {'Show conversations'}\n </Button>\n ) : (\n <ToggleButtonGroup\n size=\"small\"\n exclusive\n value={kind}\n onChange={(_, value: StaffAiConversationKind | null) => value && show(value)}\n aria-label=\"Which conversations\"\n >\n <ToggleButton value=\"assist\">{'Assist chat'}</ToggleButton>\n <ToggleButton value=\"jobs\">{'AI jobs'}</ToggleButton>\n </ToggleButtonGroup>\n ),\n }}\n contentGutterX\n contentGutterY\n >\n {kind === null ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {`What people in this organization typed to ${PLATFORM_BRAND_NAME} AI, and what it answered. Opening it is recorded in the audit log.`}\n </Typography>\n ) : (\n <Stack spacing={2} divider={<Divider flexItem />}>\n {error ? <Alert severity=\"warning\">{error}</Alert> : null}\n {!loading && !error && !rows.length ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {kind === 'assist'\n ? 'No Assist chat in the last 180 days.'\n : 'No AI jobs yet.'}\n </Typography>\n ) : null}\n {rows.map((row) =>\n kind === 'assist' ? (\n <AssistRow key={row.id} row={row as StaffAiAssistRow} />\n ) : (\n <JobRow key={row.id} row={row as StaffAiJobRow} />\n ),\n )}\n {loading ? (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {'Loading…'}\n </Typography>\n ) : null}\n {rows.length || page > 0 ? (\n <ListPagination\n page={page}\n pageSize={STAFF_AI_CONVERSATIONS_PAGE}\n rowCount={rows.length}\n hasMore={Boolean(next)}\n disabled={loading}\n onPageChange={(target) => void load(kind, target, cursors[target] ?? null)}\n />\n ) : null}\n </Stack>\n )}\n </CardDisplay>\n )\n}\n\nStaffOrgAiConversations.displayName = 'StaffOrgAiConversations'\n\nexport default StaffOrgAiConversations\n"],"names":["PLATFORM_BRAND_NAME","pluginDocsHelp","CardDisplay","ListPagination","authorizedFetch","useUser","Alert","Box","Button","Chip","Divider","Stack","ToggleButton","ToggleButtonGroup","Typography","useCallback","useRef","useState","STAFF_AI_CONVERSATIONS_PAGE","when","iso","Date","toLocaleString","who","person","email","name","uid","money","value","toFixed","Words","label","children","variant","color","sx","whiteSpace","overflowWrap","Meta","direction","useFlexGap","flexWrap","gap","alignItems","AssistRow","row","spacing","fontWeight","by","at","route","size","model","estCostUsd","feedback","question","answer","Result","result","kind","insights","join","summary","standing","nextStep","filter","Boolean","subject","body","matches","JobRow","status","credits","brief","outputs","length","map","output","note","error","severity","StaffOrgAiConversations","orgId","data","user","userRef","current","setKind","rows","setRows","cursors","setCursors","page","setPage","next","setNext","loading","setLoading","setError","load","target","targetPage","after","params","URLSearchParams","set","response","payload","json","catch","ok","existing","kept","slice","show","header","help","anchor","excerpt","HeaderProps","action","onClick","exclusive","onChange","_","aria-label","contentGutterX","contentGutterY","divider","flexItem","id","pageSize","rowCount","hasMore","disabled","onPageChange","displayName"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAED;;AAEA,SAASA,mBAAmB,QAAQ,eAAc;AAClD,SAASC,cAAc,QAAQ,mCAAkC;AACjE,SAASC,WAAW,QAAQ,uBAAsB;AAClD,SAASC,cAAc,QAAQ,4DAA2D;AAC1F,SAASC,eAAe,QAAQ,2CAA0C;AAC1E,SAASC,OAAO,QAAQ,iCAAgC;AACxD,SACEC,KAAK,EACLC,GAAG,EACHC,MAAM,EACNC,IAAI,EACJC,OAAO,EACPC,KAAK,EACLC,YAAY,EACZC,iBAAiB,EACjBC,UAAU,QACL,gBAAe;AACtB,SAASC,WAAW,EAAEC,MAAM,EAAEC,QAAQ,QAAwB,QAAO;AACrE,SACEC,2BAA2B,QAOtB,yCAAqC;AAE5C;;;;;;;;CAQC,GAED,MAAMC,OAAO,CAACC,MAAwBA,MAAM,IAAIC,KAAKD,KAAKE,cAAc,KAAK;AAE7E,MAAMC,MAAM,CAACC;QACXA,MAAAA;YAAAA,QAAAA,gBAAAA,OAAOC,KAAK,YAAZD,gBAAgBA,OAAOE,IAAI,YAA3BF,OAAgCA,OAAOG,GAAG,GAAG,CAAC,IAAI,EAAEH,OAAOG,GAAG,EAAE,GAAG;;AAErE,MAAMC,QAAQ,CAACC,QAA0BA,UAAU,OAAO,OAAO,CAAC,CAAC,EAAEA,MAAMC,OAAO,CAACD,QAAQ,IAAI,IAAI,IAAI;AAEvG,sEAAsE,GACtE,MAAME,QAAQ,CAAC,EAAEC,KAAK,EAAEC,QAAQ,EAAuC,iBACrE,MAAC1B;;0BACC,KAACO;gBAAWoB,SAAQ;gBAAWC,OAAM;0BAClCH;;0BAEH,KAAClB;gBAAWoB,SAAQ;gBAAQE,IAAI;oBAAEC,YAAY;oBAAYC,cAAc;gBAAW;0BAChFL,YAAY;;;;AAKnB,MAAMM,OAAO,CAAC,EAAEN,QAAQ,EAA2B,iBACjD,KAACtB;QAAM6B,WAAU;QAAMC,UAAU;QAACL,IAAI;YAAEM,UAAU;YAAQC,KAAK;YAAGC,YAAY;QAAS;kBACpFX;;AAIL,MAAMY,YAAY,CAAC,EAAEC,GAAG,EAA6B,iBACnD,MAACnC;QAAMoC,SAAS;;0BACd,MAACR;;kCACC,KAACzB;wBAAWoB,SAAQ;wBAAQE,IAAI;4BAAEY,YAAY;wBAAI;kCAC/CzB,IAAIuB,IAAIG,EAAE;;kCAEb,KAACnC;wBAAWoB,SAAQ;wBAAQC,OAAM;kCAC/BhB,KAAK2B,IAAII,EAAE;;oBAEbJ,IAAIK,KAAK,iBAAG,KAAC1C;wBAAK2C,MAAK;wBAAQlB,SAAQ;wBAAWF,OAAOc,IAAIK,KAAK;yBAAO;oBACzEL,IAAIO,KAAK,iBAAG,KAAC5C;wBAAK2C,MAAK;wBAAQlB,SAAQ;wBAAWF,OAAOc,IAAIO,KAAK;yBAAO;oBACzEzB,MAAMkB,IAAIQ,UAAU,kBAAI,KAAC7C;wBAAK2C,MAAK;wBAAQlB,SAAQ;wBAAWF,OAAOJ,MAAMkB,IAAIQ,UAAU;yBAAQ;oBACjGR,IAAIS,QAAQ,iBACX,KAAC9C;wBAAK2C,MAAK;wBAAQjB,OAAOW,IAAIS,QAAQ,KAAK,OAAO,YAAY;wBAAWvB,OAAO,CAAC,MAAM,EAAEc,IAAIS,QAAQ,EAAE;yBACrG;;;0BAEN,KAACxB;gBAAMC,OAAM;0BAAYc,IAAIU,QAAQ;;0BACrC,KAACzB;gBAAMC,OAAM;0BAAUc,IAAIW,MAAM;;;;AAIrC,MAAMC,SAAS,CAAC,EAAEC,MAAM,EAAgC;IACtD,OAAQA,OAAOC,IAAI;QACjB,KAAK;YACH,qBACE,KAAC7B;gBAAMC,OAAM;0BACV;uBAAI2B,OAAOE,QAAQ;uBAAMF,OAAOhB,GAAG,GAAG;wBAAC,CAAC,cAAc,EAAEgB,OAAOhB,GAAG,EAAE;qBAAC,GAAG,EAAE;iBAAE,CAACmB,IAAI,CAAC;;QAGzF,KAAK;YACH,qBACE,KAAC/B;gBAAMC,OAAM;0BACV;oBAAC2B,OAAOI,OAAO;oBAAEJ,OAAOK,QAAQ;oBAAEL,OAAOM,QAAQ,GAAG,CAAC,WAAW,EAAEN,OAAOM,QAAQ,EAAE,GAAG;iBAAK,CACzFC,MAAM,CAACC,SACPL,IAAI,CAAC;;QAGd,KAAK;YACH,qBAAO,KAAC/B;gBAAMC,OAAM;0BAAe,CAAC,SAAS,EAAE2B,OAAOS,OAAO,CAAC,IAAI,EAAET,OAAOU,IAAI,EAAE;;QACnF,KAAK;YACH,qBAAO,KAACtC;gBAAMC,OAAM;0BAAkB2B,OAAOW,OAAO,CAACR,IAAI,CAAC;;IAC9D;AACF;AAEA,MAAMS,SAAS,CAAC,EAAEzB,GAAG,EAA0B,iBAC7C,MAACnC;QAAMoC,SAAS;;0BACd,MAACR;;kCACC,KAACzB;wBAAWoB,SAAQ;wBAAQE,IAAI;4BAAEY,YAAY;wBAAI;kCAC/CzB,IAAIuB,IAAIG,EAAE;;kCAEb,KAACnC;wBAAWoB,SAAQ;wBAAQC,OAAM;kCAC/BhB,KAAK2B,IAAII,EAAE;;kCAEd,KAACzC;wBAAK2C,MAAK;wBAAQlB,SAAQ;wBAAWF,OAAOc,IAAIc,IAAI;;kCACrD,KAACnD;wBACC2C,MAAK;wBACLjB,OAAOW,IAAI0B,MAAM,KAAK,SAAS,YAAY1B,IAAI0B,MAAM,KAAK,WAAW,UAAU;wBAC/ExC,OAAOc,IAAI0B,MAAM;;kCAEnB,KAAC/D;wBAAK2C,MAAK;wBAAQlB,SAAQ;wBAAWF,OAAO,GAAGc,IAAI2B,OAAO,CAACnD,cAAc,GAAG,QAAQ,CAAC;;;;0BAExF,KAACS;gBAAMC,OAAM;0BAASc,IAAI4B,KAAK;;YAC9B5B,IAAIa,MAAM,iBAAG,KAACD;gBAAOC,QAAQb,IAAIa,MAAM;iBAAO;YAC9Cb,IAAI6B,OAAO,CAACC,MAAM,iBACjB,KAAC7C;gBAAMC,OAAM;0BACVc,IAAI6B,OAAO,CACTE,GAAG,CAAC,CAACC,SAAW;wBAACA,OAAO9C,KAAK;wBAAE8C,OAAOC,IAAI;qBAAC,CAACb,MAAM,CAACC,SAASL,IAAI,CAAC,QACjEA,IAAI,CAAC;iBAER;YACHhB,IAAIkC,KAAK,iBAAG,KAAC1E;gBAAM2E,UAAS;0BAASnC,IAAIkC,KAAK;iBAAY;;;AAI/D,MAAME,0BAA0B,CAAC,EAAEC,KAAK,EAAqB;IAC3D,MAAM,EAAEC,MAAMC,IAAI,EAAE,GAAGhF;IACvB,MAAMiF,UAAUtE,OAAOqE;IACvBC,QAAQC,OAAO,GAAGF;IAClB,MAAM,CAACzB,MAAM4B,QAAQ,GAAGvE,SAAyC;IACjE,MAAM,CAACwE,MAAMC,QAAQ,GAAGzE,SAAkD,EAAE;IAC5E,sEAAsE;IACtE,yEAAyE;IACzE,8BAA8B;IAC9B,MAAM,CAAC0E,SAASC,WAAW,GAAG3E,SAA+B;QAAC;KAAK;IACnE,MAAM,CAAC4E,MAAMC,QAAQ,GAAG7E,SAAS;IACjC,MAAM,CAAC8E,MAAMC,QAAQ,GAAG/E,SAAwB;IAChD,MAAM,CAACgF,SAASC,WAAW,GAAGjF,SAAS;IACvC,MAAM,CAAC+D,OAAOmB,SAAS,GAAGlF,SAAwB;IAElD,MAAMmF,OAAOrF,YACX,OAAOsF,QAAiCC,YAAoBC;QAC1D,MAAMhB,UAAUD,QAAQC,OAAO;QAC/B,IAAI,CAACA,WAAW,CAACJ,OAAO;QACxBe,WAAW;QACXC,SAAS;QACT,IAAI;YACF,MAAMK,SAAS,IAAIC,gBAAgB;gBAAEtB;gBAAOvB,MAAMyC;YAAO;YACzD,IAAIE,OAAOC,OAAOE,GAAG,CAAC,SAASH;YAC/B,MAAMI,WAAW,MAAMvG,gBAAgBmF,SAAS,CAAC,4BAA4B,EAAEiB,QAAQ;YACvF,MAAMI,UAAW,MAAMD,SAASE,IAAI,GAAGC,KAAK,CAAC,IAAM;YAGnD,IAAI,CAACH,SAASI,EAAE,IAAI,CAACH,SAAS;;gBAC5BT,iBAASS,2BAAAA,QAAS5B,KAAK,mBAAI;gBAC3B;YACF;YACAU,QAAQkB,QAAQnB,IAAI;YACpBK,QAAQQ;YACRN,QAAQY,QAAQb,IAAI;YACpBH,WAAW,CAACoB;gBACV,MAAMC,OAAOD,SAASE,KAAK,CAAC,GAAGZ,aAAa;gBAC5C,OAAOM,QAAQb,IAAI,GAAG;uBAAIkB;oBAAML,QAAQb,IAAI;iBAAC,GAAGkB;YAClD;QACF,EAAE,eAAM;YACNd,SAAS;QACX,SAAU;YACRD,WAAW;QACb;IACF,GACA;QAACf;KAAM;IAGT,MAAMgC,OAAOpG,YACX,CAACsF;QACCb,QAAQa;QACRX,QAAQ,EAAE;QACVM,QAAQ;QACRF,QAAQ;QACRF,WAAW;YAAC;SAAK;QACjB,KAAKQ,KAAKC,QAAQ,GAAG;IACvB,GACA;QAACD;KAAK;IAGR,qBACE,KAAClG;QACCkH,QAAO;QACPC,MAAMpH,eAAe,gBAAgB;YACnCqH,QAAQ;YACRC,SACE,CAAC,6BAA6B,EAAEvH,oBAAoB,qKAAqK,CAAC;QAC9N;QACAwH,aAAa;YACXC,QACE7D,SAAS,qBACP,KAACpD;gBAAO4C,MAAK;gBAAQsE,SAAS,IAAMP,KAAK;0BACtC;+BAGH,MAACtG;gBACCuC,MAAK;gBACLuE,SAAS;gBACT9F,OAAO+B;gBACPgE,UAAU,CAACC,GAAGhG,QAA0CA,SAASsF,KAAKtF;gBACtEiG,cAAW;;kCAEX,KAAClH;wBAAaiB,OAAM;kCAAU;;kCAC9B,KAACjB;wBAAaiB,OAAM;kCAAQ;;;;QAGpC;QACAkG,cAAc;QACdC,cAAc;kBAEbpE,SAAS,qBACR,KAAC9C;YAAWoB,SAAQ;YAAQC,OAAM;sBAC/B,CAAC,0CAA0C,EAAEnC,oBAAoB,mEAAmE,CAAC;2BAGxI,MAACW;YAAMoC,SAAS;YAAGkF,uBAAS,KAACvH;gBAAQwH,QAAQ;;;gBAC1ClD,sBAAQ,KAAC1E;oBAAM2E,UAAS;8BAAWD;qBAAiB;gBACpD,CAACiB,WAAW,CAACjB,SAAS,CAACS,KAAKb,MAAM,iBACjC,KAAC9D;oBAAWoB,SAAQ;oBAAQC,OAAM;8BAC/ByB,SAAS,WACN,yCACA;qBAEJ;gBACH6B,KAAKZ,GAAG,CAAC,CAAC/B,MACTc,SAAS,yBACP,KAACf;wBAAuBC,KAAKA;uBAAbA,IAAIqF,EAAE,kBAEtB,KAAC5D;wBAAoBzB,KAAKA;uBAAbA,IAAIqF,EAAE;gBAGtBlC,wBACC,KAACnF;oBAAWoB,SAAQ;oBAAQC,OAAM;8BAC/B;qBAED;gBACHsD,KAAKb,MAAM,IAAIiB,OAAO,kBACrB,KAAC1F;oBACC0F,MAAMA;oBACNuC,UAAUlH;oBACVmH,UAAU5C,KAAKb,MAAM;oBACrB0D,SAASnE,QAAQ4B;oBACjBwC,UAAUtC;oBACVuC,cAAc,CAACnC;4BAAmCV;+BAAxB,KAAKS,KAAKxC,MAAMyC,SAAQV,kBAAAA,OAAO,CAACU,OAAO,YAAfV,kBAAmB;;qBAErE;;;;AAKd;AAEAT,wBAAwBuD,WAAW,GAAG;AAEtC,eAAevD,wBAAuB"}
|
|
@@ -23,7 +23,7 @@ import { listUsageAlertContributors, registerUsageAlertContributor } from "@agly
|
|
|
23
23
|
import { registerPluginUsageMeter } from "@aglyn/aglyn/plugin-manager/plugin-usage-meters";
|
|
24
24
|
import { registerOperatorAlerts } from "@aglyn/aglyn/plugin-manager/operator-alerts";
|
|
25
25
|
import { AI_PLUGIN_ID, AI_USAGE_METER_ID } from "./constants.js";
|
|
26
|
-
import { AI_PROVIDER_UNAVAILABLE } from "./operator-alerts.js";
|
|
26
|
+
import { AI_BUILD_PARTLY_FAILED, AI_JOB_FAILED, AI_PROVIDER_UNAVAILABLE } from "./operator-alerts.js";
|
|
27
27
|
import { registerAiDeclarations } from "./declarations.js";
|
|
28
28
|
/** The provider-spend staff alerts' contributor id under the plugin. */ const AI_USAGE_ALERTS_ID = 'provider-spend';
|
|
29
29
|
/**
|
|
@@ -134,10 +134,13 @@ import { registerAiDeclarations } from "./declarations.js";
|
|
|
134
134
|
pluginId: AI_PLUGIN_ID
|
|
135
135
|
});
|
|
136
136
|
}
|
|
137
|
-
// The platform provider account alert (AGL-3377),
|
|
138
|
-
//
|
|
137
|
+
// The platform provider account alert (AGL-3377), and a job failing or a
|
|
138
|
+
// build finishing with parts failed on our side (AGL-3683), listed on
|
|
139
|
+
// Staff → Operator alerts before the first one is raised.
|
|
139
140
|
registerOperatorAlerts([
|
|
140
|
-
AI_PROVIDER_UNAVAILABLE
|
|
141
|
+
AI_PROVIDER_UNAVAILABLE,
|
|
142
|
+
AI_JOB_FAILED,
|
|
143
|
+
AI_BUILD_PARTLY_FAILED
|
|
141
144
|
], {
|
|
142
145
|
pluginId: AI_PLUGIN_ID
|
|
143
146
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../libs/plugins/ai/src/lib/declarations.server.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// Each registry from its own module, not the `@aglyn/aglyn/server` barrel:\n// boot needs three registries rather than the whole server surface, and a\n// suite that stubs that barrel wholesale still loads these declarations\n// against the real registries.\nimport {\n listPluginEventHandlers,\n registerPluginEventHandler,\n} from '@aglyn/aglyn/plugin-manager/plugin-events'\nimport {\n listPluginUserErasers,\n registerPluginUserEraser,\n} from '@aglyn/aglyn/plugin-manager/plugin-user-erasure'\nimport {\n listUsageAlertContributors,\n registerUsageAlertContributor,\n} from '@aglyn/aglyn/plugin-manager/usage-alert-contributors'\nimport { registerPluginUsageMeter } from '@aglyn/aglyn/plugin-manager/plugin-usage-meters'\nimport { registerOperatorAlerts } from '@aglyn/aglyn/plugin-manager/operator-alerts'\nimport { AI_PLUGIN_ID, AI_USAGE_METER_ID } from './constants'\nimport { AI_PROVIDER_UNAVAILABLE } from './operator-alerts'\nimport { registerAiDeclarations } from './declarations'\n\n/** The provider-spend staff alerts' contributor id under the plugin. */\nconst AI_USAGE_ALERTS_ID = 'provider-spend'\n\n/**\n * The plugin's SERVER declarations (AGL-2939): what the server must know\n * at boot, before any door of the plugin has been called. The two platform\n * events the plugin writes activity for — the AI add-on bought or dropped,\n * an `ai.*` permission moved — are raised by core billing and membership\n * routes that never load the plugin's API surface, so the subscriptions\n * have to be in place from the first request. So does the eraser: an\n * account erasure is a core route too, and a person's AI usage months sit\n * under each org, keyed by the uid, where no core delete reaches them. So\n * does the usage alert contributor (AGL-2984): the usage-alerts sweep is a\n * core cron, and it evaluates the plugin's staff alerts on provider spend for\n * every org it reads.\n *\n * Light at boot by construction: the writers behind the handlers are\n * imported when the first event arrives, and the alert rules when the sweep\n * first evaluates an org, not when the process starts, so the boot cost is\n * the registration and nothing that touches Firestore.\n */\nexport function registerAiServerDeclarations(): void {\n registerAiDeclarations()\n // Idempotent against each REGISTRY rather than a module flag, so a\n // registry reset (a spec) or a second module instance registers again.\n if (!listPluginEventHandlers('org.seatAddons.changed').includes(AI_PLUGIN_ID)) {\n registerPluginEventHandler(\n 'org.seatAddons.changed',\n async ({ orgId, actor, before, after }) => {\n const { logAiAddonChanged } = await import('./activity/ai-activity')\n await logAiAddonChanged(orgId, actor, { before, after })\n },\n { pluginId: AI_PLUGIN_ID },\n )\n registerPluginEventHandler(\n 'org.permissions.changed',\n async ({ orgId, actor, subject, permission, granted }) => {\n if (!permission.startsWith('ai.')) return\n const { logAiPermissionChanged } = await import('./activity/ai-activity')\n await logAiPermissionChanged(orgId, actor, { subject, permission, granted })\n },\n { pluginId: AI_PLUGIN_ID },\n )\n }\n // THE PLATFORM'S BILLING EVENTS (AGL-3011). Subscribed at boot for the\n // same reason as the two above: they are raised by the billing webhook,\n // which never loads an AI door, and a workspace's overage standing moving\n // late is a workspace charged or refused against a fact we already had.\n //\n // The handler modules are imported when the first event arrives, so a\n // process that never receives one pays only for the registration.\n if (!listPluginEventHandlers('billing.invoice.paid').includes(AI_PLUGIN_ID)) {\n registerPluginEventHandler(\n 'billing.invoice.paid',\n async (payload) => {\n const { onAiBillingInvoicePaid } = await import('./billing/ai-overage-events')\n await onAiBillingInvoicePaid(payload)\n },\n { pluginId: AI_PLUGIN_ID },\n )\n registerPluginEventHandler(\n 'billing.invoice.failed',\n async (payload) => {\n const { onAiBillingInvoiceFailed } = await import('./billing/ai-overage-events')\n await onAiBillingInvoiceFailed(payload)\n },\n { pluginId: AI_PLUGIN_ID },\n )\n registerPluginEventHandler(\n 'billing.invoice.closed',\n async (payload) => {\n const { onAiBillingInvoiceClosed } = await import('./billing/ai-overage-events')\n await onAiBillingInvoiceClosed(payload)\n },\n { pluginId: AI_PLUGIN_ID },\n )\n registerPluginEventHandler(\n 'billing.dispute.opened',\n async (payload) => {\n const { onAiBillingDisputeOpened } = await import('./billing/ai-overage-events')\n await onAiBillingDisputeOpened(payload)\n },\n { pluginId: AI_PLUGIN_ID },\n )\n registerPluginEventHandler(\n 'billing.paymentMethod.changed',\n async (payload) => {\n const { onAiBillingPaymentMethodChanged } = await import(\n './billing/ai-overage-events'\n )\n await onAiBillingPaymentMethodChanged(payload)\n },\n { pluginId: AI_PLUGIN_ID },\n )\n }\n // The plugin's meter in the monthly usage sweep: the month's provider spend\n // onto the rollup, the credits past the band onto the invoice, and — from\n // the cutover month (AGL-3011) — the close-out of what the plugin invoices\n // itself. Registered at boot because the sweep is a core cron, and declared\n // in `usageAxes` so the sweep refuses to bill a month without it. The same\n // registration again replaces itself.\n registerPluginUsageMeter({\n pluginId: AI_PLUGIN_ID,\n id: AI_USAGE_METER_ID,\n measure: async (context) => {\n const { measureAiMonth } = await import('./billing/ai-month-meter')\n return measureAiMonth(context)\n },\n closeMonth: async (context) => {\n const { closeAiMonth } = await import('./billing/ai-month-meter')\n await closeAiMonth(context)\n },\n })\n if (!listPluginUserErasers().includes(AI_PLUGIN_ID)) {\n registerPluginUserEraser(\n async (request) => {\n const { eraseAiUsageForUser } = await import('./usage/ai-usage-eraser')\n return eraseAiUsageForUser(request)\n },\n { pluginId: AI_PLUGIN_ID },\n )\n }\n // The platform provider account alert (AGL-3377), listed on Staff →\n // Operator alerts before the first one is ever raised.\n registerOperatorAlerts([AI_PROVIDER_UNAVAILABLE], { pluginId: AI_PLUGIN_ID })\n if (\n !listUsageAlertContributors().some(\n (contributor) =>\n contributor.pluginId === AI_PLUGIN_ID &&\n contributor.id === AI_USAGE_ALERTS_ID,\n )\n ) {\n registerUsageAlertContributor({\n pluginId: AI_PLUGIN_ID,\n id: AI_USAGE_ALERTS_ID,\n evaluate: async (context) => {\n const { evaluateAiUsageAlerts } = await import('./usage/ai-usage-alerts')\n await evaluateAiUsageAlerts(context)\n },\n quotaChecks: async (context) => {\n const { aiQuotaChecks } = await import('./usage/ai-quota-checks')\n return aiQuotaChecks(context)\n },\n })\n }\n}\n\nregisterAiServerDeclarations()\n"],"names":["listPluginEventHandlers","registerPluginEventHandler","listPluginUserErasers","registerPluginUserEraser","listUsageAlertContributors","registerUsageAlertContributor","registerPluginUsageMeter","registerOperatorAlerts","AI_PLUGIN_ID","AI_USAGE_METER_ID","AI_PROVIDER_UNAVAILABLE","registerAiDeclarations","AI_USAGE_ALERTS_ID","registerAiServerDeclarations","includes","orgId","actor","before","after","logAiAddonChanged","pluginId","subject","permission","granted","startsWith","logAiPermissionChanged","payload","onAiBillingInvoicePaid","onAiBillingInvoiceFailed","onAiBillingInvoiceClosed","onAiBillingDisputeOpened","onAiBillingPaymentMethodChanged","id","measure","context","measureAiMonth","closeMonth","closeAiMonth","request","eraseAiUsageForUser","some","contributor","evaluate","evaluateAiUsageAlerts","quotaChecks","aiQuotaChecks"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/plugins/ai/src/lib/declarations.server.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// Each registry from its own module, not the `@aglyn/aglyn/server` barrel:\n// boot needs three registries rather than the whole server surface, and a\n// suite that stubs that barrel wholesale still loads these declarations\n// against the real registries.\nimport {\n listPluginEventHandlers,\n registerPluginEventHandler,\n} from '@aglyn/aglyn/plugin-manager/plugin-events'\nimport {\n listPluginUserErasers,\n registerPluginUserEraser,\n} from '@aglyn/aglyn/plugin-manager/plugin-user-erasure'\nimport {\n listUsageAlertContributors,\n registerUsageAlertContributor,\n} from '@aglyn/aglyn/plugin-manager/usage-alert-contributors'\nimport { registerPluginUsageMeter } from '@aglyn/aglyn/plugin-manager/plugin-usage-meters'\nimport { registerOperatorAlerts } from '@aglyn/aglyn/plugin-manager/operator-alerts'\nimport { AI_PLUGIN_ID, AI_USAGE_METER_ID } from './constants'\nimport { AI_BUILD_PARTLY_FAILED, AI_JOB_FAILED, AI_PROVIDER_UNAVAILABLE } from './operator-alerts'\nimport { registerAiDeclarations } from './declarations'\n\n/** The provider-spend staff alerts' contributor id under the plugin. */\nconst AI_USAGE_ALERTS_ID = 'provider-spend'\n\n/**\n * The plugin's SERVER declarations (AGL-2939): what the server must know\n * at boot, before any door of the plugin has been called. The two platform\n * events the plugin writes activity for — the AI add-on bought or dropped,\n * an `ai.*` permission moved — are raised by core billing and membership\n * routes that never load the plugin's API surface, so the subscriptions\n * have to be in place from the first request. So does the eraser: an\n * account erasure is a core route too, and a person's AI usage months sit\n * under each org, keyed by the uid, where no core delete reaches them. So\n * does the usage alert contributor (AGL-2984): the usage-alerts sweep is a\n * core cron, and it evaluates the plugin's staff alerts on provider spend for\n * every org it reads.\n *\n * Light at boot by construction: the writers behind the handlers are\n * imported when the first event arrives, and the alert rules when the sweep\n * first evaluates an org, not when the process starts, so the boot cost is\n * the registration and nothing that touches Firestore.\n */\nexport function registerAiServerDeclarations(): void {\n registerAiDeclarations()\n // Idempotent against each REGISTRY rather than a module flag, so a\n // registry reset (a spec) or a second module instance registers again.\n if (!listPluginEventHandlers('org.seatAddons.changed').includes(AI_PLUGIN_ID)) {\n registerPluginEventHandler(\n 'org.seatAddons.changed',\n async ({ orgId, actor, before, after }) => {\n const { logAiAddonChanged } = await import('./activity/ai-activity')\n await logAiAddonChanged(orgId, actor, { before, after })\n },\n { pluginId: AI_PLUGIN_ID },\n )\n registerPluginEventHandler(\n 'org.permissions.changed',\n async ({ orgId, actor, subject, permission, granted }) => {\n if (!permission.startsWith('ai.')) return\n const { logAiPermissionChanged } = await import('./activity/ai-activity')\n await logAiPermissionChanged(orgId, actor, { subject, permission, granted })\n },\n { pluginId: AI_PLUGIN_ID },\n )\n }\n // THE PLATFORM'S BILLING EVENTS (AGL-3011). Subscribed at boot for the\n // same reason as the two above: they are raised by the billing webhook,\n // which never loads an AI door, and a workspace's overage standing moving\n // late is a workspace charged or refused against a fact we already had.\n //\n // The handler modules are imported when the first event arrives, so a\n // process that never receives one pays only for the registration.\n if (!listPluginEventHandlers('billing.invoice.paid').includes(AI_PLUGIN_ID)) {\n registerPluginEventHandler(\n 'billing.invoice.paid',\n async (payload) => {\n const { onAiBillingInvoicePaid } = await import('./billing/ai-overage-events')\n await onAiBillingInvoicePaid(payload)\n },\n { pluginId: AI_PLUGIN_ID },\n )\n registerPluginEventHandler(\n 'billing.invoice.failed',\n async (payload) => {\n const { onAiBillingInvoiceFailed } = await import('./billing/ai-overage-events')\n await onAiBillingInvoiceFailed(payload)\n },\n { pluginId: AI_PLUGIN_ID },\n )\n registerPluginEventHandler(\n 'billing.invoice.closed',\n async (payload) => {\n const { onAiBillingInvoiceClosed } = await import('./billing/ai-overage-events')\n await onAiBillingInvoiceClosed(payload)\n },\n { pluginId: AI_PLUGIN_ID },\n )\n registerPluginEventHandler(\n 'billing.dispute.opened',\n async (payload) => {\n const { onAiBillingDisputeOpened } = await import('./billing/ai-overage-events')\n await onAiBillingDisputeOpened(payload)\n },\n { pluginId: AI_PLUGIN_ID },\n )\n registerPluginEventHandler(\n 'billing.paymentMethod.changed',\n async (payload) => {\n const { onAiBillingPaymentMethodChanged } = await import(\n './billing/ai-overage-events'\n )\n await onAiBillingPaymentMethodChanged(payload)\n },\n { pluginId: AI_PLUGIN_ID },\n )\n }\n // The plugin's meter in the monthly usage sweep: the month's provider spend\n // onto the rollup, the credits past the band onto the invoice, and — from\n // the cutover month (AGL-3011) — the close-out of what the plugin invoices\n // itself. Registered at boot because the sweep is a core cron, and declared\n // in `usageAxes` so the sweep refuses to bill a month without it. The same\n // registration again replaces itself.\n registerPluginUsageMeter({\n pluginId: AI_PLUGIN_ID,\n id: AI_USAGE_METER_ID,\n measure: async (context) => {\n const { measureAiMonth } = await import('./billing/ai-month-meter')\n return measureAiMonth(context)\n },\n closeMonth: async (context) => {\n const { closeAiMonth } = await import('./billing/ai-month-meter')\n await closeAiMonth(context)\n },\n })\n if (!listPluginUserErasers().includes(AI_PLUGIN_ID)) {\n registerPluginUserEraser(\n async (request) => {\n const { eraseAiUsageForUser } = await import('./usage/ai-usage-eraser')\n return eraseAiUsageForUser(request)\n },\n { pluginId: AI_PLUGIN_ID },\n )\n }\n // The platform provider account alert (AGL-3377), and a job failing or a\n // build finishing with parts failed on our side (AGL-3683), listed on\n // Staff → Operator alerts before the first one is raised.\n registerOperatorAlerts([AI_PROVIDER_UNAVAILABLE, AI_JOB_FAILED, AI_BUILD_PARTLY_FAILED], {\n pluginId: AI_PLUGIN_ID,\n })\n if (\n !listUsageAlertContributors().some(\n (contributor) =>\n contributor.pluginId === AI_PLUGIN_ID &&\n contributor.id === AI_USAGE_ALERTS_ID,\n )\n ) {\n registerUsageAlertContributor({\n pluginId: AI_PLUGIN_ID,\n id: AI_USAGE_ALERTS_ID,\n evaluate: async (context) => {\n const { evaluateAiUsageAlerts } = await import('./usage/ai-usage-alerts')\n await evaluateAiUsageAlerts(context)\n },\n quotaChecks: async (context) => {\n const { aiQuotaChecks } = await import('./usage/ai-quota-checks')\n return aiQuotaChecks(context)\n },\n })\n }\n}\n\nregisterAiServerDeclarations()\n"],"names":["listPluginEventHandlers","registerPluginEventHandler","listPluginUserErasers","registerPluginUserEraser","listUsageAlertContributors","registerUsageAlertContributor","registerPluginUsageMeter","registerOperatorAlerts","AI_PLUGIN_ID","AI_USAGE_METER_ID","AI_BUILD_PARTLY_FAILED","AI_JOB_FAILED","AI_PROVIDER_UNAVAILABLE","registerAiDeclarations","AI_USAGE_ALERTS_ID","registerAiServerDeclarations","includes","orgId","actor","before","after","logAiAddonChanged","pluginId","subject","permission","granted","startsWith","logAiPermissionChanged","payload","onAiBillingInvoicePaid","onAiBillingInvoiceFailed","onAiBillingInvoiceClosed","onAiBillingDisputeOpened","onAiBillingPaymentMethodChanged","id","measure","context","measureAiMonth","closeMonth","closeAiMonth","request","eraseAiUsageForUser","some","contributor","evaluate","evaluateAiUsageAlerts","quotaChecks","aiQuotaChecks"],"mappings":"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"}
|
|
@@ -17,8 +17,16 @@
|
|
|
17
17
|
import type { AglynOrgBilling } from '@aglyn/aglyn/foundation/definitions/org-billing.types';
|
|
18
18
|
import { type PluginAiCapability, type ResolvedPluginAiCapability } from '@aglyn/aglyn/plugin-manager/plugin-ai-capabilities';
|
|
19
19
|
import type { AiBuildOps } from '../model/ai-build-job';
|
|
20
|
+
import { type AiPluginDraftOwnerLookup } from './ai-job-plugin-drafts';
|
|
20
21
|
/** The operations this plugin owns, as it registers them. */
|
|
21
22
|
export declare const AI_OWNED_CAPABILITIES: readonly PluginAiCapability[];
|
|
23
|
+
/**
|
|
24
|
+
* The resource another plugin writes for each operation of this plugin's that
|
|
25
|
+
* cannot be built without it. The operation runs where that writer's owner
|
|
26
|
+
* runs — registered, switched on for the workspace and the site, and past its
|
|
27
|
+
* release flag — exactly as an operation that owner registered would.
|
|
28
|
+
*/
|
|
29
|
+
export declare const AI_OWNED_OP_WRITERS: Readonly<Partial<Record<string, string>>>;
|
|
22
30
|
/** Registers this plugin's build operations; the console surface calls it. */
|
|
23
31
|
export declare function registerAiBuildCapabilities(): void;
|
|
24
32
|
/** What decides which operations a build may use here. */
|
|
@@ -37,11 +45,15 @@ export interface AiBuildOpsDeps {
|
|
|
37
45
|
releasedPlugins?: (pluginIds: string[], orgId: string) => Promise<string[]>;
|
|
38
46
|
/** Whether a runner is registered for a kind; the machine's otherwise. */
|
|
39
47
|
hasRunner?: (kind: string) => boolean;
|
|
48
|
+
/** Which plugin writes a resource; the core's registry otherwise. */
|
|
49
|
+
writerOwner?: AiPluginDraftOwnerLookup;
|
|
40
50
|
}
|
|
41
51
|
/**
|
|
42
52
|
* The operations a build may plan on this site, by op (AGL-3616): every
|
|
43
53
|
* registered capability whose owner runs here — switched on for the
|
|
44
|
-
* workspace and the site, past its release flag
|
|
54
|
+
* workspace and the site, past its release flag; for one of this plugin's
|
|
55
|
+
* operations another plugin writes (`AI_OWNED_OP_WRITERS`), that writer's
|
|
56
|
+
* owner, and a writer registered at all — whose entitlement the plan
|
|
45
57
|
* holds, which the Free taste may use where the workspace is on it, and,
|
|
46
58
|
* for an AI-run operation, whose runner this process loaded. One release-flag
|
|
47
59
|
* read for every owner at once. What a member may do and what an allowance
|