@api-client/core 0.19.6 → 0.19.8
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/build/src/browser.d.ts +1 -1
- package/build/src/browser.d.ts.map +1 -1
- package/build/src/browser.js +1 -1
- package/build/src/browser.js.map +1 -1
- package/build/src/index.d.ts +1 -1
- package/build/src/index.d.ts.map +1 -1
- package/build/src/index.js +1 -1
- package/build/src/index.js.map +1 -1
- package/build/src/modeling/DomainProperty.d.ts +7 -0
- package/build/src/modeling/DomainProperty.d.ts.map +1 -1
- package/build/src/modeling/DomainProperty.js +10 -0
- package/build/src/modeling/DomainProperty.js.map +1 -1
- package/build/src/modeling/ai/message_parser.d.ts +1 -0
- package/build/src/modeling/ai/message_parser.d.ts.map +1 -1
- package/build/src/modeling/ai/message_parser.js +1 -0
- package/build/src/modeling/ai/message_parser.js.map +1 -1
- package/build/src/models/AiMessage.d.ts +41 -9
- package/build/src/models/AiMessage.d.ts.map +1 -1
- package/build/src/models/AiMessage.js +41 -14
- package/build/src/models/AiMessage.js.map +1 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/data/models/example-generator-api.json +12 -12
- package/package.json +1 -1
- package/src/modeling/DomainProperty.ts +11 -0
- package/src/modeling/ai/message_parser.ts +1 -0
- package/src/models/AiMessage.ts +66 -19
- package/tests/unit/modeling/domain_property.spec.ts +38 -0
- package/tests/unit/models/AiMessage.spec.ts +32 -30
|
@@ -42810,16 +42810,16 @@
|
|
|
42810
42810
|
"@id": "#219"
|
|
42811
42811
|
},
|
|
42812
42812
|
{
|
|
42813
|
-
"@id": "#
|
|
42813
|
+
"@id": "#219"
|
|
42814
42814
|
},
|
|
42815
42815
|
{
|
|
42816
|
-
"@id": "#
|
|
42816
|
+
"@id": "#216"
|
|
42817
42817
|
},
|
|
42818
42818
|
{
|
|
42819
|
-
"@id": "#
|
|
42819
|
+
"@id": "#210"
|
|
42820
42820
|
},
|
|
42821
42821
|
{
|
|
42822
|
-
"@id": "#
|
|
42822
|
+
"@id": "#213"
|
|
42823
42823
|
}
|
|
42824
42824
|
],
|
|
42825
42825
|
"doc:root": false,
|
|
@@ -44232,7 +44232,7 @@
|
|
|
44232
44232
|
"doc:ExternalDomainElement",
|
|
44233
44233
|
"doc:DomainElement"
|
|
44234
44234
|
],
|
|
44235
|
-
"doc:raw": "type: 'GENERAL'\
|
|
44235
|
+
"doc:raw": "-\n type: 'GENERAL'\n value: 'info@company.be'\n-\n type: 'IT_DEPT'\n value: 'it-service@company.be'\n",
|
|
44236
44236
|
"core:mediaType": "application/yaml",
|
|
44237
44237
|
"sourcemaps:sources": [
|
|
44238
44238
|
{
|
|
@@ -44253,7 +44253,7 @@
|
|
|
44253
44253
|
"doc:ExternalDomainElement",
|
|
44254
44254
|
"doc:DomainElement"
|
|
44255
44255
|
],
|
|
44256
|
-
"doc:raw": "type:
|
|
44256
|
+
"doc:raw": "type: \"GENERAL\"\nvalue: \"www.company.be\"\n",
|
|
44257
44257
|
"core:mediaType": "application/yaml",
|
|
44258
44258
|
"sourcemaps:sources": [
|
|
44259
44259
|
{
|
|
@@ -44274,7 +44274,7 @@
|
|
|
44274
44274
|
"doc:ExternalDomainElement",
|
|
44275
44275
|
"doc:DomainElement"
|
|
44276
44276
|
],
|
|
44277
|
-
"doc:raw": "
|
|
44277
|
+
"doc:raw": "type: 'GENERAL'\ncountryDialCode : '+32'\nareaCode : '21'\nsubscriberNumber: '12.87.00'\nformatted: '+32-(0)21 302099'\n",
|
|
44278
44278
|
"core:mediaType": "application/yaml",
|
|
44279
44279
|
"sourcemaps:sources": [
|
|
44280
44280
|
{
|
|
@@ -44295,7 +44295,7 @@
|
|
|
44295
44295
|
"doc:ExternalDomainElement",
|
|
44296
44296
|
"doc:DomainElement"
|
|
44297
44297
|
],
|
|
44298
|
-
"doc:raw": "type:
|
|
44298
|
+
"doc:raw": "type: 'GENERAL'\ncountryDialCode : '+32'\nareaCode : '22'\nsubscriberNumber: '12.87.00'\nformatted: '+32-(0)22 000000'\n",
|
|
44299
44299
|
"core:mediaType": "application/yaml",
|
|
44300
44300
|
"sourcemaps:sources": [
|
|
44301
44301
|
{
|
|
@@ -45116,22 +45116,22 @@
|
|
|
45116
45116
|
{
|
|
45117
45117
|
"@id": "#212/source-map/lexical/element_0",
|
|
45118
45118
|
"sourcemaps:element": "amf://id#212",
|
|
45119
|
-
"sourcemaps:value": "[(1,0)-(
|
|
45119
|
+
"sourcemaps:value": "[(1,0)-(7,0)]"
|
|
45120
45120
|
},
|
|
45121
45121
|
{
|
|
45122
45122
|
"@id": "#215/source-map/lexical/element_0",
|
|
45123
45123
|
"sourcemaps:element": "amf://id#215",
|
|
45124
|
-
"sourcemaps:value": "[(1,0)-(
|
|
45124
|
+
"sourcemaps:value": "[(1,0)-(3,0)]"
|
|
45125
45125
|
},
|
|
45126
45126
|
{
|
|
45127
45127
|
"@id": "#218/source-map/lexical/element_0",
|
|
45128
45128
|
"sourcemaps:element": "amf://id#218",
|
|
45129
|
-
"sourcemaps:value": "[(1,0)-(
|
|
45129
|
+
"sourcemaps:value": "[(1,0)-(6,0)]"
|
|
45130
45130
|
},
|
|
45131
45131
|
{
|
|
45132
45132
|
"@id": "#221/source-map/lexical/element_0",
|
|
45133
45133
|
"sourcemaps:element": "amf://id#221",
|
|
45134
|
-
"sourcemaps:value": "[(1,0)-(
|
|
45134
|
+
"sourcemaps:value": "[(1,0)-(6,0)]"
|
|
45135
45135
|
},
|
|
45136
45136
|
{
|
|
45137
45137
|
"@id": "#338/source-map/synthesized-field/element_1",
|
package/package.json
CHANGED
|
@@ -542,6 +542,17 @@ export class DomainProperty extends DomainElement {
|
|
|
542
542
|
return object.schema as PropertyWebBindings
|
|
543
543
|
}
|
|
544
544
|
|
|
545
|
+
/**
|
|
546
|
+
* Reads the web binding definition, if any.
|
|
547
|
+
* Useful for reading binding data without mutating the model when the binding
|
|
548
|
+
* is missing (unlike `getWebBinding()` which creates the binding when missing).
|
|
549
|
+
* @returns The web binding definition, if any
|
|
550
|
+
*/
|
|
551
|
+
readWebBinding(): PropertyWebBindings | undefined {
|
|
552
|
+
const object = this.bindings.find((i) => i.type === 'web') as PropertyBinding | undefined
|
|
553
|
+
return object?.schema as PropertyWebBindings | undefined
|
|
554
|
+
}
|
|
555
|
+
|
|
545
556
|
/**
|
|
546
557
|
* Returns the schema value of the binding, if any was created.
|
|
547
558
|
* @param type The type of the binding to read.
|
|
@@ -12,6 +12,7 @@ import { DataDomainDelta } from './DataDomainDelta.js'
|
|
|
12
12
|
*
|
|
13
13
|
* @param msg The generic AI chat message.
|
|
14
14
|
* @returns The parsed in-memory wrapper context message.
|
|
15
|
+
* @deprecated Use `AiModelMessage.processMessageSafe` instead.
|
|
15
16
|
*/
|
|
16
17
|
export function parseAiChatMessage(msg: AiMessageSchema): AiUserMessage | AiModelMessageWithDelta {
|
|
17
18
|
if (msg.role === 'user') {
|
package/src/models/AiMessage.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { AiMessageKind } from './kinds.js'
|
|
|
3
3
|
import { nanoid } from '../nanoid.js'
|
|
4
4
|
import type { AiDomainDelta } from '../modeling/ai/types.js'
|
|
5
5
|
import { DataDomainDelta } from '../modeling/ai/DataDomainDelta.js'
|
|
6
|
+
import { detectReasoning } from '../modeling/ai/message_parser.js'
|
|
6
7
|
|
|
7
8
|
export type AiMessageRole = 'user' | 'model'
|
|
8
9
|
export type AiMessageState = 'loading' | 'complete' | 'error' | 'terminated'
|
|
@@ -210,21 +211,39 @@ export class AiUserMessage extends AiMessageBase<AiUserMessageSchema> implements
|
|
|
210
211
|
}
|
|
211
212
|
}
|
|
212
213
|
|
|
213
|
-
|
|
214
|
+
/**
|
|
215
|
+
* Model messages have the `text` that most likely is a structured JSON
|
|
216
|
+
* with the `delta` and `reasoning` properties. When an `AiModelMessage` is instantiated,
|
|
217
|
+
* it will try to parse the `text` into the `delta` and `reasoning` properties, leaving the
|
|
218
|
+
* `text` property unchanged.
|
|
219
|
+
*
|
|
220
|
+
* The delta object will be different for different models and different use cases.
|
|
221
|
+
* It is up to the model to define the delta object. However, the delta object should
|
|
222
|
+
* be normalized by each child class.
|
|
223
|
+
*
|
|
224
|
+
* @template D The type of the delta.
|
|
225
|
+
*/
|
|
226
|
+
export abstract class AiModelMessage<D = unknown>
|
|
227
|
+
extends AiMessageBase<AiModelMessageSchema>
|
|
228
|
+
implements AiModelMessageSchema
|
|
229
|
+
{
|
|
214
230
|
state: AiMessageState
|
|
215
231
|
applied?: boolean
|
|
216
232
|
thoughts: string
|
|
217
233
|
|
|
218
234
|
/**
|
|
219
|
-
* The delta
|
|
235
|
+
* The extracted delta from the message.
|
|
220
236
|
*/
|
|
221
|
-
delta?:
|
|
237
|
+
delta?: D
|
|
238
|
+
|
|
222
239
|
/**
|
|
223
|
-
* The reasoning
|
|
240
|
+
* The extracted reasoning from the message.
|
|
224
241
|
* Format in markdown.
|
|
225
242
|
*/
|
|
226
243
|
reasoning?: string
|
|
227
244
|
|
|
245
|
+
#reasoningEnded = false
|
|
246
|
+
|
|
228
247
|
static createSchema(input: Partial<AiModelMessageSchema>): AiModelMessageSchema {
|
|
229
248
|
const base = AiMessageBase.createBaseSchema(input)
|
|
230
249
|
return {
|
|
@@ -241,6 +260,7 @@ export class AiModelMessage extends AiMessageBase<AiModelMessageSchema> implemen
|
|
|
241
260
|
this.state = input.state || 'loading'
|
|
242
261
|
this.applied = input.applied
|
|
243
262
|
this.thoughts = input.thoughts || ''
|
|
263
|
+
this.processMessageSafe()
|
|
244
264
|
}
|
|
245
265
|
|
|
246
266
|
override toJSON(): AiModelMessageSchema {
|
|
@@ -268,6 +288,8 @@ export class AiModelMessage extends AiMessageBase<AiModelMessageSchema> implemen
|
|
|
268
288
|
|
|
269
289
|
/**
|
|
270
290
|
* Adds a text chunk to the message. Useful when streaming.
|
|
291
|
+
*
|
|
292
|
+
* Note, this function progressively detects the reasoning on each chunk.
|
|
271
293
|
* @param text The text chunk to add.
|
|
272
294
|
*/
|
|
273
295
|
addText(text?: string): void {
|
|
@@ -275,6 +297,15 @@ export class AiModelMessage extends AiMessageBase<AiModelMessageSchema> implemen
|
|
|
275
297
|
return
|
|
276
298
|
}
|
|
277
299
|
this.text += text
|
|
300
|
+
if (this.#reasoningEnded) {
|
|
301
|
+
return
|
|
302
|
+
}
|
|
303
|
+
const before = this.reasoning
|
|
304
|
+
const after = detectReasoning(this.text)
|
|
305
|
+
if (after && after === before) {
|
|
306
|
+
this.#reasoningEnded = true
|
|
307
|
+
}
|
|
308
|
+
this.reasoning = after
|
|
278
309
|
}
|
|
279
310
|
|
|
280
311
|
/**
|
|
@@ -283,12 +314,13 @@ export class AiModelMessage extends AiMessageBase<AiModelMessageSchema> implemen
|
|
|
283
314
|
* It sets the delta and reasoning fields, if found in the message.
|
|
284
315
|
*/
|
|
285
316
|
processMessage(): void {
|
|
286
|
-
|
|
317
|
+
const { text } = this
|
|
318
|
+
if (!text) {
|
|
287
319
|
return
|
|
288
320
|
}
|
|
289
|
-
const parsed = JSON.parse(
|
|
321
|
+
const parsed = JSON.parse(text)
|
|
290
322
|
if (parsed.delta) {
|
|
291
|
-
this.delta =
|
|
323
|
+
this.delta = this.normalizeDelta(parsed.delta)
|
|
292
324
|
}
|
|
293
325
|
if (parsed.reasoning) {
|
|
294
326
|
this.reasoning = parsed.reasoning
|
|
@@ -307,29 +339,44 @@ export class AiModelMessage extends AiMessageBase<AiModelMessageSchema> implemen
|
|
|
307
339
|
}
|
|
308
340
|
}
|
|
309
341
|
|
|
342
|
+
/**
|
|
343
|
+
* Normalizes the delta to the final shape required by the system.
|
|
344
|
+
*
|
|
345
|
+
* Probabilistic models can produce deltas that are not always what the author expected.
|
|
346
|
+
* For example, the DataDomain delta has `modifiedEntities` property that sometimes is
|
|
347
|
+
* populated multiple times by the same entity. This should be normalized to a single
|
|
348
|
+
* operation so that the UI can correctly render the changes, without an expensive lookup
|
|
349
|
+
* operations. The author of the message model should predict these situations and handle
|
|
350
|
+
* them accordingly.
|
|
351
|
+
*
|
|
352
|
+
* @param delta The delta to normalize.
|
|
353
|
+
* @returns The normalized delta.
|
|
354
|
+
*/
|
|
355
|
+
abstract normalizeDelta(delta: D): D
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* A model message that contains a delta of type `AiDomainDelta`.
|
|
360
|
+
*/
|
|
361
|
+
export class AiModelDataDomainMessage extends AiModelMessage<AiDomainDelta> {
|
|
310
362
|
/**
|
|
311
363
|
* Creates an empty model message. Useful when initializing LLM flow.
|
|
312
364
|
* @param session The session key.
|
|
313
365
|
* @returns An empty model message.
|
|
314
366
|
*/
|
|
315
|
-
static createEmpty(session: string):
|
|
316
|
-
return new
|
|
367
|
+
static createEmpty(session: string): AiModelDataDomainMessage {
|
|
368
|
+
return new AiModelDataDomainMessage({
|
|
317
369
|
session,
|
|
318
370
|
state: 'loading',
|
|
319
371
|
})
|
|
320
372
|
}
|
|
373
|
+
|
|
374
|
+
override normalizeDelta(delta: AiDomainDelta): AiDomainDelta {
|
|
375
|
+
return DataDomainDelta.normalize(delta)
|
|
376
|
+
}
|
|
321
377
|
}
|
|
322
378
|
|
|
323
379
|
/**
|
|
324
380
|
* A union type representing any valid chat message in the AI session history.
|
|
325
381
|
*/
|
|
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
|
-
}
|
|
382
|
+
export type AiMessage = AiUserMessage | AiModelMessage | AiModelDataDomainMessage
|
|
@@ -771,6 +771,44 @@ test.group('DomainProperty.readBinding()', () => {
|
|
|
771
771
|
})
|
|
772
772
|
})
|
|
773
773
|
|
|
774
|
+
test.group('DomainProperty.readWebBinding()', () => {
|
|
775
|
+
test('returns undefined if no web binding exists', ({ assert }) => {
|
|
776
|
+
const dataDomain = new DataDomain()
|
|
777
|
+
const property = new DomainProperty(dataDomain, 'test-parent')
|
|
778
|
+
const binding = property.readWebBinding()
|
|
779
|
+
assert.isUndefined(binding)
|
|
780
|
+
})
|
|
781
|
+
|
|
782
|
+
test('returns the web binding schema if it exists', ({ assert }) => {
|
|
783
|
+
const dataDomain = new DataDomain()
|
|
784
|
+
const property = new DomainProperty(dataDomain, 'test-parent', {
|
|
785
|
+
bindings: [{ type: 'web', schema: { format: 'float' } }],
|
|
786
|
+
})
|
|
787
|
+
const webBindings = property.readWebBinding()
|
|
788
|
+
assert.deepEqual(webBindings, { format: 'float' })
|
|
789
|
+
})
|
|
790
|
+
|
|
791
|
+
test('returns undefined if the web binding exists but has no schema', ({ assert }) => {
|
|
792
|
+
const dataDomain = new DataDomain()
|
|
793
|
+
const property = new DomainProperty(dataDomain, 'test-parent', {
|
|
794
|
+
// @ts-expect-error Testing undefined value
|
|
795
|
+
bindings: [{ type: 'web', schema: undefined }],
|
|
796
|
+
})
|
|
797
|
+
const webBindings = property.readWebBinding()
|
|
798
|
+
assert.isUndefined(webBindings)
|
|
799
|
+
})
|
|
800
|
+
|
|
801
|
+
test('returns undefined if the web binding exists but the schema is null', ({ assert }) => {
|
|
802
|
+
const dataDomain = new DataDomain()
|
|
803
|
+
const property = new DomainProperty(dataDomain, 'test-parent', {
|
|
804
|
+
// @ts-expect-error Testing null value
|
|
805
|
+
bindings: [{ type: 'web', schema: null }],
|
|
806
|
+
})
|
|
807
|
+
const webBindings = property.readWebBinding()
|
|
808
|
+
assert.isNull(webBindings)
|
|
809
|
+
})
|
|
810
|
+
})
|
|
811
|
+
|
|
774
812
|
test.group('DomainProperty.toApiShape()', () => {
|
|
775
813
|
test('returns an object', ({ assert }) => {
|
|
776
814
|
const dataDomain = new DataDomain()
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { test } from '@japa/runner'
|
|
2
|
-
import { AiUserMessage,
|
|
2
|
+
import { AiUserMessage, AiModelDataDomainMessage } from '../../../src/models/AiMessage.js'
|
|
3
3
|
import { AiMessageKind } from '../../../src/models/kinds.js'
|
|
4
4
|
|
|
5
5
|
test.group('AiMessage | AiUserMessage', () => {
|
|
@@ -72,13 +72,13 @@ test.group('AiMessage | AiUserMessage', () => {
|
|
|
72
72
|
})
|
|
73
73
|
})
|
|
74
74
|
|
|
75
|
-
test.group('AiMessage |
|
|
75
|
+
test.group('AiMessage | AiModelDataDomainMessage', () => {
|
|
76
76
|
test('createSchema validates required session', ({ assert }) => {
|
|
77
|
-
assert.throws(() =>
|
|
77
|
+
assert.throws(() => AiModelDataDomainMessage.createSchema({}), 'Session is required to create an AiMessage.')
|
|
78
78
|
})
|
|
79
79
|
|
|
80
80
|
test('createSchema builds valid model schema', ({ assert }) => {
|
|
81
|
-
const schema =
|
|
81
|
+
const schema = AiModelDataDomainMessage.createSchema({ session: 'session1', text: 'Response' })
|
|
82
82
|
assert.isString(schema.key)
|
|
83
83
|
assert.isNotEmpty(schema.key)
|
|
84
84
|
assert.equal(schema.kind, AiMessageKind)
|
|
@@ -93,7 +93,7 @@ test.group('AiMessage | AiModelMessage', () => {
|
|
|
93
93
|
})
|
|
94
94
|
|
|
95
95
|
test('constructor builds AiModelMessage instance', ({ assert }) => {
|
|
96
|
-
const msg = new
|
|
96
|
+
const msg = new AiModelDataDomainMessage({
|
|
97
97
|
key: 'msg1',
|
|
98
98
|
session: 'sess1',
|
|
99
99
|
text: 'Model utterance',
|
|
@@ -117,7 +117,7 @@ test.group('AiMessage | AiModelMessage', () => {
|
|
|
117
117
|
})
|
|
118
118
|
|
|
119
119
|
test('toJSON correctly serializes an AiModelMessage', ({ assert }) => {
|
|
120
|
-
const msg = new
|
|
120
|
+
const msg = new AiModelDataDomainMessage({
|
|
121
121
|
key: 'msg1',
|
|
122
122
|
session: 'sess1',
|
|
123
123
|
text: 'Message Data',
|
|
@@ -148,7 +148,7 @@ test.group('AiMessage | AiModelMessage', () => {
|
|
|
148
148
|
})
|
|
149
149
|
|
|
150
150
|
test('addThought safely appends thoughts', ({ assert }) => {
|
|
151
|
-
const msg = new
|
|
151
|
+
const msg = new AiModelDataDomainMessage({ session: 's1' })
|
|
152
152
|
msg.addThought('Hello ')
|
|
153
153
|
msg.addThought('World!')
|
|
154
154
|
msg.addThought()
|
|
@@ -156,20 +156,40 @@ test.group('AiMessage | AiModelMessage', () => {
|
|
|
156
156
|
})
|
|
157
157
|
|
|
158
158
|
test('addText safely appends text', ({ assert }) => {
|
|
159
|
-
const msg = new
|
|
159
|
+
const msg = new AiModelDataDomainMessage({ session: 's1' })
|
|
160
160
|
msg.addText('Hello ')
|
|
161
161
|
msg.addText('World!')
|
|
162
162
|
msg.addText()
|
|
163
163
|
assert.equal(msg.text, 'Hello World!')
|
|
164
164
|
})
|
|
165
165
|
|
|
166
|
+
test('addText progressively detects reasoning and stops when reasoning ends', ({ assert }) => {
|
|
167
|
+
const msg = new AiModelDataDomainMessage({ session: 's1' })
|
|
168
|
+
|
|
169
|
+
msg.addText('{"reason')
|
|
170
|
+
assert.isUndefined(msg.reasoning)
|
|
171
|
+
|
|
172
|
+
msg.addText('ing": "I ')
|
|
173
|
+
assert.equal(msg.reasoning, 'I ')
|
|
174
|
+
|
|
175
|
+
msg.addText('think')
|
|
176
|
+
assert.equal(msg.reasoning, 'I think')
|
|
177
|
+
|
|
178
|
+
msg.addText(' therefore "')
|
|
179
|
+
assert.equal(msg.reasoning, 'I think therefore ')
|
|
180
|
+
|
|
181
|
+
// This triggers after === before, freezing reasoning detection.
|
|
182
|
+
msg.addText(', "delta": {')
|
|
183
|
+
assert.equal(msg.reasoning, 'I think therefore ')
|
|
184
|
+
})
|
|
185
|
+
|
|
166
186
|
test('processMessage throws on invalid JSON', ({ assert }) => {
|
|
167
|
-
const msg = new
|
|
187
|
+
const msg = new AiModelDataDomainMessage({ session: 's1', text: 'NOT JSON' })
|
|
168
188
|
assert.throws(() => msg.processMessage(), SyntaxError)
|
|
169
189
|
})
|
|
170
190
|
|
|
171
191
|
test('processMessage parses delta and reasoning', ({ assert }) => {
|
|
172
|
-
const msg = new
|
|
192
|
+
const msg = new AiModelDataDomainMessage({
|
|
173
193
|
session: 's1',
|
|
174
194
|
text: JSON.stringify({
|
|
175
195
|
reasoning: 'I need to make models',
|
|
@@ -183,34 +203,16 @@ test.group('AiMessage | AiModelMessage', () => {
|
|
|
183
203
|
})
|
|
184
204
|
|
|
185
205
|
test('processMessageSafe swallows errors', ({ assert }) => {
|
|
186
|
-
const msg = new
|
|
206
|
+
const msg = new AiModelDataDomainMessage({ session: 's1', text: 'NOT JSON' })
|
|
187
207
|
msg.processMessageSafe() // should not throw
|
|
188
208
|
assert.isUndefined(msg.delta)
|
|
189
209
|
assert.isUndefined(msg.reasoning)
|
|
190
210
|
})
|
|
191
211
|
|
|
192
212
|
test('createEmpty generates loading stub', ({ assert }) => {
|
|
193
|
-
const msg =
|
|
213
|
+
const msg = AiModelDataDomainMessage.createEmpty('sess1')
|
|
194
214
|
assert.equal(msg.session, 'sess1')
|
|
195
215
|
assert.equal(msg.state, 'loading')
|
|
196
216
|
assert.equal(msg.role, 'model')
|
|
197
217
|
})
|
|
198
218
|
})
|
|
199
|
-
|
|
200
|
-
test.group('AiMessage | AiMessageFactory', () => {
|
|
201
|
-
test('fromSchema generates AiUserMessage when role=user', ({ assert }) => {
|
|
202
|
-
const schema = AiUserMessage.createSchema({ session: 'sess', text: 'Hello User' })
|
|
203
|
-
const msg = AiMessageFactory.fromSchema(schema)
|
|
204
|
-
assert.instanceOf(msg, AiUserMessage)
|
|
205
|
-
assert.equal(msg.role, 'user')
|
|
206
|
-
assert.equal(msg.text, 'Hello User')
|
|
207
|
-
})
|
|
208
|
-
|
|
209
|
-
test('fromSchema generates AiModelMessage when role=model', ({ assert }) => {
|
|
210
|
-
const schema = AiModelMessage.createSchema({ session: 'sess', text: 'Hello Model' })
|
|
211
|
-
const msg = AiMessageFactory.fromSchema(schema)
|
|
212
|
-
assert.instanceOf(msg, AiModelMessage)
|
|
213
|
-
assert.equal(msg.role, 'model')
|
|
214
|
-
assert.equal(msg.text, 'Hello Model')
|
|
215
|
-
})
|
|
216
|
-
})
|