@api-client/core 0.19.1 → 0.19.3
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 +5 -1
- package/build/src/browser.d.ts.map +1 -1
- package/build/src/browser.js +4 -0
- package/build/src/browser.js.map +1 -1
- package/build/src/index.d.ts +4 -0
- package/build/src/index.d.ts.map +1 -1
- package/build/src/index.js +4 -0
- package/build/src/index.js.map +1 -1
- package/build/src/mocking/ModelingMock.d.ts +2 -0
- package/build/src/mocking/ModelingMock.d.ts.map +1 -1
- package/build/src/mocking/ModelingMock.js +2 -0
- package/build/src/mocking/ModelingMock.js.map +1 -1
- package/build/src/mocking/lib/Ai.d.ts +11 -0
- package/build/src/mocking/lib/Ai.d.ts.map +1 -0
- package/build/src/mocking/lib/Ai.js +53 -0
- package/build/src/mocking/lib/Ai.js.map +1 -0
- package/build/src/modeling/ai/DataDomainDelta.d.ts +146 -0
- package/build/src/modeling/ai/DataDomainDelta.d.ts.map +1 -0
- package/build/src/modeling/ai/DataDomainDelta.js +729 -0
- package/build/src/modeling/ai/DataDomainDelta.js.map +1 -0
- package/build/src/modeling/ai/DomainSerialization.d.ts +20 -0
- package/build/src/modeling/ai/DomainSerialization.d.ts.map +1 -0
- package/build/src/modeling/ai/DomainSerialization.js +185 -0
- package/build/src/modeling/ai/DomainSerialization.js.map +1 -0
- package/build/src/modeling/ai/domain_response_schema.d.ts +806 -0
- package/build/src/modeling/ai/domain_response_schema.d.ts.map +1 -0
- package/build/src/modeling/ai/domain_response_schema.js +289 -0
- package/build/src/modeling/ai/domain_response_schema.js.map +1 -0
- package/build/src/modeling/ai/domain_tools.d.ts +68 -0
- package/build/src/modeling/ai/domain_tools.d.ts.map +1 -0
- package/build/src/modeling/ai/domain_tools.js +71 -0
- package/build/src/modeling/ai/domain_tools.js.map +1 -0
- package/build/src/modeling/ai/index.d.ts +10 -0
- package/build/src/modeling/ai/index.d.ts.map +1 -0
- package/build/src/modeling/ai/index.js +9 -0
- package/build/src/modeling/ai/index.js.map +1 -0
- package/build/src/modeling/ai/message_parser.d.ts +23 -0
- package/build/src/modeling/ai/message_parser.d.ts.map +1 -0
- package/build/src/modeling/ai/message_parser.js +93 -0
- package/build/src/modeling/ai/message_parser.js.map +1 -0
- package/build/src/modeling/ai/prompts/domain_system.d.ts +6 -0
- package/build/src/modeling/ai/prompts/domain_system.d.ts.map +1 -0
- package/build/src/modeling/ai/prompts/domain_system.js +80 -0
- package/build/src/modeling/ai/prompts/domain_system.js.map +1 -0
- package/build/src/modeling/ai/tools/DataDomain.tools.d.ts +25 -0
- package/build/src/modeling/ai/tools/DataDomain.tools.d.ts.map +1 -0
- package/build/src/modeling/ai/tools/DataDomain.tools.js +334 -0
- package/build/src/modeling/ai/tools/DataDomain.tools.js.map +1 -0
- package/build/src/modeling/ai/tools/Semantic.tools.d.ts +48 -0
- package/build/src/modeling/ai/tools/Semantic.tools.d.ts.map +1 -0
- package/build/src/modeling/ai/tools/Semantic.tools.js +36 -0
- package/build/src/modeling/ai/tools/Semantic.tools.js.map +1 -0
- package/build/src/modeling/ai/tools/config.d.ts +13 -0
- package/build/src/modeling/ai/tools/config.d.ts.map +1 -0
- package/build/src/modeling/ai/tools/config.js +2 -0
- package/build/src/modeling/ai/tools/config.js.map +1 -0
- package/build/src/modeling/ai/types.d.ts +302 -0
- package/build/src/modeling/ai/types.d.ts.map +1 -0
- package/build/src/modeling/ai/types.js +40 -0
- package/build/src/modeling/ai/types.js.map +1 -0
- package/build/src/models/AiMessage.d.ts +185 -0
- package/build/src/models/AiMessage.d.ts.map +1 -0
- package/build/src/models/AiMessage.js +203 -0
- package/build/src/models/AiMessage.js.map +1 -0
- package/build/src/models/AiSession.d.ts +80 -0
- package/build/src/models/AiSession.d.ts.map +1 -0
- package/build/src/models/AiSession.js +102 -0
- package/build/src/models/AiSession.js.map +1 -0
- package/build/src/models/kinds.d.ts +2 -0
- package/build/src/models/kinds.d.ts.map +1 -1
- package/build/src/models/kinds.js +2 -0
- package/build/src/models/kinds.js.map +1 -1
- package/build/src/sdk/AiSdk.d.ts +93 -0
- package/build/src/sdk/AiSdk.d.ts.map +1 -0
- package/build/src/sdk/AiSdk.js +348 -0
- package/build/src/sdk/AiSdk.js.map +1 -0
- package/build/src/sdk/RouteBuilder.d.ts +7 -0
- package/build/src/sdk/RouteBuilder.d.ts.map +1 -1
- package/build/src/sdk/RouteBuilder.js +18 -0
- package/build/src/sdk/RouteBuilder.js.map +1 -1
- package/build/src/sdk/Sdk.d.ts +2 -0
- package/build/src/sdk/Sdk.d.ts.map +1 -1
- package/build/src/sdk/Sdk.js +2 -0
- package/build/src/sdk/Sdk.js.map +1 -1
- package/build/src/sdk/SdkBase.d.ts +4 -0
- package/build/src/sdk/SdkBase.d.ts.map +1 -1
- package/build/src/sdk/SdkBase.js.map +1 -1
- package/build/src/sdk/SdkMock.d.ts +15 -0
- package/build/src/sdk/SdkMock.d.ts.map +1 -1
- package/build/src/sdk/SdkMock.js +118 -0
- package/build/src/sdk/SdkMock.js.map +1 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/data/models/example-generator-api.json +22 -22
- package/package.json +3 -3
- package/src/mocking/ModelingMock.ts +2 -0
- package/src/mocking/lib/Ai.ts +71 -0
- package/src/modeling/ai/DataDomainDelta.ts +798 -0
- package/src/modeling/ai/DomainSerialization.ts +199 -0
- package/src/modeling/ai/domain_response_schema.ts +301 -0
- package/src/modeling/ai/domain_tools.ts +76 -0
- package/src/modeling/ai/message_parser.ts +101 -0
- package/src/modeling/ai/prompts/domain_system.ts +79 -0
- package/src/modeling/ai/readme.md +8 -0
- package/src/modeling/ai/tools/DataDomain.tools.ts +365 -0
- package/src/modeling/ai/tools/Semantic.tools.ts +38 -0
- package/src/modeling/ai/tools/config.ts +13 -0
- package/src/modeling/ai/tools/readme.md +3 -0
- package/src/modeling/ai/types.ts +306 -0
- package/src/models/AiMessage.ts +335 -0
- package/src/models/AiSession.ts +160 -0
- package/src/models/kinds.ts +2 -0
- package/src/sdk/AiSdk.ts +395 -0
- package/src/sdk/RouteBuilder.ts +27 -0
- package/src/sdk/Sdk.ts +3 -0
- package/src/sdk/SdkBase.ts +4 -0
- package/src/sdk/SdkMock.ts +185 -0
- package/tests/unit/mocking/current/Ai.spec.ts +109 -0
- package/tests/unit/modeling/ai/DataDomainDelta.spec.ts +419 -0
- package/tests/unit/modeling/ai/DomainAiTools.spec.ts +29 -0
- package/tests/unit/modeling/ai/DomainSerialization.spec.ts +143 -0
- package/tests/unit/modeling/ai/message_parser.spec.ts +157 -0
- package/tests/unit/modeling/ai/tools/DataDomain.tools.spec.ts +64 -0
- package/tests/unit/modeling/ai/tools/Semantic.tools.spec.ts +55 -0
- package/tests/unit/models/AiMessage.spec.ts +216 -0
- package/tests/unit/models/AiSession.spec.ts +147 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import type { DataDomain } from '../DataDomain.js'
|
|
2
|
+
import type { DomainNamespace } from '../DomainNamespace.js'
|
|
3
|
+
import type {
|
|
4
|
+
AiDataDomainSchema,
|
|
5
|
+
AiDomainAssociation,
|
|
6
|
+
AiDomainEntityResponseSchema,
|
|
7
|
+
AiDomainEntitySchema,
|
|
8
|
+
AiDomainProperty,
|
|
9
|
+
AiDomainSemantic,
|
|
10
|
+
} from './types.js'
|
|
11
|
+
import type { DomainAssociation, DomainEntity, DomainProperty } from '../index.js'
|
|
12
|
+
|
|
13
|
+
function serializeProperty(prop: DomainProperty): AiDomainProperty {
|
|
14
|
+
const result: AiDomainProperty = {
|
|
15
|
+
key: prop.key,
|
|
16
|
+
type: prop.type,
|
|
17
|
+
}
|
|
18
|
+
if (prop.info.name) {
|
|
19
|
+
result.name = prop.info.name
|
|
20
|
+
}
|
|
21
|
+
if (prop.info.displayName) {
|
|
22
|
+
result.displayName = prop.info.displayName
|
|
23
|
+
}
|
|
24
|
+
if (prop.info.description) {
|
|
25
|
+
result.description = prop.info.description
|
|
26
|
+
}
|
|
27
|
+
if (Array.isArray(prop.semantics) && prop.semantics.length > 0) {
|
|
28
|
+
result.semantics = prop.semantics.map((s) => {
|
|
29
|
+
const res: AiDomainSemantic = { id: s.id }
|
|
30
|
+
if (s.config) res.config = { ...s.config }
|
|
31
|
+
return res
|
|
32
|
+
})
|
|
33
|
+
}
|
|
34
|
+
result.constraints = {}
|
|
35
|
+
if (typeof prop.required === 'boolean') {
|
|
36
|
+
result.constraints.required = prop.required
|
|
37
|
+
}
|
|
38
|
+
if (typeof prop.unique === 'boolean') {
|
|
39
|
+
result.constraints.unique = prop.unique
|
|
40
|
+
}
|
|
41
|
+
if (typeof prop.index === 'boolean') {
|
|
42
|
+
result.constraints.index = prop.index
|
|
43
|
+
}
|
|
44
|
+
if (typeof prop.primary === 'boolean') {
|
|
45
|
+
result.constraints.primary = prop.primary
|
|
46
|
+
}
|
|
47
|
+
if (typeof prop.multiple === 'boolean') {
|
|
48
|
+
result.constraints.multiple = prop.multiple
|
|
49
|
+
}
|
|
50
|
+
if (typeof prop.readOnly === 'boolean') {
|
|
51
|
+
result.constraints.readOnly = prop.readOnly
|
|
52
|
+
}
|
|
53
|
+
if (typeof prop.writeOnly === 'boolean') {
|
|
54
|
+
result.constraints.writeOnly = prop.writeOnly
|
|
55
|
+
}
|
|
56
|
+
if (typeof prop.deprecated === 'boolean') {
|
|
57
|
+
result.deprecated = prop.deprecated
|
|
58
|
+
}
|
|
59
|
+
if (prop.schema) {
|
|
60
|
+
result.schema = { ...prop.schema }
|
|
61
|
+
}
|
|
62
|
+
return result
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function serializeAssociation(assoc: DomainAssociation): AiDomainAssociation {
|
|
66
|
+
const result: AiDomainAssociation = {
|
|
67
|
+
key: assoc.key,
|
|
68
|
+
targets: [],
|
|
69
|
+
}
|
|
70
|
+
if (assoc.info.name) {
|
|
71
|
+
result.name = assoc.info.name
|
|
72
|
+
}
|
|
73
|
+
if (assoc.info.displayName) {
|
|
74
|
+
result.displayName = assoc.info.displayName
|
|
75
|
+
}
|
|
76
|
+
if (assoc.info.description) {
|
|
77
|
+
result.description = assoc.info.description
|
|
78
|
+
}
|
|
79
|
+
if (Array.isArray(assoc.semantics) && assoc.semantics.length > 0) {
|
|
80
|
+
result.semantics = assoc.semantics.map((s) => {
|
|
81
|
+
const res: AiDomainSemantic = { id: s.id }
|
|
82
|
+
if (s.config) res.config = { ...s.config }
|
|
83
|
+
return res
|
|
84
|
+
})
|
|
85
|
+
}
|
|
86
|
+
if (typeof assoc.required === 'boolean') {
|
|
87
|
+
result.required = assoc.required
|
|
88
|
+
}
|
|
89
|
+
if (typeof assoc.onDelete === 'string') {
|
|
90
|
+
result.onDelete = assoc.onDelete
|
|
91
|
+
}
|
|
92
|
+
if (assoc.schema) {
|
|
93
|
+
result.schema = { ...assoc.schema }
|
|
94
|
+
}
|
|
95
|
+
return result
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Serializes an entity to an AI domain entity response schema.
|
|
100
|
+
* It is used by the `get_entity_details` tool to send a serialized entity information to the AI.
|
|
101
|
+
*
|
|
102
|
+
* @param entity The entity to serialize.
|
|
103
|
+
* @param modelKey The key of the model the entity belongs to.
|
|
104
|
+
* @returns The AI domain entity response schema.
|
|
105
|
+
*/
|
|
106
|
+
export function serializeEntity(entity: DomainEntity, modelKey: string): AiDomainEntityResponseSchema {
|
|
107
|
+
const result: AiDomainEntityResponseSchema = {
|
|
108
|
+
key: entity.key,
|
|
109
|
+
modelKey,
|
|
110
|
+
}
|
|
111
|
+
if (entity.info.name) {
|
|
112
|
+
result.name = entity.info.name
|
|
113
|
+
}
|
|
114
|
+
if (entity.info.displayName) {
|
|
115
|
+
result.displayName = entity.info.displayName
|
|
116
|
+
}
|
|
117
|
+
if (entity.info.description) {
|
|
118
|
+
result.description = entity.info.description
|
|
119
|
+
}
|
|
120
|
+
if (Array.isArray(entity.tags) && entity.tags.length > 0) {
|
|
121
|
+
result.tags = [...entity.tags]
|
|
122
|
+
}
|
|
123
|
+
if (Array.isArray(entity.semantics) && entity.semantics.length > 0) {
|
|
124
|
+
result.semantics = entity.semantics.map((s) => {
|
|
125
|
+
const res: AiDomainSemantic = { id: s.id }
|
|
126
|
+
if (s.config) res.config = { ...s.config }
|
|
127
|
+
return res
|
|
128
|
+
})
|
|
129
|
+
}
|
|
130
|
+
result.properties = []
|
|
131
|
+
for (const prop of entity.listProperties()) {
|
|
132
|
+
result.properties.push(serializeProperty(prop))
|
|
133
|
+
}
|
|
134
|
+
result.associations = []
|
|
135
|
+
for (const assoc of entity.listAssociations()) {
|
|
136
|
+
result.associations.push(serializeAssociation(assoc))
|
|
137
|
+
}
|
|
138
|
+
return result
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Serializes an entity to a minimal AI domain entity schema.
|
|
143
|
+
*
|
|
144
|
+
* @param entity The entity to serialize.
|
|
145
|
+
* @param modelKey The key of the model the entity belongs to.
|
|
146
|
+
* @returns The AI domain entity schema.
|
|
147
|
+
*/
|
|
148
|
+
function serializeEntityMinimal(entity: DomainEntity, modelKey: string): AiDomainEntitySchema {
|
|
149
|
+
const result: AiDomainEntitySchema = {
|
|
150
|
+
key: entity.key,
|
|
151
|
+
modelKey,
|
|
152
|
+
}
|
|
153
|
+
if (entity.info.name) {
|
|
154
|
+
result.name = entity.info.name
|
|
155
|
+
}
|
|
156
|
+
if (entity.info.description) {
|
|
157
|
+
result.description = entity.info.description
|
|
158
|
+
}
|
|
159
|
+
return result
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Processes a namespace and serializes its models and entities to the schema sent to the AI endpoint.
|
|
164
|
+
* @param ns The namespace to process.
|
|
165
|
+
* @param result The result schema to add the models and entities to.
|
|
166
|
+
*/
|
|
167
|
+
function processNamespace(ns: DomainNamespace | DataDomain, result: AiDataDomainSchema): void {
|
|
168
|
+
for (const childNs of ns.listNamespaces()) {
|
|
169
|
+
processNamespace(childNs, result)
|
|
170
|
+
}
|
|
171
|
+
for (const model of ns.listModels()) {
|
|
172
|
+
result.models.push({
|
|
173
|
+
key: model.key,
|
|
174
|
+
name: model.info.name || model.info.displayName || model.key,
|
|
175
|
+
description: model.info.description,
|
|
176
|
+
})
|
|
177
|
+
for (const entity of model.listEntities()) {
|
|
178
|
+
result.entities.push(serializeEntityMinimal(entity, model.key))
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Serializes a data domain to a minimal AI domain schema.
|
|
185
|
+
* It is used to serialize the domain to send it to the AI endpoint.
|
|
186
|
+
* @param domain The data domain to serialize.
|
|
187
|
+
* @returns The AI domain schema.
|
|
188
|
+
*/
|
|
189
|
+
export function serializeDomainForAi(domain: DataDomain): AiDataDomainSchema {
|
|
190
|
+
const result: AiDataDomainSchema = {
|
|
191
|
+
key: domain.key,
|
|
192
|
+
name: domain.info.name || domain.info.displayName || 'Unnamed Domain',
|
|
193
|
+
models: [],
|
|
194
|
+
entities: [],
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
processNamespace(domain, result)
|
|
198
|
+
return result
|
|
199
|
+
}
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import { Type } from './types.js'
|
|
2
|
+
|
|
3
|
+
const SemanticSchema = {
|
|
4
|
+
type: Type.OBJECT,
|
|
5
|
+
properties: {
|
|
6
|
+
id: { type: Type.STRING },
|
|
7
|
+
config: { type: Type.OBJECT },
|
|
8
|
+
},
|
|
9
|
+
required: ['id'],
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const SchemaDefaultValue = {
|
|
13
|
+
type: Type.OBJECT,
|
|
14
|
+
properties: {
|
|
15
|
+
type: {
|
|
16
|
+
type: Type.STRING,
|
|
17
|
+
description: 'Enum: literal, function',
|
|
18
|
+
},
|
|
19
|
+
value: {
|
|
20
|
+
type: Type.STRING,
|
|
21
|
+
description: 'The default value of the property',
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
required: ['type'],
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const PropertySchemaShape = {
|
|
28
|
+
type: Type.OBJECT,
|
|
29
|
+
properties: {
|
|
30
|
+
minimum: { type: Type.NUMBER },
|
|
31
|
+
maximum: { type: Type.NUMBER },
|
|
32
|
+
exclusiveMinimum: { type: Type.BOOLEAN },
|
|
33
|
+
exclusiveMaximum: { type: Type.BOOLEAN },
|
|
34
|
+
multipleOf: { type: Type.NUMBER },
|
|
35
|
+
enum: { type: Type.ARRAY, items: { type: Type.STRING } },
|
|
36
|
+
examples: { type: Type.ARRAY, items: { type: Type.STRING } },
|
|
37
|
+
defaultValue: SchemaDefaultValue,
|
|
38
|
+
pattern: { type: Type.STRING },
|
|
39
|
+
},
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const PropertyConstraintsSchema = {
|
|
43
|
+
type: Type.OBJECT,
|
|
44
|
+
properties: {
|
|
45
|
+
required: { type: Type.BOOLEAN },
|
|
46
|
+
unique: { type: Type.BOOLEAN },
|
|
47
|
+
index: { type: Type.BOOLEAN },
|
|
48
|
+
primary: { type: Type.BOOLEAN },
|
|
49
|
+
multiple: { type: Type.BOOLEAN },
|
|
50
|
+
readOnly: { type: Type.BOOLEAN },
|
|
51
|
+
writeOnly: { type: Type.BOOLEAN },
|
|
52
|
+
},
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Must comply with the `AiDomainProperty` type.
|
|
57
|
+
*/
|
|
58
|
+
const PropertySchema = {
|
|
59
|
+
type: Type.OBJECT,
|
|
60
|
+
properties: {
|
|
61
|
+
key: { type: Type.STRING },
|
|
62
|
+
name: { type: Type.STRING },
|
|
63
|
+
displayName: { type: Type.STRING },
|
|
64
|
+
description: { type: Type.STRING },
|
|
65
|
+
type: {
|
|
66
|
+
type: Type.STRING,
|
|
67
|
+
description: 'Enum: string, number, boolean, date, datetime, time, binary',
|
|
68
|
+
},
|
|
69
|
+
constraints: PropertyConstraintsSchema,
|
|
70
|
+
deprecated: { type: Type.BOOLEAN },
|
|
71
|
+
schema: PropertySchemaShape,
|
|
72
|
+
semantics: {
|
|
73
|
+
type: Type.ARRAY,
|
|
74
|
+
items: SemanticSchema,
|
|
75
|
+
description: "List of semantics applied to this property. Note: ONLY use semantics with scope='property'.",
|
|
76
|
+
},
|
|
77
|
+
tags: { type: Type.ARRAY, items: { type: Type.STRING } },
|
|
78
|
+
},
|
|
79
|
+
required: ['key', 'name', 'type', 'displayName', 'description'],
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const AssociationSchemaShape = {
|
|
83
|
+
type: Type.OBJECT,
|
|
84
|
+
properties: {
|
|
85
|
+
linked: { type: Type.BOOLEAN },
|
|
86
|
+
unionType: { type: Type.STRING, description: 'Enum: allOf, anyOf, oneOf, not' },
|
|
87
|
+
},
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Must comply with the `AiDomainAssociation` type.
|
|
92
|
+
*/
|
|
93
|
+
const AssociationSchema = {
|
|
94
|
+
type: Type.OBJECT,
|
|
95
|
+
properties: {
|
|
96
|
+
key: { type: Type.STRING },
|
|
97
|
+
name: { type: Type.STRING },
|
|
98
|
+
displayName: { type: Type.STRING },
|
|
99
|
+
description: { type: Type.STRING },
|
|
100
|
+
targets: { type: Type.ARRAY, items: { type: Type.STRING }, description: 'List of target entity keys' },
|
|
101
|
+
required: { type: Type.BOOLEAN },
|
|
102
|
+
multiple: {
|
|
103
|
+
type: Type.BOOLEAN,
|
|
104
|
+
description: 'Whether the association can have multiple targets (like User has multiple addresses)',
|
|
105
|
+
},
|
|
106
|
+
onDelete: { type: Type.STRING, description: 'Enum: restrict, cascade, setNull, doNothing' },
|
|
107
|
+
semantics: {
|
|
108
|
+
type: Type.ARRAY,
|
|
109
|
+
items: SemanticSchema,
|
|
110
|
+
description: "List of semantics applied to this association. Note: ONLY use semantics with scope='association'.",
|
|
111
|
+
},
|
|
112
|
+
schema: AssociationSchemaShape,
|
|
113
|
+
},
|
|
114
|
+
required: ['key', 'name', 'targets', 'displayName', 'description'],
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Must comply with the `AiDataModel` type.
|
|
119
|
+
*/
|
|
120
|
+
const ModelSchema = {
|
|
121
|
+
type: Type.OBJECT,
|
|
122
|
+
properties: {
|
|
123
|
+
key: { type: Type.STRING },
|
|
124
|
+
name: { type: Type.STRING },
|
|
125
|
+
description: { type: Type.STRING },
|
|
126
|
+
},
|
|
127
|
+
required: ['key', 'name'],
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Must comply with the `AiDomainEntityResponseSchema` type.
|
|
132
|
+
*/
|
|
133
|
+
const EntitySchema = {
|
|
134
|
+
type: Type.OBJECT,
|
|
135
|
+
properties: {
|
|
136
|
+
key: { type: Type.STRING },
|
|
137
|
+
modelKey: { type: Type.STRING, description: 'The Domain Model this entity belongs to (e.g. "users", "shipping")' },
|
|
138
|
+
name: { type: Type.STRING },
|
|
139
|
+
displayName: { type: Type.STRING },
|
|
140
|
+
description: { type: Type.STRING },
|
|
141
|
+
tags: { type: Type.ARRAY, items: { type: Type.STRING } },
|
|
142
|
+
semantics: {
|
|
143
|
+
type: Type.ARRAY,
|
|
144
|
+
items: SemanticSchema,
|
|
145
|
+
description: "List of semantics applied to this entity. Note: ONLY use semantics with scope='entity'.",
|
|
146
|
+
},
|
|
147
|
+
properties: { type: Type.ARRAY, items: PropertySchema },
|
|
148
|
+
associations: { type: Type.ARRAY, items: AssociationSchema },
|
|
149
|
+
},
|
|
150
|
+
required: ['key', 'name', 'modelKey', 'displayName', 'description'],
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const PropertyDeltaSchema = {
|
|
154
|
+
type: Type.OBJECT,
|
|
155
|
+
properties: {
|
|
156
|
+
key: { type: Type.STRING },
|
|
157
|
+
name: { type: Type.STRING },
|
|
158
|
+
displayName: { type: Type.STRING },
|
|
159
|
+
description: { type: Type.STRING },
|
|
160
|
+
type: {
|
|
161
|
+
type: Type.STRING,
|
|
162
|
+
description: 'Enum: string, number, boolean, date, datetime, time, binary',
|
|
163
|
+
},
|
|
164
|
+
constraints: PropertyConstraintsSchema,
|
|
165
|
+
deprecated: { type: Type.BOOLEAN },
|
|
166
|
+
schema: PropertySchemaShape,
|
|
167
|
+
addedSemantics: {
|
|
168
|
+
type: Type.ARRAY,
|
|
169
|
+
items: SemanticSchema,
|
|
170
|
+
description: "Semantics to add. Note: ONLY use semantics with scope='property'.",
|
|
171
|
+
},
|
|
172
|
+
modifiedSemantics: { type: Type.ARRAY, items: SemanticSchema },
|
|
173
|
+
deletedSemanticIds: { type: Type.ARRAY, items: { type: Type.STRING } },
|
|
174
|
+
},
|
|
175
|
+
required: ['key'],
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const AssociationDeltaSchema = {
|
|
179
|
+
type: Type.OBJECT,
|
|
180
|
+
properties: {
|
|
181
|
+
key: { type: Type.STRING },
|
|
182
|
+
name: { type: Type.STRING },
|
|
183
|
+
displayName: { type: Type.STRING },
|
|
184
|
+
description: { type: Type.STRING },
|
|
185
|
+
targets: { type: Type.ARRAY, items: { type: Type.STRING } },
|
|
186
|
+
required: { type: Type.BOOLEAN },
|
|
187
|
+
multiple: {
|
|
188
|
+
type: Type.BOOLEAN,
|
|
189
|
+
description: 'Whether the association can have multiple targets (like User has multiple addresses)',
|
|
190
|
+
},
|
|
191
|
+
onDelete: { type: Type.STRING, description: 'Enum: restrict, cascade, setNull, doNothing' },
|
|
192
|
+
addedSemantics: {
|
|
193
|
+
type: Type.ARRAY,
|
|
194
|
+
items: SemanticSchema,
|
|
195
|
+
description: "Semantics to add. Note: ONLY use semantics with scope='association'.",
|
|
196
|
+
},
|
|
197
|
+
modifiedSemantics: { type: Type.ARRAY, items: SemanticSchema },
|
|
198
|
+
deletedSemanticIds: { type: Type.ARRAY, items: { type: Type.STRING } },
|
|
199
|
+
},
|
|
200
|
+
required: ['key'],
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Must comply with the `AiDomainDeltaResponse` type.
|
|
205
|
+
*/
|
|
206
|
+
export const DOMAIN_SCHEMA = {
|
|
207
|
+
type: Type.OBJECT,
|
|
208
|
+
properties: {
|
|
209
|
+
sessionTitle: {
|
|
210
|
+
type: Type.STRING,
|
|
211
|
+
description: 'A short, 3-to-5 word descriptive title for this data modeling session.',
|
|
212
|
+
},
|
|
213
|
+
reasoning: {
|
|
214
|
+
type: Type.STRING,
|
|
215
|
+
description: 'Conversational response analyzing the request or explaining changes, in markdown format',
|
|
216
|
+
},
|
|
217
|
+
delta: {
|
|
218
|
+
type: Type.OBJECT,
|
|
219
|
+
properties: {
|
|
220
|
+
addedModels: {
|
|
221
|
+
type: Type.ARRAY,
|
|
222
|
+
items: ModelSchema,
|
|
223
|
+
description: 'Brand new models to create',
|
|
224
|
+
},
|
|
225
|
+
deletedModelKeys: {
|
|
226
|
+
type: Type.ARRAY,
|
|
227
|
+
items: { type: Type.STRING },
|
|
228
|
+
description:
|
|
229
|
+
'Keys of completely removed models. This also removes all entities and associations in the model.',
|
|
230
|
+
},
|
|
231
|
+
modifiedModels: {
|
|
232
|
+
type: Type.ARRAY,
|
|
233
|
+
items: ModelSchema,
|
|
234
|
+
description: 'Models to modify in the domain',
|
|
235
|
+
},
|
|
236
|
+
addedEntities: {
|
|
237
|
+
type: Type.ARRAY,
|
|
238
|
+
items: EntitySchema,
|
|
239
|
+
description: 'Brand new entities to create',
|
|
240
|
+
},
|
|
241
|
+
deletedEntityKeys: {
|
|
242
|
+
type: Type.ARRAY,
|
|
243
|
+
items: { type: Type.STRING },
|
|
244
|
+
description: 'Keys of completely removed entities',
|
|
245
|
+
},
|
|
246
|
+
modifiedEntities: {
|
|
247
|
+
type: Type.ARRAY,
|
|
248
|
+
items: {
|
|
249
|
+
type: Type.OBJECT,
|
|
250
|
+
properties: {
|
|
251
|
+
key: { type: Type.STRING, description: 'The original key of the existing entity being modified' },
|
|
252
|
+
modelKey: {
|
|
253
|
+
type: Type.STRING,
|
|
254
|
+
description: 'Change this to migrate the entity to a different model (boundary)',
|
|
255
|
+
},
|
|
256
|
+
name: { type: Type.STRING },
|
|
257
|
+
displayName: { type: Type.STRING },
|
|
258
|
+
description: { type: Type.STRING },
|
|
259
|
+
tags: { type: Type.ARRAY, items: { type: Type.STRING } },
|
|
260
|
+
addedSemantics: {
|
|
261
|
+
type: Type.ARRAY,
|
|
262
|
+
items: SemanticSchema,
|
|
263
|
+
description: "Semantics to add. Note: ONLY use semantics with scope='entity'.",
|
|
264
|
+
},
|
|
265
|
+
modifiedSemantics: { type: Type.ARRAY, items: SemanticSchema },
|
|
266
|
+
deletedSemanticIds: { type: Type.ARRAY, items: { type: Type.STRING } },
|
|
267
|
+
addedProperties: { type: Type.ARRAY, items: PropertySchema },
|
|
268
|
+
modifiedProperties: { type: Type.ARRAY, items: PropertyDeltaSchema },
|
|
269
|
+
deletedPropertyKeys: { type: Type.ARRAY, items: { type: Type.STRING } },
|
|
270
|
+
addedAssociations: { type: Type.ARRAY, items: AssociationSchema },
|
|
271
|
+
modifiedAssociations: { type: Type.ARRAY, items: AssociationDeltaSchema },
|
|
272
|
+
deletedAssociationKeys: { type: Type.ARRAY, items: { type: Type.STRING } },
|
|
273
|
+
},
|
|
274
|
+
required: [
|
|
275
|
+
'key',
|
|
276
|
+
// 'addedSemantics',
|
|
277
|
+
// 'modifiedSemantics',
|
|
278
|
+
// 'deletedSemanticIds',
|
|
279
|
+
// 'addedProperties',
|
|
280
|
+
// 'modifiedProperties',
|
|
281
|
+
// 'deletedPropertyKeys',
|
|
282
|
+
// 'addedAssociations',
|
|
283
|
+
// 'modifiedAssociations',
|
|
284
|
+
// 'deletedAssociationKeys',
|
|
285
|
+
],
|
|
286
|
+
},
|
|
287
|
+
description: 'Modifications to existing entities like adding, removing, or changing properties/associations',
|
|
288
|
+
},
|
|
289
|
+
},
|
|
290
|
+
required: [
|
|
291
|
+
'addedModels',
|
|
292
|
+
'deletedModelKeys',
|
|
293
|
+
'modifiedModels',
|
|
294
|
+
'addedEntities',
|
|
295
|
+
'deletedEntityKeys',
|
|
296
|
+
'modifiedEntities',
|
|
297
|
+
],
|
|
298
|
+
},
|
|
299
|
+
},
|
|
300
|
+
required: ['reasoning', 'delta'],
|
|
301
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Type } from './types.js'
|
|
2
|
+
import { get_semantic_details, list_semantics } from './tools/Semantic.tools.js'
|
|
3
|
+
import { explain_schema, get_entity_details } from './tools/DataDomain.tools.js'
|
|
4
|
+
import { ToolConfig } from './tools/config.js'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* All tools available for the AI to use when modeling a domain.
|
|
8
|
+
*/
|
|
9
|
+
export const tools = [
|
|
10
|
+
{
|
|
11
|
+
functionDeclarations: [
|
|
12
|
+
{
|
|
13
|
+
name: 'list_semantics',
|
|
14
|
+
description: 'List all available data semantics, their scopes, and whether they have configuration options.',
|
|
15
|
+
parametersJsonSchema: {
|
|
16
|
+
type: Type.OBJECT,
|
|
17
|
+
properties: {},
|
|
18
|
+
required: [],
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
name: 'get_semantic_details',
|
|
23
|
+
description:
|
|
24
|
+
'Get detailed information about a specific data semantic, notably its JSON ' +
|
|
25
|
+
'configuration schema properties, to determine what additional config you might want to provide.',
|
|
26
|
+
parametersJsonSchema: {
|
|
27
|
+
type: Type.OBJECT,
|
|
28
|
+
properties: {
|
|
29
|
+
semanticId: {
|
|
30
|
+
type: Type.STRING,
|
|
31
|
+
description: 'The exact ID of the semantic (e.g. Semantic#Password, Semantic#Tags)',
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
required: ['semanticId'],
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: 'get_entity_details',
|
|
39
|
+
description: 'Get the full details of an entity given its key, including properties, associations, and tags.',
|
|
40
|
+
parametersJsonSchema: {
|
|
41
|
+
type: Type.OBJECT,
|
|
42
|
+
properties: {
|
|
43
|
+
entityKey: {
|
|
44
|
+
type: Type.STRING,
|
|
45
|
+
description: 'The exact key/ID of the entity to fetch details for.',
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
required: ['entityKey'],
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: 'explain_schema',
|
|
53
|
+
description: 'Explains the schema of a data type.',
|
|
54
|
+
parametersJsonSchema: {
|
|
55
|
+
type: Type.OBJECT,
|
|
56
|
+
properties: {
|
|
57
|
+
dataType: {
|
|
58
|
+
type: Type.STRING,
|
|
59
|
+
description: 'The data type (e.g. string, number, boolean, date, datetime, time, binary)',
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
required: ['dataType'],
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
],
|
|
66
|
+
},
|
|
67
|
+
]
|
|
68
|
+
|
|
69
|
+
export type ToolFunction = (config: ToolConfig, args: Record<string, unknown>) => unknown | Promise<unknown>
|
|
70
|
+
|
|
71
|
+
export const functions: Record<string, ToolFunction> = {
|
|
72
|
+
list_semantics,
|
|
73
|
+
get_semantic_details,
|
|
74
|
+
explain_schema,
|
|
75
|
+
get_entity_details,
|
|
76
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import type { AiModelMessageWithDelta } from './types.js'
|
|
2
|
+
import type { AiMessageSchema, AiUserMessage } from '../../models/AiMessage.js'
|
|
3
|
+
import { DataDomainDelta } from './DataDomainDelta.js'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Parses an incoming `AiMessage` and maps it directly into its runtime
|
|
7
|
+
* representations `AiUserMessage` or `AiModelMessageWithDelta`.
|
|
8
|
+
*
|
|
9
|
+
* If the message is a model message, it attempts to parse the structured JSON
|
|
10
|
+
* contents in `msg.text` and sets the `delta` field accordingly. The `text` field
|
|
11
|
+
* is replaced with the reasoning text, or remains original if parsing fails/is omitted.
|
|
12
|
+
*
|
|
13
|
+
* @param msg The generic AI chat message.
|
|
14
|
+
* @returns The parsed in-memory wrapper context message.
|
|
15
|
+
*/
|
|
16
|
+
export function parseAiChatMessage(msg: AiMessageSchema): AiUserMessage | AiModelMessageWithDelta {
|
|
17
|
+
if (msg.role === 'user') {
|
|
18
|
+
return msg as AiUserMessage
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const modelMsg = { ...msg } as AiModelMessageWithDelta
|
|
22
|
+
|
|
23
|
+
// Try to parse the delta structure
|
|
24
|
+
if (modelMsg.state === 'complete' && modelMsg.text) {
|
|
25
|
+
try {
|
|
26
|
+
const parsedJSON = JSON.parse(modelMsg.text)
|
|
27
|
+
modelMsg.delta = parsedJSON.delta ? DataDomainDelta.normalize(parsedJSON.delta) : undefined
|
|
28
|
+
modelMsg.text = parsedJSON.reasoning || modelMsg.text
|
|
29
|
+
} catch {
|
|
30
|
+
// It might legitimately not be valid JSON yet if it crashed mid-stream,
|
|
31
|
+
// fallback to retaining original shape.
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return modelMsg
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* When a model response is generated it may contain the `reasoning` property. But because
|
|
40
|
+
* that property might still be generated it might not be a valid JSON. This function checks
|
|
41
|
+
* if the text contains reasoning and returns it if it does.
|
|
42
|
+
* @param text The text to check.
|
|
43
|
+
* @returns The reasoning string if it exists, otherwise undefined.
|
|
44
|
+
*/
|
|
45
|
+
export function detectReasoning(text: string): string | undefined {
|
|
46
|
+
try {
|
|
47
|
+
const parsedJSON = JSON.parse(text)
|
|
48
|
+
return parsedJSON.reasoning
|
|
49
|
+
} catch {
|
|
50
|
+
// Continue below
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const searchStr = '"reasoning"'
|
|
54
|
+
const keyIndex = text.indexOf(searchStr)
|
|
55
|
+
if (keyIndex === -1) {
|
|
56
|
+
return undefined
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const afterKey = text.substring(keyIndex + searchStr.length)
|
|
60
|
+
const colonIndex = afterKey.indexOf(':')
|
|
61
|
+
if (colonIndex === -1) {
|
|
62
|
+
return undefined
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const afterColon = afterKey.substring(colonIndex + 1)
|
|
66
|
+
const quoteIndex = afterColon.indexOf('"')
|
|
67
|
+
if (quoteIndex === -1) {
|
|
68
|
+
return undefined
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const valueStr = afterColon.substring(quoteIndex + 1)
|
|
72
|
+
let isEscaped = false
|
|
73
|
+
let endIndex = -1
|
|
74
|
+
|
|
75
|
+
for (let i = 0; i < valueStr.length; i++) {
|
|
76
|
+
const char = valueStr[i]
|
|
77
|
+
if (char === '\\' && !isEscaped) {
|
|
78
|
+
isEscaped = true
|
|
79
|
+
} else if (char === '"' && !isEscaped) {
|
|
80
|
+
endIndex = i
|
|
81
|
+
break
|
|
82
|
+
} else {
|
|
83
|
+
isEscaped = false
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const extracted = endIndex !== -1 ? valueStr.substring(0, endIndex) : valueStr
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
// Try to safely parse the literal string value.
|
|
91
|
+
return JSON.parse('"' + extracted + '"')
|
|
92
|
+
} catch {
|
|
93
|
+
// string replace fallback
|
|
94
|
+
return extracted
|
|
95
|
+
.replace(/\\n/g, '\n')
|
|
96
|
+
.replace(/\\r/g, '\r')
|
|
97
|
+
.replace(/\\t/g, '\t')
|
|
98
|
+
.replace(/\\"/g, '"')
|
|
99
|
+
.replace(/\\\\/g, '\\')
|
|
100
|
+
}
|
|
101
|
+
}
|