@stndrds/schema 1.0.0-alpha.265 → 1.0.0-alpha.267

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 (47) hide show
  1. package/dist/all--B2_3ksI.d.ts +465 -0
  2. package/dist/all-D5zeUllO.d.mts +465 -0
  3. package/dist/chunk-63WWFZFY.js +1262 -0
  4. package/dist/{chunk-ZBQEMIAV.js → chunk-FDIAOFHS.js} +11 -8
  5. package/dist/chunk-ITGE3PBX.mjs +1215 -0
  6. package/dist/{chunk-UXCJ3NI4.mjs → chunk-KDHDC7E6.mjs} +150 -9
  7. package/dist/{chunk-U36ZIBEM.mjs → chunk-O73ROMWQ.mjs} +15 -6
  8. package/dist/{chunk-QIWADKYA.mjs → chunk-POULKEJM.mjs} +11 -9
  9. package/dist/{chunk-EBGRZUIH.js → chunk-Q4SZAMJT.js} +5 -0
  10. package/dist/{chunk-NGGU6BSN.mjs → chunk-QMLO7V5E.mjs} +6 -6
  11. package/dist/{chunk-L4U5QEQL.js → chunk-QN2N3IJZ.js} +158 -8
  12. package/dist/{chunk-JUKLL5RJ.mjs → chunk-R5LAJCBU.mjs} +5 -2
  13. package/dist/{chunk-NI3HCSYH.js → chunk-V6Q7HCA7.js} +11 -11
  14. package/dist/{chunk-QAF3HNKQ.js → chunk-ZPFOKBIN.js} +16 -5
  15. package/dist/exceptions.d.mts +21 -8
  16. package/dist/exceptions.d.ts +21 -8
  17. package/dist/exceptions.js +42 -38
  18. package/dist/exceptions.mjs +1 -1
  19. package/dist/helpers-C1VVEAOO.d.mts +76 -0
  20. package/dist/helpers-vQ6kp8ET.d.ts +76 -0
  21. package/dist/index-Bq1KrQkR.d.ts +2413 -0
  22. package/dist/index-DtxtOBYT.d.mts +2413 -0
  23. package/dist/index.d.mts +1516 -2212
  24. package/dist/index.d.ts +1516 -2212
  25. package/dist/index.js +1294 -1038
  26. package/dist/index.mjs +911 -905
  27. package/dist/{helpers-eyrnPJEF.d.ts → objects-A1ED9af-.d.ts} +32 -77
  28. package/dist/{helpers-uKLet0kF.d.mts → objects-BCaBw2ef.d.mts} +32 -77
  29. package/dist/validation/all.d.mts +4 -2
  30. package/dist/validation/all.d.ts +4 -2
  31. package/dist/validation/all.js +88 -16
  32. package/dist/validation/all.mjs +9 -9
  33. package/dist/validation/complex/phone.js +2 -2
  34. package/dist/validation/complex/phone.mjs +1 -1
  35. package/dist/validation/config/index.d.mts +5 -18
  36. package/dist/validation/config/index.d.ts +5 -18
  37. package/dist/validation/config/index.js +34 -4
  38. package/dist/validation/config/index.mjs +7 -1
  39. package/dist/validation/object/index.d.mts +2 -2
  40. package/dist/validation/object/index.d.ts +2 -2
  41. package/dist/validation/object/index.js +19 -19
  42. package/dist/validation/object/index.mjs +7 -7
  43. package/dist/validation/primitives/text.js +2 -2
  44. package/dist/validation/primitives/text.mjs +1 -1
  45. package/package.json +2 -2
  46. package/dist/chunk-PGERPYDR.js +0 -2
  47. package/dist/chunk-SP3PNHYF.mjs +0 -1
@@ -0,0 +1,2413 @@
1
+ import { z } from 'zod';
2
+ import { A as Attribute, f as AttributeType, e as RollupAttribute } from './attributes-lBLiOIY3.mjs';
3
+ import { IconName, MimeType } from '@stndrds/constants';
4
+ import { Uuid } from './utils.mjs';
5
+ import { L as ListViewTabVisibility, T as Timestamps, R as ResourceVisibility } from './objects-BCaBw2ef.mjs';
6
+
7
+ /** Operators for text-based attributes */
8
+ type TextFilterOperator = "is" | "is_not" | "contains" | "not_contains" | "starts_with" | "ends_with" | "is_empty" | "is_not_empty";
9
+ /** Operators for number-based attributes */
10
+ type NumberFilterOperator = "is" | "is_not" | "less_than" | "greater_than" | "less_or_equal" | "greater_or_equal" | "is_empty" | "is_not_empty";
11
+ /** Operators for checkbox — `is` with a boolean rule value (a checkbox always has a value) */
12
+ type CheckboxFilterOperator = "is";
13
+ /** Operators for date-based attributes (ordering shares the numeric vocabulary) */
14
+ type DateFilterOperator = "is" | "is_not" | "less_than" | "greater_than" | "less_or_equal" | "greater_or_equal" | "is_within" | "on_day_month" | "is_empty" | "is_not_empty";
15
+ /** Operators for select-based attributes (supports single or multi-value filtering) */
16
+ type SelectFilterOperator = "is" | "is_not" | "any_of" | "none_of" | "is_empty" | "is_not_empty";
17
+ /** Operators for multiselect-based attributes — set membership only */
18
+ type MultiselectFilterOperator = "any_of" | "none_of" | "is_empty" | "is_not_empty";
19
+ /**
20
+ * Operators for relation-based attributes (covers single, multi-value, and
21
+ * reference-shaped filtering — user, relation, document share the same
22
+ * edge-backed operator set). Membership is `any_of`/`none_of` only.
23
+ */
24
+ type RelationFilterOperator = "is" | "is_not" | "any_of" | "none_of" | "is_empty" | "is_not_empty";
25
+ /**
26
+ * All possible filter operators — the canonical set of 16.
27
+ * Short input codes (`lt`, `gte`, `eq`, `in`, …) are accepted at entry only
28
+ * and normalized via SYNONYM_ALIASES; they are never stored and never typed.
29
+ */
30
+ type FilterOperator = TextFilterOperator | NumberFilterOperator | CheckboxFilterOperator | DateFilterOperator | SelectFilterOperator | MultiselectFilterOperator | RelationFilterOperator;
31
+ /** Relative date value for "is_within" operator */
32
+ interface RelativeDateValue {
33
+ amount: number;
34
+ unit: "days" | "weeks" | "months" | "years";
35
+ direction: "past" | "future";
36
+ }
37
+ /** Currency filter value with amount and optional currency codes
38
+ * - code: undefined or [] = any currency
39
+ * - code: string[] = filter by specific currencies
40
+ */
41
+ interface CurrencyFilterValue {
42
+ value: number | null;
43
+ code?: string[];
44
+ }
45
+ /** Phone filter value with number and optional country code */
46
+ interface PhoneFilterValue {
47
+ phoneNumber: string | null;
48
+ countryCode?: string;
49
+ }
50
+ /**
51
+ * A filter value resolved at query time from the execution context.
52
+ * Stored verbatim in a view's filter; replaced with a concrete value by the
53
+ * runtime before reaching any query layer. Discriminated by the `dynamic` key —
54
+ * no static FilterValue carries it.
55
+ */
56
+ type DynamicValue = {
57
+ dynamic: "actor";
58
+ ref: "current";
59
+ } | {
60
+ dynamic: "date";
61
+ anchor: "today";
62
+ } | {
63
+ dynamic: "date";
64
+ anchor: "now";
65
+ };
66
+ /** Filter value can be various types depending on the attribute */
67
+ type FilterValue = string | number | boolean | string[] | RelativeDateValue | CurrencyFilterValue | PhoneFilterValue | DynamicValue | null;
68
+ /** Existence quantifier for qualified edge rules. Maps to SQL EXISTS / NOT EXISTS. */
69
+ type EdgeQuantifier = "any" | "none";
70
+ /** A single filter rule */
71
+ interface FilterRule {
72
+ /** Root attribute name (scalar attribute, or a reference attribute when `property` is set). */
73
+ attribute: string;
74
+ /**
75
+ * If set, this rule filters on a qualified edge property.
76
+ * Requires `attribute` to be a reference attribute (today: `relation` or `document`) that has `.qualifyWith()`.
77
+ * The `operator` must be valid for the property's type, not the root attribute's type.
78
+ */
79
+ property?: string;
80
+ /**
81
+ * Existence quantifier for qualified edge rules ("at least one" vs "none").
82
+ * Only valid when `property` is set. Maps to SQL EXISTS / NOT EXISTS.
83
+ * Defaults to the operator-derived polarity when omitted.
84
+ */
85
+ quantifier?: EdgeQuantifier;
86
+ /** Filter operator */
87
+ operator: FilterOperator;
88
+ /** Filter value (null for operators like is_empty) */
89
+ value: FilterValue;
90
+ }
91
+ /**
92
+ * Extended filter rule with optional attribute definition.
93
+ * When provided, enables smarter type-aware filtering (e.g., array operators for multiselect).
94
+ */
95
+ interface ExtendedFilterRule extends FilterRule {
96
+ /** Full attribute definition for type-aware filtering */
97
+ attributeDef?: Attribute;
98
+ }
99
+ /** Combinator for filter rules */
100
+ type FilterCombinator = "and" | "or";
101
+ /** Complete filter state (simple mode) */
102
+ interface FilterState {
103
+ /** How to combine rules */
104
+ combinator: FilterCombinator;
105
+ /** List of filter rules */
106
+ rules: FilterRule[];
107
+ }
108
+ /**
109
+ * A filter group containing rules (used in advanced mode)
110
+ * Groups can be nested up to 2 levels deep
111
+ */
112
+ interface FilterGroup {
113
+ /** Unique identifier for this group */
114
+ id: string;
115
+ /** How to combine rules within this group */
116
+ combinator: FilterCombinator;
117
+ /** List of filter rules in this group */
118
+ rules: FilterRule[];
119
+ }
120
+ /**
121
+ * Advanced filter state with nested groups
122
+ * Structure: AdvancedFilterState -> FilterGroup[] -> FilterRule[]
123
+ * Maximum 2 levels of nesting
124
+ */
125
+ interface AdvancedFilterState {
126
+ /** How to combine groups at the top level */
127
+ combinator: FilterCombinator;
128
+ /** List of filter groups */
129
+ groups: FilterGroup[];
130
+ }
131
+ /** Sort direction */
132
+ type SortDirection = "asc" | "desc";
133
+ /** A single sort rule */
134
+ interface SortRule {
135
+ /** Attribute name to sort by */
136
+ attribute: string;
137
+ /** Sort direction */
138
+ direction: SortDirection;
139
+ }
140
+ /** Complete query state with search, filters, sorts, and pagination */
141
+ interface QueryState {
142
+ /** Full-text search query */
143
+ search?: string;
144
+ /** Filter configuration (simple mode) */
145
+ filters?: FilterState;
146
+ /** Advanced filter configuration (grouped mode) */
147
+ advancedFilters?: AdvancedFilterState;
148
+ /** Sort configuration (multiple sorts supported) */
149
+ sorts?: SortRule[];
150
+ /** Pagination */
151
+ limit?: number;
152
+ offset?: number;
153
+ }
154
+ /** Mapping of attribute types to their valid operators (rollup excluded — use getRollupFilterOperators()) */
155
+ declare const OPERATORS_BY_TYPE: Record<Exclude<AttributeType, "rollup">, readonly FilterOperator[]>;
156
+ /** Check if an operator requires a value */
157
+ type NoValueOperator = "is_empty" | "is_not_empty";
158
+ /** Operators that don't require a value */
159
+ declare const NO_VALUE_OPERATORS: readonly NoValueOperator[];
160
+ /**
161
+ * Check if an operator requires a value
162
+ */
163
+ declare function isNoValueOperator(operator: FilterOperator): operator is NoValueOperator;
164
+ /**
165
+ * Get the filter operators for a rollup attribute based on its aggregation function and target type.
166
+ *
167
+ * - earliest / latest → date operators
168
+ * - original → operators matching targetAttributeType (falls back to numeric if unknown)
169
+ * - all other functions → numeric operators (sum, avg, count, percent, etc.)
170
+ */
171
+ declare function getRollupFilterOperators(attr: RollupAttribute): readonly FilterOperator[];
172
+
173
+ /**
174
+ * Type of view - determines the config structure
175
+ */
176
+ type ViewType = "detail" | "list";
177
+ /**
178
+ * Creation behavior when clicking the "+" button
179
+ * - `redirect`: Create the record then navigate to its detail page
180
+ * - `inline`: Insert an empty row in the table (no navigation)
181
+ * - `peek`: Create a draft immediately and open it in the record stack side panel
182
+ */
183
+ type CreateMode = "redirect" | "inline" | "peek";
184
+ /**
185
+ * Inline attribute group configuration
186
+ * Groups multiple attributes into a single composite field with dropdown editing
187
+ */
188
+ interface AttributeGroupField {
189
+ /** Unique identifier for the group */
190
+ id: string;
191
+ /** Display label for the composite field */
192
+ label: string;
193
+ /** Description shown in the dropdown */
194
+ description?: string;
195
+ /** Attribute names to include in this group */
196
+ attributes: string[];
197
+ /**
198
+ * Template for the display value
199
+ * Uses {attributeName} syntax for interpolation
200
+ * @example "{billing_street}, {billing_city} {billing_postal_code}"
201
+ */
202
+ displayTemplate?: string;
203
+ }
204
+ /**
205
+ * Field definition within a form group
206
+ * Can be either a single attribute or an inline attribute group
207
+ */
208
+ interface Field {
209
+ /** Attribute name to display (for single attribute fields) */
210
+ attribute?: string;
211
+ /** Inline attribute group (groups multiple attributes into one composite field) */
212
+ attributeGroup?: AttributeGroupField;
213
+ /** Grid span (1-12 columns) */
214
+ span?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
215
+ /** Override label for this view (only for single attribute fields) */
216
+ label?: string;
217
+ /** Force read-only display */
218
+ readOnly?: boolean;
219
+ }
220
+ /**
221
+ * Base properties shared by all group types
222
+ */
223
+ interface BaseGroup {
224
+ id: string;
225
+ label: string;
226
+ description?: string;
227
+ collapsible?: boolean;
228
+ collapsed?: boolean;
229
+ order?: number;
230
+ }
231
+ /**
232
+ * Group of fields for organizing forms (default group type)
233
+ */
234
+ interface FieldGroup extends BaseGroup {
235
+ /** Discriminant */
236
+ type: "fields";
237
+ fields: Field[];
238
+ }
239
+ /**
240
+ * Group that displays related records for a relation attribute
241
+ */
242
+ interface RelationGroup extends BaseGroup {
243
+ type: "relation";
244
+ /** Relation attribute name on the source object */
245
+ attribute: string;
246
+ /** Columns to display (auto-detected from target object if empty) */
247
+ columns?: string[];
248
+ /** Read-only mode */
249
+ readOnly?: boolean;
250
+ /** Allow creating new related records */
251
+ allowCreate?: boolean;
252
+ }
253
+ /**
254
+ * Discriminated union of all group types
255
+ */
256
+ type Group = FieldGroup | RelationGroup;
257
+ type TabType = "form" | "table" | "custom" | "activity" | "richtext" | "documents" | "forms" | "emails";
258
+ /**
259
+ * Base properties shared by all tab types
260
+ */
261
+ interface BaseTab {
262
+ id: string;
263
+ name: string;
264
+ label: string;
265
+ icon?: IconName;
266
+ order?: number;
267
+ }
268
+ /**
269
+ * Form layout density
270
+ */
271
+ type FormDensity = "compact" | "comfortable" | "spacious";
272
+ /**
273
+ * Form tab - displays attributes organized in groups
274
+ */
275
+ interface FormTab extends BaseTab {
276
+ type: "form";
277
+ groups: Group[];
278
+ /** Number of grid columns (1, 2, or 3). Default: 2 */
279
+ formColumns?: 1 | 2 | 3;
280
+ /** Layout density. Default: "comfortable" */
281
+ density?: FormDensity;
282
+ }
283
+ /**
284
+ * Direct relation on the current object
285
+ *
286
+ * @example Contact.companies → shows Companies linked via the "companies" relation
287
+ */
288
+ interface RelationSource {
289
+ type: "relation";
290
+ /** Relation attribute name on the current object */
291
+ attribute: string;
292
+ }
293
+ /**
294
+ * Inverse lookup — records from another object that point to us
295
+ *
296
+ * @example On Company, show Contacts where Contact.company = this Company
297
+ */
298
+ interface InverseSource {
299
+ type: "inverse";
300
+ /** Object name that has the relation to us */
301
+ object: string;
302
+ /** Relation attribute name on the source object that points to us */
303
+ attribute: string;
304
+ }
305
+ /**
306
+ * Where table data comes from — either a direct relation or an inverse lookup
307
+ */
308
+ type TableSource = RelationSource | InverseSource;
309
+ /**
310
+ * Table tab - displays related records in a table
311
+ *
312
+ * The `source` field determines where data comes from.
313
+ *
314
+ * @example Direct: source = { type: "relation", attribute: "members" }
315
+ * @example Inverse: source = { type: "inverse", object: "contacts", attribute: "company" }
316
+ */
317
+ interface TableTab extends BaseTab {
318
+ type: "table";
319
+ /** Where the data comes from */
320
+ source: TableSource;
321
+ /** Columns to display (attribute names from the resolved target object) */
322
+ columns: string[];
323
+ /** Allow creating new records */
324
+ allowCreate?: boolean;
325
+ /** Creation behavior when allowCreate is true. Default: "redirect" */
326
+ createMode?: CreateMode;
327
+ /** Allow inline editing */
328
+ allowEdit?: boolean;
329
+ /** Allow deleting records */
330
+ allowDelete?: boolean;
331
+ /** Default filters applied to the table */
332
+ filters?: FilterState;
333
+ /** Default sort rules */
334
+ sorts?: SortRule[];
335
+ }
336
+ /**
337
+ * Custom tab - renders a developer-defined component
338
+ */
339
+ interface CustomTab extends BaseTab {
340
+ type: "custom";
341
+ /** Component identifier to render */
342
+ component: string;
343
+ /** Props to pass to the component */
344
+ props?: Record<string, unknown>;
345
+ }
346
+ /**
347
+ * Activity tab - displays activity feed for the current record
348
+ */
349
+ interface ActivityTab extends BaseTab {
350
+ type: "activity";
351
+ limit?: number;
352
+ }
353
+ /**
354
+ * Richtext tab - displays a block editor for a richtext attribute
355
+ */
356
+ interface RichtextTab extends BaseTab {
357
+ type: "richtext";
358
+ /** Richtext attribute to display in the BlockEditor */
359
+ attribute: string;
360
+ /** Optional text attribute for an editable title input above the editor */
361
+ titleAttribute?: string;
362
+ }
363
+ /**
364
+ * Documents tab - displays all documents attached to the record
365
+ */
366
+ interface DocumentsTab extends BaseTab {
367
+ type: "documents";
368
+ allowUpload?: boolean;
369
+ allowRemove?: boolean;
370
+ hideAttachments?: boolean;
371
+ }
372
+ /**
373
+ * Forms tab - displays available forms for creating related records
374
+ */
375
+ interface FormsTab extends BaseTab {
376
+ type: "forms";
377
+ /** Object name to filter forms by slot (derived from record context, but can be overridden) */
378
+ objectName?: string;
379
+ }
380
+ /**
381
+ * Emails tab - displays emails associated with the record at query time via the
382
+ * values of configured email-bearing text attributes. Config-only: no schema change.
383
+ */
384
+ interface EmailsTab extends BaseTab {
385
+ type: "emails";
386
+ /** Names of text attributes whose values hold email addresses to match on. */
387
+ emailAttributeIds: string[];
388
+ }
389
+ /**
390
+ * Union of all tab types (for detail views)
391
+ */
392
+ type Tab = FormTab | TableTab | CustomTab | ActivityTab | RichtextTab | DocumentsTab | FormsTab | EmailsTab;
393
+ /**
394
+ * List view layout mode
395
+ * - `table`: Table/grid layout
396
+ * - `kanban`: Kanban board layout (grouped by attribute)
397
+ */
398
+ type ListViewLayout = "table" | "kanban";
399
+ /**
400
+ * Tab within a list view — each tab carries its own full display configuration.
401
+ *
402
+ * @example
403
+ * ```typescript
404
+ * const tabs: ListViewTab[] = [
405
+ * { id: "all", label: "All Contacts", default: true, visibility: "workspace", layout: "table", columns: ["name", "email", "status"] },
406
+ * { id: "active", label: "Active", visibility: "workspace", layout: "table", columns: ["name", "email"], filters: activeFilter },
407
+ * { id: "pipeline", label: "Pipeline", visibility: "workspace", layout: "kanban", columns: ["name", "amount"], groupByAttribute: "stage" },
408
+ * ];
409
+ * ```
410
+ */
411
+ interface ListViewTab {
412
+ /** Unique identifier */
413
+ id: string;
414
+ /** Display label */
415
+ label: string;
416
+ /** Icon */
417
+ icon?: IconName;
418
+ /** Default tab (shown on load) */
419
+ default?: boolean;
420
+ /**
421
+ * Record scope this tab reads. `all` (the default) imposes no scope, so the
422
+ * tab shows every workspace record plus the viewer's own private ones;
423
+ * `workspace` and `private` narrow it to exactly one.
424
+ */
425
+ visibility: ListViewTabVisibility;
426
+ /** Layout mode */
427
+ layout: ListViewLayout;
428
+ /** Attribute names to display as columns */
429
+ columns: string[];
430
+ /** Column widths in pixels */
431
+ columnSizing?: Record<string, number>;
432
+ /** Filters applied to this tab */
433
+ filters?: FilterGroup;
434
+ /** Sort rules for this tab */
435
+ sorts?: SortRule[];
436
+ /** Attribute to group by (required when layout is "kanban") */
437
+ groupByAttribute?: string;
438
+ /** When true, the tab is read-only: no cell editing, no create, no delete */
439
+ readOnly?: boolean;
440
+ /** Creation behavior when clicking "+". Default: "redirect" */
441
+ createMode?: CreateMode;
442
+ /** User attribute to display on kanban cards (bottom-left) */
443
+ cardUserAttribute?: string;
444
+ /** Date attribute to display on kanban cards (bottom-right) */
445
+ cardDateAttribute?: string;
446
+ /** Order of kanban columns (by option value) - for kanban layout only */
447
+ kanbanColumnOrder?: string[];
448
+ /** Visibility of kanban columns (by option value) - for kanban layout only */
449
+ kanbanColumnVisibility?: Record<string, boolean>;
450
+ /** Pinned kanban columns (by option value) - for kanban layout only */
451
+ kanbanPinnedColumns?: string[];
452
+ }
453
+ /**
454
+ * Configuration for the side panel displayed alongside tab content.
455
+ * When present, a right-side panel shows the configured attributes as flat fields.
456
+ */
457
+ interface SidePanelConfig {
458
+ /** Attribute names to display as flat fields in the panel */
459
+ attributes: string[];
460
+ /** Width in pixels. @default 320 */
461
+ width?: number;
462
+ }
463
+ /**
464
+ * Configuration for detail views (RecordEditView)
465
+ */
466
+ interface DetailViewConfig {
467
+ /** Tabs in this view */
468
+ tabs: Tab[];
469
+ /** Optional side panel with flat attribute fields */
470
+ sidePanel?: SidePanelConfig;
471
+ }
472
+ /**
473
+ * Configuration for list views (RecordsView)
474
+ *
475
+ * Each tab carries its own full config (layout, columns, filters, sorts, groupBy).
476
+ * The view only holds shared base filters applied to ALL tabs.
477
+ */
478
+ interface ListViewConfig {
479
+ /** Base filters applied to ALL tabs (scoping, tenant, etc.) */
480
+ defaultFilters?: FilterGroup;
481
+ /** Tabs — at least one required. Each carries its own full config. */
482
+ tabs: ListViewTab[];
483
+ }
484
+ /**
485
+ * Union of all view configs
486
+ */
487
+ type ViewConfig = DetailViewConfig | ListViewConfig;
488
+ /**
489
+ * Base view properties shared by all view types
490
+ */
491
+ interface BaseViewDefinition {
492
+ /** Unique identifier (UUID, assigned by database) */
493
+ id?: string;
494
+ /** Technical name (kebab-case) */
495
+ name: string;
496
+ /** Display label */
497
+ label: string;
498
+ /** Description */
499
+ description?: string;
500
+ /** Icon */
501
+ icon?: IconName;
502
+ /** Object this view belongs to (object name) */
503
+ object: string;
504
+ /** Default view for this object+type combination */
505
+ default?: boolean;
506
+ /** Extensible metadata */
507
+ metadata?: Record<string, unknown>;
508
+ }
509
+ /**
510
+ * Detail view definition
511
+ */
512
+ interface DetailViewDefinition extends BaseViewDefinition {
513
+ type: "detail";
514
+ config: DetailViewConfig;
515
+ }
516
+ /**
517
+ * List view definition
518
+ */
519
+ interface ListViewDefinition extends BaseViewDefinition {
520
+ type: "list";
521
+ config: ListViewConfig;
522
+ }
523
+ /**
524
+ * Unified view definition - discriminated union by type
525
+ */
526
+ type ViewDefinition = DetailViewDefinition | ListViewDefinition;
527
+ /**
528
+ * Configuration overrides for user customizations
529
+ * Only stores the delta from the source view
530
+ */
531
+ interface ConfigOverrides {
532
+ tabs?: ListViewTab[];
533
+ hiddenTabIds?: string[];
534
+ detailTabs?: Tab[];
535
+ hiddenDetailTabIds?: string[];
536
+ }
537
+ /**
538
+ * User customization overlay for a view
539
+ * Stored per user, merged at runtime with the source view
540
+ */
541
+ interface ViewOverlay {
542
+ /** Unique identifier */
543
+ id: string;
544
+ /** View ID this overlay applies to (UUID or virtual ID) */
545
+ viewId: string;
546
+ /** User ID who owns this overlay */
547
+ userId: string;
548
+ /** Configuration overrides (delta only) */
549
+ configOverrides: ConfigOverrides;
550
+ /** User's default view for this object (stored in overlay) */
551
+ isUserDefault?: boolean;
552
+ /** Created timestamp */
553
+ createdAt: Date;
554
+ /** Updated timestamp */
555
+ updatedAt: Date;
556
+ }
557
+ /**
558
+ * Check if a view is a detail view
559
+ */
560
+ declare function isDetailView(view: ViewDefinition): view is DetailViewDefinition;
561
+ /**
562
+ * Check if a view is a list view
563
+ */
564
+ declare function isListView(view: ViewDefinition): view is ListViewDefinition;
565
+ /**
566
+ * Check if a group is a field group (default type)
567
+ */
568
+ declare function isFieldGroup(group: Group): group is FieldGroup;
569
+ /**
570
+ * Check if a group is a relation group
571
+ */
572
+ declare function isRelationGroup(group: Group): group is RelationGroup;
573
+
574
+ /**
575
+ * Scope of a permission rule.
576
+ * - `object`: Controls access to an entire object type (business data)
577
+ * - `system`: Controls access to platform resources (people, workspace, API keys, etc.)
578
+ */
579
+ type PermissionScope = "object" | "system";
580
+ /**
581
+ * Actions that can be performed on a resource.
582
+ *
583
+ * `observe` is intentionally excluded from `ALL_ACTIONS` ("full" preset) — it
584
+ * is only meaningful for runnable resources (agent sessions) where it grants
585
+ * read-only visibility on the run timeline without implying CRUD.
586
+ */
587
+ type Action = "read" | "create" | "update" | "delete" | "manage" | "observe";
588
+ /**
589
+ * System resources that can be managed.
590
+ * - `people`: User profiles, invitations, roles and permissions
591
+ * - `workspace`: Tenant settings and workspace-level configuration
592
+ * - `architect`: Architect settings, templates, and configurations
593
+ */
594
+ type SystemResource = "people" | "workspace" | "architect" | "feature-flags" | "files" | "views" | "forms" | "documents" | "audit" | "api-keys" | "connectors" | "env-vars" | "session";
595
+ /**
596
+ * Preset access levels for simplified permission configuration.
597
+ * - `full`: All CRUD actions
598
+ * - `read-only`: Only read action
599
+ * - `none`: No actions
600
+ * - `custom`: Manual selection of individual actions
601
+ */
602
+ type AccessLevel = "full" | "read-only" | "none" | "custom";
603
+ declare const ALL_ACTIONS: Action[];
604
+ /**
605
+ * Derive an AccessLevel from a list of actions.
606
+ */
607
+ declare function actionsToAccessLevel(actions: Action[]): AccessLevel;
608
+ /**
609
+ * Convert an AccessLevel preset to its corresponding actions.
610
+ */
611
+ declare function accessLevelToActions(level: Exclude<AccessLevel, "custom">): Action[];
612
+ /**
613
+ * Role definition - Groups permissions together.
614
+ *
615
+ * Roles are tenant-scoped and can be system-defined (immutable) or custom.
616
+ *
617
+ * @example
618
+ * ```typescript
619
+ * const ownerRole: Role = {
620
+ * id: "role-123",
621
+ * tenantId: "tenant-456",
622
+ * name: "owner",
623
+ * label: "Owner",
624
+ * description: "Full access to all platform features and data",
625
+ * system: true,
626
+ * createdAt: new Date(),
627
+ * updatedAt: new Date(),
628
+ * };
629
+ * ```
630
+ */
631
+ interface Role extends Timestamps {
632
+ id: Uuid;
633
+ tenantId: Uuid;
634
+ /**
635
+ * Technical name (unique per tenant, used in code).
636
+ * Examples: "owner", "member", "sales_manager"
637
+ */
638
+ name: string;
639
+ /**
640
+ * Display name shown in UI.
641
+ */
642
+ label: string;
643
+ /**
644
+ * Optional description of the role's purpose.
645
+ */
646
+ description?: string;
647
+ /**
648
+ * If true, this role cannot be modified or deleted.
649
+ * Used for built-in roles like "owner".
650
+ */
651
+ system: boolean;
652
+ }
653
+ /**
654
+ * Permission definition - Grants specific actions on a target.
655
+ *
656
+ * A permission belongs to a role and defines what actions are allowed
657
+ * on a specific target (object or system resource).
658
+ *
659
+ * @example
660
+ * ```typescript
661
+ * // Allow read and update on companies object
662
+ * const permission: Permission = {
663
+ * id: "perm-123",
664
+ * roleId: "role-456",
665
+ * scope: "object",
666
+ * target: "companies",
667
+ * actions: ["read", "update"],
668
+ * createdAt: new Date(),
669
+ * };
670
+ *
671
+ * // Wildcard permission for all objects
672
+ * const wildcardPerm: Permission = {
673
+ * id: "perm-789",
674
+ * roleId: "role-456",
675
+ * scope: "object",
676
+ * target: "*",
677
+ * actions: ["read", "create", "update", "delete"],
678
+ * createdAt: new Date(),
679
+ * };
680
+ * ```
681
+ */
682
+ interface Permission {
683
+ id: Uuid;
684
+ roleId: Uuid;
685
+ /**
686
+ * Scope of this permission.
687
+ */
688
+ scope: PermissionScope;
689
+ /**
690
+ * Target of the permission.
691
+ * - For `object` scope: object name (e.g., "companies") or "*" for all
692
+ * - For `system` scope: system resource (e.g., "people", "workspace") or "*" for all
693
+ */
694
+ target: string;
695
+ /**
696
+ * Actions allowed on the target.
697
+ */
698
+ actions: Action[];
699
+ createdAt: Date;
700
+ }
701
+ /**
702
+ * Links a user profile to a role within a tenant.
703
+ *
704
+ * A user can have multiple roles, and their permissions are additive (union).
705
+ *
706
+ * Note: `userProfileId` references UserProfile.id from the user_profiles table,
707
+ * NOT the auth provider ID (authId). This keeps permissions tied to the
708
+ * application's user management, not the authentication layer.
709
+ */
710
+ interface UserRoleAssignment {
711
+ id: Uuid;
712
+ /**
713
+ * User profile ID (UserProfile.id from user_profiles table).
714
+ * This links to the application's user management system,
715
+ * not the auth provider's user ID.
716
+ */
717
+ userProfileId: Uuid;
718
+ roleId: Uuid;
719
+ tenantId: Uuid;
720
+ /**
721
+ * When the role was assigned.
722
+ */
723
+ assignedAt: Date;
724
+ /**
725
+ * Actor ID of who assigned this role (for audit trail).
726
+ */
727
+ assignedBy?: Uuid;
728
+ }
729
+ /**
730
+ * Computed permissions for a user.
731
+ *
732
+ * This is the merged result of all roles assigned to a user.
733
+ * Returned by the API for permission checks.
734
+ */
735
+ interface EffectivePermissions {
736
+ /**
737
+ * Object-level permissions.
738
+ * Key is the object name, value is array of allowed actions.
739
+ * Special key "*" means permission applies to all objects.
740
+ */
741
+ objectPermissions: Record<string, Action[]>;
742
+ /**
743
+ * System-level permissions.
744
+ * Key is the system resource (people, workspace), value is array of allowed actions.
745
+ * Special key "*" means permission applies to all system resources.
746
+ */
747
+ systemPermissions: Record<string, Action[]>;
748
+ }
749
+ /**
750
+ * Permissions for a specific object.
751
+ * Convenience type for frontend use.
752
+ */
753
+ interface ObjectPermissions {
754
+ canRead: boolean;
755
+ canCreate: boolean;
756
+ canUpdate: boolean;
757
+ canDelete: boolean;
758
+ canManage: boolean;
759
+ }
760
+ /**
761
+ * Permissions for a specific system resource.
762
+ * Convenience type for frontend use.
763
+ */
764
+ interface SystemPermissions {
765
+ canRead: boolean;
766
+ canCreate: boolean;
767
+ canUpdate: boolean;
768
+ canDelete: boolean;
769
+ canManage: boolean;
770
+ }
771
+ /**
772
+ * Input for creating a new role.
773
+ * TenantId is automatically set from TenantContext.
774
+ */
775
+ interface CreateRoleInput {
776
+ name: string;
777
+ label: string;
778
+ description?: string;
779
+ /** Framework-owned default roles are system:true (immutable, auto-assignable). Custom roles default false. */
780
+ system?: boolean;
781
+ }
782
+ /**
783
+ * Input for updating an existing role.
784
+ */
785
+ interface UpdateRoleInput {
786
+ label?: string;
787
+ description?: string;
788
+ }
789
+ /**
790
+ * Input for creating a permission.
791
+ */
792
+ interface CreatePermissionInput {
793
+ scope: PermissionScope;
794
+ target: string;
795
+ /**
796
+ * Actions allowed on the target.
797
+ */
798
+ actions: Action[];
799
+ }
800
+ /**
801
+ * Input for assigning a role to a user.
802
+ */
803
+ interface AssignRoleInput {
804
+ /**
805
+ * User profile ID (UserProfile.id).
806
+ */
807
+ userProfileId: Uuid;
808
+ roleId: Uuid;
809
+ tenantId: Uuid;
810
+ assignedBy?: Uuid;
811
+ }
812
+
813
+ /**
814
+ * Type of mentionable entity
815
+ */
816
+ type MentionEntityType = "user" | "record" | (string & {});
817
+ /**
818
+ * A mention reference stored with a message
819
+ */
820
+ interface MentionReference {
821
+ /** Unique ID for this mention instance */
822
+ id: string;
823
+ /** Entity type (user, record, or custom) */
824
+ type: MentionEntityType;
825
+ /** Entity ID (user ID or record ID) */
826
+ entityId: string;
827
+ /** Display label at time of mention (cached for display even if entity is deleted) */
828
+ label: string;
829
+ /** Object name for records, undefined for users */
830
+ objectName?: string;
831
+ /** Start position in the message text */
832
+ startIndex: number;
833
+ /** End position in the message text */
834
+ endIndex: number;
835
+ }
836
+ /**
837
+ * Context data for a mentioned entity (sent to AI)
838
+ */
839
+ interface MentionedEntityContext {
840
+ /** Entity type */
841
+ type: MentionEntityType;
842
+ /** Entity ID */
843
+ entityId: string;
844
+ /** Display label */
845
+ label: string;
846
+ /** Object name for records */
847
+ objectName?: string;
848
+ /** Additional context data (record values, user details, etc.) */
849
+ data?: Record<string, unknown>;
850
+ }
851
+ /**
852
+ * Full mention context for AI
853
+ */
854
+ interface MentionedContext {
855
+ /** All mentioned entities with their context data */
856
+ entities: MentionedEntityContext[];
857
+ /** Summary text for AI system prompt */
858
+ summary: string;
859
+ }
860
+
861
+ type DocumentKind = "file" | "folder";
862
+ interface Document extends Timestamps {
863
+ id: Uuid;
864
+ tenantId: Uuid;
865
+ title: string;
866
+ kind: DocumentKind;
867
+ parentId?: Uuid | null;
868
+ description?: string;
869
+ contentHash?: string;
870
+ createdBy?: Uuid;
871
+ updatedBy?: Uuid;
872
+ deletedAt?: Date | null;
873
+ /**
874
+ * Fractional ordering position within `(tenantId, parentId)`. Lower values
875
+ * sort first. New rows default to `max(siblings) + 1024` so reorderings can
876
+ * insert between neighbours without renumbering. The server may rebalance
877
+ * positions in the background to keep the spacing bounded.
878
+ */
879
+ position: number;
880
+ }
881
+ interface DocumentWithSubCount extends Document {
882
+ subCount: number | null;
883
+ }
884
+ /** OCR processing lifecycle for a single file within a document pack. */
885
+ type FileOcrStatus = "pending" | "processing" | "completed" | "failed";
886
+ /**
887
+ * A single anonymous file belonging to a document pack.
888
+ * Unlike the slot-based model, files carry no slot name — order within the
889
+ * pack is `position` only, and `name` is provenance (originalName), never a
890
+ * label rendered in the UI.
891
+ */
892
+ interface DocumentFile {
893
+ id: Uuid;
894
+ documentId: Uuid;
895
+ position: number;
896
+ /** Provenance only (originalName) — never rendered as a label. */
897
+ name: string;
898
+ mimeType: string;
899
+ size: number;
900
+ ocrStatus: FileOcrStatus | null;
901
+ ocrText: string | null;
902
+ ocrConfidence: number | null;
903
+ processedAt: Date | null;
904
+ }
905
+ type DocumentWithFiles = Document & {
906
+ files: DocumentFile[];
907
+ };
908
+ interface CreateDocument {
909
+ title: string;
910
+ kind?: DocumentKind;
911
+ parentId?: Uuid | null;
912
+ description?: string;
913
+ position?: number;
914
+ }
915
+ /**
916
+ * Reference to a record attribute that should atomically attach a freshly
917
+ * created Document. Passed alongside `CreateDocument` to make creation
918
+ * link-aware end-to-end (client → REST → service → repo).
919
+ *
920
+ * The server requires this — orphan Documents are not creatable through the
921
+ * REST API.
922
+ */
923
+ interface CreateDocumentLink {
924
+ objectName: string;
925
+ sourceRecordId: string;
926
+ attributeName: string;
927
+ }
928
+ interface UpdateDocument {
929
+ title?: string;
930
+ parentId?: Uuid | null;
931
+ position?: number;
932
+ }
933
+ interface DocumentListOptions {
934
+ limit?: number;
935
+ offset?: number;
936
+ }
937
+ interface RecordDocuments {
938
+ /** Documents grouped by attribute name (includes system 'attachments' attribute) */
939
+ byAttribute: Record<string, DocumentWithFiles[]>;
940
+ }
941
+
942
+ /**
943
+ * Storage provider type
944
+ */
945
+ type StorageProvider = "s3" | "gcs" | "azure" | "local" | "cloudflare-r2" | string;
946
+ /**
947
+ * File - Represents uploaded file metadata and storage info
948
+ *
949
+ * ARCHITECTURE:
950
+ * - Fixed table (no custom attributes)
951
+ * - Manages file storage metadata
952
+ * - uploadedBy links to user_profiles table
953
+ * - Supports soft delete via deletedAt
954
+ *
955
+ * @example
956
+ * ```typescript
957
+ * const file: File = {
958
+ * id: "file-123",
959
+ * tenantId: "tenant-456",
960
+ * name: "contract-2025.pdf",
961
+ * originalName: "Contract Acme Corp 2025.pdf",
962
+ * mimeType: "application/pdf",
963
+ * size: 2458624,
964
+ * storageProvider: "s3",
965
+ * storagePath: "tenants/456/files/2025/11/contract-2025.pdf",
966
+ * storageBucket: "my-app-files",
967
+ * url: "https://cdn.example.com/files/file-123",
968
+ * uploadedBy: "profile-789",
969
+ * folderPath: "/contracts/2025",
970
+ * createdAt: new Date(),
971
+ * updatedAt: new Date(),
972
+ * };
973
+ * ```
974
+ */
975
+ interface File extends Timestamps {
976
+ id: Uuid;
977
+ tenantId: Uuid;
978
+ /**
979
+ * File name (sanitized for storage)
980
+ */
981
+ name: string;
982
+ /**
983
+ * Original file name (as uploaded by user)
984
+ */
985
+ originalName: string;
986
+ /**
987
+ * MIME type (e.g., "application/pdf", "image/jpeg")
988
+ */
989
+ mimeType: MimeType | string;
990
+ /**
991
+ * File size in bytes
992
+ */
993
+ size: number;
994
+ /**
995
+ * Storage provider (s3, gcs, azure, local, etc.)
996
+ */
997
+ storageProvider: StorageProvider;
998
+ /**
999
+ * Path in the storage bucket
1000
+ */
1001
+ storagePath: string;
1002
+ /**
1003
+ * Storage bucket name (if applicable)
1004
+ */
1005
+ storageBucket?: string;
1006
+ /**
1007
+ * Public or signed URL to access the file
1008
+ */
1009
+ url: string;
1010
+ /**
1011
+ * User who uploaded the file (FK to user_profiles)
1012
+ * Optional for system-generated files or anonymous uploads.
1013
+ */
1014
+ uploadedBy?: Uuid;
1015
+ /**
1016
+ * Folder path for organization (e.g., "/contracts/2025")
1017
+ */
1018
+ folderPath?: string;
1019
+ /**
1020
+ * Soft delete timestamp (null = not deleted)
1021
+ */
1022
+ deletedAt?: Date;
1023
+ /**
1024
+ * Document this file belongs to, when the file is a member of a document
1025
+ * pack. NULL for files that aren't part of a document (e.g. freshly
1026
+ * uploaded blobs not yet attached to a pack).
1027
+ */
1028
+ documentId?: Uuid | null;
1029
+ /**
1030
+ * Append-only position within the owning document pack (plain integer,
1031
+ * `max(position) + 1`). Packs are NOT reorderable (spec §2).
1032
+ */
1033
+ position?: number | null;
1034
+ /**
1035
+ * OCR processing status for this file, when applicable.
1036
+ */
1037
+ ocrStatus?: FileOcrStatus | null;
1038
+ /**
1039
+ * Extracted OCR text, when processing has completed.
1040
+ */
1041
+ ocrText?: string | null;
1042
+ /**
1043
+ * OCR confidence score, when processing has completed.
1044
+ */
1045
+ ocrConfidence?: number | null;
1046
+ /**
1047
+ * Timestamp of the last OCR processing attempt.
1048
+ */
1049
+ processedAt?: Date | null;
1050
+ }
1051
+ /**
1052
+ * Data required to create a new file record
1053
+ */
1054
+ /**
1055
+ * Data for creating a new file.
1056
+ * Tenant ID is automatically set from execution context.
1057
+ */
1058
+ interface CreateFile {
1059
+ name: string;
1060
+ originalName: string;
1061
+ mimeType: MimeType | string;
1062
+ size: number;
1063
+ storageProvider: StorageProvider;
1064
+ storagePath: string;
1065
+ storageBucket?: string;
1066
+ url: string;
1067
+ uploadedBy?: Uuid;
1068
+ folderPath?: string;
1069
+ documentId?: Uuid | null;
1070
+ position?: number | null;
1071
+ ocrStatus?: FileOcrStatus | null;
1072
+ ocrText?: string | null;
1073
+ ocrConfidence?: number | null;
1074
+ processedAt?: Date | null;
1075
+ }
1076
+ /**
1077
+ * Data for updating an existing file record
1078
+ */
1079
+ interface UpdateFile {
1080
+ name?: string;
1081
+ folderPath?: string;
1082
+ documentId?: Uuid | null;
1083
+ position?: number | null;
1084
+ ocrStatus?: FileOcrStatus | null;
1085
+ ocrText?: string | null;
1086
+ ocrConfidence?: number | null;
1087
+ processedAt?: Date | null;
1088
+ }
1089
+
1090
+ /**
1091
+ * Outcome of a compaction pass: a no-op (context already small enough), an LLM
1092
+ * `summary`, or a degraded `truncation` (the summarizer failed/timed out/returned
1093
+ * empty, so older messages were dropped and a notice injected). Canonical home —
1094
+ * `runtime` re-exports this and `react` imports it; never duplicate the literals.
1095
+ */
1096
+ type CompactionStrategy = "no-op" | "summary" | "truncation";
1097
+ type AgentRunStatus = "pending" | "running" | "completed" | "failed" | "cancelled" | "paused";
1098
+ type AgentSessionStatus = "active" | "idle" | "completed" | "failed" | "cancelled" | "waiting_human" | "waiting_agents" | "timeout" | "expired";
1099
+ /**
1100
+ * Statuses a session never leaves. Lives beside the union it partitions so
1101
+ * every consumer shares it — runtime orchestration decides whether to keep
1102
+ * working, and the React SSE lifecycle decides whether to stay connected.
1103
+ * Splitting them is how `timeout` and `expired` came to close a session on the
1104
+ * server while the browser kept reconnecting to it.
1105
+ */
1106
+ declare const SESSION_TERMINAL_STATUSES: readonly ["completed", "failed", "cancelled", "timeout", "expired"];
1107
+ type TerminalSessionStatus = (typeof SESSION_TERMINAL_STATUSES)[number];
1108
+ declare function isTerminalSessionStatus(status: AgentSessionStatus): status is TerminalSessionStatus;
1109
+ type AgentSessionMode = "interactive" | "autonomous";
1110
+ /** Whether a class of tool call is confirmed by a human or executed straight away. */
1111
+ type ApprovalMode = "ask" | "auto";
1112
+ /**
1113
+ * An agent's declared stance per risk class. Code-owned and versioned: there is
1114
+ * deliberately no policy table (see the `agent_execution_policies` guardrail).
1115
+ */
1116
+ interface AgentApprovalPolicy {
1117
+ mutation: ApprovalMode;
1118
+ destructive: ApprovalMode;
1119
+ outward: ApprovalMode;
1120
+ }
1121
+ declare const DEFAULT_APPROVAL_POLICY: AgentApprovalPolicy;
1122
+ /**
1123
+ * The switch shown at the bottom-left of the composer. `auto` relaxes
1124
+ * `mutation` only — deletions and outward sends keep asking.
1125
+ */
1126
+ type SessionApprovalMode = "manual" | "auto";
1127
+ type AgentMissionPolicy = "off" | "observe" | "enforce";
1128
+ type AgentMissionStatus = "active" | "verifying" | "completed" | "needs_review" | "abandoned";
1129
+ declare const TODO_PLAN_STATUSES: readonly ["active", "completed", "promoted", "abandoned"];
1130
+ type AgentTodoPlanStatus = (typeof TODO_PLAN_STATUSES)[number];
1131
+ type TriggerEventType = "record.created" | "record.updated" | "record.deleted" | "form.submitted" | "agent.completed" | "webhook" | "schedule";
1132
+ type AgentTriggerType = Extract<TriggerEventType, "record.created" | "record.updated" | "record.deleted">;
1133
+ type ProviderName = "anthropic" | "openai" | "google" | "mistral";
1134
+ interface ModelDefinition {
1135
+ provider: ProviderName;
1136
+ model: string;
1137
+ maxTokens?: number;
1138
+ /**
1139
+ * Total context window in tokens (e.g. 200000 for Claude Sonnet).
1140
+ * Required by the compaction subsystem when this model is used as the
1141
+ * summary model; optional otherwise.
1142
+ */
1143
+ contextWindow?: number;
1144
+ }
1145
+ interface RetryPolicy {
1146
+ maxRetries: number;
1147
+ backoffMs: number;
1148
+ backoffMultiplier: number;
1149
+ }
1150
+ interface AgentExecutionConfig {
1151
+ maxConcurrentRuns: number;
1152
+ retryPolicy: RetryPolicy;
1153
+ timeoutMs: number;
1154
+ costLimitUsd?: number;
1155
+ }
1156
+ /**
1157
+ * Shared base config used by AgentDefinition, inline runs, and AgentSession.
1158
+ */
1159
+ interface AgentConfig {
1160
+ systemPrompt: string;
1161
+ model: ModelDefinition;
1162
+ tools?: string[];
1163
+ timeoutMs?: number;
1164
+ costLimitUsd?: number | null;
1165
+ canDelegate: boolean;
1166
+ maxDepth: number;
1167
+ maxTreeCostUsd?: number;
1168
+ critic?: CriticConfig;
1169
+ missionPolicy?: AgentMissionPolicy;
1170
+ }
1171
+ interface CriticConfig {
1172
+ enabled: boolean;
1173
+ model?: ModelDefinition;
1174
+ systemPrompt?: string;
1175
+ maxRetries?: number;
1176
+ }
1177
+ /**
1178
+ * Standalone trigger definition (replaces embedded AgentTrigger[]).
1179
+ * Triggers are now first-class entities with their own lifecycle.
1180
+ */
1181
+ interface AgentTriggerDefinition {
1182
+ id: string;
1183
+ tenantId: string;
1184
+ definitionId: string;
1185
+ name?: string;
1186
+ eventType: TriggerEventType;
1187
+ objectId?: string;
1188
+ watchedFields?: string[];
1189
+ formDefinitionId?: string;
1190
+ sourceAgentId?: string;
1191
+ webhookPath?: string;
1192
+ cronExpression?: string;
1193
+ timezone?: string;
1194
+ filter?: FilterState;
1195
+ inputBuilder?: string;
1196
+ debounceMs?: number;
1197
+ enabled: boolean;
1198
+ lastFiredAt?: Date;
1199
+ createdAt: Date;
1200
+ updatedAt: Date;
1201
+ }
1202
+ interface AgentSchedule {
1203
+ cron: string;
1204
+ timezone?: string;
1205
+ enabled: boolean;
1206
+ input?: Record<string, unknown>;
1207
+ inputBuilder?: string;
1208
+ }
1209
+ /**
1210
+ * Declarative trigger carried by an {@link AgentBlueprint}. The boot sync
1211
+ * reconciles the agent's AgentTriggerDefinition rows to match, using `name`
1212
+ * as the stable identity.
1213
+ */
1214
+ /**
1215
+ * System permission an actor must hold to see and use an agent. When
1216
+ * declared, the agent listing and session-creation gates hide/refuse the
1217
+ * agent for any actor lacking `action` on `resource` — checked via
1218
+ * `PermissionService.canAccessSystemByActor`. Absent by default: the
1219
+ * overwhelming majority of agents are visible to every actor.
1220
+ */
1221
+ interface AgentRequiredPermission {
1222
+ resource: SystemResource;
1223
+ action: Action;
1224
+ }
1225
+ interface AgentTriggerBlueprint {
1226
+ name: string;
1227
+ eventType: TriggerEventType;
1228
+ objectId?: string;
1229
+ watchedFields?: string[];
1230
+ formDefinitionId?: string;
1231
+ sourceAgentId?: string;
1232
+ webhookPath?: string;
1233
+ cronExpression?: string;
1234
+ timezone?: string;
1235
+ filter?: FilterState;
1236
+ inputBuilder?: string;
1237
+ debounceMs?: number;
1238
+ enabled: boolean;
1239
+ }
1240
+ /**
1241
+ * Code-declared agent definition produced by the `agent()` builder.
1242
+ * Contains everything an AgentDefinition needs except runtime-assigned
1243
+ * fields (id, tenantId, createdBy, timestamps). `system: true` blueprints
1244
+ * are seeded/reconciled at boot and immutable through the public API.
1245
+ */
1246
+ interface AgentBlueprint {
1247
+ name: string;
1248
+ /**
1249
+ * Display text shown wherever this agent's identity is rendered in the
1250
+ * UI — `undefined` falls back to `name`. A separate concern from `name`
1251
+ * on purpose: `name` is the stable identity the boot sync matches rows
1252
+ * on (`system-agent-sync.service.ts`), so renaming the display text (or
1253
+ * translating it) must never require touching that identity.
1254
+ */
1255
+ label?: string;
1256
+ icon?: string;
1257
+ description?: string;
1258
+ systemPrompt: string;
1259
+ model: ModelDefinition;
1260
+ tools?: string[];
1261
+ schedule?: AgentSchedule;
1262
+ config: AgentExecutionConfig;
1263
+ canDelegate?: boolean;
1264
+ maxDepth?: number;
1265
+ maxTreeCostUsd?: number;
1266
+ system: boolean;
1267
+ /** Code-declared agents are workspace-visible; private is runtime-only. */
1268
+ visibility: ResourceVisibility;
1269
+ triggers: AgentTriggerBlueprint[];
1270
+ requiredPermission?: AgentRequiredPermission;
1271
+ approval?: AgentApprovalPolicy;
1272
+ }
1273
+ interface AgentMessageAttachment {
1274
+ id: string;
1275
+ name: string;
1276
+ mimeType: string;
1277
+ size: number;
1278
+ }
1279
+ /**
1280
+ * The text to show wherever an agent's identity is rendered — its `label`
1281
+ * when declared, else its technical `name` verbatim (never capitalised or
1282
+ * otherwise transformed here: every existing agent must keep rendering
1283
+ * exactly as it does today until it explicitly declares a `label`).
1284
+ */
1285
+ declare function agentDisplayName(agent: Pick<AgentBlueprint, "name" | "label">): string;
1286
+ interface AgentMissionArtifact {
1287
+ path: string;
1288
+ description: string;
1289
+ mediaType?: string;
1290
+ }
1291
+ interface AgentMissionRubricCriterion {
1292
+ id: string;
1293
+ description: string;
1294
+ }
1295
+ interface AgentMissionRubric {
1296
+ criteria: AgentMissionRubricCriterion[];
1297
+ createdAt: string;
1298
+ }
1299
+ interface AgentMissionVerification {
1300
+ cycle: number;
1301
+ attempts: number;
1302
+ maxAttempts: number;
1303
+ lastVerdict?: "pass" | "fail";
1304
+ lastFeedback?: string;
1305
+ missingCriteria?: string[];
1306
+ lastEvidenceHash?: string;
1307
+ pendingEvidenceHash?: string;
1308
+ lastAttemptAt?: string;
1309
+ verifierCostUsd?: number;
1310
+ verifierInputTokens?: number;
1311
+ verifierOutputTokens?: number;
1312
+ }
1313
+ interface AgentMission {
1314
+ id: string;
1315
+ tenantId: string;
1316
+ sessionId: string;
1317
+ activationMessageId?: string;
1318
+ status: AgentMissionStatus;
1319
+ objective: string;
1320
+ todos: AITodoItem[];
1321
+ artifacts: AgentMissionArtifact[];
1322
+ rubric?: AgentMissionRubric;
1323
+ verification: AgentMissionVerification;
1324
+ version: number;
1325
+ createdBy?: string;
1326
+ createdAt: Date;
1327
+ updatedAt: Date;
1328
+ completedAt?: Date;
1329
+ }
1330
+ /** UI-safe mission lifecycle snapshot returned by REST and realtime surfaces. */
1331
+ interface AgentMissionView {
1332
+ id: string;
1333
+ sessionId: string;
1334
+ status: AgentMissionStatus;
1335
+ objective: string;
1336
+ todos: AITodoItem[];
1337
+ artifacts: AgentMissionArtifact[];
1338
+ verification: Pick<AgentMissionVerification, "cycle" | "attempts" | "maxAttempts" | "lastVerdict" | "lastFeedback" | "missingCriteria" | "lastAttemptAt">;
1339
+ version: number;
1340
+ createdAt: string;
1341
+ updatedAt: string;
1342
+ completedAt?: string;
1343
+ }
1344
+ interface AgentMissionPage {
1345
+ items: AgentMissionView[];
1346
+ nextCursor?: string;
1347
+ }
1348
+ /** A lightweight, pre-mission todo plan scoped to one agent session. */
1349
+ interface AgentTodoPlan {
1350
+ id: string;
1351
+ tenantId: string;
1352
+ sessionId: string;
1353
+ activationMessageId?: string;
1354
+ status: AgentTodoPlanStatus;
1355
+ todos: AITodoItem[];
1356
+ version: number;
1357
+ createdBy?: string;
1358
+ createdAt: Date;
1359
+ updatedAt: Date;
1360
+ completedAt?: Date;
1361
+ promotedMissionId?: string;
1362
+ }
1363
+ /** UI-safe todo plan lifecycle snapshot returned by REST and realtime surfaces. */
1364
+ interface AgentTodoPlanView {
1365
+ id: string;
1366
+ sessionId: string;
1367
+ status: AgentTodoPlanStatus;
1368
+ todos: AITodoItem[];
1369
+ version: number;
1370
+ createdAt: string;
1371
+ updatedAt: string;
1372
+ completedAt?: string;
1373
+ promotedMissionId?: string;
1374
+ }
1375
+ interface AgentDefinition {
1376
+ id: string;
1377
+ tenantId: string;
1378
+ name: string;
1379
+ /** Display text shown wherever this agent's identity is rendered — see `AgentBlueprint.label`. `undefined` falls back to `name`. */
1380
+ label?: string;
1381
+ icon?: string;
1382
+ description?: string;
1383
+ systemPrompt: string;
1384
+ model: ModelDefinition;
1385
+ tools?: string[];
1386
+ schedule?: AgentSchedule;
1387
+ config: AgentExecutionConfig;
1388
+ /** Code-declared (immutable via public API); reconciled by the boot sync. */
1389
+ system: boolean;
1390
+ visibility: ResourceVisibility;
1391
+ ownedBy: string | null;
1392
+ createdBy: string;
1393
+ createdAt: Date;
1394
+ updatedAt: Date;
1395
+ deletedAt?: Date;
1396
+ canDelegate?: boolean;
1397
+ maxDepth?: number;
1398
+ maxTreeCostUsd?: number;
1399
+ critic?: CriticConfig;
1400
+ missionPolicy?: AgentMissionPolicy;
1401
+ autoDecide?: boolean;
1402
+ fileIds?: string[];
1403
+ attachments?: File[];
1404
+ requiredPermission?: AgentRequiredPermission;
1405
+ }
1406
+ interface AgentRun {
1407
+ id: string;
1408
+ definitionId?: string;
1409
+ parentRunId?: string;
1410
+ depth: number;
1411
+ inlineConfig?: AgentConfig;
1412
+ tenantId: string;
1413
+ createdBy?: string;
1414
+ status: AgentRunStatus;
1415
+ retryCount: number;
1416
+ input: Record<string, unknown>;
1417
+ output?: Record<string, unknown>;
1418
+ error?: string;
1419
+ tokenUsage?: {
1420
+ input: number;
1421
+ output: number;
1422
+ };
1423
+ costUsd?: number;
1424
+ startedAt?: Date;
1425
+ completedAt?: Date;
1426
+ createdAt: Date;
1427
+ sessionId?: string;
1428
+ rootRunId?: string;
1429
+ triggerId?: string;
1430
+ /** Source domain-event id that launched this run; used for redelivery idempotency. */
1431
+ sourceEventId?: string;
1432
+ treeCostUsd?: number;
1433
+ effectiveSystemPrompt?: string;
1434
+ /** Monotonic fencing token, incremented on each lease acquisition. */
1435
+ attemptId?: number;
1436
+ /** Worker id currently holding the execution lease (null when free). */
1437
+ leaseOwner?: string;
1438
+ /** When the current lease expires; a run is re-acquirable once past this. */
1439
+ leaseExpiresAt?: Date;
1440
+ }
1441
+ interface AgentSession {
1442
+ id: string;
1443
+ tenantId: string;
1444
+ mode: AgentSessionMode;
1445
+ status: AgentSessionStatus;
1446
+ /**
1447
+ * D4's SECOND approval level: the human's per-conversation switch. The first
1448
+ * level is the agent's own code-declared {@link AgentApprovalPolicy}; both
1449
+ * are read together by `requiresApproval`, and this one relaxes the
1450
+ * `mutation` class ONLY.
1451
+ *
1452
+ * Required on read, not optional: the column is `NOT NULL DEFAULT 'auto'`,
1453
+ * so every read path yields a concrete posture. Writes may omit it — see
1454
+ * `AgentRepository.createSession`, whose input type drops it precisely
1455
+ * because the default lives in the database.
1456
+ */
1457
+ approvalMode: SessionApprovalMode;
1458
+ definitionId?: string;
1459
+ inlineConfig?: AgentConfig;
1460
+ parentSessionId?: string;
1461
+ rootSessionId: string;
1462
+ depth: number;
1463
+ missionPrompt?: string;
1464
+ treeCostUsd: number;
1465
+ name?: string;
1466
+ metadata?: Record<string, unknown>;
1467
+ createdBy?: string;
1468
+ createdAt: Date;
1469
+ updatedAt: Date;
1470
+ completedAt?: Date;
1471
+ expiresAt?: Date;
1472
+ archivedAt?: Date;
1473
+ /** Per-actor read marker. Populated by list endpoints when the caller is known. */
1474
+ lastReadAt?: Date;
1475
+ /** Convenience flag: true when session has activity since `lastReadAt` (or never read). */
1476
+ isUnread?: boolean;
1477
+ }
1478
+ type ToolPartState = "streaming" | "running" | "completed" | "error";
1479
+ /**
1480
+ * Structured cause for a tool part that ended in `state: "error"` without the
1481
+ * tool having run. Lets the UI render a localized explanation instead of the
1482
+ * raw error string.
1483
+ */
1484
+ type ToolPartErrorCode = "output_limit_reached" | "interrupted";
1485
+ /**
1486
+ * Damage measured from a tool's input WITHOUT executing it — what a
1487
+ * confirmation card states so the human decides on numbers rather than on a
1488
+ * tool name (D3: "the confirmation quantifies the damage").
1489
+ *
1490
+ * Lives here, in the contracts package, because it is written to the message
1491
+ * part (see `approvalImpact` below) and therefore crosses runtime, adapters
1492
+ * and UI alike. The runtime's `ToolPreview`/`ToolRiskEntry` re-export it
1493
+ * rather than redefining it.
1494
+ */
1495
+ interface ToolImpact {
1496
+ /** One human sentence, used as the confirmation title. */
1497
+ label: string;
1498
+ /**
1499
+ * The authorization gate refused the call.
1500
+ *
1501
+ * A flag rather than a wording: the label is written server-side, where no
1502
+ * recipient locale is in reach, so a refusal used to read "Suppression
1503
+ * refusée" to every user in every language. The card renders its own copy
1504
+ * from this.
1505
+ */
1506
+ denied?: boolean;
1507
+ /**
1508
+ * What a delete preview is about to remove, as data rather than as a
1509
+ * sentence. The label is written server-side with no recipient locale in
1510
+ * reach, so "Supprimer 12 records" reached every user in every language —
1511
+ * and its thousands separator was pinned to `fr-FR` besides. The card
1512
+ * composes its own headline from this.
1513
+ */
1514
+ deletion?: {
1515
+ /** The record or document's own name; data, not copy. */
1516
+ target?: string;
1517
+ /** How many are going, when there is no single target to name. */
1518
+ count?: number;
1519
+ /** Days the deletion can still be undone, if it can. */
1520
+ restorableDays?: number;
1521
+ };
1522
+ /** Named counts, e.g. `{ records: 1284, brokenLinks: 63 }`. */
1523
+ counts?: Record<string, number>;
1524
+ warnings?: string[];
1525
+ }
1526
+ /**
1527
+ * Whether the agent's conclusion depends on the human it just sollicited (D7).
1528
+ *
1529
+ * - `required` (the default, fail-closed): the session PARKS on the request and
1530
+ * RESUMES the parked turn when the answer lands. Forgetting to declare
1531
+ * anything therefore produces a visible wait, never a human answer thrown
1532
+ * into a void.
1533
+ * - `optional`: the session TERMINATES normally with the request still in
1534
+ * flight, and the answer REOPENS it through a new turn. Without this, an
1535
+ * incidental question would immobilise the conversation for the full 24h
1536
+ * expiry horizon — sandbox anchored to the tree, lease held, and a finished
1537
+ * conversation displayed as "in progress".
1538
+ *
1539
+ * Orthogonal to who does the work: this says only WHETHER we wait.
1540
+ *
1541
+ * Lives here, in the contracts package, because it is written to the message
1542
+ * part (see `humanRequestNeed` below) and therefore crosses runtime, adapters
1543
+ * and UI alike.
1544
+ */
1545
+ type HumanRequestNeed = "required" | "optional";
1546
+ type AgentMessagePart = {
1547
+ type: "text";
1548
+ text: string;
1549
+ } | {
1550
+ type: "reasoning";
1551
+ text: string;
1552
+ } | {
1553
+ type: "error";
1554
+ error: string;
1555
+ errorClass?: string;
1556
+ } | {
1557
+ type: "tool";
1558
+ toolCallId: string;
1559
+ name: string;
1560
+ args: Record<string, unknown>;
1561
+ result?: unknown;
1562
+ error?: string;
1563
+ errorCode?: ToolPartErrorCode;
1564
+ state: ToolPartState;
1565
+ durationMs?: number;
1566
+ /**
1567
+ * Set when this call was suspended by the approval gate (a risky tool
1568
+ * awaiting a human decision — see `toolApproval` in the AI SDK config).
1569
+ * The part legitimately stays in its current state (`running`) with no
1570
+ * result/error while the human decides; presence of this id is what
1571
+ * distinguishes "waiting on a human" from "crashed mid-call" on resume,
1572
+ * for ANY tool name — unlike the HITL exemption, which is keyed on a
1573
+ * fixed set of tool names (`ask_questions`).
1574
+ */
1575
+ approvalId?: string;
1576
+ /**
1577
+ * What this suspended call would do, measured ONCE at suspension time
1578
+ * from the tool's declared `preview` (D13). Persisted next to
1579
+ * `approvalId` instead of being recomputed per reader: the same card is
1580
+ * rendered by three hosts (composer, notification queue, record
1581
+ * banner), and a queue of ten pending requests would otherwise fire ten
1582
+ * previews per host. The UI therefore shows it dated ("12 records · 4
1583
+ * min ago"), bounded by the 24h expiry.
1584
+ *
1585
+ * Absent when the tool declares no `preview` (a `mutation`-class tool
1586
+ * cannot have one, by construction of `ToolRiskEntry`) or when the
1587
+ * preview threw — a broken preview must never swallow the suspension.
1588
+ */
1589
+ approvalImpact?: ToolImpact;
1590
+ /**
1591
+ * The human's decision on `approvalId`: `true` approved, `false` refused.
1592
+ * Absent while the decision is still pending. The approver's identity is
1593
+ * carried by the audit trail, not this field.
1594
+ */
1595
+ approved?: boolean;
1596
+ /**
1597
+ * The human's optional rationale for `approved` (Finding 3, final
1598
+ * review): why they decided as they did. Purely informational — it
1599
+ * never changes what executes, only what the agent (and any audit
1600
+ * reader) is told about the decision.
1601
+ */
1602
+ approvalReason?: string;
1603
+ /**
1604
+ * Whether this call's human request gates the agent's conclusion (D7) —
1605
+ * set on ANY part that is awaiting a human, both an `ask_questions` call
1606
+ * (declared by the agent through the tool's own `answerNeed` input) and
1607
+ * an approval-gated call (always `required`: the tool cannot run at all
1608
+ * until someone decides).
1609
+ *
1610
+ * Absent means `required` too — that is the fail-closed reading every
1611
+ * consumer must apply (`resolveHumanRequestNeed`), so a pre-migration row
1612
+ * or a shape this codebase failed to stamp can only ever produce a
1613
+ * visible wait, never a silently dropped human answer.
1614
+ */
1615
+ humanRequestNeed?: HumanRequestNeed;
1616
+ /**
1617
+ * Whether the session's `auto` mode would have let THIS call through —
1618
+ * i.e. whether offering "always allow this here" on its card would be
1619
+ * honest. Computed server-side at suspension by re-evaluating the one
1620
+ * owner of the decision (`requiresApproval`) with `sessionMode: "auto"`,
1621
+ * so it can never drift from the policy: it IS the policy, asked a
1622
+ * different question.
1623
+ *
1624
+ * It exists because the card cannot infer it. The tempting shortcut —
1625
+ * "no measured impact means `mutation`, since only `destructive` and
1626
+ * `outward` carry a `preview`" — is false: a preview that threw or timed
1627
+ * out also yields no impact, so a deletion would masquerade as a
1628
+ * mutation and the card would promise an ease the mode does not grant.
1629
+ *
1630
+ * Absent means "do not offer it", which is the fail-closed reading a
1631
+ * pre-migration row must produce.
1632
+ */
1633
+ approvalRelaxableByAuto?: boolean;
1634
+ } | {
1635
+ type: "file";
1636
+ fileId: string;
1637
+ name: string;
1638
+ mimeType: string;
1639
+ } | {
1640
+ type: "compaction";
1641
+ state: "in-progress";
1642
+ reason: "preflight_threshold" | "overflow_recovery";
1643
+ estimatedTokens?: number;
1644
+ reportedTokens?: number;
1645
+ } | {
1646
+ type: "compaction";
1647
+ state: "completed";
1648
+ tokensBefore: number;
1649
+ tokensAfter: number;
1650
+ tokensSaved: number;
1651
+ strategy: CompactionStrategy;
1652
+ durationMs: number;
1653
+ /**
1654
+ * Raw summary text produced by the summarizer LLM. Persisted so that
1655
+ * follow-up turns can reuse it instead of re-running the summarizer.
1656
+ */
1657
+ summary?: string;
1658
+ } | {
1659
+ type: "compaction";
1660
+ state: "failed";
1661
+ /** Human-readable reason from the CompactionImpossibleError. */
1662
+ reason: string;
1663
+ durationMs?: number;
1664
+ };
1665
+ /**
1666
+ * Persisted message in an agent session.
1667
+ * Unified type for both interactive and autonomous sessions.
1668
+ */
1669
+ interface AgentSessionMessage {
1670
+ id: string;
1671
+ sessionId: string;
1672
+ tenantId?: string;
1673
+ runId?: string;
1674
+ role: "user" | "assistant" | "system" | "tool";
1675
+ parts: AgentMessagePart[];
1676
+ attachments?: AgentMessageAttachment[];
1677
+ mentions?: MentionReference[];
1678
+ model?: ModelDefinition;
1679
+ tokenUsage?: {
1680
+ input: number;
1681
+ output: number;
1682
+ };
1683
+ metadata?: Record<string, unknown>;
1684
+ createdAt: Date;
1685
+ }
1686
+ interface AgentToolCall {
1687
+ id: string;
1688
+ name: string;
1689
+ arguments: Record<string, unknown>;
1690
+ result?: unknown;
1691
+ error?: string;
1692
+ durationMs?: number;
1693
+ /** Set by StreamEventAccumulator.reconcile() when the tool call was cut off before completing. */
1694
+ errorCode?: ToolPartErrorCode;
1695
+ }
1696
+ interface RecordAgentEvent {
1697
+ type: AgentTriggerType;
1698
+ objectId: string;
1699
+ recordId: string;
1700
+ tenantId: string;
1701
+ data?: Record<string, unknown>;
1702
+ }
1703
+ interface FormSubmittedAgentEvent {
1704
+ type: "form.submitted";
1705
+ tenantId: string;
1706
+ formId: string;
1707
+ formName: string;
1708
+ submissionId: string;
1709
+ createdBy?: string;
1710
+ createdRecordIds: Record<string, string>;
1711
+ data: {
1712
+ formId: string;
1713
+ formName: string;
1714
+ submissionId: string;
1715
+ createdBy?: string;
1716
+ createdRecordIds: Record<string, string>;
1717
+ slotValues: Record<string, Record<string, unknown>>;
1718
+ stepValues: Record<string, Record<string, unknown>>;
1719
+ };
1720
+ }
1721
+ type AgentEvent = RecordAgentEvent | FormSubmittedAgentEvent;
1722
+ interface AgentDashboard {
1723
+ activeRuns: number;
1724
+ pendingRuns: number;
1725
+ failedToday: number;
1726
+ completedToday: number;
1727
+ totalCostToday: number;
1728
+ totalCostWeek: number;
1729
+ }
1730
+ /**
1731
+ * Message role in a conversation
1732
+ */
1733
+ type AIMessageRole = "user" | "assistant";
1734
+ /**
1735
+ * An AI model available for selection by the user.
1736
+ * Configured on the backend and exposed via GET /agent/models.
1737
+ */
1738
+ interface AIAvailableModel {
1739
+ /** Model identifier exposed to the UI (e.g. "claude-sonnet-4-6") */
1740
+ id: string;
1741
+ /**
1742
+ * Provider model ID sent to the underlying SDK. Defaults to `id` when omitted.
1743
+ * Use this to register multiple registry entries (different `contextWindow`,
1744
+ * `label`, etc.) that route to the same upstream model — e.g. a test entry
1745
+ * with a reduced context window for QA of the compaction system.
1746
+ */
1747
+ apiModelId?: string;
1748
+ /** Provider name (e.g. "anthropic", "google") */
1749
+ provider: string;
1750
+ /** Display label (e.g. "Claude 4.6 Sonnet") */
1751
+ label: string;
1752
+ /** Whether this is the default model */
1753
+ isDefault?: boolean;
1754
+ /**
1755
+ * Total context window in tokens. Optional — resolved from the vendored
1756
+ * models.dev snapshot when omitted. Set explicitly only for a deliberate cap
1757
+ * (e.g. a QA reduced-window entry).
1758
+ */
1759
+ contextWindow?: number;
1760
+ /**
1761
+ * Maximum output tokens. Optional — resolved from the models.dev snapshot when
1762
+ * omitted. Set explicitly only for a deliberate cap.
1763
+ */
1764
+ maxOutputTokens?: number;
1765
+ /**
1766
+ * Set true for a model newer than the models.dev snapshot. When true,
1767
+ * `contextWindow` and `maxOutputTokens` MUST be provided explicitly. Token
1768
+ * cost stays unknown (never developer-specified) until the snapshot lists it.
1769
+ */
1770
+ unverified?: boolean;
1771
+ /** If true, this model is used for generating compaction summaries */
1772
+ isCompactionModel?: boolean;
1773
+ /** If true, this model is used for fast utility generations (regex, formula, …) */
1774
+ isUtilityModel?: boolean;
1775
+ }
1776
+ /**
1777
+ * Tool call status during execution
1778
+ */
1779
+ type AIToolCallStatus = "pending" | "running" | "streaming" | "success" | "error";
1780
+ /**
1781
+ * Tool call information for chat UI
1782
+ */
1783
+ interface AIToolCall {
1784
+ /** Unique tool call ID */
1785
+ id: string;
1786
+ /** Tool name */
1787
+ name: string;
1788
+ /** Tool arguments */
1789
+ args?: Record<string, unknown>;
1790
+ /** Tool result (when complete) */
1791
+ result?: unknown;
1792
+ /** Error message if failed */
1793
+ error?: string;
1794
+ /** Execution status */
1795
+ status: AIToolCallStatus;
1796
+ }
1797
+ /**
1798
+ * Part type for message content
1799
+ */
1800
+ type AIChatMessagePartType = "text" | "attachment" | "tool" | "thinking" | "reasoning" | "todo" | "question" | "error" | "approval" | "record" | "search-results" | "compaction" | (string & {});
1801
+ /**
1802
+ * Data for text part
1803
+ */
1804
+ interface TextPartData {
1805
+ text: string;
1806
+ isStreaming?: boolean;
1807
+ }
1808
+ /**
1809
+ * Data for tool part (same as AIToolCall)
1810
+ */
1811
+ interface ToolPartData {
1812
+ id: string;
1813
+ name: string;
1814
+ args?: Record<string, unknown>;
1815
+ result?: unknown;
1816
+ error?: string;
1817
+ errorCode?: ToolPartErrorCode;
1818
+ status: AIToolCallStatus;
1819
+ /** Raw JSON string accumulating during tool-input streaming (cleared on tool_input_end) */
1820
+ partialInput?: string;
1821
+ /**
1822
+ * Set when this call is suspended pending a human approval decision — mirrors
1823
+ * `AgentMessagePart`'s `"tool"` variant so a reloaded conversation still shows
1824
+ * the call as awaiting a human rather than as a generic "running" state.
1825
+ */
1826
+ approvalId?: string;
1827
+ /**
1828
+ * What the suspended call would do, as measured ONCE at suspension time and
1829
+ * persisted on the part (D13) — never recomputed by the renderer. Because
1830
+ * the number is a snapshot of that moment and the request lives up to 24h,
1831
+ * the card must show it DATED ("3 records · il y a 4 min") rather than as a
1832
+ * live count. Absent when the tool declared no preview, or when the preview
1833
+ * threw: a degraded card, never a lost one.
1834
+ */
1835
+ approvalImpact?: ToolImpact;
1836
+ /**
1837
+ * The human's decision, once recorded: `true` approved, `false` refused,
1838
+ * `undefined` still pending. It has to reach the renderer, not just the
1839
+ * request: between the decision and the end of the re-execution the part
1840
+ * legitimately stays `running` WITH its `approvalId`, so a card keyed on
1841
+ * `approvalId` alone would come back offering two live buttons on a request
1842
+ * that is already settled.
1843
+ */
1844
+ approved?: boolean;
1845
+ /**
1846
+ * Whether the session's `auto` mode would have let this call through, so the
1847
+ * card knows if "always allow this here" is an honest offer. Mirrors
1848
+ * `AgentMessagePart`'s field of the same name — see it for why the card
1849
+ * cannot derive this itself. Absent means do not offer it.
1850
+ */
1851
+ approvalRelaxableByAuto?: boolean;
1852
+ }
1853
+ /**
1854
+ * Data for thinking part
1855
+ */
1856
+ interface ThinkingPartData {
1857
+ isStreaming: boolean;
1858
+ startTime?: number;
1859
+ }
1860
+ /**
1861
+ * Data for reasoning part (Extended Thinking content)
1862
+ */
1863
+ interface ReasoningPartData {
1864
+ /** Reasoning content (accumulated during streaming) */
1865
+ content: string;
1866
+ /** Whether reasoning is still streaming */
1867
+ isStreaming: boolean;
1868
+ /** Start timestamp for elapsed time display */
1869
+ startTime?: number;
1870
+ }
1871
+ /**
1872
+ * A part of a chat message.
1873
+ * Parts are ordered chronologically as they arrive from the stream.
1874
+ */
1875
+ interface AIChatMessagePart {
1876
+ /** Part type */
1877
+ type: AIChatMessagePartType;
1878
+ /** Unique part ID */
1879
+ id: string;
1880
+ /** Part-specific data */
1881
+ data: unknown;
1882
+ }
1883
+ /**
1884
+ * Terminal status of a dispatched subagent, mirrored onto the parent-visible
1885
+ * notification. `completed` reads as success; everything else reads as failure.
1886
+ */
1887
+ type AISubagentStatus = "completed" | "failed" | "cancelled" | "timeout" | "expired";
1888
+ /**
1889
+ * Narrow, UI-ready projection of an `agent-notification` message. Derived by the
1890
+ * react mapper from the raw `AgentSessionMessage.metadata` so the UI never has to
1891
+ * touch untrusted wrapper text: the title comes from {@link childName}/{@link status}
1892
+ * and {@link body} is the child's report already unwrapped from its `<subagent_result>`
1893
+ * envelope.
1894
+ */
1895
+ interface AIChatNotification {
1896
+ childSessionId: string;
1897
+ childName: string;
1898
+ status: AISubagentStatus;
1899
+ /** Child's report, unwrapped from the `<subagent_result>` envelope; rendered as markdown. */
1900
+ body: string;
1901
+ }
1902
+ /**
1903
+ * Chat message for runtime/streaming.
1904
+ *
1905
+ * All content is represented as ordered parts (text, tools, thinking, etc.)
1906
+ * Parts are in chronological order as they arrive from the stream.
1907
+ *
1908
+ * Used in:
1909
+ * - useAgentChat hook
1910
+ * - AI chat UI components
1911
+ * - Stream processing
1912
+ */
1913
+ interface AIChatMessage {
1914
+ /** Unique message ID */
1915
+ id: string;
1916
+ /** Message role */
1917
+ role: AIMessageRole;
1918
+ /** Ordered message parts (text, tools, thinking, etc.) */
1919
+ parts: AIChatMessagePart[];
1920
+ /** Whether the message is still streaming */
1921
+ isStreaming?: boolean;
1922
+ /** Message timestamp */
1923
+ timestamp?: Date;
1924
+ /** Error message if the message failed */
1925
+ error?: string;
1926
+ /**
1927
+ * Present only for subagent-completion notifications. When set, the UI renders
1928
+ * a compact collapsible callout in the agent flow instead of a user bubble, and
1929
+ * ignores {@link parts} (which still hold the raw wrapper text).
1930
+ */
1931
+ notification?: AIChatNotification;
1932
+ /**
1933
+ * Tokens reported by the provider after this message completed. The `input`
1934
+ * value reflects the size of the conversation Anthropic actually saw on
1935
+ * that turn — used by the chat composer to render a context-window
1936
+ * progress ring.
1937
+ */
1938
+ tokenUsage?: {
1939
+ input: number;
1940
+ output: number;
1941
+ };
1942
+ }
1943
+ /**
1944
+ * Question types supported by the agent
1945
+ */
1946
+ type AIQuestionType = "text" | "choice" | "confirm" | "multiselect";
1947
+ /**
1948
+ * Option for choice/multiselect questions
1949
+ */
1950
+ interface AIQuestionOption {
1951
+ value: string;
1952
+ label: string;
1953
+ description?: string;
1954
+ }
1955
+ /**
1956
+ * Question from the agent to the user
1957
+ */
1958
+ interface AIQuestion {
1959
+ /** Unique question ID */
1960
+ id: string;
1961
+ /** Question type */
1962
+ type: AIQuestionType;
1963
+ /** Question text */
1964
+ question: string;
1965
+ /** Options for choice/multiselect */
1966
+ options?: AIQuestionOption[];
1967
+ /** Placeholder for text input */
1968
+ placeholder?: string;
1969
+ /** Whether answer is required */
1970
+ required?: boolean;
1971
+ /** Min selections for multiselect */
1972
+ minSelections?: number;
1973
+ /** Max selections for multiselect */
1974
+ maxSelections?: number;
1975
+ }
1976
+ /**
1977
+ * Answer format for questions
1978
+ */
1979
+ type AIQuestionAnswer = {
1980
+ type: "text";
1981
+ value: string;
1982
+ } | {
1983
+ type: "choice";
1984
+ value: string;
1985
+ } | {
1986
+ type: "confirm";
1987
+ value: boolean;
1988
+ } | {
1989
+ type: "multiselect";
1990
+ value: string[];
1991
+ };
1992
+ /**
1993
+ * Option for batch questions
1994
+ */
1995
+ interface AIBatchQuestionOption {
1996
+ /** Value returned when selected */
1997
+ value: string;
1998
+ /** Display label */
1999
+ label: string;
2000
+ /**
2001
+ * What choosing this option means, or what it costs. Rendered under the
2002
+ * label, in the quiet weight: a batch of bare labels asks the human to
2003
+ * infer the trade-off the agent already knows.
2004
+ */
2005
+ description?: string;
2006
+ }
2007
+ /**
2008
+ * Kind of field a batch question is answered with.
2009
+ *
2010
+ * `record` (constraining the answer to a real `recordId`) is deliberately
2011
+ * absent: it needs a record selector, which is a feature of its own rather
2012
+ * than a field variant.
2013
+ */
2014
+ type AIBatchQuestionType = "choice" | "text" | "boolean";
2015
+ /**
2016
+ * Question in a batch (for ask_questions tool)
2017
+ */
2018
+ interface AIBatchQuestion {
2019
+ /** Unique question ID */
2020
+ id: string;
2021
+ /** Question text to display */
2022
+ question: string;
2023
+ /**
2024
+ * Kind of field to answer with. Optional for backwards compatibility: when
2025
+ * absent it is derived from the shape — `options` present means `choice`,
2026
+ * otherwise `text`. Only `boolean` cannot be derived, so it must be declared.
2027
+ */
2028
+ type?: AIBatchQuestionType;
2029
+ /** Predefined options (if provided, displayed as buttons) */
2030
+ options?: AIBatchQuestionOption[];
2031
+ /**
2032
+ * Several options may be chosen at once, and the answer comes back as an
2033
+ * array. Decided by the agent per question, because only it knows whether
2034
+ * the choices are mutually exclusive; a human forced to pick one of three
2035
+ * non-exclusive options answers a question nobody asked.
2036
+ */
2037
+ multiSelect?: boolean;
2038
+ /** Allow custom text input in addition to options */
2039
+ allowCustomAnswer?: boolean;
2040
+ /** Placeholder for custom input field */
2041
+ placeholder?: string;
2042
+ }
2043
+ /**
2044
+ * A single answer, in the type the question asked for. A `boolean` question
2045
+ * answered with the string `"true"` would leave the model re-parsing display
2046
+ * text — the same class of mistake as returning an option's label instead of
2047
+ * its value. A `multiSelect` question answers with the array for the same
2048
+ * reason: joining it into `"a, b"` would hand the model a string to split back
2049
+ * apart, and one whose separator can appear inside a value.
2050
+ */
2051
+ type AIBatchAnswerValue = string | boolean | string[];
2052
+ /**
2053
+ * Answer returned by the AgentQuestions widget
2054
+ */
2055
+ interface AIBatchQuestionAnswer {
2056
+ /** True if user skipped all questions */
2057
+ skipped: boolean;
2058
+ /** Map of question ID to the answer given, in the question's own type */
2059
+ answers: Record<string, AIBatchAnswerValue>;
2060
+ }
2061
+ /**
2062
+ * Todo item status
2063
+ */
2064
+ declare const TODO_STATUSES: readonly ["pending", "in_progress", "completed", "blocked"];
2065
+ type AITodoStatus = (typeof TODO_STATUSES)[number];
2066
+ /**
2067
+ * Todo item in a task list
2068
+ */
2069
+ interface AITodoItem {
2070
+ id: string;
2071
+ description: string;
2072
+ status: AITodoStatus;
2073
+ result?: string;
2074
+ updatedAt?: number;
2075
+ }
2076
+ /**
2077
+ * Persisted bounds on a todo, beside the type they constrain.
2078
+ *
2079
+ * Both sides of the wire enforce them: the runtime zod schema when it writes,
2080
+ * and the React projection parser when it reads an untrusted payload back.
2081
+ * React cannot import the runtime, which is why these numbers used to be
2082
+ * copied there under a "keep aligned with the canonical persisted schema"
2083
+ * comment — a synchronisation the compiler could not check.
2084
+ */
2085
+ declare const MAX_TODOS = 50;
2086
+ declare const MAX_TODO_ID_CHARS = 80;
2087
+ declare const MAX_TODO_DESCRIPTION_CHARS = 500;
2088
+ declare const MAX_TODO_RESULT_CHARS = 2000;
2089
+ /**
2090
+ * Todo list managed by the agent
2091
+ */
2092
+ interface AITodoList {
2093
+ items: AITodoItem[];
2094
+ progress: number;
2095
+ isComplete: boolean;
2096
+ }
2097
+ /**
2098
+ * AI Usage Metrics record
2099
+ */
2100
+ interface AIUsageMetrics {
2101
+ id: string;
2102
+ tenantId: string;
2103
+ date: Date;
2104
+ requestCount: number;
2105
+ totalTokens: number;
2106
+ totalCost: number;
2107
+ providerBreakdown: Record<string, AIProviderMetrics>;
2108
+ toolUsage: Record<string, number>;
2109
+ }
2110
+ /**
2111
+ * Provider-specific metrics
2112
+ */
2113
+ interface AIProviderMetrics {
2114
+ requests: number;
2115
+ tokens: number;
2116
+ cost: number;
2117
+ }
2118
+ /**
2119
+ * Memory type for categorization
2120
+ *
2121
+ * - `soul`: Tenant identity and persona (admin-managed)
2122
+ * - `user`: Per-user facts and preferences
2123
+ * - `daily`: Auto-generated daily summaries
2124
+ * - `session`: Auto-generated conversation summaries
2125
+ */
2126
+ type AIMemoryType = "soul" | "user" | "daily" | "session";
2127
+ /**
2128
+ * Advanced memory entry for OpenClaw-style memory system
2129
+ */
2130
+ interface AIMemoryEntry {
2131
+ id: string;
2132
+ tenantId: string;
2133
+ userId: string | null;
2134
+ conversationId: string | null;
2135
+ type: AIMemoryType;
2136
+ content: string;
2137
+ embedding: number[] | null;
2138
+ importance: number;
2139
+ source: string;
2140
+ createdAt: Date;
2141
+ updatedAt: Date;
2142
+ expiresAt: Date | null;
2143
+ }
2144
+ /**
2145
+ * Compaction summary for conversation history compression
2146
+ */
2147
+ interface AICompactionSummary {
2148
+ id: string;
2149
+ tenantId: string;
2150
+ userId: string;
2151
+ conversationId: string;
2152
+ summary: string;
2153
+ originalMessageCount: number;
2154
+ tokenCountBefore: number;
2155
+ tokenCountAfter: number;
2156
+ compactedAt: Date;
2157
+ }
2158
+
2159
+ interface AddAttributeInput {
2160
+ name: string;
2161
+ label: string;
2162
+ type: AttributeType;
2163
+ required?: boolean;
2164
+ unique?: boolean;
2165
+ description?: string;
2166
+ placeholder?: string;
2167
+ icon?: IconName;
2168
+ defaultValue?: unknown;
2169
+ metadata?: Record<string, unknown>;
2170
+ [key: string]: unknown;
2171
+ }
2172
+ interface CreateCustomObjectInput {
2173
+ name: string;
2174
+ label: string;
2175
+ pluralLabel?: string;
2176
+ labelExpression: string;
2177
+ embeddingExpression?: string;
2178
+ description?: string;
2179
+ icon?: IconName;
2180
+ attributes?: (Attribute | {
2181
+ build: () => Attribute;
2182
+ })[];
2183
+ metadata?: Record<string, unknown>;
2184
+ }
2185
+ interface UpdateObjectInput {
2186
+ label?: string;
2187
+ pluralLabel?: string;
2188
+ description?: string;
2189
+ icon?: IconName;
2190
+ labelExpression?: string;
2191
+ embeddingExpression?: string;
2192
+ metadata?: Record<string, unknown>;
2193
+ }
2194
+ interface CreateViewInput {
2195
+ objectName: string;
2196
+ type: ViewType;
2197
+ name: string;
2198
+ label: string;
2199
+ description?: string;
2200
+ icon?: IconName;
2201
+ config: ViewConfig;
2202
+ default?: boolean;
2203
+ metadata?: Record<string, unknown>;
2204
+ }
2205
+ interface UpdateViewInput {
2206
+ label?: string;
2207
+ description?: string;
2208
+ icon?: IconName;
2209
+ config?: ViewConfig;
2210
+ default?: boolean;
2211
+ metadata?: Record<string, unknown>;
2212
+ }
2213
+ interface RelationOption {
2214
+ id: string;
2215
+ objectId: string;
2216
+ objectName: string;
2217
+ objectLabel: string;
2218
+ objectIcon?: string;
2219
+ label: string;
2220
+ }
2221
+ interface RelationOptionsResponse {
2222
+ options: RelationOption[];
2223
+ hasMore: boolean;
2224
+ total: number;
2225
+ nextOffset?: number;
2226
+ }
2227
+ interface StreamEventMessagePersisted {
2228
+ type: "message_persisted";
2229
+ message: AgentSessionMessage;
2230
+ }
2231
+ /**
2232
+ * An already-persisted message had its parts updated out-of-band (e.g. a
2233
+ * pending HITL tool part closed when the user replied). Clients replace the
2234
+ * stored message in place without touching streaming state.
2235
+ */
2236
+ interface StreamEventMessageUpdated {
2237
+ type: "message_updated";
2238
+ message: AgentSessionMessage;
2239
+ }
2240
+ /** A committed, UI-safe mission lifecycle snapshot. */
2241
+ interface StreamEventMissionUpdate {
2242
+ type: "mission_update";
2243
+ mission: AgentMissionView;
2244
+ }
2245
+ /** A committed, UI-safe lightweight todo plan lifecycle snapshot. */
2246
+ interface StreamEventTodoPlanUpdate {
2247
+ type: "todo_plan_update";
2248
+ plan: AgentTodoPlanView;
2249
+ }
2250
+ interface StreamEventCompactionStart {
2251
+ type: "compaction_start";
2252
+ reason: "preflight_threshold" | "overflow_recovery";
2253
+ estimatedTokens?: number;
2254
+ reportedTokens?: number;
2255
+ }
2256
+ interface StreamEventCompactionEnd {
2257
+ type: "compaction_end";
2258
+ tokensBefore: number;
2259
+ tokensAfter: number;
2260
+ tokensSaved: number;
2261
+ strategy: CompactionStrategy;
2262
+ durationMs: number;
2263
+ summary?: string;
2264
+ }
2265
+ interface StreamEventCompactionFailed {
2266
+ type: "compaction_failed";
2267
+ reason: string;
2268
+ }
2269
+ /**
2270
+ * Emitted once per agent turn, just before `complete`, carrying the exact
2271
+ * provider token usage enriched with context-window utilization and cost.
2272
+ * All fields are computed server-side — consumers display without recalculating.
2273
+ */
2274
+ interface StreamEventUsage {
2275
+ type: "usage";
2276
+ inputTokens: number;
2277
+ outputTokens: number;
2278
+ totalTokens: number;
2279
+ cacheReadTokens?: number;
2280
+ cacheCreationTokens?: number;
2281
+ /** Context window size of the model (in tokens). */
2282
+ contextWindow: number;
2283
+ /** totalTokens / contextWindow, clamped to [0, 1]. Computed server-side. */
2284
+ utilization: number;
2285
+ /** Estimated cost in USD. Undefined when pricing is unknown — never faked. */
2286
+ costUsd?: number;
2287
+ }
2288
+
2289
+ declare const statusGroupSchema: z.ZodEnum<{
2290
+ idle: "idle";
2291
+ in_progress: "in_progress";
2292
+ finished: "finished";
2293
+ }>;
2294
+ declare const selectOptionWriteSchema: z.ZodObject<{
2295
+ value: z.ZodString;
2296
+ label: z.ZodString;
2297
+ description: z.ZodOptional<z.ZodString>;
2298
+ inverse: z.ZodOptional<z.ZodString>;
2299
+ archived: z.ZodOptional<z.ZodBoolean>;
2300
+ color: z.ZodEnum<{
2301
+ gray: "gray";
2302
+ slate: "slate";
2303
+ blue: "blue";
2304
+ sky: "sky";
2305
+ indigo: "indigo";
2306
+ green: "green";
2307
+ emerald: "emerald";
2308
+ teal: "teal";
2309
+ red: "red";
2310
+ rose: "rose";
2311
+ yellow: "yellow";
2312
+ amber: "amber";
2313
+ orange: "orange";
2314
+ purple: "purple";
2315
+ violet: "violet";
2316
+ fuchsia: "fuchsia";
2317
+ pink: "pink";
2318
+ cyan: "cyan";
2319
+ lime: "lime";
2320
+ }>;
2321
+ }, z.core.$strict>;
2322
+ declare const multiselectOptionWriteSchema: z.ZodObject<{
2323
+ value: z.ZodString;
2324
+ label: z.ZodString;
2325
+ description: z.ZodOptional<z.ZodString>;
2326
+ inverse: z.ZodOptional<z.ZodString>;
2327
+ archived: z.ZodOptional<z.ZodBoolean>;
2328
+ color: z.ZodEnum<{
2329
+ gray: "gray";
2330
+ slate: "slate";
2331
+ blue: "blue";
2332
+ sky: "sky";
2333
+ indigo: "indigo";
2334
+ green: "green";
2335
+ emerald: "emerald";
2336
+ teal: "teal";
2337
+ red: "red";
2338
+ rose: "rose";
2339
+ yellow: "yellow";
2340
+ amber: "amber";
2341
+ orange: "orange";
2342
+ purple: "purple";
2343
+ violet: "violet";
2344
+ fuchsia: "fuchsia";
2345
+ pink: "pink";
2346
+ cyan: "cyan";
2347
+ lime: "lime";
2348
+ }>;
2349
+ }, z.core.$strict>;
2350
+ declare const statusOptionWriteSchema: z.ZodObject<{
2351
+ value: z.ZodString;
2352
+ label: z.ZodString;
2353
+ description: z.ZodOptional<z.ZodString>;
2354
+ inverse: z.ZodOptional<z.ZodString>;
2355
+ archived: z.ZodOptional<z.ZodBoolean>;
2356
+ color: z.ZodEnum<{
2357
+ gray: "gray";
2358
+ slate: "slate";
2359
+ blue: "blue";
2360
+ sky: "sky";
2361
+ indigo: "indigo";
2362
+ green: "green";
2363
+ emerald: "emerald";
2364
+ teal: "teal";
2365
+ red: "red";
2366
+ rose: "rose";
2367
+ yellow: "yellow";
2368
+ amber: "amber";
2369
+ orange: "orange";
2370
+ purple: "purple";
2371
+ violet: "violet";
2372
+ fuchsia: "fuchsia";
2373
+ pink: "pink";
2374
+ cyan: "cyan";
2375
+ lime: "lime";
2376
+ }>;
2377
+ group: z.ZodEnum<{
2378
+ idle: "idle";
2379
+ in_progress: "in_progress";
2380
+ finished: "finished";
2381
+ }>;
2382
+ }, z.core.$strict>;
2383
+ /**
2384
+ * Map of attribute type to config schema
2385
+ */
2386
+ declare const attributeConfigSchemas: Record<AttributeType, z.ZodObject<z.ZodRawShape>>;
2387
+ /**
2388
+ * Get the config schema for a specific attribute type
2389
+ */
2390
+ declare function getAttributeConfigSchema(type: AttributeType): z.ZodObject<z.ZodRawShape>;
2391
+ /**
2392
+ * Validate and strip unknown properties from attribute config
2393
+ * This ensures only allowed properties are stored in the database
2394
+ */
2395
+ declare function parseAttributeConfig(type: AttributeType, config: Record<string, unknown>): Record<string, unknown>;
2396
+ /**
2397
+ * Strict parser for newly created attribute definitions.
2398
+ *
2399
+ * Top-level config remains strip-compatible with the historical config
2400
+ * contract, while newly written icons and select-like option objects are
2401
+ * validated strictly.
2402
+ */
2403
+ declare function parseAttributeConfigForCreate(type: AttributeType, input: unknown): Record<string, unknown>;
2404
+ /**
2405
+ * Patch-aware parser for persisted attributes.
2406
+ *
2407
+ * An explicit options patch owns and strictly validates the complete new
2408
+ * list. Omission means the stored legacy list is preserved without
2409
+ * reconstruction, including options that predate required colours/groups.
2410
+ */
2411
+ declare function parseAttributeConfigForUpdate(stored: Attribute, patch: Partial<AddAttributeInput>): Record<string, unknown>;
2412
+
2413
+ export { type AIQuestionOption as $, type Action as A, type AIBatchQuestion as B, type ConfigOverrides as C, type DetailViewConfig as D, type AIBatchQuestionAnswer as E, type FilterState as F, type Group as G, type AIBatchQuestionOption as H, type AIBatchQuestionType as I, type AIChatMessage as J, type AIChatMessagePart as K, type ListViewConfig as L, type ModelDefinition as M, type AIChatMessagePartType as N, type AIChatNotification as O, type PermissionScope as P, type AICompactionSummary as Q, type RelationGroup as R, type SortRule as S, type TriggerEventType as T, type AIMemoryEntry as U, type ViewType as V, type AIMemoryType as W, type AIMessageRole as X, type AIProviderMetrics as Y, type AIQuestion as Z, type AIQuestionAnswer as _, type ViewConfig as a, type EffectivePermissions as a$, type AIQuestionType as a0, type AISubagentStatus as a1, type AITodoItem as a2, type AITodoList as a3, type AITodoStatus as a4, type AIToolCall as a5, type AIToolCallStatus as a6, type AIUsageMetrics as a7, ALL_ACTIONS as a8, type AccessLevel as a9, type AgentTodoPlanStatus as aA, type AgentTodoPlanView as aB, type AgentToolCall as aC, type AgentTriggerDefinition as aD, type AgentTriggerType as aE, type ApprovalMode as aF, type AssignRoleInput as aG, type CompactionStrategy as aH, type CreateCustomObjectInput as aI, type CreateDocument as aJ, type CreateDocumentLink as aK, type CreateFile as aL, type CreatePermissionInput as aM, type CreateRoleInput as aN, type CreateViewInput as aO, type CriticConfig as aP, type CurrencyFilterValue as aQ, type CustomTab as aR, DEFAULT_APPROVAL_POLICY as aS, type Document as aT, type DocumentFile as aU, type DocumentKind as aV, type DocumentListOptions as aW, type DocumentWithFiles as aX, type DocumentWithSubCount as aY, type DocumentsTab as aZ, type EdgeQuantifier as a_, type ActivityTab as aa, type AddAttributeInput as ab, type AdvancedFilterState as ac, type AgentConfig as ad, type AgentDashboard as ae, type AgentDefinition as af, type AgentEvent as ag, type AgentMessageAttachment as ah, type AgentMessagePart as ai, type AgentMission as aj, type AgentMissionArtifact as ak, type AgentMissionPage as al, type AgentMissionPolicy as am, type AgentMissionRubric as an, type AgentMissionRubricCriterion as ao, type AgentMissionStatus as ap, type AgentMissionVerification as aq, type AgentMissionView as ar, type AgentRequiredPermission as as, type AgentRun as at, type AgentRunStatus as au, type AgentSession as av, type AgentSessionMessage as aw, type AgentSessionMode as ax, type AgentSessionStatus as ay, type AgentTodoPlan as az, type FilterOperator as b, type UpdateObjectInput as b$, type EmailsTab as b0, type ExtendedFilterRule as b1, type File as b2, type FileOcrStatus as b3, type FilterCombinator as b4, type FilterGroup as b5, type FormDensity as b6, type FormSubmittedAgentEvent as b7, type FormTab as b8, type FormsTab as b9, type Role as bA, SESSION_TERMINAL_STATUSES as bB, type SessionApprovalMode as bC, type SortDirection as bD, type StorageProvider as bE, type StreamEventCompactionEnd as bF, type StreamEventCompactionFailed as bG, type StreamEventCompactionStart as bH, type StreamEventMessagePersisted as bI, type StreamEventMessageUpdated as bJ, type StreamEventMissionUpdate as bK, type StreamEventTodoPlanUpdate as bL, type StreamEventUsage as bM, type SystemPermissions as bN, TODO_PLAN_STATUSES as bO, TODO_STATUSES as bP, type TabType as bQ, type TableSource as bR, type TerminalSessionStatus as bS, type TextPartData as bT, type ThinkingPartData as bU, type ToolImpact as bV, type ToolPartData as bW, type ToolPartErrorCode as bX, type ToolPartState as bY, type UpdateDocument as bZ, type UpdateFile as b_, type HumanRequestNeed as ba, type InverseSource as bb, type ListViewLayout as bc, MAX_TODOS as bd, MAX_TODO_DESCRIPTION_CHARS as be, MAX_TODO_ID_CHARS as bf, MAX_TODO_RESULT_CHARS as bg, type MentionEntityType as bh, type MentionReference as bi, type MentionedContext as bj, type MentionedEntityContext as bk, NO_VALUE_OPERATORS as bl, type NoValueOperator as bm, OPERATORS_BY_TYPE as bn, type ObjectPermissions as bo, type Permission as bp, type PhoneFilterValue as bq, type QueryState as br, type ReasoningPartData as bs, type RecordAgentEvent as bt, type RecordDocuments as bu, type RelationOption as bv, type RelationOptionsResponse as bw, type RelationSource as bx, type RetryPolicy as by, type RichtextTab as bz, type SystemResource as c, type UpdateRoleInput as c0, type UpdateViewInput as c1, type UserRoleAssignment as c2, type ViewOverlay as c3, accessLevelToActions as c4, actionsToAccessLevel as c5, agentDisplayName as c6, getRollupFilterOperators as c7, isDetailView as c8, isFieldGroup as c9, isListView as ca, isNoValueOperator as cb, isRelationGroup as cc, isTerminalSessionStatus as cd, multiselectOptionWriteSchema as ce, parseAttributeConfig as cf, parseAttributeConfigForCreate as cg, parseAttributeConfigForUpdate as ch, selectOptionWriteSchema as ci, statusGroupSchema as cj, statusOptionWriteSchema as ck, attributeConfigSchemas as cl, getAttributeConfigSchema as cm, type ProviderName as d, type AgentSchedule as e, type AgentExecutionConfig as f, type AgentApprovalPolicy as g, type AgentTriggerBlueprint as h, type AgentBlueprint as i, type DetailViewDefinition as j, type SidePanelConfig as k, type Field as l, type AttributeGroupField as m, type FieldGroup as n, type TableTab as o, type CreateMode as p, type Tab as q, type ListViewDefinition as r, type ViewDefinition as s, type ListViewTab as t, type FilterValue as u, type FilterRule as v, type DynamicValue as w, type RelativeDateValue as x, type AIAvailableModel as y, type AIBatchAnswerValue as z };