@vectoriox/iox-ui 5.51.0 → 5.53.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.
- package/design-core/index.d.ts +27 -0
- package/fesm2022/vectoriox-iox-ui-design-core.mjs +24 -0
- package/fesm2022/vectoriox-iox-ui-design-core.mjs.map +1 -1
- package/fesm2022/vectoriox-iox-ui-generation-core.mjs +142 -1
- package/fesm2022/vectoriox-iox-ui-generation-core.mjs.map +1 -1
- package/fesm2022/vectoriox-iox-ui-harness-core.mjs +496 -311
- package/fesm2022/vectoriox-iox-ui-harness-core.mjs.map +1 -1
- package/generation-core/index.d.ts +146 -2
- package/harness-core/index.d.ts +147 -2
- package/package.json +1 -1
- package/src/design-core/flavor-spec.generated.ts +24 -0
- package/src/design-core/style-presets.ts +3 -0
- package/src/generation-core/ai-run.ts +205 -0
- package/src/generation-core/public-api.ts +1 -0
- package/src/harness-core/business-types.ts +2 -0
- package/src/harness-core/harness-spec.generated.ts +240 -120
- package/src/harness-core/rank.ts +17 -1
- package/src/harness-core/site-analysis.ts +70 -0
|
@@ -1695,6 +1695,7 @@ export const SPEC_STYLE_PRESETS = [
|
|
|
1695
1695
|
"Minimalism & Swiss Style"
|
|
1696
1696
|
],
|
|
1697
1697
|
"blurb": "Clean, light and easy to read. Says \"you are in good hands\".",
|
|
1698
|
+
"blurbHe": "נקי, בהיר וקל לקריאה. אומר \"אתם בידיים טובות\".",
|
|
1698
1699
|
"slice": true
|
|
1699
1700
|
},
|
|
1700
1701
|
{
|
|
@@ -1727,6 +1728,7 @@ export const SPEC_STYLE_PRESETS = [
|
|
|
1727
1728
|
"Swiss Modernism 2.0"
|
|
1728
1729
|
],
|
|
1729
1730
|
"blurb": "Black on white, a strict grid, nothing extra.",
|
|
1731
|
+
"blurbHe": "שחור על לבן, גריד קפדני, בלי שום תוספות.",
|
|
1730
1732
|
"slice": true
|
|
1731
1733
|
},
|
|
1732
1734
|
{
|
|
@@ -1757,6 +1759,7 @@ export const SPEC_STYLE_PRESETS = [
|
|
|
1757
1759
|
"Trust & Authority (landing)"
|
|
1758
1760
|
],
|
|
1759
1761
|
"blurb": "Navy, plain type, firm edges. Serious without being cold.",
|
|
1762
|
+
"blurbHe": "כחול כהה, אותיות פשוטות ופינות חדות. רציני, אבל לא קר.",
|
|
1760
1763
|
"slice": true
|
|
1761
1764
|
},
|
|
1762
1765
|
{
|
|
@@ -1788,6 +1791,7 @@ export const SPEC_STYLE_PRESETS = [
|
|
|
1788
1791
|
"Accessible & Ethical"
|
|
1789
1792
|
],
|
|
1790
1793
|
"blurb": "Bright, soft and reassuring, with rounded buttons.",
|
|
1794
|
+
"blurbHe": "בהיר, רך ומרגיע, עם כפתורים מעוגלים.",
|
|
1791
1795
|
"slice": false
|
|
1792
1796
|
},
|
|
1793
1797
|
{
|
|
@@ -1820,6 +1824,7 @@ export const SPEC_STYLE_PRESETS = [
|
|
|
1820
1824
|
"Editorial Grid / Magazine"
|
|
1821
1825
|
],
|
|
1822
1826
|
"blurb": "White walls and a quiet serif. The work does the talking.",
|
|
1827
|
+
"blurbHe": "קירות לבנים וסריף שקט. העבודות מדברות בעד עצמן.",
|
|
1823
1828
|
"slice": true
|
|
1824
1829
|
},
|
|
1825
1830
|
{
|
|
@@ -1851,6 +1856,7 @@ export const SPEC_STYLE_PRESETS = [
|
|
|
1851
1856
|
"Nature Distilled"
|
|
1852
1857
|
],
|
|
1853
1858
|
"blurb": "Cream paper, terracotta and a soft serif, like a good magazine.",
|
|
1859
|
+
"blurbHe": "נייר בצבע שמנת, טרקוטה וסריף רך, כמו מגזין טוב.",
|
|
1854
1860
|
"slice": true
|
|
1855
1861
|
},
|
|
1856
1862
|
{
|
|
@@ -1882,6 +1888,7 @@ export const SPEC_STYLE_PRESETS = [
|
|
|
1882
1888
|
"Nature Distilled"
|
|
1883
1889
|
],
|
|
1884
1890
|
"blurb": "Rose-tinted cream, a fine serif and slow, gentle motion.",
|
|
1891
|
+
"blurbHe": "שמנת בגוון ורוד, סריף עדין ותנועה איטית ורכה.",
|
|
1885
1892
|
"slice": true
|
|
1886
1893
|
},
|
|
1887
1894
|
{
|
|
@@ -1914,6 +1921,7 @@ export const SPEC_STYLE_PRESETS = [
|
|
|
1914
1921
|
"Liquid Glass (luxury rows, without the glass)"
|
|
1915
1922
|
],
|
|
1916
1923
|
"blurb": "Bronze on warm white. Expensive, never loud.",
|
|
1924
|
+
"blurbHe": "ברונזה על לבן חם. יוקרתי, אבל אף פעם לא צעקני.",
|
|
1917
1925
|
"slice": false
|
|
1918
1926
|
},
|
|
1919
1927
|
{
|
|
@@ -1945,6 +1953,7 @@ export const SPEC_STYLE_PRESETS = [
|
|
|
1945
1953
|
"Vibrant & Block-based"
|
|
1946
1954
|
],
|
|
1947
1955
|
"blurb": "A night out: dark rooms, one bright colour, lively motion.",
|
|
1956
|
+
"blurbHe": "יציאה בלילה: חללים כהים, צבע בוהק אחד ותנועה תוססת.",
|
|
1948
1957
|
"slice": false
|
|
1949
1958
|
},
|
|
1950
1959
|
{
|
|
@@ -1976,6 +1985,7 @@ export const SPEC_STYLE_PRESETS = [
|
|
|
1976
1985
|
"Brutalism"
|
|
1977
1986
|
],
|
|
1978
1987
|
"blurb": "Black, sharp and orange. A shop with attitude.",
|
|
1988
|
+
"blurbHe": "שחור, חד וכתום. עסק עם אופי.",
|
|
1979
1989
|
"slice": false
|
|
1980
1990
|
},
|
|
1981
1991
|
{
|
|
@@ -2008,6 +2018,7 @@ export const SPEC_STYLE_PRESETS = [
|
|
|
2008
2018
|
"Minimalism & Swiss Style"
|
|
2009
2019
|
],
|
|
2010
2020
|
"blurb": "Pictures on black, like a darkened gallery.",
|
|
2021
|
+
"blurbHe": "תמונות על רקע שחור, כמו בגלריה חשוכה.",
|
|
2011
2022
|
"slice": true
|
|
2012
2023
|
},
|
|
2013
2024
|
{
|
|
@@ -2040,6 +2051,7 @@ export const SPEC_STYLE_PRESETS = [
|
|
|
2040
2051
|
"Minimalism & Swiss Style"
|
|
2041
2052
|
],
|
|
2042
2053
|
"blurb": "Dark, precise and modern, for people who build things.",
|
|
2054
|
+
"blurbHe": "כהה, מדויק ועכשווי, לאנשים שבונים דברים.",
|
|
2043
2055
|
"slice": false
|
|
2044
2056
|
},
|
|
2045
2057
|
{
|
|
@@ -2071,6 +2083,7 @@ export const SPEC_STYLE_PRESETS = [
|
|
|
2071
2083
|
"Soft UI Evolution"
|
|
2072
2084
|
],
|
|
2073
2085
|
"blurb": "Frosted panels over a soft teal light. Fresh and calm.",
|
|
2086
|
+
"blurbHe": "משטחי זכוכית חלבית על אור טורקיז רך. רענן ורגוע.",
|
|
2074
2087
|
"slice": true
|
|
2075
2088
|
},
|
|
2076
2089
|
{
|
|
@@ -2101,6 +2114,7 @@ export const SPEC_STYLE_PRESETS = [
|
|
|
2101
2114
|
"Glassmorphism"
|
|
2102
2115
|
],
|
|
2103
2116
|
"blurb": "Sea-blue glass and big photos. Makes people want to go.",
|
|
2117
|
+
"blurbHe": "זכוכית בכחול של ים ותמונות גדולות. מעורר חשק לנסוע.",
|
|
2104
2118
|
"slice": false
|
|
2105
2119
|
},
|
|
2106
2120
|
{
|
|
@@ -2132,6 +2146,7 @@ export const SPEC_STYLE_PRESETS = [
|
|
|
2132
2146
|
"Spatial UI (VisionOS)"
|
|
2133
2147
|
],
|
|
2134
2148
|
"blurb": "Grey glass and lots of space around your pictures.",
|
|
2149
|
+
"blurbHe": "זכוכית אפורה והרבה מרחב סביב התמונות שלכם.",
|
|
2135
2150
|
"slice": true
|
|
2136
2151
|
},
|
|
2137
2152
|
{
|
|
@@ -2162,6 +2177,7 @@ export const SPEC_STYLE_PRESETS = [
|
|
|
2162
2177
|
"Vibrant & Block-based"
|
|
2163
2178
|
],
|
|
2164
2179
|
"blurb": "Warm coral and bouncy buttons. Full of energy.",
|
|
2180
|
+
"blurbHe": "אלמוג חם וכפתורים קופצניים. מלא אנרגיה.",
|
|
2165
2181
|
"slice": false
|
|
2166
2182
|
},
|
|
2167
2183
|
{
|
|
@@ -2193,6 +2209,7 @@ export const SPEC_STYLE_PRESETS = [
|
|
|
2193
2209
|
"Soft UI Evolution"
|
|
2194
2210
|
],
|
|
2195
2211
|
"blurb": "Berry red, round shapes, a cheerful headline face.",
|
|
2212
|
+
"blurbHe": "אדום פירות יער, צורות עגולות ופונט כותרות עליז.",
|
|
2196
2213
|
"slice": true
|
|
2197
2214
|
},
|
|
2198
2215
|
{
|
|
@@ -2224,6 +2241,7 @@ export const SPEC_STYLE_PRESETS = [
|
|
|
2224
2241
|
"Organic Biophilic"
|
|
2225
2242
|
],
|
|
2226
2243
|
"blurb": "Leaf green and soft, open shapes. Welcoming to everyone.",
|
|
2244
|
+
"blurbHe": "ירוק עלים וצורות רכות ופתוחות. מזמין את כולם.",
|
|
2227
2245
|
"slice": false
|
|
2228
2246
|
},
|
|
2229
2247
|
{
|
|
@@ -2254,6 +2272,7 @@ export const SPEC_STYLE_PRESETS = [
|
|
|
2254
2272
|
"Vibrant & Block-based"
|
|
2255
2273
|
],
|
|
2256
2274
|
"blurb": "Teal, chunky and playful. Made for families.",
|
|
2275
|
+
"blurbHe": "טורקיז, צורות שמנמנות והרבה שובבות. נועד למשפחות.",
|
|
2257
2276
|
"slice": false
|
|
2258
2277
|
},
|
|
2259
2278
|
{
|
|
@@ -2285,6 +2304,7 @@ export const SPEC_STYLE_PRESETS = [
|
|
|
2285
2304
|
"Organic Biophilic"
|
|
2286
2305
|
],
|
|
2287
2306
|
"blurb": "Dusty rose and soft lavender light. A celebration.",
|
|
2307
|
+
"blurbHe": "ורוד עתיק ואור לבנדר רך. תחושה של חגיגה.",
|
|
2288
2308
|
"slice": true
|
|
2289
2309
|
},
|
|
2290
2310
|
{
|
|
@@ -2316,6 +2336,7 @@ export const SPEC_STYLE_PRESETS = [
|
|
|
2316
2336
|
"Vibrant & Block-based"
|
|
2317
2337
|
],
|
|
2318
2338
|
"blurb": "Thick outlines and orange. Proud of what you make.",
|
|
2339
|
+
"blurbHe": "קווי מתאר עבים וכתום. גאים במה שאתם יוצרים.",
|
|
2319
2340
|
"slice": true
|
|
2320
2341
|
},
|
|
2321
2342
|
{
|
|
@@ -2348,6 +2369,7 @@ export const SPEC_STYLE_PRESETS = [
|
|
|
2348
2369
|
"Vibrant & Block-based"
|
|
2349
2370
|
],
|
|
2350
2371
|
"blurb": "Pink, heavy type, poster energy.",
|
|
2372
|
+
"blurbHe": "ורוד, אותיות כבדות, אנרגיה של פוסטר.",
|
|
2351
2373
|
"slice": false
|
|
2352
2374
|
},
|
|
2353
2375
|
{
|
|
@@ -2379,6 +2401,7 @@ export const SPEC_STYLE_PRESETS = [
|
|
|
2379
2401
|
"Anti-Polish / Raw Aesthetic"
|
|
2380
2402
|
],
|
|
2381
2403
|
"blurb": "Electric blue and an odd, wide face. Made by hand, on purpose.",
|
|
2404
|
+
"blurbHe": "כחול חשמלי ופונט רחב ומשונה. נראה כמו עבודת יד, ובכוונה.",
|
|
2382
2405
|
"slice": false
|
|
2383
2406
|
},
|
|
2384
2407
|
{
|
|
@@ -2410,6 +2433,7 @@ export const SPEC_STYLE_PRESETS = [
|
|
|
2410
2433
|
"Flat Design"
|
|
2411
2434
|
],
|
|
2412
2435
|
"blurb": "Green and bright, like a market stall in the morning.",
|
|
2436
|
+
"blurbHe": "ירוק ובהיר, כמו דוכן בשוק בבוקר.",
|
|
2413
2437
|
"slice": false
|
|
2414
2438
|
}
|
|
2415
2439
|
] as const;
|
|
@@ -21,8 +21,11 @@ export type PresetMode = Exclude<DesignMode, 'auto'>;
|
|
|
21
21
|
|
|
22
22
|
export interface StylePreset {
|
|
23
23
|
readonly id: string;
|
|
24
|
+
/** A proper name — never translated. */
|
|
24
25
|
readonly name: string;
|
|
25
26
|
readonly blurb: string;
|
|
27
|
+
/** The blurb in Hebrew (2026-10-25). */
|
|
28
|
+
readonly blurbHe: string;
|
|
26
29
|
readonly flavorId: string;
|
|
27
30
|
readonly seed: string;
|
|
28
31
|
readonly tint: TintId;
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The AI pipeline's WIRE vocabulary (AI plan §3c, §3n, M0): what iox-cms's `ai` API answers and what every client
|
|
3
|
+
* of it reads — the steps a model works on, who pays (IOX credits or the studio's own key), a model of the vetted
|
|
4
|
+
* list with its price per token class, the one cost → credits rule (1 credit = 1 US cent of what the AI cost, D4),
|
|
5
|
+
* the refusals (board 11) and a generation's stages. ONE definition: iox-cms meters and refuses with it, the
|
|
6
|
+
* Settings ▸ AI screen and the wizard show it. Pure types, enums and helpers; no transport, no prices typed here.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export enum AiProviderId {
|
|
10
|
+
Anthropic = 'anthropic',
|
|
11
|
+
OpenRouter = 'openrouter',
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** Who pays: the platform's credits, or the studio's own provider key (metered for display, never charged). */
|
|
15
|
+
export enum AiKeyMode {
|
|
16
|
+
Platform = 'platform',
|
|
17
|
+
Own = 'own',
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** The steps a model works on (board 9's rows), in screen order. */
|
|
21
|
+
export enum AiStep {
|
|
22
|
+
ReadMessage = 'read',
|
|
23
|
+
PlanSite = 'plan',
|
|
24
|
+
ChangePlan = 'change',
|
|
25
|
+
MakePictures = 'pictures',
|
|
26
|
+
NameStructures = 'scan',
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const AI_STEPS: ReadonlyArray<AiStep> = Object.values(AiStep);
|
|
30
|
+
|
|
31
|
+
/** What a model must be able to do for a step to run on it. */
|
|
32
|
+
export enum AiCapability {
|
|
33
|
+
StructuredOutput = 'structured-output',
|
|
34
|
+
ImageInput = 'image-input',
|
|
35
|
+
ImageOutput = 'image-output',
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const AI_STEP_NEEDS: Readonly<Record<AiStep, ReadonlyArray<AiCapability>>> = {
|
|
39
|
+
[AiStep.ReadMessage]: [AiCapability.StructuredOutput, AiCapability.ImageInput],
|
|
40
|
+
[AiStep.PlanSite]: [AiCapability.StructuredOutput],
|
|
41
|
+
[AiStep.ChangePlan]: [AiCapability.StructuredOutput],
|
|
42
|
+
[AiStep.MakePictures]: [AiCapability.ImageOutput],
|
|
43
|
+
[AiStep.NameStructures]: [AiCapability.StructuredOutput],
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/** Tokens a typical use of a step reads and writes (plan §3d "Where credits go") — what a shown estimate is made of. */
|
|
47
|
+
export const AI_STEP_TYPICAL_TOKENS: Readonly<Record<AiStep, AiTokenCounts>> = {
|
|
48
|
+
[AiStep.ReadMessage]: { input: 8_800, output: 1_500, cacheWrite: 0, cacheRead: 0 },
|
|
49
|
+
[AiStep.PlanSite]: { input: 12_000, output: 7_000, cacheWrite: 0, cacheRead: 0 },
|
|
50
|
+
[AiStep.ChangePlan]: { input: 6_000, output: 500, cacheWrite: 0, cacheRead: 0 },
|
|
51
|
+
[AiStep.MakePictures]: { input: 1_120, output: 0, cacheWrite: 0, cacheRead: 0 },
|
|
52
|
+
[AiStep.NameStructures]: { input: 80_000, output: 10_000, cacheWrite: 0, cacheRead: 0 },
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/** Tokens by the class a provider prices them in. */
|
|
56
|
+
export interface AiTokenCounts {
|
|
57
|
+
input: number;
|
|
58
|
+
output: number;
|
|
59
|
+
/** Written to the prompt cache (priced above input). */
|
|
60
|
+
cacheWrite: number;
|
|
61
|
+
/** Read from the prompt cache (priced well below input). */
|
|
62
|
+
cacheRead: number;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** US dollars per million tokens, per class. A class without a price is priced as input. */
|
|
66
|
+
export interface AiTokenPrice {
|
|
67
|
+
input: number;
|
|
68
|
+
output: number;
|
|
69
|
+
cacheWrite?: number;
|
|
70
|
+
cacheRead?: number;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** A model of the vetted list (served by the control plane with the entitlements, §3n) — its price travels with it. */
|
|
74
|
+
export interface AiModelEntry {
|
|
75
|
+
id: string;
|
|
76
|
+
provider: `${AiProviderId}`;
|
|
77
|
+
label: string;
|
|
78
|
+
/** The steps it may be chosen for. */
|
|
79
|
+
steps: ReadonlyArray<`${AiStep}`>;
|
|
80
|
+
/** The steps it is the default for (board 9's "recommended"). */
|
|
81
|
+
recommendedFor?: ReadonlyArray<`${AiStep}`>;
|
|
82
|
+
capabilities: ReadonlyArray<`${AiCapability}`>;
|
|
83
|
+
/** Null when the provider reports each call's cost itself and the list carries no price. */
|
|
84
|
+
price: AiTokenPrice | null;
|
|
85
|
+
/** Kept so old ledger rows still name it; never offered, and a studio's choice of it falls back to the default. */
|
|
86
|
+
retired?: boolean;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** 1 credit = 1 US cent of what the AI actually cost (decision D4). */
|
|
90
|
+
export const CREDITS_PER_USD = 100;
|
|
91
|
+
const TOKENS_PER_PRICE_UNIT = 1_000_000;
|
|
92
|
+
const CREDIT_PRECISION = 1e6;
|
|
93
|
+
|
|
94
|
+
export const NO_TOKENS: Readonly<AiTokenCounts> = Object.freeze({ input: 0, output: 0, cacheWrite: 0, cacheRead: 0 });
|
|
95
|
+
|
|
96
|
+
/** What `tokens` cost at `price`, in US dollars. */
|
|
97
|
+
export function costUsd(tokens: AiTokenCounts, price: AiTokenPrice): number {
|
|
98
|
+
const perToken = (perMillion: number | undefined, fallback: number) => (perMillion ?? fallback) / TOKENS_PER_PRICE_UNIT;
|
|
99
|
+
return tokens.input * perToken(price.input, 0)
|
|
100
|
+
+ tokens.output * perToken(price.output, 0)
|
|
101
|
+
+ tokens.cacheWrite * perToken(price.cacheWrite, price.input)
|
|
102
|
+
+ tokens.cacheRead * perToken(price.cacheRead, price.input);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** Dollars → credits, kept to a millionth of a credit (a short read costs a fraction of one). */
|
|
106
|
+
export function creditsOfUsd(usd: number): number {
|
|
107
|
+
return Math.round(usd * CREDITS_PER_USD * CREDIT_PRECISION) / CREDIT_PRECISION;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** The credits a typical use of `step` costs on a model of `price` — never typed, always computed (§3d). */
|
|
111
|
+
export function estimateStepCredits(step: AiStep, price: AiTokenPrice, tokens: AiTokenCounts = AI_STEP_TYPICAL_TOKENS[step]): number {
|
|
112
|
+
return creditsOfUsd(costUsd(tokens, price));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** Can `model` do `step`? The step's needs against the model's capabilities. */
|
|
116
|
+
export function modelCanDo(model: Pick<AiModelEntry, 'capabilities'>, step: AiStep): boolean {
|
|
117
|
+
return AI_STEP_NEEDS[step].every(need => model.capabilities.includes(need));
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** Why AI did not run (board 11). The server refuses with these BEFORE any model call. */
|
|
121
|
+
export enum AiRefusalCode {
|
|
122
|
+
NotInPlan = 'ai.notInPlan',
|
|
123
|
+
OutOfCredits = 'ai.outOfCredits',
|
|
124
|
+
CapReached = 'ai.capReached',
|
|
125
|
+
NotConnected = 'ai.notConnected',
|
|
126
|
+
KeyInvalid = 'ai.keyInvalid',
|
|
127
|
+
PlanUnknown = 'ai.planUnknown',
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/** The HTTP status each refusal answers with (board 11). */
|
|
131
|
+
export const AI_REFUSAL_STATUS: Readonly<Record<AiRefusalCode, number>> = {
|
|
132
|
+
[AiRefusalCode.NotInPlan]: 403,
|
|
133
|
+
[AiRefusalCode.OutOfCredits]: 402,
|
|
134
|
+
[AiRefusalCode.CapReached]: 402,
|
|
135
|
+
[AiRefusalCode.NotConnected]: 409,
|
|
136
|
+
[AiRefusalCode.KeyInvalid]: 409,
|
|
137
|
+
[AiRefusalCode.PlanUnknown]: 503,
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
/** What a refusal offers next. */
|
|
141
|
+
export enum AiNextKind {
|
|
142
|
+
/** Ask IOX (a prefilled email to the operator, until a plan can be bought — D2). */
|
|
143
|
+
Contact = 'contact',
|
|
144
|
+
/** Open Settings ▸ AI. */
|
|
145
|
+
Settings = 'settings',
|
|
146
|
+
/** Try again later, or with less. */
|
|
147
|
+
Retry = 'retry',
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export const AI_REFUSAL_NEXT: Readonly<Record<AiRefusalCode, AiNextKind>> = {
|
|
151
|
+
[AiRefusalCode.NotInPlan]: AiNextKind.Contact,
|
|
152
|
+
[AiRefusalCode.OutOfCredits]: AiNextKind.Contact,
|
|
153
|
+
[AiRefusalCode.CapReached]: AiNextKind.Retry,
|
|
154
|
+
[AiRefusalCode.NotConnected]: AiNextKind.Settings,
|
|
155
|
+
[AiRefusalCode.KeyInvalid]: AiNextKind.Settings,
|
|
156
|
+
[AiRefusalCode.PlanUnknown]: AiNextKind.Retry,
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
export interface AiRefusal {
|
|
160
|
+
code: AiRefusalCode;
|
|
161
|
+
planName?: string;
|
|
162
|
+
/** Credits left this period (platform credits only). */
|
|
163
|
+
remaining?: number;
|
|
164
|
+
/** What the refused call would have cost, about. */
|
|
165
|
+
estimate?: number;
|
|
166
|
+
next: { kind: AiNextKind; href?: string };
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** The studio's AI credits this period (the connector's meter, E4). `allowance: null` = unlimited. */
|
|
170
|
+
export interface AiMeter {
|
|
171
|
+
used: number;
|
|
172
|
+
allowance: number | null;
|
|
173
|
+
remaining: number | null;
|
|
174
|
+
periodStart: string;
|
|
175
|
+
periodEnd: string;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/** A generation's stages (§3d). The runner works while `task` is set; otherwise the owner has the next move. */
|
|
179
|
+
export enum AiGenerationStage {
|
|
180
|
+
Reading = 'reading',
|
|
181
|
+
Analysis = 'analysis',
|
|
182
|
+
Design = 'design',
|
|
183
|
+
Plan = 'plan',
|
|
184
|
+
Build = 'build',
|
|
185
|
+
Done = 'done',
|
|
186
|
+
Failed = 'failed',
|
|
187
|
+
Cancelled = 'cancelled',
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/** The stages nothing advances any more. */
|
|
191
|
+
export const FINAL_GENERATION_STAGES: ReadonlyArray<AiGenerationStage> = [AiGenerationStage.Done, AiGenerationStage.Failed, AiGenerationStage.Cancelled];
|
|
192
|
+
|
|
193
|
+
/** How one model call ended — a ledger row's status. */
|
|
194
|
+
export enum AiCallStatus {
|
|
195
|
+
/** Written before the call: a reservation at the estimate until the call settles. */
|
|
196
|
+
Started = 'started',
|
|
197
|
+
Ok = 'ok',
|
|
198
|
+
/** The answer came back and the shared validator refused it (with a path). */
|
|
199
|
+
Invalid = 'invalid',
|
|
200
|
+
/** The model declined (a provider refusal) — charged what the provider reports. */
|
|
201
|
+
Refused = 'refused',
|
|
202
|
+
Error = 'error',
|
|
203
|
+
/** The process died during the call: charged at the estimate, since what it cost was never reported. */
|
|
204
|
+
Interrupted = 'interrupted',
|
|
205
|
+
}
|
|
@@ -90,6 +90,8 @@ export const isLookRule = (rule: AvoidRule): rule is LookRule => 'when' in rule;
|
|
|
90
90
|
export interface GoodFit {
|
|
91
91
|
readonly preset: string;
|
|
92
92
|
readonly reason: string;
|
|
93
|
+
/** The reason in Hebrew (2026-10-25). */
|
|
94
|
+
readonly reasonHe: string;
|
|
93
95
|
}
|
|
94
96
|
|
|
95
97
|
export interface BusinessType {
|