@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.
- package/dist/all--B2_3ksI.d.ts +465 -0
- package/dist/all-D5zeUllO.d.mts +465 -0
- package/dist/chunk-63WWFZFY.js +1262 -0
- package/dist/{chunk-ZBQEMIAV.js → chunk-FDIAOFHS.js} +11 -8
- package/dist/chunk-ITGE3PBX.mjs +1215 -0
- package/dist/{chunk-UXCJ3NI4.mjs → chunk-KDHDC7E6.mjs} +150 -9
- package/dist/{chunk-U36ZIBEM.mjs → chunk-O73ROMWQ.mjs} +15 -6
- package/dist/{chunk-QIWADKYA.mjs → chunk-POULKEJM.mjs} +11 -9
- package/dist/{chunk-EBGRZUIH.js → chunk-Q4SZAMJT.js} +5 -0
- package/dist/{chunk-NGGU6BSN.mjs → chunk-QMLO7V5E.mjs} +6 -6
- package/dist/{chunk-L4U5QEQL.js → chunk-QN2N3IJZ.js} +158 -8
- package/dist/{chunk-JUKLL5RJ.mjs → chunk-R5LAJCBU.mjs} +5 -2
- package/dist/{chunk-NI3HCSYH.js → chunk-V6Q7HCA7.js} +11 -11
- package/dist/{chunk-QAF3HNKQ.js → chunk-ZPFOKBIN.js} +16 -5
- package/dist/exceptions.d.mts +21 -8
- package/dist/exceptions.d.ts +21 -8
- package/dist/exceptions.js +42 -38
- package/dist/exceptions.mjs +1 -1
- package/dist/helpers-C1VVEAOO.d.mts +76 -0
- package/dist/helpers-vQ6kp8ET.d.ts +76 -0
- package/dist/index-Bq1KrQkR.d.ts +2413 -0
- package/dist/index-DtxtOBYT.d.mts +2413 -0
- package/dist/index.d.mts +1516 -2212
- package/dist/index.d.ts +1516 -2212
- package/dist/index.js +1294 -1038
- package/dist/index.mjs +911 -905
- package/dist/{helpers-eyrnPJEF.d.ts → objects-A1ED9af-.d.ts} +32 -77
- package/dist/{helpers-uKLet0kF.d.mts → objects-BCaBw2ef.d.mts} +32 -77
- package/dist/validation/all.d.mts +4 -2
- package/dist/validation/all.d.ts +4 -2
- package/dist/validation/all.js +88 -16
- package/dist/validation/all.mjs +9 -9
- package/dist/validation/complex/phone.js +2 -2
- package/dist/validation/complex/phone.mjs +1 -1
- package/dist/validation/config/index.d.mts +5 -18
- package/dist/validation/config/index.d.ts +5 -18
- package/dist/validation/config/index.js +34 -4
- package/dist/validation/config/index.mjs +7 -1
- package/dist/validation/object/index.d.mts +2 -2
- package/dist/validation/object/index.d.ts +2 -2
- package/dist/validation/object/index.js +19 -19
- package/dist/validation/object/index.mjs +7 -7
- package/dist/validation/primitives/text.js +2 -2
- package/dist/validation/primitives/text.mjs +1 -1
- package/package.json +2 -2
- package/dist/chunk-PGERPYDR.js +0 -2
- 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 };
|