@aglyn/plugins-ai 1.0.0-beta.238 → 1.0.0-beta.240

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.
Files changed (88) hide show
  1. package/package.json +17 -17
  2. package/src/lib/components/ai-job-links.js +8 -0
  3. package/src/lib/components/ai-job-links.js.map +1 -1
  4. package/src/lib/components/ai-job-requests.d.ts +5 -0
  5. package/src/lib/components/ai-job-requests.js +4 -2
  6. package/src/lib/components/ai-job-requests.js.map +1 -1
  7. package/src/lib/components/ai-jobs-store.d.ts +12 -0
  8. package/src/lib/components/ai-jobs-store.js +15 -0
  9. package/src/lib/components/ai-jobs-store.js.map +1 -1
  10. package/src/lib/components/ai-usage-meter-refresh.d.ts +35 -0
  11. package/src/lib/components/ai-usage-meter-refresh.js +63 -0
  12. package/src/lib/components/ai-usage-meter-refresh.js.map +1 -0
  13. package/src/lib/components/assist-panel.component.js +17 -1
  14. package/src/lib/components/assist-panel.component.js.map +1 -1
  15. package/src/lib/components/use-ai-usage-meter.d.ts +2 -0
  16. package/src/lib/components/use-ai-usage-meter.js +8 -3
  17. package/src/lib/components/use-ai-usage-meter.js.map +1 -1
  18. package/src/lib/jobs/ai-build-unit-outcome.d.ts +3 -1
  19. package/src/lib/jobs/ai-build-unit-outcome.js +19 -3
  20. package/src/lib/jobs/ai-build-unit-outcome.js.map +1 -1
  21. package/src/lib/jobs/ai-job-build-step.js +29 -2
  22. package/src/lib/jobs/ai-job-build-step.js.map +1 -1
  23. package/src/lib/jobs/ai-job-draft-ids.js +7 -2
  24. package/src/lib/jobs/ai-job-draft-ids.js.map +1 -1
  25. package/src/lib/jobs/ai-job-form-dataset.d.ts +100 -0
  26. package/src/lib/jobs/ai-job-form-dataset.js +161 -0
  27. package/src/lib/jobs/ai-job-form-dataset.js.map +1 -0
  28. package/src/lib/jobs/ai-job-form-step.d.ts +15 -3
  29. package/src/lib/jobs/ai-job-form-step.js +37 -9
  30. package/src/lib/jobs/ai-job-form-step.js.map +1 -1
  31. package/src/lib/jobs/ai-job-layout-language.js +7 -2
  32. package/src/lib/jobs/ai-job-layout-language.js.map +1 -1
  33. package/src/lib/jobs/ai-job-page-language.d.ts +9 -0
  34. package/src/lib/jobs/ai-job-page-language.js +44 -4
  35. package/src/lib/jobs/ai-job-page-language.js.map +1 -1
  36. package/src/lib/jobs/ai-job-page-sections.js +13 -2
  37. package/src/lib/jobs/ai-job-page-sections.js.map +1 -1
  38. package/src/lib/jobs/ai-job-page-step.js +32 -2
  39. package/src/lib/jobs/ai-job-page-step.js.map +1 -1
  40. package/src/lib/jobs/ai-job-plan-step.d.ts +18 -0
  41. package/src/lib/jobs/ai-job-plan-step.js +41 -4
  42. package/src/lib/jobs/ai-job-plan-step.js.map +1 -1
  43. package/src/lib/jobs/ai-job-site-datasets.d.ts +183 -0
  44. package/src/lib/jobs/ai-job-site-datasets.js +530 -0
  45. package/src/lib/jobs/ai-job-site-datasets.js.map +1 -0
  46. package/src/lib/jobs/ai-job-site-step.d.ts +15 -8
  47. package/src/lib/jobs/ai-job-site-step.js +148 -29
  48. package/src/lib/jobs/ai-job-site-step.js.map +1 -1
  49. package/src/lib/jobs/fixtures/ai-dataset-site-plan-recordings.d.ts +30 -0
  50. package/src/lib/jobs/fixtures/ai-dataset-site-plan-recordings.js +637 -0
  51. package/src/lib/jobs/fixtures/ai-dataset-site-plan-recordings.js.map +1 -0
  52. package/src/lib/layout-language/ai-layout-compiler.d.ts +10 -0
  53. package/src/lib/layout-language/ai-layout-compiler.js +93 -1
  54. package/src/lib/layout-language/ai-layout-compiler.js.map +1 -1
  55. package/src/lib/layout-language/ai-layout-gaps.js +17 -1
  56. package/src/lib/layout-language/ai-layout-gaps.js.map +1 -1
  57. package/src/lib/layout-language/ai-layout-listings.d.ts +32 -3
  58. package/src/lib/layout-language/ai-layout-listings.js +62 -9
  59. package/src/lib/layout-language/ai-layout-listings.js.map +1 -1
  60. package/src/lib/layout-language/ai-layout-pictures.js +12 -4
  61. package/src/lib/layout-language/ai-layout-pictures.js.map +1 -1
  62. package/src/lib/model/ai-build-job.d.ts +2 -0
  63. package/src/lib/model/ai-build-job.js +16 -1
  64. package/src/lib/model/ai-build-job.js.map +1 -1
  65. package/src/lib/model/ai-build-plan.d.ts +23 -3
  66. package/src/lib/model/ai-build-plan.js +47 -6
  67. package/src/lib/model/ai-build-plan.js.map +1 -1
  68. package/src/lib/model/ai-plan-capabilities.d.ts +7 -0
  69. package/src/lib/model/ai-plan-capabilities.js.map +1 -1
  70. package/src/lib/model/ai-site-job.d.ts +19 -2
  71. package/src/lib/model/ai-site-job.js +21 -6
  72. package/src/lib/model/ai-site-job.js.map +1 -1
  73. package/src/lib/runtime/ai-dataset-generation.d.ts +77 -0
  74. package/src/lib/runtime/ai-dataset-generation.js +127 -0
  75. package/src/lib/runtime/ai-dataset-generation.js.map +1 -0
  76. package/src/lib/runtime/ai-doctrine-validators.d.ts +84 -0
  77. package/src/lib/runtime/ai-doctrine-validators.js +307 -1
  78. package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
  79. package/src/lib/runtime/ai-doctrine.js +10 -4
  80. package/src/lib/runtime/ai-doctrine.js.map +1 -1
  81. package/src/lib/runtime/ai-node-tree.d.ts +2 -0
  82. package/src/lib/runtime/ai-node-tree.js +16 -0
  83. package/src/lib/runtime/ai-node-tree.js.map +1 -1
  84. package/src/lib/tools/ai-dataset-tool.d.ts +68 -0
  85. package/src/lib/tools/ai-dataset-tool.js +231 -0
  86. package/src/lib/tools/ai-dataset-tool.js.map +1 -0
  87. package/src/lib/usage/free-ai-credits-left.js +26 -2
  88. package/src/lib/usage/free-ai-credits-left.js.map +1 -1
@@ -24,7 +24,8 @@ import { AiUpstreamError } from "../runtime/ai-runtime.js";
24
24
  * failed on our side, or failed on the model's or the workspace's.
25
25
  *
26
26
  * Shared by both steps, and importing neither, so neither imports the other.
27
- */ /** What a unit says when it finished without reporting anything. */ export const AI_BUILD_UNIT_EMPTY_COPY = 'It could not be built this time.';
27
+ */ /** The resource the data plugin writes a dataset under (AGL-3616). */ export const AI_DATASET_DRAFT_RESOURCE = 'dataset';
28
+ /** What a unit says when it finished without reporting anything. */ export const AI_BUILD_UNIT_EMPTY_COPY = 'It could not be built this time.';
28
29
  /** What a unit's model declining the request says. */ export const AI_BUILD_UNIT_REFUSED_COPY = 'The AI declined to build this one.';
29
30
  /** A runner's outcome narrowed to its spend: no plan, no review, nothing the delegating job keeps. */ export function aiUnitSpend(outcome) {
30
31
  return _extends({
@@ -124,8 +125,23 @@ import { AiUpstreamError } from "../runtime/ai-runtime.js";
124
125
  var _outputs_find;
125
126
  const creation = unit.creation;
126
127
  const row = rows.get(unit.slot);
127
- if (!creation || !row || !aiBuildItemDelivered(row) || !row.outputs.length) continue;
128
- if (creation.kind !== 'layout' && creation.kind !== 'form' && creation.kind !== 'component') continue;
128
+ if (!row || !aiBuildItemDelivered(row) || !row.outputs.length) continue;
129
+ // A build's dataset item (AGL-3616), which the data plugin wrote: a page
130
+ // lists it, or is its record template, by the name the plan gave it.
131
+ if (unit.item) {
132
+ const output = outputs.find((entry)=>entry.id === row.outputs[0]);
133
+ if ((output == null ? void 0 : output.draftResource) === AI_DATASET_DRAFT_RESOURCE) {
134
+ built.set(unit.item.name.toLowerCase(), {
135
+ id: output.id,
136
+ label: output.label || unit.item.name,
137
+ kind: 'dataset'
138
+ });
139
+ }
140
+ continue;
141
+ }
142
+ if (!creation) continue;
143
+ // A dataset a site start created (AGL-3616) is a record a page names too.
144
+ if (creation.kind !== 'layout' && creation.kind !== 'form' && creation.kind !== 'component' && creation.kind !== 'dataset') continue;
129
145
  const id = row.outputs[0];
130
146
  const label = ((_outputs_find = outputs.find((output)=>output.id === id)) == null ? void 0 : _outputs_find.label) || creation.name;
131
147
  built.set(creation.name.toLowerCase(), {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/jobs/ai-build-unit-outcome.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { aiBuildItemDelivered, type AiBuildUnit } from '../model/ai-build-job'\nimport type { AiJobItemLedger, AiJobOutput } from '../model/ai-jobs.types'\nimport { AiUpstreamError } from '../runtime/ai-runtime'\nimport type { AiSiteBuiltRef } from './ai-job-site-step'\nimport type { AiJobItemOutcome, AiJobStepOutcome } from './ai-job-text-step'\n\n/**\n * One delegated unit's pass as an ITEM of a job settled item by item\n * (AGL-3616) — a `build`, and a site scaffold, which is the build's preset.\n * The runner's spend is the pass's; what the runner came to is the item's\n * row: still running, built (or built without something that failed),\n * failed on our side, or failed on the model's or the workspace's.\n *\n * Shared by both steps, and importing neither, so neither imports the other.\n */\n\n/** What a unit says when it finished without reporting anything. */\nexport const AI_BUILD_UNIT_EMPTY_COPY = 'It could not be built this time.'\n\n/** What a unit's model declining the request says. */\nexport const AI_BUILD_UNIT_REFUSED_COPY = 'The AI declined to build this one.'\n\n/** A runner's outcome narrowed to its spend: no plan, no review, nothing the delegating job keeps. */\nexport function aiUnitSpend(outcome: AiJobStepOutcome): AiJobStepOutcome {\n return {\n outputs: outcome.outputs,\n usage: outcome.usage,\n estCostUsd: outcome.estCostUsd,\n model: outcome.model,\n stopReason: outcome.stopReason,\n ...(outcome.effort ? { effort: outcome.effort } : {}),\n }\n}\n\n/**\n * What a runner's outcome comes to for its item; `null` when the unit\n * reported what it built and the caller decides whether that counts.\n */\nexport function aiUnitFailure(slot: string, outcome: AiJobStepOutcome): AiJobItemOutcome | null {\n const outputs = outcome.outputs.map((output) => output.id)\n if (outcome.refused) {\n return { slot, status: 'failed', failure: { ours: false, reason: 'refused', message: AI_BUILD_UNIT_REFUSED_COPY }, outputs }\n }\n if (outcome.review) {\n // A building rule still broken after its re-ask is ours (AGL-3596); a\n // site at an allowance is the workspace's to change.\n const ours = outcome.review.reason === 'doctrine'\n return {\n slot,\n status: 'failed',\n failure: {\n ours,\n reason: ours ? 'doctrine-refused' : 'review',\n message: outcome.review.message || AI_BUILD_UNIT_EMPTY_COPY,\n ...(outcome.review.detail ? { detail: outcome.review.detail } : {}),\n },\n outputs,\n }\n }\n if (outcome.failure) {\n return { slot, status: 'failed', failure: { ours: true, reason: 'step-failure', message: outcome.failure }, outputs }\n }\n if (outcome.continue) return { slot, status: 'running', outputs }\n if (!outcome.outputs.length) {\n return { slot, status: 'failed', failure: { ours: true, reason: 'step-failure', message: AI_BUILD_UNIT_EMPTY_COPY } }\n }\n return null\n}\n\n/**\n * Whether an error a unit's runner threw is the machine's to retry — a\n * provider that will answer later, or a budget that ended — rather than this\n * item's failure.\n */\nexport function aiUnitErrorRetryable(error: unknown): boolean {\n if (error instanceof AiUpstreamError && error.retryable) return true\n const name = (error as { name?: string } | null)?.name\n return name === 'AbortError' || name === 'TimeoutError'\n}\n\n/**\n * What the build has created that a later unit can name: each delivered\n * creation's record, by its plan name. A creation's first output is the\n * record it wrote.\n */\nexport function aiBuildBuiltRefs(\n units: readonly AiBuildUnit[],\n ledger: readonly AiJobItemLedger[],\n outputs: readonly Pick<AiJobOutput, 'id' | 'label'>[],\n): Map<string, AiSiteBuiltRef> {\n const rows = new Map(ledger.map((row) => [row.slot, row]))\n const built = new Map<string, AiSiteBuiltRef>()\n for (const unit of units) {\n const creation = unit.creation\n const row = rows.get(unit.slot)\n if (!creation || !row || !aiBuildItemDelivered(row) || !row.outputs.length) continue\n if (creation.kind !== 'layout' && creation.kind !== 'form' && creation.kind !== 'component') continue\n const id = row.outputs[0]\n const label = outputs.find((output) => output.id === id)?.label || creation.name\n built.set(creation.name.toLowerCase(), { id, label, kind: creation.kind })\n }\n return built\n}\n"],"names":["aiBuildItemDelivered","AiUpstreamError","AI_BUILD_UNIT_EMPTY_COPY","AI_BUILD_UNIT_REFUSED_COPY","aiUnitSpend","outcome","outputs","usage","estCostUsd","model","stopReason","effort","aiUnitFailure","slot","map","output","id","refused","status","failure","ours","reason","message","review","detail","continue","length","aiUnitErrorRetryable","error","retryable","name","aiBuildBuiltRefs","units","ledger","rows","Map","row","built","unit","creation","get","kind","label","find","set","toLowerCase"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/jobs/ai-build-unit-outcome.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { aiBuildItemDelivered, type AiBuildUnit } from '../model/ai-build-job'\nimport type { AiJobItemLedger, AiJobOutput } from '../model/ai-jobs.types'\nimport { AiUpstreamError } from '../runtime/ai-runtime'\nimport type { AiSiteBuiltRef } from './ai-job-site-step'\nimport type { AiJobItemOutcome, AiJobStepOutcome } from './ai-job-text-step'\n\n/**\n * One delegated unit's pass as an ITEM of a job settled item by item\n * (AGL-3616) — a `build`, and a site scaffold, which is the build's preset.\n * The runner's spend is the pass's; what the runner came to is the item's\n * row: still running, built (or built without something that failed),\n * failed on our side, or failed on the model's or the workspace's.\n *\n * Shared by both steps, and importing neither, so neither imports the other.\n */\n\n/** The resource the data plugin writes a dataset under (AGL-3616). */\nexport const AI_DATASET_DRAFT_RESOURCE = 'dataset'\n\n/** What a unit says when it finished without reporting anything. */\nexport const AI_BUILD_UNIT_EMPTY_COPY = 'It could not be built this time.'\n\n/** What a unit's model declining the request says. */\nexport const AI_BUILD_UNIT_REFUSED_COPY = 'The AI declined to build this one.'\n\n/** A runner's outcome narrowed to its spend: no plan, no review, nothing the delegating job keeps. */\nexport function aiUnitSpend(outcome: AiJobStepOutcome): AiJobStepOutcome {\n return {\n outputs: outcome.outputs,\n usage: outcome.usage,\n estCostUsd: outcome.estCostUsd,\n model: outcome.model,\n stopReason: outcome.stopReason,\n ...(outcome.effort ? { effort: outcome.effort } : {}),\n }\n}\n\n/**\n * What a runner's outcome comes to for its item; `null` when the unit\n * reported what it built and the caller decides whether that counts.\n */\nexport function aiUnitFailure(slot: string, outcome: AiJobStepOutcome): AiJobItemOutcome | null {\n const outputs = outcome.outputs.map((output) => output.id)\n if (outcome.refused) {\n return { slot, status: 'failed', failure: { ours: false, reason: 'refused', message: AI_BUILD_UNIT_REFUSED_COPY }, outputs }\n }\n if (outcome.review) {\n // A building rule still broken after its re-ask is ours (AGL-3596); a\n // site at an allowance is the workspace's to change.\n const ours = outcome.review.reason === 'doctrine'\n return {\n slot,\n status: 'failed',\n failure: {\n ours,\n reason: ours ? 'doctrine-refused' : 'review',\n message: outcome.review.message || AI_BUILD_UNIT_EMPTY_COPY,\n ...(outcome.review.detail ? { detail: outcome.review.detail } : {}),\n },\n outputs,\n }\n }\n if (outcome.failure) {\n return { slot, status: 'failed', failure: { ours: true, reason: 'step-failure', message: outcome.failure }, outputs }\n }\n if (outcome.continue) return { slot, status: 'running', outputs }\n if (!outcome.outputs.length) {\n return { slot, status: 'failed', failure: { ours: true, reason: 'step-failure', message: AI_BUILD_UNIT_EMPTY_COPY } }\n }\n return null\n}\n\n/**\n * Whether an error a unit's runner threw is the machine's to retry — a\n * provider that will answer later, or a budget that ended — rather than this\n * item's failure.\n */\nexport function aiUnitErrorRetryable(error: unknown): boolean {\n if (error instanceof AiUpstreamError && error.retryable) return true\n const name = (error as { name?: string } | null)?.name\n return name === 'AbortError' || name === 'TimeoutError'\n}\n\n/**\n * What the build has created that a later unit can name: each delivered\n * creation's record, by its plan name. A creation's first output is the\n * record it wrote.\n */\nexport function aiBuildBuiltRefs(\n units: readonly AiBuildUnit[],\n ledger: readonly AiJobItemLedger[],\n outputs: readonly (Pick<AiJobOutput, 'id' | 'label'> & Partial<Pick<AiJobOutput, 'draftResource'>>)[],\n): Map<string, AiSiteBuiltRef> {\n const rows = new Map(ledger.map((row) => [row.slot, row]))\n const built = new Map<string, AiSiteBuiltRef>()\n for (const unit of units) {\n const creation = unit.creation\n const row = rows.get(unit.slot)\n if (!row || !aiBuildItemDelivered(row) || !row.outputs.length) continue\n // A build's dataset item (AGL-3616), which the data plugin wrote: a page\n // lists it, or is its record template, by the name the plan gave it.\n if (unit.item) {\n const output = outputs.find((entry) => entry.id === row.outputs[0])\n if (output?.draftResource === AI_DATASET_DRAFT_RESOURCE) {\n built.set(unit.item.name.toLowerCase(), { id: output.id, label: output.label || unit.item.name, kind: 'dataset' })\n }\n continue\n }\n if (!creation) continue\n // A dataset a site start created (AGL-3616) is a record a page names too.\n if (creation.kind !== 'layout' && creation.kind !== 'form' && creation.kind !== 'component' && creation.kind !== 'dataset') continue\n const id = row.outputs[0]\n const label = outputs.find((output) => output.id === id)?.label || creation.name\n built.set(creation.name.toLowerCase(), { id, label, kind: creation.kind })\n }\n return built\n}\n"],"names":["aiBuildItemDelivered","AiUpstreamError","AI_DATASET_DRAFT_RESOURCE","AI_BUILD_UNIT_EMPTY_COPY","AI_BUILD_UNIT_REFUSED_COPY","aiUnitSpend","outcome","outputs","usage","estCostUsd","model","stopReason","effort","aiUnitFailure","slot","map","output","id","refused","status","failure","ours","reason","message","review","detail","continue","length","aiUnitErrorRetryable","error","retryable","name","aiBuildBuiltRefs","units","ledger","rows","Map","row","built","unit","creation","get","item","find","entry","draftResource","set","toLowerCase","label","kind"],"mappings":"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"}
@@ -35,6 +35,9 @@ import { aiPluginDraftAdmissionRefusal, aiPluginDraftWriter } from "./ai-job-plu
35
35
  import { aiSitePageWritten, aiSiteResolvedRef } from "./ai-job-site-step.js";
36
36
  import { AI_LAYOUT_SITE_PAGES_INPUT, aiLayoutSitePagesOfPlan } from "./ai-job-layout-site-pages.js";
37
37
  import { AI_LAYOUT_FORM_PAGE_INPUT, AI_LAYOUT_LANGUAGE_INPUT, aiLayoutFormPageOfPlan } from "./ai-job-page-language.js";
38
+ import { aiDatasetListingsOf } from "./ai-job-site-datasets.js";
39
+ import { AI_FORM_DATASET_MADE_INPUT } from "./ai-job-form-dataset.js";
40
+ import { AI_LAYOUT_LISTINGS_INPUT } from "../layout-language/ai-layout-listings.js";
38
41
  import { AI_JOB_BRIEF_MAX_CHARS } from "./ai-job-text-step.js";
39
42
  import { aiJobPublishesBuild, aiPublishGuidedSite } from "./ai-site-publish.js";
40
43
  import { AI_PLANNED_JOB_KINDS, aiJobStepRunMinimumMs, aiJobStepRunnerFor, registerAiJobStep, registerAiJobStepPasses } from "./ai-jobs.js";
@@ -103,6 +106,7 @@ import { AI_PLANNED_JOB_KINDS, aiJobStepRunMinimumMs, aiJobStepRunnerFor, regist
103
106
  * is built without, and which blocks its sections place.
104
107
  */ export function aiBuildUnitJob(job, unit, context) {
105
108
  var _job_outputs, _plan_labels, _context_briefLines, _ref;
109
+ var _unit_creation, _unitPlan_create_;
106
110
  const plan = job.plan;
107
111
  const built = aiBuildBuiltRefs(context.units, context.ledger, (_job_outputs = job.outputs) != null ? _job_outputs : []);
108
112
  const labels = _extends({}, (_plan_labels = plan.labels) != null ? _plan_labels : {});
@@ -125,7 +129,9 @@ import { AI_PLANNED_JOB_KINDS, aiJobStepRunMinimumMs, aiJobStepRunnerFor, regist
125
129
  unitPlan.create = [
126
130
  _extends({}, unit.creation, {
127
131
  duplicateOf: aiSiteResolvedRef(unit.creation.duplicateOf, built)
128
- })
132
+ }, unit.creation.writesTo ? {
133
+ writesTo: aiSiteResolvedRef(unit.creation.writesTo, built)
134
+ } : {})
129
135
  ];
130
136
  brief.push(`Build the ${unit.creation.kind} “${unit.creation.name}”: ${unit.creation.why}`);
131
137
  }
@@ -187,6 +193,9 @@ import { AI_PLANNED_JOB_KINDS, aiJobStepRunMinimumMs, aiJobStepRunnerFor, regist
187
193
  originJobId: aiOriginJobId(job)
188
194
  });
189
195
  delete inputs[AI_BUILD_PUBLISH_INPUT];
196
+ // A dataset this build made for its form, which the form may bind (AGL-3616).
197
+ const madeFor = ((_unit_creation = unit.creation) == null ? void 0 : _unit_creation.kind) === 'form' && isAiPlanNewRef(unit.creation.writesTo) ? (_unitPlan_create_ = unitPlan.create[0]) == null ? void 0 : _unitPlan_create_.writesTo : null;
198
+ if (madeFor) inputs[AI_FORM_DATASET_MADE_INPUT] = madeFor;
190
199
  // A build's pages and layouts are designed in the layout language and
191
200
  // compiled (AGL-3660), told the pages the build plans and where its form is.
192
201
  if (context.kind === 'page' || context.kind === 'layout') {
@@ -195,6 +204,22 @@ import { AI_PLANNED_JOB_KINDS, aiJobStepRunMinimumMs, aiJobStepRunnerFor, regist
195
204
  if (pages.length) inputs[AI_LAYOUT_SITE_PAGES_INPUT] = pages;
196
205
  const formPage = aiLayoutFormPageOfPlan(plan);
197
206
  if (formPage) inputs[AI_LAYOUT_FORM_PAGE_INPUT] = formPage;
207
+ // The datasets this build made, repeated in the sections that name them (AGL-3616).
208
+ const datasets = [
209
+ ...built.entries()
210
+ ].filter(([, entry])=>entry.kind === 'dataset').map(([name, entry])=>{
211
+ var _ref;
212
+ var _context_units_find;
213
+ return {
214
+ id: entry.id,
215
+ name: (_ref = (_context_units_find = context.units.find((one)=>{
216
+ var _one_item;
217
+ return ((_one_item = one.item) == null ? void 0 : _one_item.name.toLowerCase()) === name;
218
+ })) == null ? void 0 : _context_units_find.label) != null ? _ref : entry.label
219
+ };
220
+ });
221
+ const listings = aiDatasetListingsOf(datasets, plan.screens);
222
+ if (listings.length) inputs[AI_LAYOUT_LISTINGS_INPUT] = listings;
198
223
  }
199
224
  return _extends({}, job, {
200
225
  $id: aiBuildUnitJobId(job, unit),
@@ -270,9 +295,11 @@ export function createAiJobBuildStep(deps = {}) {
270
295
  /** The build's last pass puts its pages live, where it was asked and confirmed. */ const finish = async (outcome, extraPages = [])=>{
271
296
  var _job_outputs;
272
297
  if (!aiJobPublishesBuild(job) || job.sitePublish || !job.hostId) return outcome;
298
+ // A record template renders once per record only once its binding is
299
+ // saved, so it is never published at its own address (AGL-3616).
273
300
  const pageIds = new Set(units.filter((one)=>{
274
301
  var _rows_get;
275
- return one.screen && aiBuildItemDelivered((_rows_get = rows.get(one.slot)) != null ? _rows_get : {
302
+ return one.screen && !one.screen.record && aiBuildItemDelivered((_rows_get = rows.get(one.slot)) != null ? _rows_get : {
276
303
  status: 'pending'
277
304
  });
278
305
  }).flatMap((one)=>{
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/jobs/ai-job-build-step.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { aiJobCancelAsked } from './ai-job-cancel'\nimport type { AglynOrgBilling } from '@aglyn/aglyn/foundation/definitions/org-billing.types'\nimport { resolveEffectivePlan } from '@aglyn/aglyn/app-utils/plan-entitlements'\nimport { resolveOrgIdForHost } from '@aglyn/tenant-data-admin/server/organizations'\nimport {\n AI_BUILD_LIMITS,\n AI_BUILD_PUBLISH_INPUT,\n aiArticle,\n aiBuildCreditRange,\n aiBuildDegradation,\n aiBuildInitialLedger,\n aiBuildItemDelivered,\n aiBuildItemOpen,\n aiBuildNextUnit,\n aiBuildOrder,\n aiBuildPlacedItemLines,\n aiBuildPlanShapeRefusal,\n aiBuildSmaller,\n aiBuildUnits,\n type AiBuildOps,\n type AiBuildUnit,\n} from '../model/ai-build-job'\nimport { isAiPlanNewRef, type AiBuildPlanCreateKind } from '../model/ai-build-plan'\nimport type {\n AiJob,\n AiJobItemFailure,\n AiJobItemLedger,\n AiJobKind,\n AiJobOutput,\n AiJobPlan,\n} from '../model/ai-jobs.types'\nimport { AI_SITE_MAX_SECTIONS } from '../model/ai-site-job'\nimport {\n AI_CREDITS_CONFIRM_CODE,\n aiCreditsPromptFor,\n aiCreditsPromptText,\n type AiCreditRange,\n type AiCreditsPrompt,\n type AiCreditsSmaller,\n} from '../model/ai-credit-estimate'\nimport { aiFreeCreditsNoneLeftText } from '../model/ai-site-job'\nimport { readFreeAiCreditsLeft } from '../usage/free-ai-credits-left'\nimport { aiModelForStep } from '../providers/routing'\nimport {\n AI_BUILD_UNIT_EMPTY_COPY,\n aiBuildBuiltRefs,\n aiUnitErrorRetryable,\n aiUnitFailure,\n aiUnitSpend,\n} from './ai-build-unit-outcome'\nimport { aiBuildOps, type AiBuildOpsContext } from './ai-build-capabilities'\nimport {\n aiJobAdmissionRefusal,\n registerAiJobAdmission,\n type AiJobAdmission,\n type AiJobAdmissionContext,\n type AiJobAdmissionRefusal,\n} from './ai-job-admission'\nimport { aiOriginJobId } from './ai-job-draft-ids'\nimport { readAiDraftNodes } from './ai-job-drafts'\nimport { aiConfirmedPlan, aiUnspentOutcome } from './ai-job-generation'\nimport { AI_JOB_PAGE_STEP_MINIMUM_MS } from './ai-job-page-budget'\nimport {\n aiPluginDraftAdmissionRefusal,\n aiPluginDraftWriter,\n type AiPluginDraftWriterLookup,\n} from './ai-job-plugin-drafts'\nimport { aiSitePageWritten, aiSiteResolvedRef } from './ai-job-site-step'\nimport { AI_LAYOUT_SITE_PAGES_INPUT, aiLayoutSitePagesOfPlan } from './ai-job-layout-site-pages'\nimport { AI_LAYOUT_FORM_PAGE_INPUT, AI_LAYOUT_LANGUAGE_INPUT, aiLayoutFormPageOfPlan } from './ai-job-page-language'\nimport {\n AI_JOB_BRIEF_MAX_CHARS,\n type AiJobItemOutcome,\n type AiJobStepOutcome,\n type AiJobStepRunner,\n} from './ai-job-text-step'\nimport { aiJobPublishesBuild, aiPublishGuidedSite } from './ai-site-publish'\nimport {\n AI_PLANNED_JOB_KINDS,\n aiJobStepRunMinimumMs,\n aiJobStepRunnerFor,\n registerAiJobStep,\n registerAiJobStepPasses,\n} from './ai-jobs'\n\n/**\n * The build step (AGL-3616): the generation step of a `build` job, run once\n * the member confirmed the plan their request produced.\n *\n * Like the site scaffold it generalizes, it builds nothing itself and asks no\n * model of its own. Each pass takes the next unit in dependency order and\n * hands it to what builds that kind of thing — a page, layout, form,\n * component, email design or template to this plugin's own step, under a job\n * derived for the unit; another plugin's resource to that plugin's writer on\n * the resource-draft seam, with the content the owner's capability derives\n * from the item's arguments. One unit, one pass, one recorded spend.\n *\n * ── Settled item by item ────────────────────────────────────────────────\n *\n * Where a unit stands is read from the job's ITEM LEDGER, never from counting\n * outputs: the machine writes each pass's row in the transaction that\n * records its spend (`recordStep`). A unit that fails is a FAILED ROW, not a\n * failed job: the pass reports it, the machine gives back that item's spend\n * where the failure was ours, and the next pass builds the next unit. What\n * depended on it is built without it, or skipped where it cannot stand\n * without it (`aiBuildDegradation`). The machine ends the job when nothing is\n * left: `done` when anything was delivered, `failed` — its planning given\n * back too — when nothing was.\n *\n * ── Drafts, unless asked and confirmed ───────────────────────────────────\n *\n * Every unit writes the draft its own kind writes, which nothing publishes.\n * Only a build whose request asked to publish AND whose member ticked the\n * plan card's box puts its built pages live, once, on its last pass, through\n * the guided start's publish.\n */\n\n/** What a build answers with no confirmed plan to build. */\nexport const AI_BUILD_NO_PLAN_COPY = 'This build has no confirmed plan to build.'\n\n/** What a unit says when nothing on this site builds its operation any more. */\nexport const aiBuildUnavailableCopy = (noun: string): string =>\n `Not built: ${aiArticle(noun)} cannot be made on this site right now.`\n\n\n/** What a page that was reported built but holds none of its plan says. */\nexport const AI_BUILD_PAGE_NOT_WRITTEN_COPY = 'The page was not written from its plan.'\n\n\n/**\n * The most passes a build's step may take: every unit at a page's worst — its\n * sections and its listing — so a runner that never finishes is still\n * bounded while the largest plan is not. Try again starts the count over.\n */\nexport const AI_BUILD_MAX_PASSES = AI_BUILD_LIMITS.units * (AI_SITE_MAX_SECTIONS + 1)\n\n/** The job kind a creation of the build is built by. */\nconst CREATION_JOB_KINDS: Partial<Record<AiBuildPlanCreateKind, AiJobKind>> = {\n layout: 'layout',\n form: 'form',\n component: 'component',\n email: 'email',\n}\n\n/** The job kind a unit is built by, where an AI runner builds it. */\nexport function aiBuildUnitJobKind(unit: AiBuildUnit, ops: AiBuildOps): AiJobKind | null {\n if (unit.screen) return 'page'\n if (unit.creation) return CREATION_JOB_KINDS[unit.creation.kind] ?? null\n const runnerKind = ops.get(unit.op)?.runnerKind\n return runnerKind ? (runnerKind as AiJobKind) : null\n}\n\n/** The id a unit's job, and so its draft, is named by. */\nexport function aiBuildUnitJobId(job: Pick<AiJob, '$id'>, unit: AiBuildUnit): string {\n return unit.creation?.id ?? unit.screen?.id ?? unit.item?.id ?? `${job.$id}-${unit.slot}`\n}\n\n/**\n * The job a unit is built under (generalizing `aiSiteUnitJob`): this job's\n * org, site, creator and model; the kind that builds the unit; a plan\n * narrowed to the unit, its `new:` references resolved to what was built and\n * the failed ones left out; and a brief that says what the unit is, what it\n * is built without, and which blocks its sections place.\n */\nexport function aiBuildUnitJob(\n job: AiJob,\n unit: AiBuildUnit,\n context: {\n kind: AiJobKind\n units: readonly AiBuildUnit[]\n ledger: readonly AiJobItemLedger[]\n ops: AiBuildOps\n briefLines?: readonly string[]\n },\n): AiJob {\n const plan = job.plan as AiJobPlan\n const built = aiBuildBuiltRefs(context.units, context.ledger, job.outputs ?? [])\n const labels = { ...(plan.labels ?? {}) }\n for (const entry of built.values()) labels[entry.id] = entry.label\n const brief = [job.brief.trim()]\n const unitPlan: AiJobPlan = { ...plan, labels, reuse: [...plan.reuse], create: [], screens: [] }\n delete unitPlan.items\n const placedByScreens = new Set(plan.screens.flatMap((screen) => screen.sections.flatMap((section) => section.uses)))\n if (unit.creation) {\n unitPlan.reuse = plan.reuse.filter((entry) => !placedByScreens.has(entry.id))\n unitPlan.create = [{ ...unit.creation, duplicateOf: aiSiteResolvedRef(unit.creation.duplicateOf, built) }]\n brief.push(`Build the ${unit.creation.kind} “${unit.creation.name}”: ${unit.creation.why}`)\n }\n if (unit.screen) {\n const screen = unit.screen\n for (const entry of built.values()) {\n unitPlan.reuse.push({ kind: entry.kind, id: entry.id, purpose: `the ${entry.kind} this request built` })\n }\n let builtLayout: string | null = null\n for (const entry of built.values()) if (entry.kind === 'layout') builtLayout = builtLayout ?? entry.id\n unitPlan.screens = [\n {\n ...screen,\n // A page whose layout failed renders inside the site's own: the page\n // step falls back to it when the plan names none.\n layout: aiSiteResolvedRef(screen.layout, built) ?? (isAiPlanNewRef(screen.layout) ? builtLayout : null),\n template: aiSiteResolvedRef(screen.template, built),\n duplicateOf: aiSiteResolvedRef(screen.duplicateOf, built),\n record: screen.record\n ? { ...screen.record, dataset: aiSiteResolvedRef(screen.record.dataset, built) ?? screen.record.dataset }\n : null,\n sections: screen.sections.map((section) => ({\n ...section,\n uses: section.uses\n .map((ref) => aiSiteResolvedRef(ref, built))\n .filter((ref): ref is string => !!ref),\n })),\n },\n ]\n brief.push(`Build the page “${screen.title}”, at ${screen.slug}.`)\n brief.push(...aiBuildPlacedItemLines(unit, { units: context.units, ledger: context.ledger, ops: context.ops }))\n }\n const item = unit.item\n if (item) {\n const noun = context.ops.get(item.op)?.noun ?? item.op\n brief.push(`Build the ${noun} “${item.name}”${item.why ? `: ${item.why}` : '.'}`)\n // A planned kind's step builds the plan's first creation of its kind.\n unitPlan.create = AI_PLANNED_JOB_KINDS.includes(context.kind)\n ? [{ kind: context.kind as AiBuildPlanCreateKind, name: item.name, why: item.why, duplicateOf: null, fields: [], ...(item.id ? { id: item.id } : {}) }]\n : []\n }\n brief.push(...(context.briefLines ?? []))\n const inputs: Record<string, unknown> = {\n ...job.inputs,\n ...(item?.args ?? {}),\n originJobId: aiOriginJobId(job),\n }\n delete inputs[AI_BUILD_PUBLISH_INPUT]\n // A build's pages and layouts are designed in the layout language and\n // compiled (AGL-3660), told the pages the build plans and where its form is.\n if (context.kind === 'page' || context.kind === 'layout') {\n inputs[AI_LAYOUT_LANGUAGE_INPUT] = true\n const pages = aiLayoutSitePagesOfPlan(plan.screens)\n if (pages.length) inputs[AI_LAYOUT_SITE_PAGES_INPUT] = pages\n const formPage = aiLayoutFormPageOfPlan(plan)\n if (formPage) inputs[AI_LAYOUT_FORM_PAGE_INPUT] = formPage\n }\n return {\n ...job,\n $id: aiBuildUnitJobId(job, unit),\n kind: context.kind,\n steps: [],\n outputs: [],\n items: null,\n plan: item && !AI_PLANNED_JOB_KINDS.includes(context.kind) ? null : unitPlan,\n inputs,\n brief: brief.join('\\n').slice(0, AI_JOB_BRIEF_MAX_CHARS),\n }\n}\n\n/** The unit's failure, for its row: ours or not, why, in customer-safe words. */\nfunction failed(\n slot: string,\n failure: AiJobItemFailure,\n extra: Partial<AiJobItemOutcome> = {},\n): AiJobItemOutcome {\n return { slot, status: 'failed', failure, ...extra }\n}\n\nexport interface AiJobBuildStepDeps {\n /** The runner registry; specs hand in fakes. */\n runnerFor?: typeof aiJobStepRunnerFor\n /** The draft writer registry; specs hand in fakes. */\n writerFor?: AiPluginDraftWriterLookup\n /** The operations this site may use; the registry and its gates otherwise. */\n opsFor?: (context: AiBuildOpsContext) => Promise<AiBuildOps>\n /** A runner kind's own admission, asked before its item runs; the registry's otherwise. */\n admissionFor?: typeof aiJobAdmissionRefusal\n /** Another plugin's admission for its writer; the seam's otherwise. */\n pluginAdmission?: typeof aiPluginDraftAdmissionRefusal\n /** The draft reader a built page is checked through. */\n readNodes?: typeof readAiDraftNodes\n /** The publish a build asked for and confirmed. */\n publish?: typeof aiPublishGuidedSite\n}\n\n/** Whether a build's workspace spends the Free taste. */\nexport function aiBuildFreeTaste(org: object | null | undefined): boolean {\n return Boolean(org) && resolveEffectivePlan(org as never) === 'free'\n}\n\n/** The site document a gate reads, or `null`. */\nasync function readHost(firestore: FirebaseFirestore.Firestore, hostId: string | null) {\n if (!hostId) return null\n return ((await firestore.collection('hosts').doc(hostId).get()).data() ?? null) as Record<string, unknown> | null\n}\n\nexport function createAiJobBuildStep(deps: AiJobBuildStepDeps = {}): AiJobStepRunner {\n const runnerFor = deps.runnerFor ?? aiJobStepRunnerFor\n const writerFor = deps.writerFor ?? aiPluginDraftWriter\n const opsFor = deps.opsFor ?? ((context) => aiBuildOps(context))\n const admissionFor = deps.admissionFor ?? aiJobAdmissionRefusal\n const pluginAdmission = deps.pluginAdmission ?? aiPluginDraftAdmissionRefusal\n const readNodes = deps.readNodes ?? readAiDraftNodes\n const publish = deps.publish ?? aiPublishGuidedSite\n\n return async (context): Promise<AiJobStepOutcome> => {\n const { job, firestore } = context\n const model = context.modelFor?.('job.plan') ?? aiModelForStep('job.plan')\n const plan = aiConfirmedPlan(job)\n if (!plan) return { ...aiUnspentOutcome(model), failure: AI_BUILD_NO_PLAN_COPY }\n const org = (context.org ?? null) as Partial<AglynOrgBilling> | null\n const units = aiBuildUnits(plan)\n const ordered = aiBuildOrder(units) ?? units\n const starting = !job.items?.length\n const ledger = starting ? aiBuildInitialLedger(units) : (job.items as AiJobItemLedger[])\n const init = starting ? { items: ledger } : {}\n const unit = aiBuildNextUnit(ordered, ledger)\n const rows = new Map(ledger.map((row) => [row.slot, row]))\n const host = await readHost(firestore, job.hostId ?? null)\n const ops = await opsFor({\n orgId: job.orgId,\n hostId: job.hostId ?? null,\n org,\n host,\n freeTaste: aiBuildFreeTaste(org),\n })\n\n /** Whether units other than this one are still to build. */\n const othersOpen = (slot: string) =>\n ordered.some((one) => one.slot !== slot && aiBuildItemOpen(rows.get(one.slot) ?? { status: 'pending' }))\n\n /** The build's last pass puts its pages live, where it was asked and confirmed. */\n const finish = async (outcome: AiJobStepOutcome, extraPages: readonly AiJobOutput[] = []): Promise<AiJobStepOutcome> => {\n if (!aiJobPublishesBuild(job) || job.sitePublish || !job.hostId) return outcome\n const pageIds = new Set(\n units\n .filter((one) => one.screen && aiBuildItemDelivered(rows.get(one.slot) ?? { status: 'pending' }))\n .flatMap((one) => rows.get(one.slot)?.outputs ?? []),\n )\n const pages = [\n ...(job.outputs ?? []).filter((output) => output.resource === 'screen' && pageIds.has(output.id)),\n ...extraPages,\n ]\n if (!pages.length) return outcome\n // A canceled build never puts anything live (AGL-3616): its pages stay drafts.\n if (await aiJobCancelAsked(firestore, job, context.signal)) return outcome\n const sitePublish = await publish(firestore, { job, outputs: pages, now: context.now }).catch((error: unknown) => {\n console.error('ai build publish threw', { orgId: job.orgId, jobId: job.$id, error })\n return null\n })\n return sitePublish ? { ...outcome, sitePublish } : outcome\n }\n\n if (!unit) return finish({ ...aiUnspentOutcome(model), ...init })\n\n const settle = (item: AiJobItemOutcome, spent: AiJobStepOutcome = aiUnspentOutcome(model)): AiJobStepOutcome => ({\n ...spent,\n ...init,\n item,\n ...(item.status === 'running' || othersOpen(unit.slot) ? { continue: true } : {}),\n })\n\n // What its dependencies came to.\n const degradation = aiBuildDegradation(unit, { units, ledger, ops })\n if (degradation.skip) {\n return settle({ slot: unit.slot, status: 'skipped', note: degradation.skip, degradedBy: degradation.degradedBy })\n }\n const capability = ops.get(unit.op)\n const noun = capability?.noun ?? unit.op\n if (!capability) return settle({ slot: unit.slot, status: 'skipped', note: aiBuildUnavailableCopy(noun) })\n const degraded = degradation.degradedBy.length > 0\n const note = degradation.notes.length ? degradation.notes.join(' ') : null\n\n // Another plugin's resource: its writer, with the content its capability derives.\n if (capability.draftResource) {\n const item = unit.item\n const writer = writerFor(capability.draftResource)\n if (!item || !writer || !job.hostId) {\n return settle({ slot: unit.slot, status: 'skipped', note: aiBuildUnavailableCopy(noun) })\n }\n const admission: AiJobAdmissionContext = {\n firestore,\n orgId: job.orgId,\n hostId: job.hostId,\n inputs: {},\n org,\n uid: job.createdBy,\n }\n const refusal = await pluginAdmission(admission, {\n kind: 'build',\n drafts: [{ resource: capability.draftResource, label: capability.noun }],\n writerFor,\n })\n if (refusal) return settle({ slot: unit.slot, status: 'skipped', note: `Not built: ${refusal.error}` })\n const dependencies: Record<string, { op: string; id: string }> = {}\n for (const slot of unit.deps) {\n const dep = units.find((one) => one.slot === slot)\n const row = rows.get(slot)\n if (!dep || !row || !aiBuildItemDelivered(row) || !row.outputs.length) continue\n dependencies[`new:${dep.label}`] = { op: dep.op, id: row.outputs[0] }\n }\n const content = capability.draftContent?.({ name: item.name, args: item.args }, { hostId: job.hostId, dependencies }) ?? item.args\n const checked = writer.check(content, { hostId: job.hostId })\n if (checked.ok === false) {\n return settle(\n failed(unit.slot, { ours: true, reason: 'step-failure', message: checked.problems[0] ?? AI_BUILD_UNIT_EMPTY_COPY }),\n )\n }\n const id = aiBuildUnitJobId(job, unit)\n const written = await writer.write({\n orgId: job.orgId,\n hostId: job.hostId,\n uid: job.createdBy,\n org,\n now: context.now,\n id,\n name: item.name,\n content,\n })\n if (written.ok === false) {\n return settle(failed(unit.slot, { ours: false, reason: 'review', message: written.error }))\n }\n const output: AiJobOutput = {\n resource: 'draft',\n id: written.id,\n versionId: written.versionId,\n hostId: job.hostId,\n label: written.name,\n draftResource: capability.draftResource,\n note: `A draft, in ${capability.where}.`,\n }\n return settle(\n {\n slot: unit.slot,\n status: degraded ? 'degraded' : 'succeeded',\n outputs: [written.id],\n note,\n ...(degraded ? { degradedBy: degradation.degradedBy } : {}),\n },\n { ...aiUnspentOutcome(model), outputs: [output] },\n )\n }\n\n // This plugin's own runner, under a job derived for the unit.\n const kind = aiBuildUnitJobKind(unit, ops)\n const runner = kind ? runnerFor(kind) : null\n if (!kind || !runner) return settle({ slot: unit.slot, status: 'skipped', note: aiBuildUnavailableCopy(noun) })\n const derived = aiBuildUnitJob(job, unit, { kind, units, ledger, ops, briefLines: degradation.briefLines })\n // An item's kind is asked its own admission first (a campaign's plan,\n // a template's subject), once, before its first pass.\n if (unit.item && rows.get(unit.slot)?.status !== 'running') {\n const refusal = await admissionFor(kind, {\n firestore,\n orgId: job.orgId,\n hostId: job.hostId ?? null,\n inputs: derived.inputs,\n org,\n uid: job.createdBy,\n }).catch((error: unknown) => {\n console.error('ai build item admission failed', { orgId: job.orgId, jobId: job.$id, slot: unit.slot, error })\n return { status: 403 as const, error: AI_BUILD_UNIT_EMPTY_COPY }\n })\n if (refusal) return settle({ slot: unit.slot, status: 'skipped', note: `Not built: ${refusal.error}` })\n }\n\n let outcome: AiJobStepOutcome\n try {\n outcome = await runner({ ...context, job: derived })\n } catch (error) {\n // A provider that will answer later is the machine's to retry; anything\n // else is this item's failure, and the build goes on.\n if (aiUnitErrorRetryable(error)) throw error\n console.error('ai build unit threw', { orgId: job.orgId, jobId: job.$id, slot: unit.slot, error })\n return settle(failed(unit.slot, { ours: true, reason: 'provider', message: AI_BUILD_UNIT_EMPTY_COPY }))\n }\n const spent = aiUnitSpend(outcome)\n const ids = outcome.outputs.map((output) => output.id)\n const stopped = aiUnitFailure(unit.slot, outcome)\n if (stopped) return settle(stopped, spent)\n // A page counts as built only when its plan's sections are in it (AGL-3596).\n if (unit.screen && job.hostId) {\n const page = outcome.outputs.find((output) => output.resource === 'screen')\n const written =\n page !== undefined &&\n (await aiSitePageWritten(\n firestore,\n { hostId: job.hostId, unitJobId: derived.$id, screen: unit.screen, draftId: page.id },\n readNodes,\n ))\n if (!written) {\n return settle(\n failed(unit.slot, { ours: true, reason: 'step-failure', message: AI_BUILD_PAGE_NOT_WRITTEN_COPY }),\n { ...spent, outputs: outcome.outputs.filter((output) => output.resource !== 'screen') },\n )\n }\n }\n const done = settle(\n {\n slot: unit.slot,\n status: degraded ? 'degraded' : 'succeeded',\n outputs: ids,\n note,\n ...(degraded ? { degradedBy: degradation.degradedBy } : {}),\n },\n spent,\n )\n if (done.continue) return done\n // The last unit: what was built goes live where it was asked and confirmed.\n rows.set(unit.slot, { ...(rows.get(unit.slot) as AiJobItemLedger), status: degraded ? 'degraded' : 'succeeded', outputs: ids })\n return finish(done, unit.screen ? outcome.outputs.filter((output) => output.resource === 'screen') : [])\n }\n}\n\nexport const runAiJobBuildStep = createAiJobBuildStep()\n\n/**\n * The least time a build's next pass needs: what the step that builds its\n * next unit registers for the job derived for it; a page pass's when the\n * next unit is another plugin's draft, which asks no model.\n */\nexport function aiBuildJobRunMinimumMs(job: AiJob): number {\n const plan = aiConfirmedPlan(job)\n if (!plan) return AI_JOB_PAGE_STEP_MINIMUM_MS\n const units = aiBuildUnits(plan)\n const ordered = aiBuildOrder(units) ?? units\n const ledger = job.items?.length ? job.items : aiBuildInitialLedger(units)\n const unit = aiBuildNextUnit(ordered, ledger)\n if (!unit) return AI_JOB_PAGE_STEP_MINIMUM_MS\n const kind: AiJobKind | null = unit.screen\n ? 'page'\n : unit.creation\n ? (CREATION_JOB_KINDS[unit.creation.kind] ?? null)\n : (AI_BUILD_ITEM_RUNNER_KINDS[unit.op] ?? null)\n if (!kind) return AI_JOB_PAGE_STEP_MINIMUM_MS\n return aiJobStepRunMinimumMs(aiBuildUnitJob(job, unit, { kind, units, ledger, ops: new Map() }))\n}\n\n/** The runner kinds this plugin's own item operations use, for the time a pass needs without the registry. */\nconst AI_BUILD_ITEM_RUNNER_KINDS: Readonly<Record<string, AiJobKind>> = {\n template: 'template',\n campaign: 'campaign',\n workflow: 'workflow',\n function: 'logic',\n edit: 'edit',\n}\n\n/**\n * What a Free build's credits say before it runs (AGL-3722), on its measured\n * p90 rather than its ceiling: `null` when what is left this month covers the\n * p90 — or when nothing is known about what is left, since each pass's\n * reservation still decides — and `null` too for a build the person chose\n * to build as far as it goes (`confirmed`), whose prompt `onConfirmed` is\n * told so the door records it. Otherwise a 409 carrying the prompt: the\n * range, what is left, and the smaller first build. Nothing left at all is a\n * 429. Read off the same two walls the reservation refuses at\n * (`readFreeAiCreditsLeft`), net of give-backs.\n */\nexport async function aiBuildFreeCreditsRefusal(input: {\n firestore: FirebaseFirestore.Firestore\n orgId: string\n org: object | null\n range: AiCreditRange\n smaller?: AiCreditsSmaller | null\n confirmed?: boolean\n onConfirmed?: (prompt: AiCreditsPrompt) => void\n now: Date\n freeCreditsLeft?: typeof readFreeAiCreditsLeft\n}): Promise<AiJobAdmissionRefusal | null> {\n const read = input.freeCreditsLeft ?? readFreeAiCreditsLeft\n const credits = await read(input.firestore, { orgId: input.orgId, org: input.org, now: input.now })\n if (!credits) return null\n if (credits.left <= 0) return { status: 429, error: aiFreeCreditsNoneLeftText(credits.resetsOn) }\n const prompt = aiCreditsPromptFor(input.range, credits, input.smaller ?? null)\n if (!prompt) return null\n if (!input.confirmed) {\n return { status: 409, error: aiCreditsPromptText(prompt, 'build'), code: AI_CREDITS_CONFIRM_CODE, credits: prompt }\n }\n input.onConfirmed?.(prompt)\n return null\n}\n\nexport interface AiBuildAdmissionDeps {\n opsFor?: (context: AiBuildOpsContext) => Promise<AiBuildOps>\n freeCreditsLeft?: typeof readFreeAiCreditsLeft\n ownerOf?: typeof resolveOrgIdForHost\n now?: () => Date\n}\n\n/**\n * A build is admitted for a site of the job's own org where a page can be\n * built; and confirmed only for a plan it can build here — its shape, its\n * operations as this site has them, and on the Free taste a measured p90\n * the month's Free credits still cover — or the person's go-ahead to build\n * what fits (AGL-3722).\n */\nexport function createAiBuildJobAdmission(deps: AiBuildAdmissionDeps = {}): AiJobAdmission {\n const opsFor = deps.opsFor ?? ((context) => aiBuildOps(context))\n const ownerOf = deps.ownerOf ?? resolveOrgIdForHost\n return async (context) => {\n if (!context.hostId) return { status: 400, error: 'Open the site to build on before asking Assist to build' }\n const owner = await ownerOf(context.hostId)\n if (!owner || owner !== context.orgId) return { status: 404, error: 'Unknown site' }\n if (!aiJobStepRunnerFor('page')) return { status: 400, error: 'Building from a request is not available yet.' }\n const plan = context.plan\n if (!plan) return null\n const org = context.org as Partial<AglynOrgBilling> | null\n const freeTaste = aiBuildFreeTaste(org)\n const host = await readHost(context.firestore, context.hostId)\n const ops = await opsFor({ orgId: context.orgId, hostId: context.hostId, org, host, freeTaste })\n const shape = aiBuildPlanShapeRefusal(plan, { freeTaste, ops })\n if (shape) return { status: 400, error: shape }\n if (freeTaste) {\n const refusal = await aiBuildFreeCreditsRefusal({\n firestore: context.firestore,\n orgId: context.orgId,\n org,\n range: aiBuildCreditRange(plan, { ops }),\n smaller: aiBuildSmaller(plan, ops),\n confirmed: context.creditsConfirmed === true,\n onConfirmed: context.onCreditsConfirmed,\n now: deps.now?.() ?? new Date(),\n freeCreditsLeft: deps.freeCreditsLeft,\n })\n if (refusal) return refusal\n }\n return null\n }\n}\n\nexport const aiBuildJobAdmission = createAiBuildJobAdmission()\n\n/**\n * Registers the build with the least time a pass needs, the time its next\n * pass needs, the passes its largest plan may take, and its admission.\n */\nexport function registerAiBuildJob(): void {\n registerAiJobStep('build', runAiJobBuildStep, {\n minimumMs: AI_JOB_PAGE_STEP_MINIMUM_MS,\n minimumMsFor: aiBuildJobRunMinimumMs,\n })\n registerAiJobStepPasses('build', AI_BUILD_MAX_PASSES)\n registerAiJobAdmission('build', aiBuildJobAdmission)\n}\n"],"names":["aiJobCancelAsked","resolveEffectivePlan","resolveOrgIdForHost","AI_BUILD_LIMITS","AI_BUILD_PUBLISH_INPUT","aiArticle","aiBuildCreditRange","aiBuildDegradation","aiBuildInitialLedger","aiBuildItemDelivered","aiBuildItemOpen","aiBuildNextUnit","aiBuildOrder","aiBuildPlacedItemLines","aiBuildPlanShapeRefusal","aiBuildSmaller","aiBuildUnits","isAiPlanNewRef","AI_SITE_MAX_SECTIONS","AI_CREDITS_CONFIRM_CODE","aiCreditsPromptFor","aiCreditsPromptText","aiFreeCreditsNoneLeftText","readFreeAiCreditsLeft","aiModelForStep","AI_BUILD_UNIT_EMPTY_COPY","aiBuildBuiltRefs","aiUnitErrorRetryable","aiUnitFailure","aiUnitSpend","aiBuildOps","aiJobAdmissionRefusal","registerAiJobAdmission","aiOriginJobId","readAiDraftNodes","aiConfirmedPlan","aiUnspentOutcome","AI_JOB_PAGE_STEP_MINIMUM_MS","aiPluginDraftAdmissionRefusal","aiPluginDraftWriter","aiSitePageWritten","aiSiteResolvedRef","AI_LAYOUT_SITE_PAGES_INPUT","aiLayoutSitePagesOfPlan","AI_LAYOUT_FORM_PAGE_INPUT","AI_LAYOUT_LANGUAGE_INPUT","aiLayoutFormPageOfPlan","AI_JOB_BRIEF_MAX_CHARS","aiJobPublishesBuild","aiPublishGuidedSite","AI_PLANNED_JOB_KINDS","aiJobStepRunMinimumMs","aiJobStepRunnerFor","registerAiJobStep","registerAiJobStepPasses","AI_BUILD_NO_PLAN_COPY","aiBuildUnavailableCopy","noun","AI_BUILD_PAGE_NOT_WRITTEN_COPY","AI_BUILD_MAX_PASSES","units","CREATION_JOB_KINDS","layout","form","component","email","aiBuildUnitJobKind","unit","ops","screen","creation","kind","runnerKind","get","op","aiBuildUnitJobId","job","id","item","$id","slot","aiBuildUnitJob","context","plan","built","ledger","outputs","labels","entry","values","label","brief","trim","unitPlan","reuse","create","screens","items","placedByScreens","Set","flatMap","sections","section","uses","filter","has","duplicateOf","push","name","why","purpose","builtLayout","template","record","dataset","map","ref","title","slug","includes","fields","briefLines","inputs","args","originJobId","pages","length","formPage","steps","join","slice","failed","failure","extra","status","aiBuildFreeTaste","org","Boolean","readHost","firestore","hostId","collection","doc","data","createAiJobBuildStep","deps","runnerFor","writerFor","opsFor","admissionFor","pluginAdmission","readNodes","publish","rows","model","modelFor","ordered","starting","init","Map","row","host","orgId","freeTaste","othersOpen","some","one","finish","outcome","extraPages","sitePublish","pageIds","output","resource","signal","now","catch","error","console","jobId","settle","spent","continue","degradation","skip","note","degradedBy","capability","degraded","notes","draftResource","writer","admission","uid","createdBy","refusal","drafts","dependencies","dep","find","content","draftContent","checked","check","ok","ours","reason","message","problems","written","write","versionId","where","runner","derived","ids","stopped","page","undefined","unitJobId","draftId","done","set","runAiJobBuildStep","aiBuildJobRunMinimumMs","AI_BUILD_ITEM_RUNNER_KINDS","campaign","workflow","function","edit","aiBuildFreeCreditsRefusal","input","read","freeCreditsLeft","credits","left","resetsOn","prompt","range","smaller","confirmed","code","onConfirmed","createAiBuildJobAdmission","ownerOf","owner","shape","creditsConfirmed","onCreditsConfirmed","Date","aiBuildJobAdmission","registerAiBuildJob","minimumMs","minimumMsFor"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/jobs/ai-job-build-step.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { aiJobCancelAsked } from './ai-job-cancel'\nimport type { AglynOrgBilling } from '@aglyn/aglyn/foundation/definitions/org-billing.types'\nimport { resolveEffectivePlan } from '@aglyn/aglyn/app-utils/plan-entitlements'\nimport { resolveOrgIdForHost } from '@aglyn/tenant-data-admin/server/organizations'\nimport {\n AI_BUILD_LIMITS,\n AI_BUILD_PUBLISH_INPUT,\n aiArticle,\n aiBuildCreditRange,\n aiBuildDegradation,\n aiBuildInitialLedger,\n aiBuildItemDelivered,\n aiBuildItemOpen,\n aiBuildNextUnit,\n aiBuildOrder,\n aiBuildPlacedItemLines,\n aiBuildPlanShapeRefusal,\n aiBuildSmaller,\n aiBuildUnits,\n type AiBuildOps,\n type AiBuildUnit,\n} from '../model/ai-build-job'\nimport { isAiPlanNewRef, type AiBuildPlanCreateKind } from '../model/ai-build-plan'\nimport type {\n AiJob,\n AiJobItemFailure,\n AiJobItemLedger,\n AiJobKind,\n AiJobOutput,\n AiJobPlan,\n} from '../model/ai-jobs.types'\nimport { AI_SITE_MAX_SECTIONS } from '../model/ai-site-job'\nimport {\n AI_CREDITS_CONFIRM_CODE,\n aiCreditsPromptFor,\n aiCreditsPromptText,\n type AiCreditRange,\n type AiCreditsPrompt,\n type AiCreditsSmaller,\n} from '../model/ai-credit-estimate'\nimport { aiFreeCreditsNoneLeftText } from '../model/ai-site-job'\nimport { readFreeAiCreditsLeft } from '../usage/free-ai-credits-left'\nimport { aiModelForStep } from '../providers/routing'\nimport {\n AI_BUILD_UNIT_EMPTY_COPY,\n aiBuildBuiltRefs,\n aiUnitErrorRetryable,\n aiUnitFailure,\n aiUnitSpend,\n} from './ai-build-unit-outcome'\nimport { aiBuildOps, type AiBuildOpsContext } from './ai-build-capabilities'\nimport {\n aiJobAdmissionRefusal,\n registerAiJobAdmission,\n type AiJobAdmission,\n type AiJobAdmissionContext,\n type AiJobAdmissionRefusal,\n} from './ai-job-admission'\nimport { aiOriginJobId } from './ai-job-draft-ids'\nimport { readAiDraftNodes } from './ai-job-drafts'\nimport { aiConfirmedPlan, aiUnspentOutcome } from './ai-job-generation'\nimport { AI_JOB_PAGE_STEP_MINIMUM_MS } from './ai-job-page-budget'\nimport {\n aiPluginDraftAdmissionRefusal,\n aiPluginDraftWriter,\n type AiPluginDraftWriterLookup,\n} from './ai-job-plugin-drafts'\nimport { aiSitePageWritten, aiSiteResolvedRef } from './ai-job-site-step'\nimport { AI_LAYOUT_SITE_PAGES_INPUT, aiLayoutSitePagesOfPlan } from './ai-job-layout-site-pages'\nimport { AI_LAYOUT_FORM_PAGE_INPUT, AI_LAYOUT_LANGUAGE_INPUT, aiLayoutFormPageOfPlan } from './ai-job-page-language'\nimport { aiDatasetListingsOf } from './ai-job-site-datasets'\nimport { AI_FORM_DATASET_MADE_INPUT } from './ai-job-form-dataset'\nimport { AI_LAYOUT_LISTINGS_INPUT } from '../layout-language/ai-layout-listings'\nimport {\n AI_JOB_BRIEF_MAX_CHARS,\n type AiJobItemOutcome,\n type AiJobStepOutcome,\n type AiJobStepRunner,\n} from './ai-job-text-step'\nimport { aiJobPublishesBuild, aiPublishGuidedSite } from './ai-site-publish'\nimport {\n AI_PLANNED_JOB_KINDS,\n aiJobStepRunMinimumMs,\n aiJobStepRunnerFor,\n registerAiJobStep,\n registerAiJobStepPasses,\n} from './ai-jobs'\n\n/**\n * The build step (AGL-3616): the generation step of a `build` job, run once\n * the member confirmed the plan their request produced.\n *\n * Like the site scaffold it generalizes, it builds nothing itself and asks no\n * model of its own. Each pass takes the next unit in dependency order and\n * hands it to what builds that kind of thing — a page, layout, form,\n * component, email design or template to this plugin's own step, under a job\n * derived for the unit; another plugin's resource to that plugin's writer on\n * the resource-draft seam, with the content the owner's capability derives\n * from the item's arguments. One unit, one pass, one recorded spend.\n *\n * ── Settled item by item ────────────────────────────────────────────────\n *\n * Where a unit stands is read from the job's ITEM LEDGER, never from counting\n * outputs: the machine writes each pass's row in the transaction that\n * records its spend (`recordStep`). A unit that fails is a FAILED ROW, not a\n * failed job: the pass reports it, the machine gives back that item's spend\n * where the failure was ours, and the next pass builds the next unit. What\n * depended on it is built without it, or skipped where it cannot stand\n * without it (`aiBuildDegradation`). The machine ends the job when nothing is\n * left: `done` when anything was delivered, `failed` — its planning given\n * back too — when nothing was.\n *\n * ── Drafts, unless asked and confirmed ───────────────────────────────────\n *\n * Every unit writes the draft its own kind writes, which nothing publishes.\n * Only a build whose request asked to publish AND whose member ticked the\n * plan card's box puts its built pages live, once, on its last pass, through\n * the guided start's publish.\n */\n\n/** What a build answers with no confirmed plan to build. */\nexport const AI_BUILD_NO_PLAN_COPY = 'This build has no confirmed plan to build.'\n\n/** What a unit says when nothing on this site builds its operation any more. */\nexport const aiBuildUnavailableCopy = (noun: string): string =>\n `Not built: ${aiArticle(noun)} cannot be made on this site right now.`\n\n\n/** What a page that was reported built but holds none of its plan says. */\nexport const AI_BUILD_PAGE_NOT_WRITTEN_COPY = 'The page was not written from its plan.'\n\n\n/**\n * The most passes a build's step may take: every unit at a page's worst — its\n * sections and its listing — so a runner that never finishes is still\n * bounded while the largest plan is not. Try again starts the count over.\n */\nexport const AI_BUILD_MAX_PASSES = AI_BUILD_LIMITS.units * (AI_SITE_MAX_SECTIONS + 1)\n\n/** The job kind a creation of the build is built by. */\nconst CREATION_JOB_KINDS: Partial<Record<AiBuildPlanCreateKind, AiJobKind>> = {\n layout: 'layout',\n form: 'form',\n component: 'component',\n email: 'email',\n}\n\n/** The job kind a unit is built by, where an AI runner builds it. */\nexport function aiBuildUnitJobKind(unit: AiBuildUnit, ops: AiBuildOps): AiJobKind | null {\n if (unit.screen) return 'page'\n if (unit.creation) return CREATION_JOB_KINDS[unit.creation.kind] ?? null\n const runnerKind = ops.get(unit.op)?.runnerKind\n return runnerKind ? (runnerKind as AiJobKind) : null\n}\n\n/** The id a unit's job, and so its draft, is named by. */\nexport function aiBuildUnitJobId(job: Pick<AiJob, '$id'>, unit: AiBuildUnit): string {\n return unit.creation?.id ?? unit.screen?.id ?? unit.item?.id ?? `${job.$id}-${unit.slot}`\n}\n\n/**\n * The job a unit is built under (generalizing `aiSiteUnitJob`): this job's\n * org, site, creator and model; the kind that builds the unit; a plan\n * narrowed to the unit, its `new:` references resolved to what was built and\n * the failed ones left out; and a brief that says what the unit is, what it\n * is built without, and which blocks its sections place.\n */\nexport function aiBuildUnitJob(\n job: AiJob,\n unit: AiBuildUnit,\n context: {\n kind: AiJobKind\n units: readonly AiBuildUnit[]\n ledger: readonly AiJobItemLedger[]\n ops: AiBuildOps\n briefLines?: readonly string[]\n },\n): AiJob {\n const plan = job.plan as AiJobPlan\n const built = aiBuildBuiltRefs(context.units, context.ledger, job.outputs ?? [])\n const labels = { ...(plan.labels ?? {}) }\n for (const entry of built.values()) labels[entry.id] = entry.label\n const brief = [job.brief.trim()]\n const unitPlan: AiJobPlan = { ...plan, labels, reuse: [...plan.reuse], create: [], screens: [] }\n delete unitPlan.items\n const placedByScreens = new Set(plan.screens.flatMap((screen) => screen.sections.flatMap((section) => section.uses)))\n if (unit.creation) {\n unitPlan.reuse = plan.reuse.filter((entry) => !placedByScreens.has(entry.id))\n unitPlan.create = [\n {\n ...unit.creation,\n duplicateOf: aiSiteResolvedRef(unit.creation.duplicateOf, built),\n // The dataset a form writes to, new or the site's own (AGL-3616); one\n // this build failed to make leaves the form as it always was.\n ...(unit.creation.writesTo ? { writesTo: aiSiteResolvedRef(unit.creation.writesTo, built) } : {}),\n },\n ]\n brief.push(`Build the ${unit.creation.kind} “${unit.creation.name}”: ${unit.creation.why}`)\n }\n if (unit.screen) {\n const screen = unit.screen\n for (const entry of built.values()) {\n unitPlan.reuse.push({ kind: entry.kind, id: entry.id, purpose: `the ${entry.kind} this request built` })\n }\n let builtLayout: string | null = null\n for (const entry of built.values()) if (entry.kind === 'layout') builtLayout = builtLayout ?? entry.id\n unitPlan.screens = [\n {\n ...screen,\n // A page whose layout failed renders inside the site's own: the page\n // step falls back to it when the plan names none.\n layout: aiSiteResolvedRef(screen.layout, built) ?? (isAiPlanNewRef(screen.layout) ? builtLayout : null),\n template: aiSiteResolvedRef(screen.template, built),\n duplicateOf: aiSiteResolvedRef(screen.duplicateOf, built),\n record: screen.record\n ? { ...screen.record, dataset: aiSiteResolvedRef(screen.record.dataset, built) ?? screen.record.dataset }\n : null,\n sections: screen.sections.map((section) => ({\n ...section,\n uses: section.uses\n .map((ref) => aiSiteResolvedRef(ref, built))\n .filter((ref): ref is string => !!ref),\n })),\n },\n ]\n brief.push(`Build the page “${screen.title}”, at ${screen.slug}.`)\n brief.push(...aiBuildPlacedItemLines(unit, { units: context.units, ledger: context.ledger, ops: context.ops }))\n }\n const item = unit.item\n if (item) {\n const noun = context.ops.get(item.op)?.noun ?? item.op\n brief.push(`Build the ${noun} “${item.name}”${item.why ? `: ${item.why}` : '.'}`)\n // A planned kind's step builds the plan's first creation of its kind.\n unitPlan.create = AI_PLANNED_JOB_KINDS.includes(context.kind)\n ? [{ kind: context.kind as AiBuildPlanCreateKind, name: item.name, why: item.why, duplicateOf: null, fields: [], ...(item.id ? { id: item.id } : {}) }]\n : []\n }\n brief.push(...(context.briefLines ?? []))\n const inputs: Record<string, unknown> = {\n ...job.inputs,\n ...(item?.args ?? {}),\n originJobId: aiOriginJobId(job),\n }\n delete inputs[AI_BUILD_PUBLISH_INPUT]\n // A dataset this build made for its form, which the form may bind (AGL-3616).\n const madeFor = unit.creation?.kind === 'form' && isAiPlanNewRef(unit.creation.writesTo) ? unitPlan.create[0]?.writesTo : null\n if (madeFor) inputs[AI_FORM_DATASET_MADE_INPUT] = madeFor\n // A build's pages and layouts are designed in the layout language and\n // compiled (AGL-3660), told the pages the build plans and where its form is.\n if (context.kind === 'page' || context.kind === 'layout') {\n inputs[AI_LAYOUT_LANGUAGE_INPUT] = true\n const pages = aiLayoutSitePagesOfPlan(plan.screens)\n if (pages.length) inputs[AI_LAYOUT_SITE_PAGES_INPUT] = pages\n const formPage = aiLayoutFormPageOfPlan(plan)\n if (formPage) inputs[AI_LAYOUT_FORM_PAGE_INPUT] = formPage\n // The datasets this build made, repeated in the sections that name them (AGL-3616).\n const datasets = [...built.entries()]\n .filter(([, entry]) => entry.kind === 'dataset')\n .map(([name, entry]) => ({ id: entry.id, name: context.units.find((one) => one.item?.name.toLowerCase() === name)?.label ?? entry.label }))\n const listings = aiDatasetListingsOf(datasets, plan.screens)\n if (listings.length) inputs[AI_LAYOUT_LISTINGS_INPUT] = listings\n }\n return {\n ...job,\n $id: aiBuildUnitJobId(job, unit),\n kind: context.kind,\n steps: [],\n outputs: [],\n items: null,\n plan: item && !AI_PLANNED_JOB_KINDS.includes(context.kind) ? null : unitPlan,\n inputs,\n brief: brief.join('\\n').slice(0, AI_JOB_BRIEF_MAX_CHARS),\n }\n}\n\n/** The unit's failure, for its row: ours or not, why, in customer-safe words. */\nfunction failed(\n slot: string,\n failure: AiJobItemFailure,\n extra: Partial<AiJobItemOutcome> = {},\n): AiJobItemOutcome {\n return { slot, status: 'failed', failure, ...extra }\n}\n\nexport interface AiJobBuildStepDeps {\n /** The runner registry; specs hand in fakes. */\n runnerFor?: typeof aiJobStepRunnerFor\n /** The draft writer registry; specs hand in fakes. */\n writerFor?: AiPluginDraftWriterLookup\n /** The operations this site may use; the registry and its gates otherwise. */\n opsFor?: (context: AiBuildOpsContext) => Promise<AiBuildOps>\n /** A runner kind's own admission, asked before its item runs; the registry's otherwise. */\n admissionFor?: typeof aiJobAdmissionRefusal\n /** Another plugin's admission for its writer; the seam's otherwise. */\n pluginAdmission?: typeof aiPluginDraftAdmissionRefusal\n /** The draft reader a built page is checked through. */\n readNodes?: typeof readAiDraftNodes\n /** The publish a build asked for and confirmed. */\n publish?: typeof aiPublishGuidedSite\n}\n\n/** Whether a build's workspace spends the Free taste. */\nexport function aiBuildFreeTaste(org: object | null | undefined): boolean {\n return Boolean(org) && resolveEffectivePlan(org as never) === 'free'\n}\n\n/** The site document a gate reads, or `null`. */\nasync function readHost(firestore: FirebaseFirestore.Firestore, hostId: string | null) {\n if (!hostId) return null\n return ((await firestore.collection('hosts').doc(hostId).get()).data() ?? null) as Record<string, unknown> | null\n}\n\nexport function createAiJobBuildStep(deps: AiJobBuildStepDeps = {}): AiJobStepRunner {\n const runnerFor = deps.runnerFor ?? aiJobStepRunnerFor\n const writerFor = deps.writerFor ?? aiPluginDraftWriter\n const opsFor = deps.opsFor ?? ((context) => aiBuildOps(context))\n const admissionFor = deps.admissionFor ?? aiJobAdmissionRefusal\n const pluginAdmission = deps.pluginAdmission ?? aiPluginDraftAdmissionRefusal\n const readNodes = deps.readNodes ?? readAiDraftNodes\n const publish = deps.publish ?? aiPublishGuidedSite\n\n return async (context): Promise<AiJobStepOutcome> => {\n const { job, firestore } = context\n const model = context.modelFor?.('job.plan') ?? aiModelForStep('job.plan')\n const plan = aiConfirmedPlan(job)\n if (!plan) return { ...aiUnspentOutcome(model), failure: AI_BUILD_NO_PLAN_COPY }\n const org = (context.org ?? null) as Partial<AglynOrgBilling> | null\n const units = aiBuildUnits(plan)\n const ordered = aiBuildOrder(units) ?? units\n const starting = !job.items?.length\n const ledger = starting ? aiBuildInitialLedger(units) : (job.items as AiJobItemLedger[])\n const init = starting ? { items: ledger } : {}\n const unit = aiBuildNextUnit(ordered, ledger)\n const rows = new Map(ledger.map((row) => [row.slot, row]))\n const host = await readHost(firestore, job.hostId ?? null)\n const ops = await opsFor({\n orgId: job.orgId,\n hostId: job.hostId ?? null,\n org,\n host,\n freeTaste: aiBuildFreeTaste(org),\n })\n\n /** Whether units other than this one are still to build. */\n const othersOpen = (slot: string) =>\n ordered.some((one) => one.slot !== slot && aiBuildItemOpen(rows.get(one.slot) ?? { status: 'pending' }))\n\n /** The build's last pass puts its pages live, where it was asked and confirmed. */\n const finish = async (outcome: AiJobStepOutcome, extraPages: readonly AiJobOutput[] = []): Promise<AiJobStepOutcome> => {\n if (!aiJobPublishesBuild(job) || job.sitePublish || !job.hostId) return outcome\n // A record template renders once per record only once its binding is\n // saved, so it is never published at its own address (AGL-3616).\n const pageIds = new Set(\n units\n .filter((one) => one.screen && !one.screen.record && aiBuildItemDelivered(rows.get(one.slot) ?? { status: 'pending' }))\n .flatMap((one) => rows.get(one.slot)?.outputs ?? []),\n )\n const pages = [\n ...(job.outputs ?? []).filter((output) => output.resource === 'screen' && pageIds.has(output.id)),\n ...extraPages,\n ]\n if (!pages.length) return outcome\n // A canceled build never puts anything live (AGL-3616): its pages stay drafts.\n if (await aiJobCancelAsked(firestore, job, context.signal)) return outcome\n const sitePublish = await publish(firestore, { job, outputs: pages, now: context.now }).catch((error: unknown) => {\n console.error('ai build publish threw', { orgId: job.orgId, jobId: job.$id, error })\n return null\n })\n return sitePublish ? { ...outcome, sitePublish } : outcome\n }\n\n if (!unit) return finish({ ...aiUnspentOutcome(model), ...init })\n\n const settle = (item: AiJobItemOutcome, spent: AiJobStepOutcome = aiUnspentOutcome(model)): AiJobStepOutcome => ({\n ...spent,\n ...init,\n item,\n ...(item.status === 'running' || othersOpen(unit.slot) ? { continue: true } : {}),\n })\n\n // What its dependencies came to.\n const degradation = aiBuildDegradation(unit, { units, ledger, ops })\n if (degradation.skip) {\n return settle({ slot: unit.slot, status: 'skipped', note: degradation.skip, degradedBy: degradation.degradedBy })\n }\n const capability = ops.get(unit.op)\n const noun = capability?.noun ?? unit.op\n if (!capability) return settle({ slot: unit.slot, status: 'skipped', note: aiBuildUnavailableCopy(noun) })\n const degraded = degradation.degradedBy.length > 0\n const note = degradation.notes.length ? degradation.notes.join(' ') : null\n\n // Another plugin's resource: its writer, with the content its capability derives.\n if (capability.draftResource) {\n const item = unit.item\n const writer = writerFor(capability.draftResource)\n if (!item || !writer || !job.hostId) {\n return settle({ slot: unit.slot, status: 'skipped', note: aiBuildUnavailableCopy(noun) })\n }\n const admission: AiJobAdmissionContext = {\n firestore,\n orgId: job.orgId,\n hostId: job.hostId,\n inputs: {},\n org,\n uid: job.createdBy,\n }\n const refusal = await pluginAdmission(admission, {\n kind: 'build',\n drafts: [{ resource: capability.draftResource, label: capability.noun }],\n writerFor,\n })\n if (refusal) return settle({ slot: unit.slot, status: 'skipped', note: `Not built: ${refusal.error}` })\n const dependencies: Record<string, { op: string; id: string }> = {}\n for (const slot of unit.deps) {\n const dep = units.find((one) => one.slot === slot)\n const row = rows.get(slot)\n if (!dep || !row || !aiBuildItemDelivered(row) || !row.outputs.length) continue\n dependencies[`new:${dep.label}`] = { op: dep.op, id: row.outputs[0] }\n }\n const content = capability.draftContent?.({ name: item.name, args: item.args }, { hostId: job.hostId, dependencies }) ?? item.args\n const checked = writer.check(content, { hostId: job.hostId })\n if (checked.ok === false) {\n return settle(\n failed(unit.slot, { ours: true, reason: 'step-failure', message: checked.problems[0] ?? AI_BUILD_UNIT_EMPTY_COPY }),\n )\n }\n const id = aiBuildUnitJobId(job, unit)\n const written = await writer.write({\n orgId: job.orgId,\n hostId: job.hostId,\n uid: job.createdBy,\n org,\n now: context.now,\n id,\n name: item.name,\n content,\n })\n if (written.ok === false) {\n return settle(failed(unit.slot, { ours: false, reason: 'review', message: written.error }))\n }\n const output: AiJobOutput = {\n resource: 'draft',\n id: written.id,\n versionId: written.versionId,\n hostId: job.hostId,\n label: written.name,\n draftResource: capability.draftResource,\n note: `A draft, in ${capability.where}.`,\n }\n return settle(\n {\n slot: unit.slot,\n status: degraded ? 'degraded' : 'succeeded',\n outputs: [written.id],\n note,\n ...(degraded ? { degradedBy: degradation.degradedBy } : {}),\n },\n { ...aiUnspentOutcome(model), outputs: [output] },\n )\n }\n\n // This plugin's own runner, under a job derived for the unit.\n const kind = aiBuildUnitJobKind(unit, ops)\n const runner = kind ? runnerFor(kind) : null\n if (!kind || !runner) return settle({ slot: unit.slot, status: 'skipped', note: aiBuildUnavailableCopy(noun) })\n const derived = aiBuildUnitJob(job, unit, { kind, units, ledger, ops, briefLines: degradation.briefLines })\n // An item's kind is asked its own admission first (a campaign's plan,\n // a template's subject), once, before its first pass.\n if (unit.item && rows.get(unit.slot)?.status !== 'running') {\n const refusal = await admissionFor(kind, {\n firestore,\n orgId: job.orgId,\n hostId: job.hostId ?? null,\n inputs: derived.inputs,\n org,\n uid: job.createdBy,\n }).catch((error: unknown) => {\n console.error('ai build item admission failed', { orgId: job.orgId, jobId: job.$id, slot: unit.slot, error })\n return { status: 403 as const, error: AI_BUILD_UNIT_EMPTY_COPY }\n })\n if (refusal) return settle({ slot: unit.slot, status: 'skipped', note: `Not built: ${refusal.error}` })\n }\n\n let outcome: AiJobStepOutcome\n try {\n outcome = await runner({ ...context, job: derived })\n } catch (error) {\n // A provider that will answer later is the machine's to retry; anything\n // else is this item's failure, and the build goes on.\n if (aiUnitErrorRetryable(error)) throw error\n console.error('ai build unit threw', { orgId: job.orgId, jobId: job.$id, slot: unit.slot, error })\n return settle(failed(unit.slot, { ours: true, reason: 'provider', message: AI_BUILD_UNIT_EMPTY_COPY }))\n }\n const spent = aiUnitSpend(outcome)\n const ids = outcome.outputs.map((output) => output.id)\n const stopped = aiUnitFailure(unit.slot, outcome)\n if (stopped) return settle(stopped, spent)\n // A page counts as built only when its plan's sections are in it (AGL-3596).\n if (unit.screen && job.hostId) {\n const page = outcome.outputs.find((output) => output.resource === 'screen')\n const written =\n page !== undefined &&\n (await aiSitePageWritten(\n firestore,\n { hostId: job.hostId, unitJobId: derived.$id, screen: unit.screen, draftId: page.id },\n readNodes,\n ))\n if (!written) {\n return settle(\n failed(unit.slot, { ours: true, reason: 'step-failure', message: AI_BUILD_PAGE_NOT_WRITTEN_COPY }),\n { ...spent, outputs: outcome.outputs.filter((output) => output.resource !== 'screen') },\n )\n }\n }\n const done = settle(\n {\n slot: unit.slot,\n status: degraded ? 'degraded' : 'succeeded',\n outputs: ids,\n note,\n ...(degraded ? { degradedBy: degradation.degradedBy } : {}),\n },\n spent,\n )\n if (done.continue) return done\n // The last unit: what was built goes live where it was asked and confirmed.\n rows.set(unit.slot, { ...(rows.get(unit.slot) as AiJobItemLedger), status: degraded ? 'degraded' : 'succeeded', outputs: ids })\n return finish(done, unit.screen ? outcome.outputs.filter((output) => output.resource === 'screen') : [])\n }\n}\n\nexport const runAiJobBuildStep = createAiJobBuildStep()\n\n/**\n * The least time a build's next pass needs: what the step that builds its\n * next unit registers for the job derived for it; a page pass's when the\n * next unit is another plugin's draft, which asks no model.\n */\nexport function aiBuildJobRunMinimumMs(job: AiJob): number {\n const plan = aiConfirmedPlan(job)\n if (!plan) return AI_JOB_PAGE_STEP_MINIMUM_MS\n const units = aiBuildUnits(plan)\n const ordered = aiBuildOrder(units) ?? units\n const ledger = job.items?.length ? job.items : aiBuildInitialLedger(units)\n const unit = aiBuildNextUnit(ordered, ledger)\n if (!unit) return AI_JOB_PAGE_STEP_MINIMUM_MS\n const kind: AiJobKind | null = unit.screen\n ? 'page'\n : unit.creation\n ? (CREATION_JOB_KINDS[unit.creation.kind] ?? null)\n : (AI_BUILD_ITEM_RUNNER_KINDS[unit.op] ?? null)\n if (!kind) return AI_JOB_PAGE_STEP_MINIMUM_MS\n return aiJobStepRunMinimumMs(aiBuildUnitJob(job, unit, { kind, units, ledger, ops: new Map() }))\n}\n\n/** The runner kinds this plugin's own item operations use, for the time a pass needs without the registry. */\nconst AI_BUILD_ITEM_RUNNER_KINDS: Readonly<Record<string, AiJobKind>> = {\n template: 'template',\n campaign: 'campaign',\n workflow: 'workflow',\n function: 'logic',\n edit: 'edit',\n}\n\n/**\n * What a Free build's credits say before it runs (AGL-3722), on its measured\n * p90 rather than its ceiling: `null` when what is left this month covers the\n * p90 — or when nothing is known about what is left, since each pass's\n * reservation still decides — and `null` too for a build the person chose\n * to build as far as it goes (`confirmed`), whose prompt `onConfirmed` is\n * told so the door records it. Otherwise a 409 carrying the prompt: the\n * range, what is left, and the smaller first build. Nothing left at all is a\n * 429. Read off the same two walls the reservation refuses at\n * (`readFreeAiCreditsLeft`), net of give-backs.\n */\nexport async function aiBuildFreeCreditsRefusal(input: {\n firestore: FirebaseFirestore.Firestore\n orgId: string\n org: object | null\n range: AiCreditRange\n smaller?: AiCreditsSmaller | null\n confirmed?: boolean\n onConfirmed?: (prompt: AiCreditsPrompt) => void\n now: Date\n freeCreditsLeft?: typeof readFreeAiCreditsLeft\n}): Promise<AiJobAdmissionRefusal | null> {\n const read = input.freeCreditsLeft ?? readFreeAiCreditsLeft\n const credits = await read(input.firestore, { orgId: input.orgId, org: input.org, now: input.now })\n if (!credits) return null\n if (credits.left <= 0) return { status: 429, error: aiFreeCreditsNoneLeftText(credits.resetsOn) }\n const prompt = aiCreditsPromptFor(input.range, credits, input.smaller ?? null)\n if (!prompt) return null\n if (!input.confirmed) {\n return { status: 409, error: aiCreditsPromptText(prompt, 'build'), code: AI_CREDITS_CONFIRM_CODE, credits: prompt }\n }\n input.onConfirmed?.(prompt)\n return null\n}\n\nexport interface AiBuildAdmissionDeps {\n opsFor?: (context: AiBuildOpsContext) => Promise<AiBuildOps>\n freeCreditsLeft?: typeof readFreeAiCreditsLeft\n ownerOf?: typeof resolveOrgIdForHost\n now?: () => Date\n}\n\n/**\n * A build is admitted for a site of the job's own org where a page can be\n * built; and confirmed only for a plan it can build here — its shape, its\n * operations as this site has them, and on the Free taste a measured p90\n * the month's Free credits still cover — or the person's go-ahead to build\n * what fits (AGL-3722).\n */\nexport function createAiBuildJobAdmission(deps: AiBuildAdmissionDeps = {}): AiJobAdmission {\n const opsFor = deps.opsFor ?? ((context) => aiBuildOps(context))\n const ownerOf = deps.ownerOf ?? resolveOrgIdForHost\n return async (context) => {\n if (!context.hostId) return { status: 400, error: 'Open the site to build on before asking Assist to build' }\n const owner = await ownerOf(context.hostId)\n if (!owner || owner !== context.orgId) return { status: 404, error: 'Unknown site' }\n if (!aiJobStepRunnerFor('page')) return { status: 400, error: 'Building from a request is not available yet.' }\n const plan = context.plan\n if (!plan) return null\n const org = context.org as Partial<AglynOrgBilling> | null\n const freeTaste = aiBuildFreeTaste(org)\n const host = await readHost(context.firestore, context.hostId)\n const ops = await opsFor({ orgId: context.orgId, hostId: context.hostId, org, host, freeTaste })\n const shape = aiBuildPlanShapeRefusal(plan, { freeTaste, ops })\n if (shape) return { status: 400, error: shape }\n if (freeTaste) {\n const refusal = await aiBuildFreeCreditsRefusal({\n firestore: context.firestore,\n orgId: context.orgId,\n org,\n range: aiBuildCreditRange(plan, { ops }),\n smaller: aiBuildSmaller(plan, ops),\n confirmed: context.creditsConfirmed === true,\n onConfirmed: context.onCreditsConfirmed,\n now: deps.now?.() ?? new Date(),\n freeCreditsLeft: deps.freeCreditsLeft,\n })\n if (refusal) return refusal\n }\n return null\n }\n}\n\nexport const aiBuildJobAdmission = createAiBuildJobAdmission()\n\n/**\n * Registers the build with the least time a pass needs, the time its next\n * pass needs, the passes its largest plan may take, and its admission.\n */\nexport function registerAiBuildJob(): void {\n registerAiJobStep('build', runAiJobBuildStep, {\n minimumMs: AI_JOB_PAGE_STEP_MINIMUM_MS,\n minimumMsFor: aiBuildJobRunMinimumMs,\n })\n registerAiJobStepPasses('build', AI_BUILD_MAX_PASSES)\n registerAiJobAdmission('build', aiBuildJobAdmission)\n}\n"],"names":["aiJobCancelAsked","resolveEffectivePlan","resolveOrgIdForHost","AI_BUILD_LIMITS","AI_BUILD_PUBLISH_INPUT","aiArticle","aiBuildCreditRange","aiBuildDegradation","aiBuildInitialLedger","aiBuildItemDelivered","aiBuildItemOpen","aiBuildNextUnit","aiBuildOrder","aiBuildPlacedItemLines","aiBuildPlanShapeRefusal","aiBuildSmaller","aiBuildUnits","isAiPlanNewRef","AI_SITE_MAX_SECTIONS","AI_CREDITS_CONFIRM_CODE","aiCreditsPromptFor","aiCreditsPromptText","aiFreeCreditsNoneLeftText","readFreeAiCreditsLeft","aiModelForStep","AI_BUILD_UNIT_EMPTY_COPY","aiBuildBuiltRefs","aiUnitErrorRetryable","aiUnitFailure","aiUnitSpend","aiBuildOps","aiJobAdmissionRefusal","registerAiJobAdmission","aiOriginJobId","readAiDraftNodes","aiConfirmedPlan","aiUnspentOutcome","AI_JOB_PAGE_STEP_MINIMUM_MS","aiPluginDraftAdmissionRefusal","aiPluginDraftWriter","aiSitePageWritten","aiSiteResolvedRef","AI_LAYOUT_SITE_PAGES_INPUT","aiLayoutSitePagesOfPlan","AI_LAYOUT_FORM_PAGE_INPUT","AI_LAYOUT_LANGUAGE_INPUT","aiLayoutFormPageOfPlan","aiDatasetListingsOf","AI_FORM_DATASET_MADE_INPUT","AI_LAYOUT_LISTINGS_INPUT","AI_JOB_BRIEF_MAX_CHARS","aiJobPublishesBuild","aiPublishGuidedSite","AI_PLANNED_JOB_KINDS","aiJobStepRunMinimumMs","aiJobStepRunnerFor","registerAiJobStep","registerAiJobStepPasses","AI_BUILD_NO_PLAN_COPY","aiBuildUnavailableCopy","noun","AI_BUILD_PAGE_NOT_WRITTEN_COPY","AI_BUILD_MAX_PASSES","units","CREATION_JOB_KINDS","layout","form","component","email","aiBuildUnitJobKind","unit","ops","screen","creation","kind","runnerKind","get","op","aiBuildUnitJobId","job","id","item","$id","slot","aiBuildUnitJob","context","plan","unitPlan","built","ledger","outputs","labels","entry","values","label","brief","trim","reuse","create","screens","items","placedByScreens","Set","flatMap","sections","section","uses","filter","has","duplicateOf","writesTo","push","name","why","purpose","builtLayout","template","record","dataset","map","ref","title","slug","includes","fields","briefLines","inputs","args","originJobId","madeFor","pages","length","formPage","datasets","entries","find","one","toLowerCase","listings","steps","join","slice","failed","failure","extra","status","aiBuildFreeTaste","org","Boolean","readHost","firestore","hostId","collection","doc","data","createAiJobBuildStep","deps","runnerFor","writerFor","opsFor","admissionFor","pluginAdmission","readNodes","publish","rows","model","modelFor","ordered","starting","init","Map","row","host","orgId","freeTaste","othersOpen","some","finish","outcome","extraPages","sitePublish","pageIds","output","resource","signal","now","catch","error","console","jobId","settle","spent","continue","degradation","skip","note","degradedBy","capability","degraded","notes","draftResource","writer","admission","uid","createdBy","refusal","drafts","dependencies","dep","content","draftContent","checked","check","ok","ours","reason","message","problems","written","write","versionId","where","runner","derived","ids","stopped","page","undefined","unitJobId","draftId","done","set","runAiJobBuildStep","aiBuildJobRunMinimumMs","AI_BUILD_ITEM_RUNNER_KINDS","campaign","workflow","function","edit","aiBuildFreeCreditsRefusal","input","read","freeCreditsLeft","credits","left","resetsOn","prompt","range","smaller","confirmed","code","onConfirmed","createAiBuildJobAdmission","ownerOf","owner","shape","creditsConfirmed","onCreditsConfirmed","Date","aiBuildJobAdmission","registerAiBuildJob","minimumMs","minimumMsFor"],"mappings":"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"}
@@ -94,12 +94,17 @@ import { _ as _extends } from "@swc/helpers/_/_extends";
94
94
  var _aiRecordedJobDraftId;
95
95
  return (_aiRecordedJobDraftId = aiRecordedJobDraftId(job, slot)) != null ? _aiRecordedJobDraftId : job.$id;
96
96
  }
97
- /** The creations a job writes as documents: a theme change is a proposal, and no job writes a dataset. */ const DRAFT_CREATION_KINDS = new Set([
97
+ /**
98
+ * The creations a job writes as documents: a theme change is a proposal. A
99
+ * dataset is written by the data plugin for a site start (AGL-3616), under
100
+ * the id minted here.
101
+ */ const DRAFT_CREATION_KINDS = new Set([
98
102
  'component',
99
103
  'form',
100
104
  'layout',
101
105
  'template',
102
- 'email'
106
+ 'email',
107
+ 'dataset'
103
108
  ]);
104
109
  /** The kinds whose step builds what their plan names, one unit a draft, and whether that includes its screens. */ const UNIT_PLAN_KINDS = {
105
110
  // A page job's own screen is its kind's draft; its plan's creations are units.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/jobs/ai-job-draft-ids.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createResourceUid } from '@aglyn/aglyn/app-utils/create-resource-uid'\nimport type { AiBuildPlan, AiBuildPlanCreateKind } from '../model/ai-build-plan'\nimport type { AiJob, AiJobDraftSlot, AiJobKind } from '../model/ai-jobs.types'\n\n/**\n * The ids a job's drafts are written under (AGL-3079).\n *\n * A draft a job writes is the resource a member would otherwise have made in\n * the console, so it is named the way the console names one: by\n * `createResourceUid()`. Each id is minted ONCE and recorded on the job before\n * the draft is written. That record is what lets a step run again safely: a\n * run cut off after its write reads the same id, finds the draft, and reports\n * it rather than writing a second.\n *\n * Where an id is recorded follows what decides the draft exists:\n *\n * - A draft the job's KIND always writes — a layout job's layout, a page\n * job's screen, a campaign's design and campaign — is minted when the job\n * is created, on the step that writes it (`AiJobStep.draftIds`).\n * - A draft the PLAN decides — what a page job's plan creates, a scaffold's\n * layout, form and pages — is minted when the plan is kept, on the plan's\n * own entry (`AiBuildPlanCreate.id`, `AiBuildPlanScreen.id`). Those are\n * built one unit a pass by the step that owns their kind, under a job named\n * by the entry's id (`aiSiteUnitJob`).\n *\n * A job whose step records no id names its draft by the job's own id, which\n * is the id every draft of such a job was written under.\n */\n\n/** The drafts each kind's step writes of its own, whatever its plan says. */\nexport const AI_JOB_DRAFT_SLOTS: Readonly<Partial<Record<AiJobKind, readonly AiJobDraftSlot[]>>> = {\n page: ['screen'],\n layout: ['layout'],\n template: ['template'],\n form: ['form'],\n component: ['component'],\n email: ['email'],\n campaign: ['email', 'campaign'],\n workflow: ['workflow'],\n // The welcome email a scaffold builds; its pages and creations are its plan's.\n site: ['email'],\n}\n\n/** Fresh ids for the drafts a job of this kind writes of its own; `null` for a kind that writes none. */\nexport function aiMintJobDraftIds(kind: AiJobKind): Partial<Record<AiJobDraftSlot, string>> | null {\n const slots = AI_JOB_DRAFT_SLOTS[kind]\n if (!slots?.length) return null\n return Object.fromEntries(slots.map((slot) => [slot, createResourceUid()]))\n}\n\n/** The id recorded on the job's steps for its draft of `slot`; `null` where none is. */\nexport function aiRecordedJobDraftId(job: Pick<AiJob, 'steps'>, slot: AiJobDraftSlot): string | null {\n for (const step of job.steps ?? []) {\n const id = step.draftIds?.[slot]\n if (typeof id === 'string' && id) return id\n }\n return null\n}\n\n/**\n * The id the job writes its draft of `slot` under, and finds it by when the\n * step runs again: the id recorded on its step, else the job's own id — which\n * names a unit's job by its plan entry's id, and a job whose step records none.\n */\nexport function aiJobDraftId(job: Pick<AiJob, '$id' | 'steps'>, slot: AiJobDraftSlot): string {\n return aiRecordedJobDraftId(job, slot) ?? job.$id\n}\n\n/** The creations a job writes as documents: a theme change is a proposal, and no job writes a dataset. */\nconst DRAFT_CREATION_KINDS: ReadonlySet<AiBuildPlanCreateKind> = new Set<AiBuildPlanCreateKind>([\n 'component',\n 'form',\n 'layout',\n 'template',\n 'email',\n])\n\n/** The kinds whose step builds what their plan names, one unit a draft, and whether that includes its screens. */\nconst UNIT_PLAN_KINDS: Readonly<Partial<Record<AiJobKind, { screens: boolean }>>> = {\n // A page job's own screen is its kind's draft; its plan's creations are units.\n page: { screens: false },\n site: { screens: true },\n // So are the components and forms a template, layout or component job\n // builds before its own record (AGL-3143 §15).\n template: { screens: false },\n layout: { screens: false },\n component: { screens: false },\n // A build names every draft its plan decides, its items' too (AGL-3616).\n build: { screens: true },\n}\n\n/**\n * The plan as a job of `kind` keeps it: for a kind that builds what its plan\n * names, a fresh id on every creation it writes as a document and, for a\n * scaffold, on every screen. An id the plan already carried is replaced —\n * a plan reused from another job names that job's drafts — so the drafts\n * this job builds are its own. Any other kind's plan is kept as it is.\n */\nexport function aiPlanWithDraftIds<T extends AiBuildPlan>(kind: AiJobKind, plan: T): T {\n const units = UNIT_PLAN_KINDS[kind]\n if (!units) return plan\n return {\n ...plan,\n create: plan.create.map((entry) =>\n DRAFT_CREATION_KINDS.has(entry.kind) ? { ...entry, id: createResourceUid() } : entry,\n ),\n screens: units.screens ? plan.screens.map((screen) => ({ ...screen, id: createResourceUid() })) : plan.screens,\n ...(plan.items ? { items: plan.items.map((item) => ({ ...item, id: createResourceUid() })) } : {}),\n }\n}\n\n/**\n * The job the member started, whichever unit is running (AGL-3596): a unit's\n * derived job carries it as `inputs.originJobId`, and a job a member started\n * is its own. What a draft is stamped with as `aiJobId`.\n */\nexport function aiOriginJobId(job: Pick<AiJob, '$id' | 'inputs'>): string {\n const origin = job.inputs?.['originJobId']\n return typeof origin === 'string' && origin ? origin : job.$id\n}\n"],"names":["createResourceUid","AI_JOB_DRAFT_SLOTS","page","layout","template","form","component","email","campaign","workflow","site","aiMintJobDraftIds","kind","slots","length","Object","fromEntries","map","slot","aiRecordedJobDraftId","job","step","steps","id","draftIds","aiJobDraftId","$id","DRAFT_CREATION_KINDS","Set","UNIT_PLAN_KINDS","screens","build","aiPlanWithDraftIds","plan","units","create","entry","has","screen","items","item","aiOriginJobId","origin","inputs"],"mappings":";AAAA;;;;;;;;;;;;;;;CAeC,GAED,SAASA,iBAAiB,QAAQ,6CAA4C;AAI9E;;;;;;;;;;;;;;;;;;;;;;;CAuBC,GAED,2EAA2E,GAC3E,OAAO,MAAMC,qBAAsF;IACjGC,MAAM;QAAC;KAAS;IAChBC,QAAQ;QAAC;KAAS;IAClBC,UAAU;QAAC;KAAW;IACtBC,MAAM;QAAC;KAAO;IACdC,WAAW;QAAC;KAAY;IACxBC,OAAO;QAAC;KAAQ;IAChBC,UAAU;QAAC;QAAS;KAAW;IAC/BC,UAAU;QAAC;KAAW;IACtB,+EAA+E;IAC/EC,MAAM;QAAC;KAAQ;AACjB,EAAC;AAED,uGAAuG,GACvG,OAAO,SAASC,kBAAkBC,IAAe;IAC/C,MAAMC,QAAQZ,kBAAkB,CAACW,KAAK;IACtC,IAAI,EAACC,yBAAAA,MAAOC,MAAM,GAAE,OAAO;IAC3B,OAAOC,OAAOC,WAAW,CAACH,MAAMI,GAAG,CAAC,CAACC,OAAS;YAACA;YAAMlB;SAAoB;AAC3E;AAEA,sFAAsF,GACtF,OAAO,SAASmB,qBAAqBC,GAAyB,EAAEF,IAAoB;QAC/DE;IAAnB,KAAK,MAAMC,SAAQD,aAAAA,IAAIE,KAAK,YAATF,aAAa,EAAE,CAAE;YACvBC;QAAX,MAAME,MAAKF,iBAAAA,KAAKG,QAAQ,qBAAbH,cAAe,CAACH,KAAK;QAChC,IAAI,OAAOK,OAAO,YAAYA,IAAI,OAAOA;IAC3C;IACA,OAAO;AACT;AAEA;;;;CAIC,GACD,OAAO,SAASE,aAAaL,GAAiC,EAAEF,IAAoB;QAC3EC;IAAP,QAAOA,wBAAAA,qBAAqBC,KAAKF,iBAA1BC,wBAAmCC,IAAIM,GAAG;AACnD;AAEA,wGAAwG,GACxG,MAAMC,uBAA2D,IAAIC,IAA2B;IAC9F;IACA;IACA;IACA;IACA;CACD;AAED,gHAAgH,GAChH,MAAMC,kBAA8E;IAClF,+EAA+E;IAC/E3B,MAAM;QAAE4B,SAAS;IAAM;IACvBpB,MAAM;QAAEoB,SAAS;IAAK;IACtB,sEAAsE;IACtE,+CAA+C;IAC/C1B,UAAU;QAAE0B,SAAS;IAAM;IAC3B3B,QAAQ;QAAE2B,SAAS;IAAM;IACzBxB,WAAW;QAAEwB,SAAS;IAAM;IAC5B,yEAAyE;IACzEC,OAAO;QAAED,SAAS;IAAK;AACzB;AAEA;;;;;;CAMC,GACD,OAAO,SAASE,mBAA0CpB,IAAe,EAAEqB,IAAO;IAChF,MAAMC,QAAQL,eAAe,CAACjB,KAAK;IACnC,IAAI,CAACsB,OAAO,OAAOD;IACnB,OAAO,aACFA;QACHE,QAAQF,KAAKE,MAAM,CAAClB,GAAG,CAAC,CAACmB,QACvBT,qBAAqBU,GAAG,CAACD,MAAMxB,IAAI,IAAI,aAAKwB;gBAAOb,IAAIvB;iBAAwBoC;QAEjFN,SAASI,MAAMJ,OAAO,GAAGG,KAAKH,OAAO,CAACb,GAAG,CAAC,CAACqB,SAAY,aAAKA;gBAAQf,IAAIvB;kBAA0BiC,KAAKH,OAAO;OAC1GG,KAAKM,KAAK,GAAG;QAAEA,OAAON,KAAKM,KAAK,CAACtB,GAAG,CAAC,CAACuB,OAAU,aAAKA;gBAAMjB,IAAIvB;;IAAwB,IAAI,CAAC;AAEpG;AAEA;;;;CAIC,GACD,OAAO,SAASyC,cAAcrB,GAAkC;QAC/CA;IAAf,MAAMsB,UAAStB,cAAAA,IAAIuB,MAAM,qBAAVvB,WAAY,CAAC,cAAc;IAC1C,OAAO,OAAOsB,WAAW,YAAYA,SAASA,SAAStB,IAAIM,GAAG;AAChE"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/jobs/ai-job-draft-ids.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { createResourceUid } from '@aglyn/aglyn/app-utils/create-resource-uid'\nimport type { AiBuildPlan, AiBuildPlanCreateKind } from '../model/ai-build-plan'\nimport type { AiJob, AiJobDraftSlot, AiJobKind } from '../model/ai-jobs.types'\n\n/**\n * The ids a job's drafts are written under (AGL-3079).\n *\n * A draft a job writes is the resource a member would otherwise have made in\n * the console, so it is named the way the console names one: by\n * `createResourceUid()`. Each id is minted ONCE and recorded on the job before\n * the draft is written. That record is what lets a step run again safely: a\n * run cut off after its write reads the same id, finds the draft, and reports\n * it rather than writing a second.\n *\n * Where an id is recorded follows what decides the draft exists:\n *\n * - A draft the job's KIND always writes — a layout job's layout, a page\n * job's screen, a campaign's design and campaign — is minted when the job\n * is created, on the step that writes it (`AiJobStep.draftIds`).\n * - A draft the PLAN decides — what a page job's plan creates, a scaffold's\n * layout, form and pages — is minted when the plan is kept, on the plan's\n * own entry (`AiBuildPlanCreate.id`, `AiBuildPlanScreen.id`). Those are\n * built one unit a pass by the step that owns their kind, under a job named\n * by the entry's id (`aiSiteUnitJob`).\n *\n * A job whose step records no id names its draft by the job's own id, which\n * is the id every draft of such a job was written under.\n */\n\n/** The drafts each kind's step writes of its own, whatever its plan says. */\nexport const AI_JOB_DRAFT_SLOTS: Readonly<Partial<Record<AiJobKind, readonly AiJobDraftSlot[]>>> = {\n page: ['screen'],\n layout: ['layout'],\n template: ['template'],\n form: ['form'],\n component: ['component'],\n email: ['email'],\n campaign: ['email', 'campaign'],\n workflow: ['workflow'],\n // The welcome email a scaffold builds; its pages and creations are its plan's.\n site: ['email'],\n}\n\n/** Fresh ids for the drafts a job of this kind writes of its own; `null` for a kind that writes none. */\nexport function aiMintJobDraftIds(kind: AiJobKind): Partial<Record<AiJobDraftSlot, string>> | null {\n const slots = AI_JOB_DRAFT_SLOTS[kind]\n if (!slots?.length) return null\n return Object.fromEntries(slots.map((slot) => [slot, createResourceUid()]))\n}\n\n/** The id recorded on the job's steps for its draft of `slot`; `null` where none is. */\nexport function aiRecordedJobDraftId(job: Pick<AiJob, 'steps'>, slot: AiJobDraftSlot): string | null {\n for (const step of job.steps ?? []) {\n const id = step.draftIds?.[slot]\n if (typeof id === 'string' && id) return id\n }\n return null\n}\n\n/**\n * The id the job writes its draft of `slot` under, and finds it by when the\n * step runs again: the id recorded on its step, else the job's own id — which\n * names a unit's job by its plan entry's id, and a job whose step records none.\n */\nexport function aiJobDraftId(job: Pick<AiJob, '$id' | 'steps'>, slot: AiJobDraftSlot): string {\n return aiRecordedJobDraftId(job, slot) ?? job.$id\n}\n\n/**\n * The creations a job writes as documents: a theme change is a proposal. A\n * dataset is written by the data plugin for a site start (AGL-3616), under\n * the id minted here.\n */\nconst DRAFT_CREATION_KINDS: ReadonlySet<AiBuildPlanCreateKind> = new Set<AiBuildPlanCreateKind>([\n 'component',\n 'form',\n 'layout',\n 'template',\n 'email',\n 'dataset',\n])\n\n/** The kinds whose step builds what their plan names, one unit a draft, and whether that includes its screens. */\nconst UNIT_PLAN_KINDS: Readonly<Partial<Record<AiJobKind, { screens: boolean }>>> = {\n // A page job's own screen is its kind's draft; its plan's creations are units.\n page: { screens: false },\n site: { screens: true },\n // So are the components and forms a template, layout or component job\n // builds before its own record (AGL-3143 §15).\n template: { screens: false },\n layout: { screens: false },\n component: { screens: false },\n // A build names every draft its plan decides, its items' too (AGL-3616).\n build: { screens: true },\n}\n\n/**\n * The plan as a job of `kind` keeps it: for a kind that builds what its plan\n * names, a fresh id on every creation it writes as a document and, for a\n * scaffold, on every screen. An id the plan already carried is replaced —\n * a plan reused from another job names that job's drafts — so the drafts\n * this job builds are its own. Any other kind's plan is kept as it is.\n */\nexport function aiPlanWithDraftIds<T extends AiBuildPlan>(kind: AiJobKind, plan: T): T {\n const units = UNIT_PLAN_KINDS[kind]\n if (!units) return plan\n return {\n ...plan,\n create: plan.create.map((entry) =>\n DRAFT_CREATION_KINDS.has(entry.kind) ? { ...entry, id: createResourceUid() } : entry,\n ),\n screens: units.screens ? plan.screens.map((screen) => ({ ...screen, id: createResourceUid() })) : plan.screens,\n ...(plan.items ? { items: plan.items.map((item) => ({ ...item, id: createResourceUid() })) } : {}),\n }\n}\n\n/**\n * The job the member started, whichever unit is running (AGL-3596): a unit's\n * derived job carries it as `inputs.originJobId`, and a job a member started\n * is its own. What a draft is stamped with as `aiJobId`.\n */\nexport function aiOriginJobId(job: Pick<AiJob, '$id' | 'inputs'>): string {\n const origin = job.inputs?.['originJobId']\n return typeof origin === 'string' && origin ? origin : job.$id\n}\n"],"names":["createResourceUid","AI_JOB_DRAFT_SLOTS","page","layout","template","form","component","email","campaign","workflow","site","aiMintJobDraftIds","kind","slots","length","Object","fromEntries","map","slot","aiRecordedJobDraftId","job","step","steps","id","draftIds","aiJobDraftId","$id","DRAFT_CREATION_KINDS","Set","UNIT_PLAN_KINDS","screens","build","aiPlanWithDraftIds","plan","units","create","entry","has","screen","items","item","aiOriginJobId","origin","inputs"],"mappings":";AAAA;;;;;;;;;;;;;;;CAeC,GAED,SAASA,iBAAiB,QAAQ,6CAA4C;AAI9E;;;;;;;;;;;;;;;;;;;;;;;CAuBC,GAED,2EAA2E,GAC3E,OAAO,MAAMC,qBAAsF;IACjGC,MAAM;QAAC;KAAS;IAChBC,QAAQ;QAAC;KAAS;IAClBC,UAAU;QAAC;KAAW;IACtBC,MAAM;QAAC;KAAO;IACdC,WAAW;QAAC;KAAY;IACxBC,OAAO;QAAC;KAAQ;IAChBC,UAAU;QAAC;QAAS;KAAW;IAC/BC,UAAU;QAAC;KAAW;IACtB,+EAA+E;IAC/EC,MAAM;QAAC;KAAQ;AACjB,EAAC;AAED,uGAAuG,GACvG,OAAO,SAASC,kBAAkBC,IAAe;IAC/C,MAAMC,QAAQZ,kBAAkB,CAACW,KAAK;IACtC,IAAI,EAACC,yBAAAA,MAAOC,MAAM,GAAE,OAAO;IAC3B,OAAOC,OAAOC,WAAW,CAACH,MAAMI,GAAG,CAAC,CAACC,OAAS;YAACA;YAAMlB;SAAoB;AAC3E;AAEA,sFAAsF,GACtF,OAAO,SAASmB,qBAAqBC,GAAyB,EAAEF,IAAoB;QAC/DE;IAAnB,KAAK,MAAMC,SAAQD,aAAAA,IAAIE,KAAK,YAATF,aAAa,EAAE,CAAE;YACvBC;QAAX,MAAME,MAAKF,iBAAAA,KAAKG,QAAQ,qBAAbH,cAAe,CAACH,KAAK;QAChC,IAAI,OAAOK,OAAO,YAAYA,IAAI,OAAOA;IAC3C;IACA,OAAO;AACT;AAEA;;;;CAIC,GACD,OAAO,SAASE,aAAaL,GAAiC,EAAEF,IAAoB;QAC3EC;IAAP,QAAOA,wBAAAA,qBAAqBC,KAAKF,iBAA1BC,wBAAmCC,IAAIM,GAAG;AACnD;AAEA;;;;CAIC,GACD,MAAMC,uBAA2D,IAAIC,IAA2B;IAC9F;IACA;IACA;IACA;IACA;IACA;CACD;AAED,gHAAgH,GAChH,MAAMC,kBAA8E;IAClF,+EAA+E;IAC/E3B,MAAM;QAAE4B,SAAS;IAAM;IACvBpB,MAAM;QAAEoB,SAAS;IAAK;IACtB,sEAAsE;IACtE,+CAA+C;IAC/C1B,UAAU;QAAE0B,SAAS;IAAM;IAC3B3B,QAAQ;QAAE2B,SAAS;IAAM;IACzBxB,WAAW;QAAEwB,SAAS;IAAM;IAC5B,yEAAyE;IACzEC,OAAO;QAAED,SAAS;IAAK;AACzB;AAEA;;;;;;CAMC,GACD,OAAO,SAASE,mBAA0CpB,IAAe,EAAEqB,IAAO;IAChF,MAAMC,QAAQL,eAAe,CAACjB,KAAK;IACnC,IAAI,CAACsB,OAAO,OAAOD;IACnB,OAAO,aACFA;QACHE,QAAQF,KAAKE,MAAM,CAAClB,GAAG,CAAC,CAACmB,QACvBT,qBAAqBU,GAAG,CAACD,MAAMxB,IAAI,IAAI,aAAKwB;gBAAOb,IAAIvB;iBAAwBoC;QAEjFN,SAASI,MAAMJ,OAAO,GAAGG,KAAKH,OAAO,CAACb,GAAG,CAAC,CAACqB,SAAY,aAAKA;gBAAQf,IAAIvB;kBAA0BiC,KAAKH,OAAO;OAC1GG,KAAKM,KAAK,GAAG;QAAEA,OAAON,KAAKM,KAAK,CAACtB,GAAG,CAAC,CAACuB,OAAU,aAAKA;gBAAMjB,IAAIvB;;IAAwB,IAAI,CAAC;AAEpG;AAEA;;;;CAIC,GACD,OAAO,SAASyC,cAAcrB,GAAkC;QAC/CA;IAAf,MAAMsB,UAAStB,cAAAA,IAAIuB,MAAM,qBAAVvB,WAAY,CAAC,cAAc;IAC1C,OAAO,OAAOsB,WAAW,YAAYA,SAASA,SAAStB,IAAIM,GAAG;AAChE"}
@@ -0,0 +1,100 @@
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
+ import { pluginResourceDraftWriter } from '@aglyn/aglyn/plugin-manager/plugin-resource-drafts';
18
+ import type { NodesMap } from '@aglyn/aglyn/types/nodes';
19
+ import type { AiSiteInventory } from '../model/ai-site-inventory';
20
+ /**
21
+ * A FORM THAT WRITES TO A DATASET (AGL-3616; Zach, 2026-10-10: Aglyn AI's
22
+ * forms can write to datasets — a volunteer sign-up into a Volunteers
23
+ * dataset, an RSVP into an event's attendees, a catering inquiry into
24
+ * Inquiries).
25
+ *
26
+ * The plan says which dataset a form writes to (`writesTo` on its creation);
27
+ * it is never inferred from what a section places. The dataset is built
28
+ * first — a site start's dataset unit, a build's dataset item, or one the
29
+ * site already has — and the form step binds the form it generated the way a
30
+ * person binds one on the Form element: the form node's `datasetId`, and
31
+ * each Form Field's `datasetFieldId` where the dataset has a field of the
32
+ * same name and a type the submitted value can be stored as. A field the
33
+ * dataset lacks is left unbound, as the Form element's mapping leaves one:
34
+ * its value stays in the Inbox copy, and a form never adds a field to a
35
+ * dataset.
36
+ *
37
+ * The gates are the platform's. The binding is made only where the plan
38
+ * includes the data store (`dataStore`), the data plugin's writer is loaded
39
+ * here and reads the dataset, and the dataset is one this job made or one the
40
+ * site's inventory shows. Records, their allowance and storage are held at
41
+ * each submission by the data plugin's own record target. Anywhere else the
42
+ * form is the form it always was, its submissions in the Inbox.
43
+ */
44
+ /** The unit input a dataset this job made for the form rides in, by id. */
45
+ export declare const AI_FORM_DATASET_MADE_INPUT = "formDatasetMade";
46
+ /** One field of the dataset a form writes to, as its writer reports it: storage type words. */
47
+ export interface AiFormDatasetField {
48
+ id: string;
49
+ name: string;
50
+ type: string;
51
+ }
52
+ /** The dataset a form writes to, with the fields a submission may fill. */
53
+ export interface AiFormDataset {
54
+ id: string;
55
+ name: string;
56
+ fields: AiFormDatasetField[];
57
+ }
58
+ /** A field name as two spellings of it compare: `fullName`, `full_name` and "Full name" are one. */
59
+ export declare function aiFormFieldKey(name: string): string;
60
+ /**
61
+ * Whether a submitted value of this form field type can be stored in a
62
+ * dataset field of this storage type. Every value a form submits is text, so
63
+ * a text field takes any of them and a number field takes a rating; any
64
+ * other pairing is left unbound rather than refused at every submission.
65
+ */
66
+ export declare function aiFormFieldFitsDataset(fieldType: string, datasetType: string): boolean;
67
+ /** What a binding came to: the fields bound, and the fields the dataset has no place for. */
68
+ export interface AiFormDatasetBinding {
69
+ bound: string[];
70
+ unbound: string[];
71
+ }
72
+ /**
73
+ * Binds a form design to a dataset, in place: the form node's `datasetId`,
74
+ * and `datasetFieldId` on each Form Field the dataset has a field for, by its
75
+ * `fieldName` or its label, each dataset field taken once. The platform's
76
+ * consent field is never bound. A binding the design already carried is
77
+ * replaced, so what the model drew never chooses where a record lands.
78
+ */
79
+ export declare function aiBindFormToDataset(nodes: NodesMap, formNodeId: string, dataset: AiFormDataset): AiFormDatasetBinding;
80
+ export interface AiFormDatasetReadDeps {
81
+ writerFor?: typeof pluginResourceDraftWriter;
82
+ }
83
+ /**
84
+ * The dataset a form may write to, or `null` where it may not: the plan
85
+ * includes no data store, the data plugin's writer is not loaded here, the
86
+ * dataset is neither one this job made nor one the site's inventory shows,
87
+ * or it has no field a submission could fill.
88
+ */
89
+ export declare function aiReadFormDataset(input: {
90
+ hostId: string;
91
+ id: string | null | undefined;
92
+ org: object | null;
93
+ inventory: Pick<AiSiteInventory, 'datasets'> | null;
94
+ /** The dataset this job made for the form, by id. */
95
+ madeId?: unknown;
96
+ }, deps?: AiFormDatasetReadDeps): Promise<AiFormDataset | null>;
97
+ /** What the form's generation is told about the dataset it writes to. */
98
+ export declare function aiFormDatasetPromptLine(dataset: AiFormDataset): string;
99
+ /** What the form's row says about where its submissions are also saved. */
100
+ export declare function aiFormDatasetNote(dataset: AiFormDataset, binding: AiFormDatasetBinding): string;