@aglyn/plugins-ai 1.0.0-beta.285 → 1.0.0-beta.287
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/assets/site-styles/nonprofit.webp +0 -0
- package/src/lib/assets/site-styles/professional.webp +0 -0
- package/src/lib/assets/site-styles/store.webp +0 -0
- package/src/lib/assets/site-styles/trades.webp +0 -0
- package/src/lib/components/ai-theme-proposal-card.component.js +12 -3
- package/src/lib/components/ai-theme-proposal-card.component.js.map +1 -1
- package/src/lib/declarations.js +5 -2
- package/src/lib/declarations.js.map +1 -1
- package/src/lib/declarations.server.js +12 -0
- package/src/lib/declarations.server.js.map +1 -1
- package/src/lib/jobs/ai-build-capabilities.d.ts +3 -1
- package/src/lib/jobs/ai-build-capabilities.js +27 -2
- package/src/lib/jobs/ai-build-capabilities.js.map +1 -1
- package/src/lib/jobs/ai-image-reads.d.ts +59 -0
- package/src/lib/jobs/ai-image-reads.js +138 -0
- package/src/lib/jobs/ai-image-reads.js.map +1 -0
- package/src/lib/jobs/ai-job-build-step.d.ts +29 -0
- package/src/lib/jobs/ai-job-build-step.js +83 -12
- package/src/lib/jobs/ai-job-build-step.js.map +1 -1
- package/src/lib/jobs/ai-job-duplicate-step.d.ts +2 -1
- package/src/lib/jobs/ai-job-duplicate-step.js +6 -6
- package/src/lib/jobs/ai-job-duplicate-step.js.map +1 -1
- package/src/lib/jobs/ai-job-import-step.d.ts +4 -2
- package/src/lib/jobs/ai-job-import-step.js +15 -11
- package/src/lib/jobs/ai-job-import-step.js.map +1 -1
- package/src/lib/jobs/ai-job-insight-step.d.ts +10 -0
- package/src/lib/jobs/ai-job-insight-step.js +23 -5
- package/src/lib/jobs/ai-job-insight-step.js.map +1 -1
- package/src/lib/jobs/ai-job-layout-language.js +2 -1
- package/src/lib/jobs/ai-job-layout-language.js.map +1 -1
- package/src/lib/jobs/ai-job-media-step.d.ts +2 -1
- package/src/lib/jobs/ai-job-media-step.js +6 -8
- package/src/lib/jobs/ai-job-media-step.js.map +1 -1
- package/src/lib/jobs/ai-job-navigation-step.d.ts +2 -1
- package/src/lib/jobs/ai-job-navigation-step.js +7 -9
- package/src/lib/jobs/ai-job-navigation-step.js.map +1 -1
- package/src/lib/jobs/ai-job-page-language.js +7 -1
- package/src/lib/jobs/ai-job-page-language.js.map +1 -1
- package/src/lib/jobs/ai-job-page-sections.js +16 -3
- package/src/lib/jobs/ai-job-page-sections.js.map +1 -1
- package/src/lib/jobs/ai-job-page-step.js +9 -1
- package/src/lib/jobs/ai-job-page-step.js.map +1 -1
- package/src/lib/jobs/ai-job-plan-step.d.ts +30 -8
- package/src/lib/jobs/ai-job-plan-step.js +78 -13
- package/src/lib/jobs/ai-job-plan-step.js.map +1 -1
- package/src/lib/jobs/ai-job-privacy-step.d.ts +4 -2
- package/src/lib/jobs/ai-job-privacy-step.js +14 -15
- package/src/lib/jobs/ai-job-privacy-step.js.map +1 -1
- package/src/lib/jobs/ai-job-products-step.js +5 -3
- package/src/lib/jobs/ai-job-products-step.js.map +1 -1
- package/src/lib/jobs/ai-job-settings-step.d.ts +2 -1
- package/src/lib/jobs/ai-job-settings-step.js +7 -8
- package/src/lib/jobs/ai-job-settings-step.js.map +1 -1
- package/src/lib/jobs/ai-job-site-content.d.ts +34 -1
- package/src/lib/jobs/ai-job-site-content.js +67 -8
- package/src/lib/jobs/ai-job-site-content.js.map +1 -1
- package/src/lib/jobs/ai-job-site-datasets.d.ts +53 -3
- package/src/lib/jobs/ai-job-site-datasets.js +298 -30
- package/src/lib/jobs/ai-job-site-datasets.js.map +1 -1
- package/src/lib/jobs/ai-job-site-step.js +6 -3
- package/src/lib/jobs/ai-job-site-step.js.map +1 -1
- package/src/lib/jobs/ai-job-site-store-pages.js +3 -3
- package/src/lib/jobs/ai-job-site-store-pages.js.map +1 -1
- package/src/lib/jobs/ai-job-tracking-step.d.ts +2 -1
- package/src/lib/jobs/ai-job-tracking-step.js +7 -8
- package/src/lib/jobs/ai-job-tracking-step.js.map +1 -1
- package/src/lib/jobs/ai-jobs-beat.d.ts +11 -7
- package/src/lib/jobs/ai-jobs-beat.js +18 -8
- package/src/lib/jobs/ai-jobs-beat.js.map +1 -1
- package/src/lib/jobs/ai-jobs-notify.d.ts +66 -1
- package/src/lib/jobs/ai-jobs-notify.js +136 -3
- package/src/lib/jobs/ai-jobs-notify.js.map +1 -1
- package/src/lib/jobs/ai-layout-stock-photos.d.ts +59 -4
- package/src/lib/jobs/ai-layout-stock-photos.js +897 -81
- package/src/lib/jobs/ai-layout-stock-photos.js.map +1 -1
- package/src/lib/jobs/ai-product-image.d.ts +14 -0
- package/src/lib/jobs/ai-product-image.js +73 -21
- package/src/lib/jobs/ai-product-image.js.map +1 -1
- package/src/lib/jobs/ai-theme-brand-inputs.d.ts +9 -1
- package/src/lib/jobs/ai-theme-brand-inputs.js +28 -2
- package/src/lib/jobs/ai-theme-brand-inputs.js.map +1 -1
- package/src/lib/jobs/fixtures/ai-site-agl4065-datasets.d.ts +175 -0
- package/src/lib/jobs/fixtures/ai-site-agl4065-datasets.js +601 -0
- package/src/lib/jobs/fixtures/ai-site-agl4065-datasets.js.map +1 -0
- package/src/lib/jobs/fixtures/ai-site-agl4065-pages.d.ts +46 -0
- package/src/lib/jobs/fixtures/ai-site-agl4065-pages.js +2862 -0
- package/src/lib/jobs/fixtures/ai-site-agl4065-pages.js.map +1 -0
- package/src/lib/jobs/fixtures/ai-site-agl4065-plans.d.ts +74 -0
- package/src/lib/jobs/fixtures/ai-site-agl4065-plans.js +888 -0
- package/src/lib/jobs/fixtures/ai-site-agl4065-plans.js.map +1 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl4065-judge.d.ts +29 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl4065-judge.js +81 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl4065-judge.js.map +1 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl4065-recordings.d.ts +87 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl4065-recordings.js +225 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl4065-recordings.js.map +1 -0
- package/src/lib/layout-language/ai-layout-compiler.d.ts +11 -0
- package/src/lib/layout-language/ai-layout-compiler.js +194 -18
- package/src/lib/layout-language/ai-layout-compiler.js.map +1 -1
- package/src/lib/layout-language/ai-layout-copy.d.ts +37 -0
- package/src/lib/layout-language/ai-layout-copy.js +383 -3
- package/src/lib/layout-language/ai-layout-copy.js.map +1 -1
- package/src/lib/layout-language/ai-layout-design.d.ts +19 -0
- package/src/lib/layout-language/ai-layout-design.js +31 -11
- package/src/lib/layout-language/ai-layout-design.js.map +1 -1
- package/src/lib/layout-language/ai-layout-listings.d.ts +7 -1
- package/src/lib/layout-language/ai-layout-listings.js +9 -1
- package/src/lib/layout-language/ai-layout-listings.js.map +1 -1
- package/src/lib/layout-language/ai-layout-pictures.d.ts +30 -0
- package/src/lib/layout-language/ai-layout-pictures.js +131 -3
- package/src/lib/layout-language/ai-layout-pictures.js.map +1 -1
- package/src/lib/layout-language/ai-layout-storefront.d.ts +18 -4
- package/src/lib/layout-language/ai-layout-storefront.js +100 -20
- package/src/lib/layout-language/ai-layout-storefront.js.map +1 -1
- package/src/lib/model/ai-build-job.d.ts +7 -0
- package/src/lib/model/ai-build-job.js +36 -7
- package/src/lib/model/ai-build-job.js.map +1 -1
- package/src/lib/model/ai-build-plan.d.ts +28 -4
- package/src/lib/model/ai-build-plan.js +49 -9
- package/src/lib/model/ai-build-plan.js.map +1 -1
- package/src/lib/model/ai-build-progress.js +3 -1
- package/src/lib/model/ai-build-progress.js.map +1 -1
- package/src/lib/model/ai-job-notice.d.ts +8 -0
- package/src/lib/model/ai-job-notice.js +33 -0
- package/src/lib/model/ai-job-notice.js.map +1 -1
- package/src/lib/model/ai-job-plan-lines.d.ts +2 -1
- package/src/lib/model/ai-job-plan-lines.js +6 -1
- package/src/lib/model/ai-job-plan-lines.js.map +1 -1
- package/src/lib/model/ai-jobs.types.d.ts +8 -0
- package/src/lib/model/ai-jobs.types.js.map +1 -1
- package/src/lib/model/ai-permissions.d.ts +13 -0
- package/src/lib/model/ai-permissions.js +29 -1
- package/src/lib/model/ai-permissions.js.map +1 -1
- package/src/lib/model/ai-products.d.ts +18 -0
- package/src/lib/model/ai-products.js +32 -0
- package/src/lib/model/ai-products.js.map +1 -1
- package/src/lib/model/ai-site-inspiration.d.ts +3 -2
- package/src/lib/model/ai-site-inspiration.js +3 -2
- package/src/lib/model/ai-site-inspiration.js.map +1 -1
- package/src/lib/plugin.js +4 -13
- package/src/lib/plugin.js.map +1 -1
- package/src/lib/providers/anthropic.js +9 -2
- package/src/lib/providers/anthropic.js.map +1 -1
- package/src/lib/providers/catalog.js +14 -5
- package/src/lib/providers/catalog.js.map +1 -1
- package/src/lib/providers/contract.d.ts +24 -1
- package/src/lib/providers/contract.js.map +1 -1
- package/src/lib/providers/routing.js +5 -2
- package/src/lib/providers/routing.js.map +1 -1
- package/src/lib/runtime/ai-dataset-generation.d.ts +99 -1
- package/src/lib/runtime/ai-dataset-generation.js +251 -3
- package/src/lib/runtime/ai-dataset-generation.js.map +1 -1
- package/src/lib/runtime/ai-dev-replay.d.ts +1 -0
- package/src/lib/runtime/ai-dev-replay.js +4 -2
- package/src/lib/runtime/ai-dev-replay.js.map +1 -1
- package/src/lib/runtime/ai-doctrine-validators.d.ts +47 -3
- package/src/lib/runtime/ai-doctrine-validators.js +343 -27
- package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
- package/src/lib/runtime/ai-doctrine.js +8 -2
- package/src/lib/runtime/ai-doctrine.js.map +1 -1
- package/src/lib/runtime/ai-icon-library.d.ts +27 -1
- package/src/lib/runtime/ai-icon-library.js +30 -3
- package/src/lib/runtime/ai-icon-library.js.map +1 -1
- package/src/lib/runtime/ai-products-generation.d.ts +11 -1
- package/src/lib/runtime/ai-products-generation.js +51 -4
- package/src/lib/runtime/ai-products-generation.js.map +1 -1
- package/src/lib/runtime/assist-answer-cache.d.ts +2 -0
- package/src/lib/runtime/assist-answer-cache.js +5 -2
- package/src/lib/runtime/assist-answer-cache.js.map +1 -1
- package/src/lib/server/ai-allotments.js +7 -2
- package/src/lib/server/ai-allotments.js.map +1 -1
- package/src/lib/server/ai-experiment-versions.js +5 -5
- package/src/lib/server/ai-experiment-versions.js.map +1 -1
- package/src/lib/server/ai-host-permissions-roster.d.ts +25 -0
- package/src/lib/server/ai-host-permissions-roster.js +33 -0
- package/src/lib/server/ai-host-permissions-roster.js.map +1 -0
- package/src/lib/server/ai-host-permissions.js +8 -6
- package/src/lib/server/ai-host-permissions.js.map +1 -1
- package/src/lib/server/ai-image-reads-route.d.ts +17 -0
- package/src/lib/server/ai-image-reads-route.js +106 -0
- package/src/lib/server/ai-image-reads-route.js.map +1 -0
- package/src/lib/server/ai-seo-apply.js +5 -5
- package/src/lib/server/ai-seo-apply.js.map +1 -1
- package/src/lib/server/ai-site-import-route.js +7 -4
- package/src/lib/server/ai-site-import-route.js.map +1 -1
- package/src/lib/server/assist-build.js +1 -0
- package/src/lib/server/assist-build.js.map +1 -1
- package/src/lib/server/assist-chat.d.ts +11 -7
- package/src/lib/server/assist-chat.js +185 -48
- package/src/lib/server/assist-chat.js.map +1 -1
- package/src/lib/server/assist-docs-query.d.ts +51 -0
- package/src/lib/server/assist-docs-query.js +57 -0
- package/src/lib/server/assist-docs-query.js.map +1 -0
- package/src/lib/server/assist-jobs-context.d.ts +102 -0
- package/src/lib/server/assist-jobs-context.js +227 -0
- package/src/lib/server/assist-jobs-context.js.map +1 -0
- package/src/lib/server/assist-view-context.d.ts +8 -4
- package/src/lib/server/assist-view-context.js +12 -7
- package/src/lib/server/assist-view-context.js.map +1 -1
- package/src/lib/server.js +12 -0
- package/src/lib/server.js.map +1 -1
- package/src/lib/tools/ai-dataset-tool.d.ts +11 -1
- package/src/lib/tools/ai-dataset-tool.js +24 -7
- package/src/lib/tools/ai-dataset-tool.js.map +1 -1
- package/src/lib/tools/ai-duplicate-resource-tool.js +5 -6
- package/src/lib/tools/ai-duplicate-resource-tool.js.map +1 -1
- package/src/lib/components/ai-collaborator-permissions-column.component.d.ts +0 -32
- package/src/lib/components/ai-collaborator-permissions-column.component.js +0 -132
- package/src/lib/components/ai-collaborator-permissions-column.component.js.map +0 -1
|
@@ -29,7 +29,7 @@ import { permissionRefusal, authForPool, checkRateLimit, emailUnverifiedResponse
|
|
|
29
29
|
import { recordUserAiRefusal } from "../usage/ai-usage-by-user.js";
|
|
30
30
|
import { estimateAssistCostUsd, publicAssistQuota, recordAssistExchange, releaseAssistMessage, reserveAssistMessage } from "../usage/assist-usage.js";
|
|
31
31
|
import { assistAnswerCacheKey, readAssistAnswerCache, writeAssistAnswerCache } from "../runtime/assist-answer-cache.js";
|
|
32
|
-
import { docsGroundingBlock, retrieveDocsSections } from "@aglyn/aglyn/app-utils/docs-retrieval";
|
|
32
|
+
import { docsGroundingBlock, docsLookupNeedsEnglish, retrieveDocsSections } from "@aglyn/aglyn/app-utils/docs-retrieval";
|
|
33
33
|
import { composeDocsLinksAnswer, deflectToDocs, questionStandsAlone, sectionLabel, sectionUrl } from "@aglyn/aglyn/app-utils/docs-deflection";
|
|
34
34
|
import { ASSIST_EDIT_TOOL_NAME, assistEditDocumentOf } from "../model/assist-edit.js";
|
|
35
35
|
import { ASSIST_EDIT_MAX_OUTPUT_TOKENS, assistEditTool, editCanvasBlock, editSelectionBlock, parseAssistEditContext, resolveAssistEdit } from "./assist-edit.js";
|
|
@@ -37,6 +37,8 @@ import { ASSIST_BUILD_TOOL_NAME } from "../model/assist-build.js";
|
|
|
37
37
|
import { assistBuildDraftsBlock, assistDraftsForTurn, parseAssistBuildDrafts } from "../model/assist-follow-up.js";
|
|
38
38
|
import { assistBuildBlock, assistBuildIntents, assistBuildIntentsBlock, assistBuildTool, resolveAssistBuild } from "./assist-build.js";
|
|
39
39
|
import { describeView, extractAssistAction, finalAssistText, resolveAssistProposal, safeOrgFacts, sanitiseId, sanitiseRoute, viewFactsBlock, viewScreenBlock, visibleAssistText, withAssistOpenDraftAction } from "./assist-view-context.js";
|
|
40
|
+
import { assistAsksAboutItsWorkspace, assistJobsHere, assistWorkspaceBlock, readAssistOpenJobs } from "./assist-jobs-context.js";
|
|
41
|
+
import { ASSIST_DOCS_QUERY_INPUT_CHARS, ASSIST_DOCS_QUERY_MAX_TOKENS, ASSIST_DOCS_QUERY_SYSTEM, parseAssistDocsQuery } from "./assist-docs-query.js";
|
|
40
42
|
import { invalidIdTokenResponse } from "@aglyn/tenant-data-admin/server/id-token-refusal";
|
|
41
43
|
// By its own entry point rather than the barrel (AGL-2903), for the reason
|
|
42
44
|
// `isRefusedIdToken` is: this route's spec replaces the barrel with a
|
|
@@ -115,7 +117,9 @@ import { checkAiClientIpRateLimit, freeAccountAgeRefusal } from "../runtime/ai-a
|
|
|
115
117
|
* answers PLUS page-context awareness (level 2 — the current route/host is
|
|
116
118
|
* injected so the assistant can walk the user through the view they are
|
|
117
119
|
* on). Free orgs get level 1 only: docs-grounded answers and deep links;
|
|
118
|
-
* any client-sent page context is deliberately dropped.
|
|
120
|
+
* any client-sent page context is deliberately dropped. Every tier is told
|
|
121
|
+
* its plan by name and, where AI jobs exist, the workspace's open ones
|
|
122
|
+
* (AGL-4075); a job on the site the page named links its page there.
|
|
119
123
|
*
|
|
120
124
|
* Streaming: the route re-emits the provider's stream as simplified
|
|
121
125
|
* `data: {type:'delta',text}` events, then one `{type:'done', exchangeId,
|
|
@@ -132,18 +136,20 @@ import { checkAiClientIpRateLimit, freeAccountAgeRefusal } from "../runtime/ai-a
|
|
|
132
136
|
* thinking plus answer together, so leaving it off the request would spend
|
|
133
137
|
* output-priced thinking tokens on "how do I publish a screen", stall the
|
|
134
138
|
* stream behind a silent think (display defaults to `omitted`, i.e. empty
|
|
135
|
-
* thinking blocks), and truncate the answer inside the same
|
|
136
|
-
* ceiling. `effort: low` is the documented posture for
|
|
137
|
-
* workload; both are asserted in the spec so a silent default
|
|
139
|
+
* thinking blocks), and truncate the answer inside the same 2,048-token
|
|
140
|
+
* ceiling (1,024 until AGL-4075). `effort: low` is the documented posture for
|
|
141
|
+
* a scoped chat workload; both are asserted in the spec so a silent default
|
|
142
|
+
* change fails.
|
|
138
143
|
*
|
|
139
|
-
* Prompt caching: the system array is ordered stable → volatile across
|
|
144
|
+
* Prompt caching: the system array is ordered stable → volatile across SIX
|
|
140
145
|
* blocks, with breakpoints after the first two.
|
|
141
146
|
*
|
|
142
147
|
* 1. static prompt [breakpoint] identical everywhere
|
|
143
148
|
* 2. screen description [breakpoint] identical per ROUTE, any tenant
|
|
144
149
|
* 3. product brand the org's name for the product
|
|
145
|
-
* 4.
|
|
146
|
-
* 5.
|
|
150
|
+
* 4. workspace its plan and open AI jobs (AGL-4075)
|
|
151
|
+
* 5. request facts workspace, host, path (paid)
|
|
152
|
+
* 6. docs retrieval follows the question
|
|
147
153
|
*
|
|
148
154
|
* On the edit and build rungs a SITE block (AGL-3661) follows the stable
|
|
149
155
|
* blocks: the business profile, status and remembered preferences of the
|
|
@@ -270,6 +276,10 @@ Rules:
|
|
|
270
276
|
- Be concise and task-focused: answer the question, give the steps, link the source. Skip preamble.
|
|
271
277
|
- If the question is not about the product, say so briefly and point the user back to product topics.
|
|
272
278
|
- If you do not know, say so and suggest contacting support from the Support page rather than guessing.
|
|
279
|
+
- A feature exists only when the documentation sections or the console page description given to you say so. When neither does, say you cannot confirm it exists rather than describing how it might work.
|
|
280
|
+
- Right-to-left layout is not supported yet: every site is laid out left to right, including in Arabic, Hebrew, Persian and Urdu. Never say otherwise.
|
|
281
|
+
- This chat takes text only. You cannot receive or open files, images or screenshots, and none can be attached here. When something needs a file, tell the user to upload it on the site's Media page.
|
|
282
|
+
- Answer in the language the user wrote in. The documentation is in English: link it as given, but write your answer in the user's language.
|
|
273
283
|
- The product's interface calls a site's pages "pages", never "screens". Routes, tools, fields and ids still say "screen" (a screenId, /screens), but always say "page" to the user.
|
|
274
284
|
|
|
275
285
|
Guiding from the current page:
|
|
@@ -607,15 +617,14 @@ ${AI_ACCEPTABLE_USE_BLOCK}`;
|
|
|
607
617
|
const pathSlug = (_route_split_filter_ = route.split('/').filter(Boolean)[0]) != null ? _route_split_filter_ : '';
|
|
608
618
|
const orgSlug = sanitiseId(String((_org_slug = org['slug']) != null ? _org_slug : '')) || (ORGLESS_PATH_SEGMENTS.has(pathSlug) ? '' : sanitiseId(pathSlug));
|
|
609
619
|
const view = describeView(route);
|
|
610
|
-
const { name
|
|
620
|
+
const { name } = safeOrgFacts(org);
|
|
611
621
|
return {
|
|
612
622
|
screen: viewScreenBlock(view, rung),
|
|
613
623
|
facts: viewFactsBlock({
|
|
614
624
|
route,
|
|
615
625
|
hostId,
|
|
616
626
|
orgSlug,
|
|
617
|
-
name
|
|
618
|
-
plan
|
|
627
|
+
name
|
|
619
628
|
}),
|
|
620
629
|
view,
|
|
621
630
|
scope: {
|
|
@@ -743,6 +752,70 @@ ${AI_ACCEPTABLE_USE_BLOCK}`;
|
|
|
743
752
|
*/ function upstreamFailureCopy(retryable) {
|
|
744
753
|
return retryable ? 'The assistant is busy right now — try again in a moment.' : 'The assistant request failed — try again.';
|
|
745
754
|
}
|
|
755
|
+
/** The docs a turn cites: each section's label and URL, and the paths the exchange records. */ function citedDocs(scored) {
|
|
756
|
+
return {
|
|
757
|
+
docs: scored.map(({ section })=>({
|
|
758
|
+
title: sectionLabel(section),
|
|
759
|
+
url: sectionUrl(section)
|
|
760
|
+
})),
|
|
761
|
+
docsPaths: scored.map(({ section })=>section.path + section.anchor)
|
|
762
|
+
};
|
|
763
|
+
}
|
|
764
|
+
/** Two calls' tokens as one turn's: the English lookup's and the answer's, on one model. */ function turnUsage(answer, lookup) {
|
|
765
|
+
var _answer_cacheWriteHourTokens, _lookup_cacheWriteHourTokens;
|
|
766
|
+
if (!lookup) return answer;
|
|
767
|
+
const hour = ((_answer_cacheWriteHourTokens = answer.cacheWriteHourTokens) != null ? _answer_cacheWriteHourTokens : 0) + ((_lookup_cacheWriteHourTokens = lookup.cacheWriteHourTokens) != null ? _lookup_cacheWriteHourTokens : 0);
|
|
768
|
+
return _extends({}, answer, {
|
|
769
|
+
inputTokens: answer.inputTokens + lookup.inputTokens,
|
|
770
|
+
outputTokens: answer.outputTokens + lookup.outputTokens,
|
|
771
|
+
cacheReadTokens: answer.cacheReadTokens + lookup.cacheReadTokens,
|
|
772
|
+
cacheWriteTokens: answer.cacheWriteTokens + lookup.cacheWriteTokens
|
|
773
|
+
}, hour ? {
|
|
774
|
+
cacheWriteHourTokens: hour
|
|
775
|
+
} : {});
|
|
776
|
+
}
|
|
777
|
+
/**
|
|
778
|
+
* The question as an English search query (AGL-4075), on the turn's own
|
|
779
|
+
* model, inside the turn the reservation admitted — see `assist-docs-query`.
|
|
780
|
+
* `null` when the lookup failed, and the docs are searched as asked; the
|
|
781
|
+
* usage comes back whatever the answer, because the tokens were spent.
|
|
782
|
+
*/ async function englishDocsQuery(model, question) {
|
|
783
|
+
try {
|
|
784
|
+
const result = await runAiRequest(_extends({
|
|
785
|
+
model,
|
|
786
|
+
maxTokens: ASSIST_DOCS_QUERY_MAX_TOKENS,
|
|
787
|
+
stream: false
|
|
788
|
+
}, CHAT_ROUTE.thinking ? {
|
|
789
|
+
thinking: CHAT_ROUTE.thinking
|
|
790
|
+
} : {}, CHAT_ROUTE.effort ? {
|
|
791
|
+
effort: CHAT_ROUTE.effort
|
|
792
|
+
} : {}, {
|
|
793
|
+
system: [
|
|
794
|
+
{
|
|
795
|
+
text: ASSIST_DOCS_QUERY_SYSTEM
|
|
796
|
+
}
|
|
797
|
+
],
|
|
798
|
+
messages: [
|
|
799
|
+
{
|
|
800
|
+
role: 'user',
|
|
801
|
+
content: question.slice(0, ASSIST_DOCS_QUERY_INPUT_CHARS)
|
|
802
|
+
}
|
|
803
|
+
]
|
|
804
|
+
}));
|
|
805
|
+
return {
|
|
806
|
+
query: result.kind === 'completion' ? parseAssistDocsQuery(result.text) : '',
|
|
807
|
+
usage: result.usage
|
|
808
|
+
};
|
|
809
|
+
} catch (error) {
|
|
810
|
+
// The answer still comes; it is grounded in what the question's own
|
|
811
|
+
// words find, as before the lookup existed.
|
|
812
|
+
console.error('assist english docs lookup failed', {
|
|
813
|
+
model,
|
|
814
|
+
error
|
|
815
|
+
});
|
|
816
|
+
return null;
|
|
817
|
+
}
|
|
818
|
+
}
|
|
746
819
|
async function handler(request) {
|
|
747
820
|
var _request_headers_get;
|
|
748
821
|
if (request.method !== 'POST') {
|
|
@@ -776,8 +849,8 @@ async function handler(request) {
|
|
|
776
849
|
});
|
|
777
850
|
}
|
|
778
851
|
try {
|
|
779
|
-
var _resolved_org, _org_slug, _ref, _ref1, _ref2, _ref3, _ref4, _ref5;
|
|
780
|
-
var _body_context, _body_context1, _body_context2, _body_context3, _quota_allotment, _quota_allotment1;
|
|
852
|
+
var _resolved_org, _org_slug, _ref, _ref1, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7;
|
|
853
|
+
var _body_context, _body_context1, _body_context2, _body_context3, _quota_allotment, _quota_allotment1, _body_context4, _body_context5;
|
|
781
854
|
const app = firebaseAdmin.app();
|
|
782
855
|
const decoded = await app.auth().verifyIdToken(idToken);
|
|
783
856
|
if (!decoded.email_verified && !isImpersonationSession(decoded)) {
|
|
@@ -906,11 +979,18 @@ async function handler(request) {
|
|
|
906
979
|
// documentation back to the user is the spend this issue exists to
|
|
907
980
|
// remove.
|
|
908
981
|
const scored = retrieveDocsSections(body.question);
|
|
909
|
-
const
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
982
|
+
const { docs, docsPaths } = citedDocs(scored);
|
|
983
|
+
// A question the docs' English cannot find by its own words (AGL-4075):
|
|
984
|
+
// looked up in English below, once a model is paying for the turn, and
|
|
985
|
+
// never answered with an English quote, since its answer is written in
|
|
986
|
+
// the asker's language.
|
|
987
|
+
const needsEnglish = docsLookupNeedsEnglish(body.question);
|
|
988
|
+
// Nor is a question about the workspace's own plan or AI jobs (AGL-4075):
|
|
989
|
+
// the docs describe every plan and every job, and only this turn's
|
|
990
|
+
// workspace block says which plan this is and where its jobs stand.
|
|
991
|
+
const asksAboutWorkspace = assistAsksAboutItsWorkspace(body.question, {
|
|
992
|
+
jobs: checkEntitlement(org, 'aiGenerative')
|
|
993
|
+
});
|
|
914
994
|
// On the edit rung a docs quote cannot carry the proposal the author may
|
|
915
995
|
// be asking for, so only a question that reads on its own — a how-to, not
|
|
916
996
|
// an instruction and not a question about "this" element — is answered
|
|
@@ -918,10 +998,10 @@ async function handler(request) {
|
|
|
918
998
|
// for a question that needs nothing around it, and the open canvas is
|
|
919
999
|
// exactly what an edit request leans on. So is a follow-up on a draft
|
|
920
1000
|
// this thread's build made (AGL-3616): "make the about page shorter".
|
|
921
|
-
const deflection = (editRung || buildRung || body.drafts.length) && !questionStandsAlone(body.question) ? null : deflectToDocs(body.question, scored, body.history.length > 0);
|
|
1001
|
+
const deflection = needsEnglish || asksAboutWorkspace || (editRung || buildRung || body.drafts.length) && !questionStandsAlone(body.question) ? null : deflectToDocs(body.question, scored, body.history.length > 0);
|
|
922
1002
|
if (deflection == null ? void 0 : deflection.answered) {
|
|
923
|
-
var
|
|
924
|
-
var
|
|
1003
|
+
var _ref8;
|
|
1004
|
+
var _body_context6, _body_context7;
|
|
925
1005
|
// Costs no provider tokens, so it takes NO reservation: a docs answer
|
|
926
1006
|
// must not spend one of a free workspace's ten messages a day. The
|
|
927
1007
|
// per-uid rate limiter above is what bounds this path, and it is the
|
|
@@ -934,8 +1014,8 @@ async function handler(request) {
|
|
|
934
1014
|
answer: deflection.answer,
|
|
935
1015
|
docs,
|
|
936
1016
|
docsPaths: deflection.quoted.map((section)=>section.path + section.anchor),
|
|
937
|
-
route: (
|
|
938
|
-
hostId: ((
|
|
1017
|
+
route: (_ref8 = (_body_context6 = body.context) == null ? void 0 : _body_context6.route) != null ? _ref8 : '',
|
|
1018
|
+
hostId: ((_body_context7 = body.context) == null ? void 0 : _body_context7.hostId) || null,
|
|
939
1019
|
tier: entitled ? 'entitled' : 'free',
|
|
940
1020
|
rate
|
|
941
1021
|
});
|
|
@@ -966,8 +1046,8 @@ async function handler(request) {
|
|
|
966
1046
|
// panel does not print this string; it has its own plain-English line for
|
|
967
1047
|
// a 501, because the person reading it is not the person who sets the var.
|
|
968
1048
|
if (!aiProviderReady()) {
|
|
969
|
-
var
|
|
970
|
-
var
|
|
1049
|
+
var _ref9;
|
|
1050
|
+
var _body_context8, _body_context9;
|
|
971
1051
|
const closest = composeDocsLinksAnswer(scored.map(({ section })=>section));
|
|
972
1052
|
if (!closest) {
|
|
973
1053
|
return Response.json({
|
|
@@ -987,13 +1067,37 @@ async function handler(request) {
|
|
|
987
1067
|
answer: closest,
|
|
988
1068
|
docs,
|
|
989
1069
|
docsPaths,
|
|
990
|
-
route: (
|
|
991
|
-
hostId: ((
|
|
1070
|
+
route: (_ref9 = (_body_context8 = body.context) == null ? void 0 : _body_context8.route) != null ? _ref9 : '',
|
|
1071
|
+
hostId: ((_body_context9 = body.context) == null ? void 0 : _body_context9.hostId) || null,
|
|
992
1072
|
tier: entitled ? 'entitled' : 'free',
|
|
993
1073
|
rate,
|
|
994
1074
|
servedBy: 'docs-links'
|
|
995
1075
|
});
|
|
996
1076
|
}
|
|
1077
|
+
// ── The workspace's open AI jobs (AGL-4075) ───────────────────────────
|
|
1078
|
+
// Read for every plan where the jobs exist at all — the same rungs the
|
|
1079
|
+
// AI jobs list at the top of this panel climbs: `aiGenerative` and the
|
|
1080
|
+
// release flag (staff preview). One bounded read, before the answer
|
|
1081
|
+
// cache, which a turn told of a job must not use. A failure leaves the
|
|
1082
|
+
// jobs out of the turn, never the answer.
|
|
1083
|
+
const jobsShown = checkEntitlement(org, 'aiGenerative') && (staff || await isServerReleaseFlagOnForOrg('release_ai_generative', body.orgId));
|
|
1084
|
+
let openJobs = null;
|
|
1085
|
+
let jobsUnread = false;
|
|
1086
|
+
if (jobsShown) {
|
|
1087
|
+
try {
|
|
1088
|
+
openJobs = await readAssistOpenJobs(firestore, {
|
|
1089
|
+
orgId: body.orgId,
|
|
1090
|
+
uid: decoded.uid
|
|
1091
|
+
});
|
|
1092
|
+
} catch (error) {
|
|
1093
|
+
console.error('assist open jobs read failed', {
|
|
1094
|
+
orgId: body.orgId,
|
|
1095
|
+
error
|
|
1096
|
+
});
|
|
1097
|
+
jobsUnread = true;
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
const plan = safeOrgFacts(org).plan;
|
|
997
1101
|
// ── The answer cache (AGL-2486) ───────────────────────────────────────
|
|
998
1102
|
// Only reached by an ESCALATION, and only on a FIRST turn: a turn with
|
|
999
1103
|
// history is answered against a conversation this key cannot describe,
|
|
@@ -1022,17 +1126,23 @@ async function handler(request) {
|
|
|
1022
1126
|
// rung (AGL-2906): that answer is composed against the canvas the request
|
|
1023
1127
|
// described, which the key cannot describe either. Nor does a turn that
|
|
1024
1128
|
// listed a build's drafts (AGL-3616): its answer may open one of them.
|
|
1025
|
-
|
|
1129
|
+
//
|
|
1130
|
+
// Nor does a turn told of an open AI job (AGL-4075), or one whose jobs
|
|
1131
|
+
// could not be read: its answer may be about that job, which has moved
|
|
1132
|
+
// on by the next time anyone asks. The plan's name, which every turn is
|
|
1133
|
+
// told, is in the key.
|
|
1134
|
+
const cacheKey = body.history.length || body.model || editRung || buildRung || body.drafts.length || jobsUnread || (openJobs == null ? void 0 : openJobs.length) ? '' : assistAnswerCacheKey({
|
|
1026
1135
|
question: body.question,
|
|
1027
1136
|
tier: entitled ? 'entitled' : 'free',
|
|
1028
1137
|
route: (_ref = (_body_context2 = body.context) == null ? void 0 : _body_context2.route) != null ? _ref : '',
|
|
1029
1138
|
model: assistModel(),
|
|
1030
|
-
productName: resolveBrandingProfile(org).productName
|
|
1139
|
+
productName: resolveBrandingProfile(org).productName,
|
|
1140
|
+
plan
|
|
1031
1141
|
});
|
|
1032
1142
|
const cached = cacheKey ? await readAssistAnswerCache(firestore, body.orgId, cacheKey) : null;
|
|
1033
1143
|
if (cached) {
|
|
1034
|
-
var _cached_docs,
|
|
1035
|
-
var
|
|
1144
|
+
var _cached_docs, _ref10;
|
|
1145
|
+
var _body_context10, _body_context11;
|
|
1036
1146
|
// Spent nothing, so it takes no reservation — the same rule the docs
|
|
1037
1147
|
// path follows, for the same reason.
|
|
1038
1148
|
return docsOnlyResponse({
|
|
@@ -1043,8 +1153,8 @@ async function handler(request) {
|
|
|
1043
1153
|
answer: cached.answer,
|
|
1044
1154
|
docs: (_cached_docs = cached.docs) != null ? _cached_docs : [],
|
|
1045
1155
|
docsPaths,
|
|
1046
|
-
route: (
|
|
1047
|
-
hostId: ((
|
|
1156
|
+
route: (_ref10 = (_body_context10 = body.context) == null ? void 0 : _body_context10.route) != null ? _ref10 : '',
|
|
1157
|
+
hostId: ((_body_context11 = body.context) == null ? void 0 : _body_context11.hostId) || null,
|
|
1048
1158
|
tier: entitled ? 'entitled' : 'free',
|
|
1049
1159
|
rate,
|
|
1050
1160
|
servedBy: 'cache'
|
|
@@ -1087,7 +1197,7 @@ async function handler(request) {
|
|
|
1087
1197
|
// month counts it beside the org counter the reservation moved.
|
|
1088
1198
|
recordUserAiRefusal(firestore, body.orgId, decoded.uid, quota);
|
|
1089
1199
|
if (!quota.allowed) {
|
|
1090
|
-
var
|
|
1200
|
+
var _ref11;
|
|
1091
1201
|
// Five refusals, not two. The spend ceiling (AGL-2264) is armed by
|
|
1092
1202
|
// default at $40, and it must not borrow the message cap's words:
|
|
1093
1203
|
// "reached its limit for the month" invites the user to count their
|
|
@@ -1139,10 +1249,10 @@ async function handler(request) {
|
|
|
1139
1249
|
}
|
|
1140
1250
|
const ownControl = assistOwnControlRefusalText(org, refusedBy);
|
|
1141
1251
|
return Response.json({
|
|
1142
|
-
error: (
|
|
1252
|
+
error: (_ref11 = ownControl != null ? ownControl : // The Free taste's own precautions (AGL-2925): a clock or an
|
|
1143
1253
|
// upgrade, in one sentence, from the same helper the other
|
|
1144
1254
|
// doors read.
|
|
1145
|
-
assistFreeTasteRefusalText(refusedBy)) != null ?
|
|
1255
|
+
assistFreeTasteRefusalText(refusedBy)) != null ? _ref11 : refusedBy === 'budget' || refusedBy === 'band' ? quota.budgetUsd === null ? 'This workspace reached its assistant spending limit for the month' : 'This workspace used its assistant credits for the month' : entitled ? 'This workspace reached its assistant limit for the month' : `Free workspaces get ${quota.limit} assistant messages a day — upgrade to Pro for more`,
|
|
1146
1256
|
reason: 'quota',
|
|
1147
1257
|
// CREDITS, never the reservation itself: it carries `costUsd`,
|
|
1148
1258
|
// `costLimitUsd` and `budgetUsd`, all three of which are our
|
|
@@ -1163,7 +1273,24 @@ async function handler(request) {
|
|
|
1163
1273
|
orgModels: (_ref2 = (_quota_allotment1 = quota.allotment) == null ? void 0 : _quota_allotment1.orgModels) != null ? _ref2 : null
|
|
1164
1274
|
});
|
|
1165
1275
|
const model = (_ref3 = choice == null ? void 0 : choice.model) != null ? _ref3 : assistModel();
|
|
1166
|
-
|
|
1276
|
+
// The docs lookup in English (AGL-4075), for a question its own words
|
|
1277
|
+
// cannot find: one small completion on this turn's model, metered with
|
|
1278
|
+
// the answer. What it finds replaces what the words found, when it
|
|
1279
|
+
// finds anything.
|
|
1280
|
+
const lookup = needsEnglish ? await englishDocsQuery(model, body.question) : null;
|
|
1281
|
+
const englishFound = (lookup == null ? void 0 : lookup.query) ? retrieveDocsSections(lookup.query) : [];
|
|
1282
|
+
const grounding = englishFound.length ? englishFound : scored;
|
|
1283
|
+
const cited = englishFound.length ? citedDocs(englishFound) : {
|
|
1284
|
+
docs,
|
|
1285
|
+
docsPaths
|
|
1286
|
+
};
|
|
1287
|
+
const docsBlock = docsGroundingBlock(grounding);
|
|
1288
|
+
// The plan by name for every workspace, and its open AI jobs (AGL-4075).
|
|
1289
|
+
const workspaceBlock = assistWorkspaceBlock({
|
|
1290
|
+
plan,
|
|
1291
|
+
jobs: openJobs,
|
|
1292
|
+
here: assistJobsHere(sanitiseRoute((_ref4 = (_body_context4 = body.context) == null ? void 0 : _body_context4.route) != null ? _ref4 : ''), (_ref5 = (_body_context5 = body.context) == null ? void 0 : _body_context5.hostId) != null ? _ref5 : '', ORGLESS_PATH_SEGMENTS)
|
|
1293
|
+
});
|
|
1167
1294
|
// Level 2 is the paid rung. A free workspace gets docs grounding and
|
|
1168
1295
|
// deep links; the view block, and with it the proposal channel, is not
|
|
1169
1296
|
// assembled at all — not assembled-then-withheld, so there is no path
|
|
@@ -1185,7 +1312,7 @@ async function handler(request) {
|
|
|
1185
1312
|
// that may change the site: the edit and build rungs, whose host was
|
|
1186
1313
|
// checked for `ai.generate` above. Free and paid read the same block. A
|
|
1187
1314
|
// site breakpoint when the stable blocks leave one, volatile otherwise.
|
|
1188
|
-
const siteHostId = (
|
|
1315
|
+
const siteHostId = (_ref6 = (_ref7 = buildRung == null ? void 0 : buildRung.hostId) != null ? _ref7 : editRung == null ? void 0 : editRung.target.hostId) != null ? _ref6 : null;
|
|
1189
1316
|
const siteContext = siteHostId ? await readAiSiteContext(firestore, {
|
|
1190
1317
|
orgId: body.orgId,
|
|
1191
1318
|
hostId: siteHostId
|
|
@@ -1249,6 +1376,14 @@ async function handler(request) {
|
|
|
1249
1376
|
text: assistBrandBlock(org),
|
|
1250
1377
|
volatile: true
|
|
1251
1378
|
},
|
|
1379
|
+
// The workspace's plan and open AI jobs (AGL-4075): per org and per
|
|
1380
|
+
// moment, so after every breakpoint, for every plan.
|
|
1381
|
+
...workspaceBlock ? [
|
|
1382
|
+
{
|
|
1383
|
+
text: workspaceBlock,
|
|
1384
|
+
volatile: true
|
|
1385
|
+
}
|
|
1386
|
+
] : [],
|
|
1252
1387
|
...guide ? [
|
|
1253
1388
|
{
|
|
1254
1389
|
text: guide.facts,
|
|
@@ -1356,7 +1491,7 @@ async function handler(request) {
|
|
|
1356
1491
|
cacheWriteTokens: 0
|
|
1357
1492
|
};
|
|
1358
1493
|
try {
|
|
1359
|
-
var _ref, _ref1, _ref2, _ref3;
|
|
1494
|
+
var _ref, _ref1, _ref2, _ref3, _ref4;
|
|
1360
1495
|
var _guide_view, _describeView, _body_context;
|
|
1361
1496
|
{
|
|
1362
1497
|
var _iteratorAbruptCompletion = false, _didIteratorError = false, _iteratorError, _return;
|
|
@@ -1499,20 +1634,22 @@ async function handler(request) {
|
|
|
1499
1634
|
}
|
|
1500
1635
|
// The data loop + meters — recorded even for a partial answer:
|
|
1501
1636
|
// tokens were spent either way and the miner wants the question.
|
|
1637
|
+
// The English lookup's tokens are this turn's too (AGL-4075).
|
|
1638
|
+
const spent = turnUsage(usage, (_ref3 = lookup == null ? void 0 : lookup.usage) != null ? _ref3 : null);
|
|
1502
1639
|
let exchangeId = null;
|
|
1503
1640
|
try {
|
|
1504
|
-
var
|
|
1641
|
+
var _ref5;
|
|
1505
1642
|
var _body_context1, _body_context2;
|
|
1506
1643
|
exchangeId = await recordAssistExchange(firestore, body.orgId, _extends({
|
|
1507
1644
|
uid: decoded.uid,
|
|
1508
1645
|
question: body.question,
|
|
1509
1646
|
answer: answer.slice(0, MAX_STORED_ANSWER_CHARS),
|
|
1510
|
-
route: (
|
|
1647
|
+
route: (_ref5 = (_body_context1 = body.context) == null ? void 0 : _body_context1.route) != null ? _ref5 : '',
|
|
1511
1648
|
hostId: ((_body_context2 = body.context) == null ? void 0 : _body_context2.hostId) || null,
|
|
1512
1649
|
model,
|
|
1513
1650
|
tier,
|
|
1514
|
-
usage,
|
|
1515
|
-
docsPaths,
|
|
1651
|
+
usage: spent,
|
|
1652
|
+
docsPaths: cited.docsPaths,
|
|
1516
1653
|
stopReason,
|
|
1517
1654
|
// The account this turn drew on, as the reservation decided
|
|
1518
1655
|
// it (AGL-2925) — so a Free turn lands on the owner's
|
|
@@ -1543,14 +1680,14 @@ async function handler(request) {
|
|
|
1543
1680
|
if (cacheKey && answer && !proposal && !build && stopReason !== 'refusal' && stopReason !== 'max_tokens' && model === assistModel()) {
|
|
1544
1681
|
await writeAssistAnswerCache(firestore, body.orgId, cacheKey, {
|
|
1545
1682
|
answer,
|
|
1546
|
-
docs
|
|
1683
|
+
docs: cited.docs
|
|
1547
1684
|
});
|
|
1548
1685
|
}
|
|
1549
1686
|
emit({
|
|
1550
1687
|
type: 'done',
|
|
1551
1688
|
exchangeId,
|
|
1552
|
-
usage,
|
|
1553
|
-
docs,
|
|
1689
|
+
usage: spent,
|
|
1690
|
+
docs: cited.docs,
|
|
1554
1691
|
// Inert data. The panel renders it as a card the user must
|
|
1555
1692
|
// confirm, and confirming navigates — see the write boundary in
|
|
1556
1693
|
// `assist-view-context.ts`.
|
|
@@ -1574,10 +1711,10 @@ async function handler(request) {
|
|
|
1574
1711
|
// The usage strip's envelope (AGL-2942): this turn's credits
|
|
1575
1712
|
// added to the pool and the asker's month the reservation read.
|
|
1576
1713
|
meter: aiUsageMeter(quota, {
|
|
1577
|
-
lastCredits: assistCreditsFromUsd(estimateAssistCostUsd(
|
|
1714
|
+
lastCredits: assistCreditsFromUsd(estimateAssistCostUsd(spent, model)),
|
|
1578
1715
|
model: {
|
|
1579
1716
|
id: model,
|
|
1580
|
-
auto: (
|
|
1717
|
+
auto: (_ref4 = choice == null ? void 0 : choice.auto) != null ? _ref4 : true
|
|
1581
1718
|
}
|
|
1582
1719
|
})
|
|
1583
1720
|
});
|