@vectoriox/iox-ui 5.79.0 → 5.81.0

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.
@@ -177,7 +177,10 @@ export function modelCanDo(model: Pick<AiModelEntry, 'capabilities'>, step: AiSt
177
177
  export enum AiRefusalCode {
178
178
  NotInPlan = 'ai.notInPlan',
179
179
  OutOfCredits = 'ai.outOfCredits',
180
+ /** A step used more than twice its estimate (a loop), or the build its plan's `aiCreditsPerGeneration`. */
180
181
  CapReached = 'ai.capReached',
182
+ /** The build asked for `GENERATION_LIMITS.plans` plans already — build one, change it with a sentence, or start over. */
183
+ PlansUsed = 'ai.plansUsed',
181
184
  NotConnected = 'ai.notConnected',
182
185
  KeyInvalid = 'ai.keyInvalid',
183
186
  PlanUnknown = 'ai.planUnknown',
@@ -188,6 +191,7 @@ export const AI_REFUSAL_STATUS: Readonly<Record<AiRefusalCode, number>> = {
188
191
  [AiRefusalCode.NotInPlan]: 403,
189
192
  [AiRefusalCode.OutOfCredits]: 402,
190
193
  [AiRefusalCode.CapReached]: 402,
194
+ [AiRefusalCode.PlansUsed]: 409,
191
195
  [AiRefusalCode.NotConnected]: 409,
192
196
  [AiRefusalCode.KeyInvalid]: 409,
193
197
  [AiRefusalCode.PlanUnknown]: 503,
@@ -201,12 +205,15 @@ export enum AiNextKind {
201
205
  Settings = 'settings',
202
206
  /** Try again later, or with less. */
203
207
  Retry = 'retry',
208
+ /** Keep the plan there is: build it, or change it with a sentence. */
209
+ KeepPlan = 'keepPlan',
204
210
  }
205
211
 
206
212
  export const AI_REFUSAL_NEXT: Readonly<Record<AiRefusalCode, AiNextKind>> = {
207
213
  [AiRefusalCode.NotInPlan]: AiNextKind.Contact,
208
214
  [AiRefusalCode.OutOfCredits]: AiNextKind.Contact,
209
215
  [AiRefusalCode.CapReached]: AiNextKind.Retry,
216
+ [AiRefusalCode.PlansUsed]: AiNextKind.KeepPlan,
210
217
  [AiRefusalCode.NotConnected]: AiNextKind.Settings,
211
218
  [AiRefusalCode.KeyInvalid]: AiNextKind.Settings,
212
219
  [AiRefusalCode.PlanUnknown]: AiNextKind.Retry,
@@ -219,6 +226,8 @@ export interface AiRefusal {
219
226
  remaining?: number;
220
227
  /** What the refused call would have cost, about. */
221
228
  estimate?: number;
229
+ /** `PlansUsed`: how many plans one build may ask for. */
230
+ plans?: number;
222
231
  next: { kind: AiNextKind; href?: string };
223
232
  }
224
233
 
@@ -95,7 +95,9 @@ export interface AiGenerationView {
95
95
  siteBuildId?: string;
96
96
  models: Partial<Record<`${AiStep}`, string>>;
97
97
  estimate: number;
98
- cap: number;
98
+ /** The plan's `aiCreditsPerGeneration` for the whole build, or null when it sets none (a step's own ceiling is
99
+ * twice that step's estimate — going back and planning again starts a new step). */
100
+ cap: number | null;
99
101
  /** Derived from the ledger — the running credit total. */
100
102
  spent: number;
101
103
  error?: { code: string; detail: string; providerMessage?: string; issues?: Array<{ code: string; path: string }> };
@@ -108,10 +110,12 @@ export interface GenerationStartRequest {
108
110
  addresses?: string[];
109
111
  }
110
112
 
111
- /** The longest message, the most files and addresses a generation starts from (Start's limits). */
113
+ /** The longest message, the most files and addresses a generation starts from (Start's limits), and how many plans
114
+ * one build may ask for (a Design pick, a Try again or "Build with these" each asks one). */
112
115
  export const GENERATION_LIMITS = {
113
116
  promptChars: 4_000,
114
117
  files: 12,
115
118
  addresses: 3,
116
119
  sentenceChars: 500,
120
+ plans: 5,
117
121
  } as const;
@@ -49,6 +49,21 @@
49
49
  .iox-field__error { margin: 4px 0 0; }
50
50
  .iox-submit { font: inherit; border: none; cursor: pointer; }
51
51
 
52
+ /* The submit button follows its FORM's state (vectoriox/iox-ui#42). Its two labels (forms-core
53
+ submitButtonLabelsHtml / IoxSubmitButtonComponent) share one grid cell, so the button keeps the longer one's
54
+ width and never jumps; the form's data-iox-state picks the one that shows — the canvas's Sending state, the
55
+ component path and the string path alike. `visibility` (not display) keeps the hidden one out of the
56
+ accessible name. Busy and disabled are written by syncSubmitButtons. */
57
+ .iox-submit__labels { display: inline-grid; }
58
+ .iox-submit__labels > * { grid-area: 1 / 1; }
59
+ .iox-form:not([data-iox-state="submitting"]) .iox-submit__busy,
60
+ .iox-form[data-iox-state="submitting"] .iox-submit__idle { visibility: hidden; }
61
+ .iox-submit[aria-busy="true"] { cursor: progress; }
62
+
63
+ /* The honeypot and the failure announcer (forms-core `formChromeHtml`, IoxFormComponent's template): off-screen
64
+ rather than display:none — some bots skip hidden inputs, and a live region must stay in the tree. */
65
+ .iox-form__hp { position: absolute; inset-inline-start: -9999px; width: 1px; height: 1px; overflow: hidden; }
66
+
52
67
  /* Visually hidden, still announced — a label may be hidden, never deleted. */
53
68
  .iox-field__label--hidden {
54
69
  position: absolute; width: 1px; height: 1px; margin: -1px;