@aglyn/plugins-ai 1.0.0-beta.231 → 1.0.0-beta.232
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/jobs/ai-build-capabilities.d.ts +13 -1
- package/src/lib/jobs/ai-build-capabilities.js +101 -7
- 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 +19 -5
- package/src/lib/jobs/ai-job-plan-step.js +54 -20
- 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 +6 -1
- package/src/lib/jobs/ai-jobs-notify.js +15 -3
- package/src/lib/jobs/ai-jobs-notify.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-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/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.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,152 @@
|
|
|
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
|
+
*/ /*==========================================
|
|
17
|
+
* WHAT A WORKSPACE ASKED AGLYN AI, FOR STAFF (AGL-3675).
|
|
18
|
+
*
|
|
19
|
+
* The staff org page showed what an org's AI cost and how many jobs ran,
|
|
20
|
+
* never what anybody asked or what came back. Those words are kept — an
|
|
21
|
+
* Assist exchange for 180 days, a job's brief and result for as long as the
|
|
22
|
+
* job — and the Privacy policy says they are accessible to us, but nothing
|
|
23
|
+
* read them, so a stalled sign-up's question could only be found in the
|
|
24
|
+
* database by hand.
|
|
25
|
+
*
|
|
26
|
+
* These are the rows the staff card lists, composed from the stored
|
|
27
|
+
* documents by pure functions so the shape is tested without Firestore:
|
|
28
|
+
*
|
|
29
|
+
* - an Assist row joins `assistExchanges/{id}` (the question, the answer,
|
|
30
|
+
* who asked) with `assistSignals/{id}` (the console route, the model, the
|
|
31
|
+
* cost and the thumbs), which share the id by design;
|
|
32
|
+
* - a job row reads `aiJobs/{id}` (the brief, the kind, the status, the
|
|
33
|
+
* credits, the outputs) and, for the kinds whose result is kept beside
|
|
34
|
+
* the job rather than as a draft, that result: an insight's answer or a
|
|
35
|
+
* CRM answer.
|
|
36
|
+
*
|
|
37
|
+
* The text is shown to the staff member who asked for it and goes nowhere
|
|
38
|
+
* else. The audit row the route writes says that it was read, never what.
|
|
39
|
+
*==========================================*/ /** Rows a page lists; the route asks for one more to learn whether there is a next page. */ export const STAFF_AI_CONVERSATIONS_PAGE = 25;
|
|
40
|
+
/** The two lists the card switches between. */ export const STAFF_AI_CONVERSATION_KINDS = [
|
|
41
|
+
'assist',
|
|
42
|
+
'jobs'
|
|
43
|
+
];
|
|
44
|
+
export function isStaffAiConversationKind(value) {
|
|
45
|
+
return typeof value === 'string' && STAFF_AI_CONVERSATION_KINDS.includes(value);
|
|
46
|
+
}
|
|
47
|
+
const text = (value)=>typeof value === 'string' ? value : '';
|
|
48
|
+
const textOrNull = (value)=>typeof value === 'string' && value.trim() ? value : null;
|
|
49
|
+
const finite = (value)=>typeof value === 'number' && Number.isFinite(value) ? value : null;
|
|
50
|
+
/** A stored time as ISO: a Firestore timestamp, a `Date`, milliseconds or an ISO string. */ export function staffAiConversationTime(value) {
|
|
51
|
+
if (value == null) return null;
|
|
52
|
+
if (typeof value.toDate === 'function') {
|
|
53
|
+
return value.toDate().toISOString();
|
|
54
|
+
}
|
|
55
|
+
if (value instanceof Date) return Number.isNaN(value.getTime()) ? null : value.toISOString();
|
|
56
|
+
if (typeof value === 'number' && Number.isFinite(value)) return new Date(value).toISOString();
|
|
57
|
+
if (typeof value === 'string' && !Number.isNaN(Date.parse(value))) return new Date(value).toISOString();
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
/** The person a uid is, from `orgs/{org}/members/{uid}` documents keyed by uid. */ export function staffAiConversationPerson(uid, members) {
|
|
61
|
+
const id = typeof uid === 'string' && uid ? uid : null;
|
|
62
|
+
const member = id ? members.get(id) : undefined;
|
|
63
|
+
return {
|
|
64
|
+
uid: id,
|
|
65
|
+
email: textOrNull(member == null ? void 0 : member['email']),
|
|
66
|
+
name: textOrNull(member == null ? void 0 : member['displayName'])
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/** One Assist exchange joined with its signal, which may already be gone or never have been written. */ export function composeStaffAiAssistRow(id, exchange, signal, members) {
|
|
70
|
+
const feedback = signal == null ? void 0 : signal['feedback'];
|
|
71
|
+
return {
|
|
72
|
+
id,
|
|
73
|
+
at: staffAiConversationTime(exchange['createdAt']),
|
|
74
|
+
by: staffAiConversationPerson(exchange['uid'], members),
|
|
75
|
+
hostId: textOrNull(exchange['hostId']),
|
|
76
|
+
route: textOrNull(signal == null ? void 0 : signal['route']),
|
|
77
|
+
question: text(exchange['question']),
|
|
78
|
+
answer: text(exchange['answer']),
|
|
79
|
+
model: textOrNull(signal == null ? void 0 : signal['model']),
|
|
80
|
+
estCostUsd: finite(signal == null ? void 0 : signal['estCostUsd']),
|
|
81
|
+
feedback: feedback === 'up' || feedback === 'down' ? feedback : null
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
/** An insight's kept answer, as `aiInsights/{jobId}` stores it. */ export function staffAiInsightResult(record) {
|
|
85
|
+
if (!record) return null;
|
|
86
|
+
const insights = Array.isArray(record['insights']) ? record['insights'].map((insight)=>text(insight == null ? void 0 : insight['text'])).filter(Boolean) : [];
|
|
87
|
+
return {
|
|
88
|
+
kind: 'insight',
|
|
89
|
+
insights,
|
|
90
|
+
gap: textOrNull(record['gap'])
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/** A CRM answer, as `aiCrmAnswers/{jobId}` stores it, by the proposal it holds. */ export function staffAiCrmResult(record) {
|
|
94
|
+
const proposal = record == null ? void 0 : record['proposal'];
|
|
95
|
+
if (!proposal) return null;
|
|
96
|
+
switch(proposal['kind']){
|
|
97
|
+
case 'record':
|
|
98
|
+
{
|
|
99
|
+
const nextStep = proposal['nextStep'];
|
|
100
|
+
const title = textOrNull(nextStep == null ? void 0 : nextStep['title']);
|
|
101
|
+
const reason = textOrNull(nextStep == null ? void 0 : nextStep['reason']);
|
|
102
|
+
return {
|
|
103
|
+
kind: 'crm-record',
|
|
104
|
+
summary: text(proposal['summary']),
|
|
105
|
+
nextStep: title ? reason ? `${title} — ${reason}` : title : null,
|
|
106
|
+
standing: textOrNull(proposal['standing'])
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
case 'email':
|
|
110
|
+
return {
|
|
111
|
+
kind: 'crm-email',
|
|
112
|
+
subject: text(proposal['subject']),
|
|
113
|
+
body: text(proposal['body'])
|
|
114
|
+
};
|
|
115
|
+
case 'mapping':
|
|
116
|
+
return {
|
|
117
|
+
kind: 'crm-mapping',
|
|
118
|
+
matches: Array.isArray(proposal['matches']) ? proposal['matches'].map((match)=>`${text(match == null ? void 0 : match['header'])} → ${text(match == null ? void 0 : match['label'])}`) : []
|
|
119
|
+
};
|
|
120
|
+
default:
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/** The collection a job kind keeps its result beside the job in, or `null` for a kind whose result is a draft. */ export function staffAiJobResultCollection(kind) {
|
|
125
|
+
if (kind === 'insight') return 'aiInsights';
|
|
126
|
+
if (kind === 'crm') return 'aiCrmAnswers';
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
/** One job, with the result kept beside it when its kind keeps one. */ export function composeStaffAiJobRow(id, job, result, members) {
|
|
130
|
+
var _finite;
|
|
131
|
+
const outputs = Array.isArray(job['outputs']) ? job['outputs'] : [];
|
|
132
|
+
return {
|
|
133
|
+
id,
|
|
134
|
+
at: staffAiConversationTime(job['createdAt']),
|
|
135
|
+
by: staffAiConversationPerson(job['createdBy'], members),
|
|
136
|
+
hostId: textOrNull(job['hostId']),
|
|
137
|
+
kind: text(job['kind']) || 'unknown',
|
|
138
|
+
status: text(job['status']) || 'unknown',
|
|
139
|
+
brief: text(job['brief']),
|
|
140
|
+
credits: (_finite = finite(job['creditsSpent'])) != null ? _finite : 0,
|
|
141
|
+
error: textOrNull(job['error']),
|
|
142
|
+
outputs: outputs.map((output)=>({
|
|
143
|
+
label: text(output == null ? void 0 : output['label']) || text(output == null ? void 0 : output['resource']) || 'Output',
|
|
144
|
+
note: textOrNull(output == null ? void 0 : output['note']),
|
|
145
|
+
resource: textOrNull(output == null ? void 0 : output['resource']),
|
|
146
|
+
hostSubdomain: textOrNull(output == null ? void 0 : output['hostSubdomain'])
|
|
147
|
+
})),
|
|
148
|
+
result
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
//# sourceMappingURL=staff-org-ai-conversations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/usage/staff-org-ai-conversations.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/*==========================================\n * WHAT A WORKSPACE ASKED AGLYN AI, FOR STAFF (AGL-3675).\n *\n * The staff org page showed what an org's AI cost and how many jobs ran,\n * never what anybody asked or what came back. Those words are kept — an\n * Assist exchange for 180 days, a job's brief and result for as long as the\n * job — and the Privacy policy says they are accessible to us, but nothing\n * read them, so a stalled sign-up's question could only be found in the\n * database by hand.\n *\n * These are the rows the staff card lists, composed from the stored\n * documents by pure functions so the shape is tested without Firestore:\n *\n * - an Assist row joins `assistExchanges/{id}` (the question, the answer,\n * who asked) with `assistSignals/{id}` (the console route, the model, the\n * cost and the thumbs), which share the id by design;\n * - a job row reads `aiJobs/{id}` (the brief, the kind, the status, the\n * credits, the outputs) and, for the kinds whose result is kept beside\n * the job rather than as a draft, that result: an insight's answer or a\n * CRM answer.\n *\n * The text is shown to the staff member who asked for it and goes nowhere\n * else. The audit row the route writes says that it was read, never what.\n *==========================================*/\n\n/** Rows a page lists; the route asks for one more to learn whether there is a next page. */\nexport const STAFF_AI_CONVERSATIONS_PAGE = 25\n\n/** The two lists the card switches between. */\nexport const STAFF_AI_CONVERSATION_KINDS = ['assist', 'jobs'] as const\nexport type StaffAiConversationKind = (typeof STAFF_AI_CONVERSATION_KINDS)[number]\n\nexport function isStaffAiConversationKind(value: unknown): value is StaffAiConversationKind {\n return typeof value === 'string' && (STAFF_AI_CONVERSATION_KINDS as readonly string[]).includes(value)\n}\n\n/** Who a row is from, as the org's member list names them. */\nexport interface StaffAiConversationPerson {\n uid: string | null\n email: string | null\n name: string | null\n}\n\nexport interface StaffAiAssistRow {\n id: string\n at: string | null\n by: StaffAiConversationPerson\n hostId: string | null\n /** The console route the question was asked from; `null` once the signal is gone or never said. */\n route: string | null\n question: string\n answer: string\n model: string | null\n estCostUsd: number | null\n /** The thumbs the person gave: `up`, `down` or `null`. */\n feedback: 'up' | 'down' | null\n}\n\n/** One thing a job made, as its output names it. */\nexport interface StaffAiJobOutputRow {\n label: string\n note: string | null\n resource: string | null\n hostSubdomain: string | null\n}\n\n/** A result kept beside the job rather than as a draft. */\nexport type StaffAiJobResult =\n | { kind: 'insight'; insights: string[]; gap: string | null }\n | { kind: 'crm-record'; summary: string; nextStep: string | null; standing: string | null }\n | { kind: 'crm-email'; subject: string; body: string }\n | { kind: 'crm-mapping'; matches: string[] }\n\nexport interface StaffAiJobRow {\n id: string\n at: string | null\n by: StaffAiConversationPerson\n hostId: string | null\n kind: string\n status: string\n brief: string\n credits: number\n error: string | null\n outputs: StaffAiJobOutputRow[]\n /** `null` when the kind keeps nothing beside the job, or the result has expired. */\n result: StaffAiJobResult | null\n}\n\nexport interface StaffAiConversationsResponse {\n kind: StaffAiConversationKind\n rows: StaffAiAssistRow[] | StaffAiJobRow[]\n /** The id to pass as `after` for the next page; `null` on the last. */\n next: string | null\n}\n\ntype Data = Record<string, unknown>\n\nconst text = (value: unknown): string => (typeof value === 'string' ? value : '')\nconst textOrNull = (value: unknown): string | null => (typeof value === 'string' && value.trim() ? value : null)\nconst finite = (value: unknown): number | null =>\n typeof value === 'number' && Number.isFinite(value) ? value : null\n\n/** A stored time as ISO: a Firestore timestamp, a `Date`, milliseconds or an ISO string. */\nexport function staffAiConversationTime(value: unknown): string | null {\n if (value == null) return null\n if (typeof (value as { toDate?: unknown }).toDate === 'function') {\n return (value as { toDate: () => Date }).toDate().toISOString()\n }\n if (value instanceof Date) return Number.isNaN(value.getTime()) ? null : value.toISOString()\n if (typeof value === 'number' && Number.isFinite(value)) return new Date(value).toISOString()\n if (typeof value === 'string' && !Number.isNaN(Date.parse(value))) return new Date(value).toISOString()\n return null\n}\n\n/** The person a uid is, from `orgs/{org}/members/{uid}` documents keyed by uid. */\nexport function staffAiConversationPerson(\n uid: unknown,\n members: ReadonlyMap<string, Data>,\n): StaffAiConversationPerson {\n const id = typeof uid === 'string' && uid ? uid : null\n const member = id ? members.get(id) : undefined\n return {\n uid: id,\n email: textOrNull(member?.['email']),\n name: textOrNull(member?.['displayName']),\n }\n}\n\n/** One Assist exchange joined with its signal, which may already be gone or never have been written. */\nexport function composeStaffAiAssistRow(\n id: string,\n exchange: Data,\n signal: Data | null,\n members: ReadonlyMap<string, Data>,\n): StaffAiAssistRow {\n const feedback = signal?.['feedback']\n return {\n id,\n at: staffAiConversationTime(exchange['createdAt']),\n by: staffAiConversationPerson(exchange['uid'], members),\n hostId: textOrNull(exchange['hostId']),\n route: textOrNull(signal?.['route']),\n question: text(exchange['question']),\n answer: text(exchange['answer']),\n model: textOrNull(signal?.['model']),\n estCostUsd: finite(signal?.['estCostUsd']),\n feedback: feedback === 'up' || feedback === 'down' ? feedback : null,\n }\n}\n\n/** An insight's kept answer, as `aiInsights/{jobId}` stores it. */\nexport function staffAiInsightResult(record: Data | null): StaffAiJobResult | null {\n if (!record) return null\n const insights = Array.isArray(record['insights'])\n ? (record['insights'] as Data[]).map((insight) => text(insight?.['text'])).filter(Boolean)\n : []\n return { kind: 'insight', insights, gap: textOrNull(record['gap']) }\n}\n\n/** A CRM answer, as `aiCrmAnswers/{jobId}` stores it, by the proposal it holds. */\nexport function staffAiCrmResult(record: Data | null): StaffAiJobResult | null {\n const proposal = record?.['proposal'] as Data | undefined\n if (!proposal) return null\n switch (proposal['kind']) {\n case 'record': {\n const nextStep = proposal['nextStep'] as Data | null | undefined\n const title = textOrNull(nextStep?.['title'])\n const reason = textOrNull(nextStep?.['reason'])\n return {\n kind: 'crm-record',\n summary: text(proposal['summary']),\n nextStep: title ? (reason ? `${title} — ${reason}` : title) : null,\n standing: textOrNull(proposal['standing']),\n }\n }\n case 'email':\n return { kind: 'crm-email', subject: text(proposal['subject']), body: text(proposal['body']) }\n case 'mapping':\n return {\n kind: 'crm-mapping',\n matches: Array.isArray(proposal['matches'])\n ? (proposal['matches'] as Data[]).map((match) => `${text(match?.['header'])} → ${text(match?.['label'])}`)\n : [],\n }\n default:\n return null\n }\n}\n\n/** The collection a job kind keeps its result beside the job in, or `null` for a kind whose result is a draft. */\nexport function staffAiJobResultCollection(kind: unknown): 'aiInsights' | 'aiCrmAnswers' | null {\n if (kind === 'insight') return 'aiInsights'\n if (kind === 'crm') return 'aiCrmAnswers'\n return null\n}\n\n/** One job, with the result kept beside it when its kind keeps one. */\nexport function composeStaffAiJobRow(\n id: string,\n job: Data,\n result: StaffAiJobResult | null,\n members: ReadonlyMap<string, Data>,\n): StaffAiJobRow {\n const outputs = Array.isArray(job['outputs']) ? (job['outputs'] as Data[]) : []\n return {\n id,\n at: staffAiConversationTime(job['createdAt']),\n by: staffAiConversationPerson(job['createdBy'], members),\n hostId: textOrNull(job['hostId']),\n kind: text(job['kind']) || 'unknown',\n status: text(job['status']) || 'unknown',\n brief: text(job['brief']),\n credits: finite(job['creditsSpent']) ?? 0,\n error: textOrNull(job['error']),\n outputs: outputs.map((output) => ({\n label: text(output?.['label']) || text(output?.['resource']) || 'Output',\n note: textOrNull(output?.['note']),\n resource: textOrNull(output?.['resource']),\n hostSubdomain: textOrNull(output?.['hostSubdomain']),\n })),\n result,\n }\n}\n"],"names":["STAFF_AI_CONVERSATIONS_PAGE","STAFF_AI_CONVERSATION_KINDS","isStaffAiConversationKind","value","includes","text","textOrNull","trim","finite","Number","isFinite","staffAiConversationTime","toDate","toISOString","Date","isNaN","getTime","parse","staffAiConversationPerson","uid","members","id","member","get","undefined","email","name","composeStaffAiAssistRow","exchange","signal","feedback","at","by","hostId","route","question","answer","model","estCostUsd","staffAiInsightResult","record","insights","Array","isArray","map","insight","filter","Boolean","kind","gap","staffAiCrmResult","proposal","nextStep","title","reason","summary","standing","subject","body","matches","match","staffAiJobResultCollection","composeStaffAiJobRow","job","result","outputs","status","brief","credits","error","output","label","note","resource","hostSubdomain"],"mappings":"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"}
|