@api-client/core 0.19.1 → 0.19.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/build/src/mocking/ModelingMock.d.ts +2 -0
  2. package/build/src/mocking/ModelingMock.d.ts.map +1 -1
  3. package/build/src/mocking/ModelingMock.js +2 -0
  4. package/build/src/mocking/ModelingMock.js.map +1 -1
  5. package/build/src/mocking/lib/Ai.d.ts +11 -0
  6. package/build/src/mocking/lib/Ai.d.ts.map +1 -0
  7. package/build/src/mocking/lib/Ai.js +53 -0
  8. package/build/src/mocking/lib/Ai.js.map +1 -0
  9. package/build/src/modeling/ai/DataDomainDelta.d.ts +146 -0
  10. package/build/src/modeling/ai/DataDomainDelta.d.ts.map +1 -0
  11. package/build/src/modeling/ai/DataDomainDelta.js +729 -0
  12. package/build/src/modeling/ai/DataDomainDelta.js.map +1 -0
  13. package/build/src/modeling/ai/DomainSerialization.d.ts +20 -0
  14. package/build/src/modeling/ai/DomainSerialization.d.ts.map +1 -0
  15. package/build/src/modeling/ai/DomainSerialization.js +185 -0
  16. package/build/src/modeling/ai/DomainSerialization.js.map +1 -0
  17. package/build/src/modeling/ai/domain_response_schema.d.ts +806 -0
  18. package/build/src/modeling/ai/domain_response_schema.d.ts.map +1 -0
  19. package/build/src/modeling/ai/domain_response_schema.js +289 -0
  20. package/build/src/modeling/ai/domain_response_schema.js.map +1 -0
  21. package/build/src/modeling/ai/domain_tools.d.ts +68 -0
  22. package/build/src/modeling/ai/domain_tools.d.ts.map +1 -0
  23. package/build/src/modeling/ai/domain_tools.js +71 -0
  24. package/build/src/modeling/ai/domain_tools.js.map +1 -0
  25. package/build/src/modeling/ai/index.d.ts +10 -0
  26. package/build/src/modeling/ai/index.d.ts.map +1 -0
  27. package/build/src/modeling/ai/index.js +9 -0
  28. package/build/src/modeling/ai/index.js.map +1 -0
  29. package/build/src/modeling/ai/message_parser.d.ts +23 -0
  30. package/build/src/modeling/ai/message_parser.d.ts.map +1 -0
  31. package/build/src/modeling/ai/message_parser.js +93 -0
  32. package/build/src/modeling/ai/message_parser.js.map +1 -0
  33. package/build/src/modeling/ai/prompts/domain_system.d.ts +6 -0
  34. package/build/src/modeling/ai/prompts/domain_system.d.ts.map +1 -0
  35. package/build/src/modeling/ai/prompts/domain_system.js +80 -0
  36. package/build/src/modeling/ai/prompts/domain_system.js.map +1 -0
  37. package/build/src/modeling/ai/tools/DataDomain.tools.d.ts +25 -0
  38. package/build/src/modeling/ai/tools/DataDomain.tools.d.ts.map +1 -0
  39. package/build/src/modeling/ai/tools/DataDomain.tools.js +334 -0
  40. package/build/src/modeling/ai/tools/DataDomain.tools.js.map +1 -0
  41. package/build/src/modeling/ai/tools/Semantic.tools.d.ts +48 -0
  42. package/build/src/modeling/ai/tools/Semantic.tools.d.ts.map +1 -0
  43. package/build/src/modeling/ai/tools/Semantic.tools.js +36 -0
  44. package/build/src/modeling/ai/tools/Semantic.tools.js.map +1 -0
  45. package/build/src/modeling/ai/tools/config.d.ts +13 -0
  46. package/build/src/modeling/ai/tools/config.d.ts.map +1 -0
  47. package/build/src/modeling/ai/tools/config.js +2 -0
  48. package/build/src/modeling/ai/tools/config.js.map +1 -0
  49. package/build/src/modeling/ai/types.d.ts +302 -0
  50. package/build/src/modeling/ai/types.d.ts.map +1 -0
  51. package/build/src/modeling/ai/types.js +40 -0
  52. package/build/src/modeling/ai/types.js.map +1 -0
  53. package/build/src/models/AiMessage.d.ts +185 -0
  54. package/build/src/models/AiMessage.d.ts.map +1 -0
  55. package/build/src/models/AiMessage.js +203 -0
  56. package/build/src/models/AiMessage.js.map +1 -0
  57. package/build/src/models/AiSession.d.ts +80 -0
  58. package/build/src/models/AiSession.d.ts.map +1 -0
  59. package/build/src/models/AiSession.js +102 -0
  60. package/build/src/models/AiSession.js.map +1 -0
  61. package/build/src/models/kinds.d.ts +2 -0
  62. package/build/src/models/kinds.d.ts.map +1 -1
  63. package/build/src/models/kinds.js +2 -0
  64. package/build/src/models/kinds.js.map +1 -1
  65. package/build/src/sdk/AiSdk.d.ts +93 -0
  66. package/build/src/sdk/AiSdk.d.ts.map +1 -0
  67. package/build/src/sdk/AiSdk.js +348 -0
  68. package/build/src/sdk/AiSdk.js.map +1 -0
  69. package/build/src/sdk/RouteBuilder.d.ts +7 -0
  70. package/build/src/sdk/RouteBuilder.d.ts.map +1 -1
  71. package/build/src/sdk/RouteBuilder.js +18 -0
  72. package/build/src/sdk/RouteBuilder.js.map +1 -1
  73. package/build/src/sdk/Sdk.d.ts +2 -0
  74. package/build/src/sdk/Sdk.d.ts.map +1 -1
  75. package/build/src/sdk/Sdk.js +2 -0
  76. package/build/src/sdk/Sdk.js.map +1 -1
  77. package/build/src/sdk/SdkBase.d.ts +4 -0
  78. package/build/src/sdk/SdkBase.d.ts.map +1 -1
  79. package/build/src/sdk/SdkBase.js.map +1 -1
  80. package/build/src/sdk/SdkMock.d.ts +15 -0
  81. package/build/src/sdk/SdkMock.d.ts.map +1 -1
  82. package/build/src/sdk/SdkMock.js +118 -0
  83. package/build/src/sdk/SdkMock.js.map +1 -1
  84. package/build/tsconfig.tsbuildinfo +1 -1
  85. package/data/models/example-generator-api.json +22 -22
  86. package/package.json +3 -3
  87. package/src/mocking/ModelingMock.ts +2 -0
  88. package/src/mocking/lib/Ai.ts +71 -0
  89. package/src/modeling/ai/DataDomainDelta.ts +798 -0
  90. package/src/modeling/ai/DomainSerialization.ts +199 -0
  91. package/src/modeling/ai/domain_response_schema.ts +301 -0
  92. package/src/modeling/ai/domain_tools.ts +76 -0
  93. package/src/modeling/ai/message_parser.ts +101 -0
  94. package/src/modeling/ai/prompts/domain_system.ts +79 -0
  95. package/src/modeling/ai/readme.md +8 -0
  96. package/src/modeling/ai/tools/DataDomain.tools.ts +365 -0
  97. package/src/modeling/ai/tools/Semantic.tools.ts +38 -0
  98. package/src/modeling/ai/tools/config.ts +13 -0
  99. package/src/modeling/ai/tools/readme.md +3 -0
  100. package/src/modeling/ai/types.ts +306 -0
  101. package/src/models/AiMessage.ts +335 -0
  102. package/src/models/AiSession.ts +160 -0
  103. package/src/models/kinds.ts +2 -0
  104. package/src/sdk/AiSdk.ts +395 -0
  105. package/src/sdk/RouteBuilder.ts +27 -0
  106. package/src/sdk/Sdk.ts +3 -0
  107. package/src/sdk/SdkBase.ts +4 -0
  108. package/src/sdk/SdkMock.ts +185 -0
  109. package/tests/unit/mocking/current/Ai.spec.ts +109 -0
  110. package/tests/unit/modeling/ai/DataDomainDelta.spec.ts +419 -0
  111. package/tests/unit/modeling/ai/DomainAiTools.spec.ts +29 -0
  112. package/tests/unit/modeling/ai/DomainSerialization.spec.ts +143 -0
  113. package/tests/unit/modeling/ai/message_parser.spec.ts +157 -0
  114. package/tests/unit/modeling/ai/tools/DataDomain.tools.spec.ts +64 -0
  115. package/tests/unit/modeling/ai/tools/Semantic.tools.spec.ts +55 -0
  116. package/tests/unit/models/AiMessage.spec.ts +216 -0
  117. package/tests/unit/models/AiSession.spec.ts +147 -0
@@ -0,0 +1,306 @@
1
+ import type { IApiAssociationShape } from '../../amf/definitions/Shapes.js'
2
+ import type { Exception } from '../../exceptions/exception.js'
3
+ import type { AiSessionSchema } from '../../models/AiSession.js'
4
+ import type { DomainPropertyType } from '../DataFormat.js'
5
+ import type { OnDeleteRule } from '../index.js'
6
+ import { SemanticType } from '../Semantics.js'
7
+ import type { AssociationTarget, PropertySchema } from '../types.js'
8
+ import type { AiMessageSchema, AiModelMessage } from '../../models/AiMessage.js'
9
+
10
+ /**
11
+ * A copy of the `Type` enum from the `@google/genai` package.
12
+ * It's here so we don't need to import the nodejs only package.
13
+ */
14
+ export enum Type {
15
+ /**
16
+ * Not specified, should not be used.
17
+ */
18
+ TYPE_UNSPECIFIED = 'TYPE_UNSPECIFIED',
19
+ /**
20
+ * OpenAPI string type
21
+ */
22
+ STRING = 'STRING',
23
+ /**
24
+ * OpenAPI number type
25
+ */
26
+ NUMBER = 'NUMBER',
27
+ /**
28
+ * OpenAPI integer type
29
+ */
30
+ INTEGER = 'INTEGER',
31
+ /**
32
+ * OpenAPI boolean type
33
+ */
34
+ BOOLEAN = 'BOOLEAN',
35
+ /**
36
+ * OpenAPI array type
37
+ */
38
+ ARRAY = 'ARRAY',
39
+ /**
40
+ * OpenAPI object type
41
+ */
42
+ OBJECT = 'OBJECT',
43
+ /**
44
+ * Null type
45
+ */
46
+ NULL = 'NULL',
47
+ }
48
+
49
+ /**
50
+ * A lightweight representation of the `DataDomain` used specifically for serializing
51
+ * the current domain state and sending it as context to the AI endpoint.
52
+ * It omits complex internal graph structures, including only essential keys, names,
53
+ * descriptions, and the hierarchical structure of models and entities.
54
+ */
55
+ export interface AiDataDomainSchema {
56
+ key: string
57
+ name: string
58
+ models: AiDataModelSchema[]
59
+ entities: AiDomainEntitySchema[]
60
+ }
61
+
62
+ /**
63
+ * A stripped-down representation of a `DomainModel` sent to the AI as part of the
64
+ * domain context. It provides the AI with the existing model hierarchy and descriptions.
65
+ */
66
+ export interface AiDataModelSchema {
67
+ key: string
68
+ name?: string
69
+ description?: string
70
+ }
71
+
72
+ /**
73
+ * Represents a semantic annotation applied to an entity, property, or association
74
+ * within the AI's understanding or response. It defines the "meaning" of a field
75
+ * (e.g., "Email", "Password", "Address").
76
+ */
77
+ export interface AiDomainSemantic {
78
+ id: SemanticType
79
+ config?: Record<string, unknown>
80
+ }
81
+
82
+ /**
83
+ * Represents a full or partial entity schema as generated by the AI in its response delta.
84
+ * It defines a new entity or updates to an existing one, including its properties,
85
+ * associations, semantics, and tags. This is also used by the `get_entity_details` tool
86
+ * to send detailed serialized entity information back to the AI.
87
+ */
88
+ export interface AiDomainEntityResponseSchema {
89
+ key: string
90
+ modelKey: string
91
+ name?: string
92
+ displayName?: string
93
+ description?: string
94
+ tags?: string[]
95
+ semantics?: AiDomainSemantic[]
96
+ properties?: AiDomainProperty[]
97
+ associations?: AiDomainAssociation[]
98
+ }
99
+
100
+ /**
101
+ * A minimal representation of an entity used purely for context-setting when
102
+ * sending the current domain structure to the AI. It excludes deeply nested
103
+ * properties and associations to save token space.
104
+ */
105
+ export interface AiDomainEntitySchema {
106
+ key: string
107
+ modelKey: string
108
+ name?: string
109
+ description?: string
110
+ }
111
+
112
+ /**
113
+ * Represents a property definition generated by the AI. It maps the complex internal
114
+ * domain property structure into a simpler, flat structure that the AI generates,
115
+ * including data types, constraints, schema metadata, and semantics.
116
+ */
117
+ export interface AiDomainProperty {
118
+ key?: string
119
+ name?: string
120
+ displayName?: string
121
+ description?: string
122
+ type: DomainPropertyType
123
+ constraints?: {
124
+ required?: boolean
125
+ unique?: boolean
126
+ index?: boolean
127
+ primary?: boolean
128
+ multiple?: boolean
129
+ readOnly?: boolean
130
+ writeOnly?: boolean
131
+ }
132
+ deprecated?: boolean
133
+ schema?: PropertySchema
134
+ semantics?: AiDomainSemantic[]
135
+ tags?: string[]
136
+ }
137
+
138
+ /**
139
+ * Represents an association definition generated by the AI, linking an entity
140
+ * to one or more target entities. It includes relationship rules (like onDelete)
141
+ * and semantic annotations.
142
+ */
143
+ export interface AiDomainAssociation {
144
+ key: string
145
+ name?: string
146
+ displayName?: string
147
+ description?: string
148
+ targets: AssociationTarget[]
149
+ required?: boolean
150
+ multiple?: boolean
151
+ onDelete?: OnDeleteRule
152
+ semantics?: AiDomainSemantic[]
153
+ schema?: IApiAssociationShape
154
+ }
155
+
156
+ /**
157
+ * The core structure representing a set of modifications (a delta) proposed by the AI.
158
+ * It contains arrays of models and entities to add, delete, or modify. The application
159
+ * processes this delta to transition the data domain to the new requested state.
160
+ */
161
+ export interface AiDomainDelta {
162
+ /**
163
+ * Models to add to the domain.
164
+ */
165
+ addedModels?: AiDataModelSchema[]
166
+ /**
167
+ * Keys of models to delete from the domain.
168
+ */
169
+ deletedModelKeys?: string[]
170
+ /**
171
+ * Models to modify in the domain.
172
+ */
173
+ modifiedModels?: AiDataModelSchema[]
174
+ /**
175
+ * Entities to add to the domain.
176
+ */
177
+ addedEntities?: AiDomainEntityResponseSchema[]
178
+ /**
179
+ * Keys of entities to delete from the domain.
180
+ */
181
+ deletedEntityKeys?: string[]
182
+ /**
183
+ * Entities to modify in the domain.
184
+ */
185
+ modifiedEntities?: AiDomainEntityDelta[]
186
+ }
187
+
188
+ /**
189
+ * The expected JSON schema structure returned by the AI endpoint when performing
190
+ * data domain manipulation. It includes the AI's step-by-step reasoning and the
191
+ * actionable delta to be applied.
192
+ */
193
+ export interface AiDomainDeltaResponse {
194
+ /**
195
+ * The LLM reasoning.
196
+ */
197
+ reasoning: string
198
+ /**
199
+ * Domain changes delta
200
+ */
201
+ delta?: AiDomainDelta
202
+ }
203
+
204
+ /**
205
+ * Union type for progressive SSE stream chunks
206
+ * received from the AI generation endpoint.
207
+ */
208
+ export type AiStreamEvent =
209
+ | { event: 'user-message'; data: AiMessageSchema }
210
+ | { event: 'agent-message'; data: AiMessageSchema }
211
+ | { event: 'thought-chunk'; data: string }
212
+ | { event: 'text-chunk'; data: string }
213
+ | { event: 'done'; data: AiMessageSchema }
214
+ | { event: 'error'; data: Exception }
215
+ | { event: 'session-updated'; data: AiSessionSchema }
216
+
217
+ /**
218
+ * Represents a targeted modification to an existing entity generated by the AI.
219
+ * Instead of providing the full entity state, the AI provides explicit arrays
220
+ * of properties, associations, and semantics to add, modify, or delete, enabling
221
+ * precise, non-destructive updates.
222
+ */
223
+ export interface AiDomainEntityDelta {
224
+ key: string
225
+ modelKey?: string // Provide to move the entity to a different model
226
+ name?: string
227
+ displayName?: string
228
+ description?: string
229
+ tags?: string[]
230
+ // Entity semantics delta
231
+ addedSemantics?: AiDomainSemantic[]
232
+ modifiedSemantics?: AiDomainSemantic[]
233
+ deletedSemanticIds?: SemanticType[]
234
+ // Explicit deltas so the LLM doesn't have to list untouched properties
235
+ addedProperties?: AiDomainProperty[]
236
+ modifiedProperties?: AiDomainPropertyDelta[]
237
+ deletedPropertyKeys?: string[]
238
+ addedAssociations?: AiDomainAssociation[]
239
+ modifiedAssociations?: AiDomainAssociationDelta[]
240
+ deletedAssociationKeys?: string[]
241
+ }
242
+
243
+ /**
244
+ * Represents a targeted modification to an existing property generated by the AI.
245
+ * It captures changes to superficial properties (name, description), type changes,
246
+ * constraint updates, and semantic alterations.
247
+ */
248
+ export interface AiDomainPropertyDelta {
249
+ key: string
250
+ name?: string
251
+ displayName?: string
252
+ description?: string
253
+ type?: DomainPropertyType
254
+ constraints?: {
255
+ required?: boolean
256
+ unique?: boolean
257
+ index?: boolean
258
+ primary?: boolean
259
+ multiple?: boolean
260
+ readOnly?: boolean
261
+ writeOnly?: boolean
262
+ }
263
+ deprecated?: boolean
264
+ // Property semantics delta
265
+ addedSemantics?: AiDomainSemantic[]
266
+ modifiedSemantics?: AiDomainSemantic[]
267
+ deletedSemanticIds?: SemanticType[]
268
+ schema?: PropertySchema
269
+ }
270
+
271
+ /**
272
+ * Represents a targeted modification to an existing association generated by the AI.
273
+ * It captures updates to relationship cardinality, target entities, deletion rules,
274
+ * and applied semantics.
275
+ */
276
+ export interface AiDomainAssociationDelta {
277
+ key: string
278
+ name?: string
279
+ displayName?: string
280
+ description?: string
281
+ targets?: AssociationTarget[]
282
+ required?: boolean
283
+ onDelete?: OnDeleteRule
284
+ // Association semantics delta
285
+ addedSemantics?: AiDomainSemantic[]
286
+ modifiedSemantics?: AiDomainSemantic[]
287
+ deletedSemanticIds?: SemanticType[]
288
+ }
289
+
290
+ /**
291
+ * An enriched, in-memory representation of a model's message that includes the globally
292
+ * parsed `AiDomainDelta` object.
293
+ * This is not stored directly in the datastore as-is; instead, the raw JSON text is stored,
294
+ * and this structure is assembled at runtime when the chat history is loaded into the UI.
295
+ */
296
+ export interface AiModelMessageWithDelta extends AiModelMessage {
297
+ /**
298
+ * The delta of the message, if any.
299
+ */
300
+ delta?: AiDomainDelta
301
+ /**
302
+ * The reasoning of the delta.
303
+ * Format in markdown.
304
+ */
305
+ reasoning?: string
306
+ }
@@ -0,0 +1,335 @@
1
+ import type { IDeletion } from './store/Deletion.js'
2
+ import { AiMessageKind } from './kinds.js'
3
+ import { nanoid } from '../nanoid.js'
4
+ import type { AiDomainDelta } from '../modeling/ai/types.js'
5
+ import { DataDomainDelta } from '../modeling/ai/DataDomainDelta.js'
6
+
7
+ export type AiMessageRole = 'user' | 'model'
8
+ export type AiMessageState = 'loading' | 'complete' | 'error' | 'terminated'
9
+
10
+ /**
11
+ * The base interface representing a single message in the domain manipulation chat history.
12
+ * It tracks metadata like timestamps, the associated session, and the raw text content.
13
+ * See `AiUserMessage` and `AiModelMessage` for specific role implementations.
14
+ */
15
+ export interface AiMessageSchemaBase {
16
+ readonly kind: typeof AiMessageKind
17
+ /**
18
+ * The datastore key of the message.
19
+ */
20
+ key: string
21
+ /**
22
+ * The role of the message.
23
+ */
24
+ role: AiMessageRole
25
+ /**
26
+ * The timestamp of when the message was created.
27
+ */
28
+ createdAt: number
29
+ /**
30
+ * The timestamp of when the message was last updated.
31
+ */
32
+ updatedAt: number
33
+ /**
34
+ * The datastore key of the session.
35
+ */
36
+ session: string
37
+ /**
38
+ * The text of the message.
39
+ */
40
+ text: string
41
+ /**
42
+ * Whether the message is deleted.
43
+ */
44
+ deleted?: boolean
45
+ /**
46
+ * The information about the delete information.
47
+ * Always set when the `deleted` is true.
48
+ */
49
+ deletedInfo?: IDeletion
50
+ }
51
+
52
+ /**
53
+ * The schema for a user message.
54
+ */
55
+ export interface AiUserMessageSchema extends AiMessageSchemaBase {
56
+ /**
57
+ * The role of the message.
58
+ */
59
+ role: 'user'
60
+ /**
61
+ * The state of the user message.
62
+ * Can only be `complete`.
63
+ */
64
+ state: 'complete'
65
+ /**
66
+ * The user utterance.
67
+ * Note, the actual message sent to the LLM may be different from the utterance
68
+ * as it has additional instructions and the domain context. However, we are not storing
69
+ * the full message in the datastore, only the utterance.
70
+ */
71
+ text: string
72
+ }
73
+
74
+ /**
75
+ * The schema for a model message.
76
+ */
77
+ export interface AiModelMessageSchema extends AiMessageSchemaBase {
78
+ /**
79
+ * The role of the message.
80
+ */
81
+ role: 'model'
82
+ /**
83
+ * The full text of the message returned by the LLM.
84
+ * It is most likely a structured message that needs to be parsed
85
+ * to the corresponding message object.
86
+ */
87
+ text: string
88
+ /**
89
+ * The state of the message.
90
+ * - loading: the message is being generated
91
+ * - complete: the message is complete
92
+ * - error: the message generation failed
93
+ * - terminated: the message generation was terminated by the user
94
+ */
95
+ state: AiMessageState
96
+ /**
97
+ * Whether the message has been applied.
98
+ */
99
+ applied?: boolean
100
+ /**
101
+ * The thoughts of the message.
102
+ */
103
+ thoughts?: string
104
+ }
105
+
106
+ /**
107
+ * A union type representing any valid chat message in the AI session history.
108
+ */
109
+ export type AiMessageSchema = AiUserMessageSchema | AiModelMessageSchema
110
+
111
+ /**
112
+ * The base class for all AI messages.
113
+ * It provides common functionality for all message types.
114
+ */
115
+ export abstract class AiMessageBase<
116
+ T extends AiMessageSchemaBase = AiMessageSchemaBase,
117
+ > implements AiMessageSchemaBase {
118
+ /**
119
+ * The kind of the schema.
120
+ */
121
+ static get Kind(): typeof AiMessageKind {
122
+ return AiMessageKind
123
+ }
124
+
125
+ /**
126
+ * The kind of the schema.
127
+ */
128
+ get kind(): typeof AiMessageKind {
129
+ return AiMessageKind
130
+ }
131
+
132
+ key: string
133
+ role: T['role']
134
+ createdAt: number
135
+ updatedAt: number
136
+ session: string
137
+ text: string
138
+ deleted: boolean
139
+ deletedInfo?: IDeletion
140
+
141
+ protected static createBaseSchema(input: Partial<AiMessageSchemaBase>): Omit<AiMessageSchemaBase, 'role'> {
142
+ const { key = nanoid(), session, text = '', createdAt = 0, updatedAt = 0 } = input
143
+ if (!session) {
144
+ throw new Error('Session is required to create an AiMessage.')
145
+ }
146
+ return {
147
+ key,
148
+ kind: AiMessageKind,
149
+ session,
150
+ text,
151
+ createdAt,
152
+ updatedAt,
153
+ }
154
+ }
155
+
156
+ constructor(input: Partial<T> = {}, role: T['role']) {
157
+ const base = AiMessageBase.createBaseSchema(input)
158
+ this.key = base.key
159
+ this.role = role
160
+ this.session = base.session
161
+ this.text = base.text
162
+ this.createdAt = base.createdAt
163
+ this.updatedAt = base.updatedAt
164
+ this.deleted = input.deleted || false
165
+ this.deletedInfo = input.deletedInfo
166
+ }
167
+
168
+ toJSON(): T {
169
+ const result = {
170
+ kind: this.kind,
171
+ key: this.key,
172
+ role: this.role,
173
+ session: this.session,
174
+ text: this.text,
175
+ createdAt: this.createdAt,
176
+ updatedAt: this.updatedAt,
177
+ }
178
+ if (this.deleted && this.deletedInfo) {
179
+ Object.assign(result, {
180
+ deleted: this.deleted,
181
+ deletedInfo: { ...this.deletedInfo },
182
+ })
183
+ }
184
+ return result as unknown as T
185
+ }
186
+ }
187
+
188
+ export class AiUserMessage extends AiMessageBase<AiUserMessageSchema> implements AiUserMessageSchema {
189
+ state: 'complete'
190
+
191
+ static createSchema(input: Partial<AiUserMessageSchema>): AiUserMessageSchema {
192
+ const base = AiMessageBase.createBaseSchema(input)
193
+ return {
194
+ ...base,
195
+ role: 'user',
196
+ state: 'complete',
197
+ }
198
+ }
199
+
200
+ constructor(input: Partial<AiUserMessageSchema> = {}) {
201
+ super(input, 'user')
202
+ this.state = 'complete'
203
+ }
204
+
205
+ override toJSON(): AiUserMessageSchema {
206
+ return {
207
+ ...super.toJSON(),
208
+ state: this.state,
209
+ }
210
+ }
211
+ }
212
+
213
+ export class AiModelMessage extends AiMessageBase<AiModelMessageSchema> implements AiModelMessageSchema {
214
+ state: AiMessageState
215
+ applied?: boolean
216
+ thoughts: string
217
+
218
+ /**
219
+ * The delta of the message, if any.
220
+ */
221
+ delta?: AiDomainDelta
222
+ /**
223
+ * The reasoning of the delta.
224
+ * Format in markdown.
225
+ */
226
+ reasoning?: string
227
+
228
+ static createSchema(input: Partial<AiModelMessageSchema>): AiModelMessageSchema {
229
+ const base = AiMessageBase.createBaseSchema(input)
230
+ return {
231
+ ...base,
232
+ role: 'model',
233
+ state: input.state || 'loading',
234
+ applied: input.applied,
235
+ thoughts: input.thoughts || '',
236
+ }
237
+ }
238
+
239
+ constructor(input: Partial<AiModelMessageSchema> = {}) {
240
+ super(input, 'model')
241
+ this.state = input.state || 'loading'
242
+ this.applied = input.applied
243
+ this.thoughts = input.thoughts || ''
244
+ }
245
+
246
+ override toJSON(): AiModelMessageSchema {
247
+ const result: AiModelMessageSchema = {
248
+ ...super.toJSON(),
249
+ state: this.state,
250
+ thoughts: this.thoughts,
251
+ }
252
+ if (this.applied !== undefined) {
253
+ result.applied = this.applied
254
+ }
255
+ return result
256
+ }
257
+
258
+ /**
259
+ * Adds a thought to the message. Useful when streaming.
260
+ * @param thought The thought to add.
261
+ */
262
+ addThought(thought?: string): void {
263
+ if (!thought) {
264
+ return
265
+ }
266
+ this.thoughts += thought
267
+ }
268
+
269
+ /**
270
+ * Adds a text chunk to the message. Useful when streaming.
271
+ * @param text The text chunk to add.
272
+ */
273
+ addText(text?: string): void {
274
+ if (!text) {
275
+ return
276
+ }
277
+ this.text += text
278
+ }
279
+
280
+ /**
281
+ * Processes the message.
282
+ * If the message is not valid JSON, it will throw an error.
283
+ * It sets the delta and reasoning fields, if found in the message.
284
+ */
285
+ processMessage(): void {
286
+ if (!this.text) {
287
+ return
288
+ }
289
+ const parsed = JSON.parse(this.text)
290
+ if (parsed.delta) {
291
+ this.delta = DataDomainDelta.normalize(parsed.delta)
292
+ }
293
+ if (parsed.reasoning) {
294
+ this.reasoning = parsed.reasoning
295
+ }
296
+ }
297
+
298
+ /**
299
+ * Processes the message safely.
300
+ * If the message is not valid JSON, it will be ignored.
301
+ */
302
+ processMessageSafe(): void {
303
+ try {
304
+ this.processMessage()
305
+ } catch {
306
+ // do nothing
307
+ }
308
+ }
309
+
310
+ /**
311
+ * Creates an empty model message. Useful when initializing LLM flow.
312
+ * @param session The session key.
313
+ * @returns An empty model message.
314
+ */
315
+ static createEmpty(session: string): AiModelMessage {
316
+ return new AiModelMessage({
317
+ session,
318
+ state: 'loading',
319
+ })
320
+ }
321
+ }
322
+
323
+ /**
324
+ * A union type representing any valid chat message in the AI session history.
325
+ */
326
+ export type AiMessage = AiUserMessage | AiModelMessage
327
+
328
+ export const AiMessageFactory = {
329
+ fromSchema(schema: Partial<AiMessageSchema>): AiMessage {
330
+ if (schema.role === 'model') {
331
+ return new AiModelMessage(schema as Partial<AiModelMessageSchema>)
332
+ }
333
+ return new AiUserMessage(schema as Partial<AiUserMessageSchema>)
334
+ },
335
+ }