@takeshape/schema 11.40.3 → 11.43.0
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/cjs/src/agents.js +87 -1
- package/dist/cjs/src/index.js +2 -0
- package/dist/cjs/src/relationships.js +86 -1
- package/dist/cjs/src/runtime-schema.js +81 -0
- package/dist/cjs/src/service-dependencies.js +167 -0
- package/dist/cjs/src/util/patch-schema.js +33 -28
- package/dist/cjs/src/validate.js +6 -0
- package/dist/esm/src/agents.js +83 -0
- package/dist/esm/src/index.js +2 -0
- package/dist/esm/src/relationships.js +85 -1
- package/dist/esm/src/runtime-schema.js +73 -0
- package/dist/esm/src/service-dependencies.js +159 -0
- package/dist/esm/src/util/patch-schema.js +33 -27
- package/dist/esm/src/validate.js +6 -0
- package/dist/types/src/agents.d.ts +4 -1
- package/dist/types/src/index.d.ts +2 -0
- package/dist/types/src/migration/types.d.ts +1 -3
- package/dist/types/src/relationships.d.ts +4 -0
- package/dist/types/src/runtime-schema.d.ts +5 -0
- package/dist/types/src/service-dependencies.d.ts +13 -0
- package/dist/types/src/types/types.d.ts +1 -0
- package/dist/types/src/util/patch-schema.d.ts +4 -4
- package/dist/types/tsconfig.types.tsbuildinfo +1 -1
- package/package.json +6 -6
package/dist/cjs/src/agents.js
CHANGED
|
@@ -3,8 +3,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.getInspectAgentSessionQueryName = exports.getAgentEndStates = exports.getAgentEndTransitions = exports.BUILT_IN_CHAT_ARG_NAMES = exports.BUILT_IN_CHAT_ARGS = exports.END_AGENT_EXECUTION = void 0;
|
|
6
|
+
exports.addAiQueries = exports.createArgs = exports.removeBuiltInArgs = exports.getInspectAgentSessionQueryName = exports.getAgentEndStates = exports.getAgentEndTransitions = exports.BUILT_IN_CHAT_ARG_NAMES = exports.BUILT_IN_CHAT_ARGS = exports.END_AGENT_EXECUTION = void 0;
|
|
7
7
|
const upperFirst_js_1 = __importDefault(require("lodash/upperFirst.js"));
|
|
8
|
+
const uniq_js_1 = __importDefault(require("lodash/uniq.js"));
|
|
9
|
+
const uniqBy_js_1 = __importDefault(require("lodash/uniqBy.js"));
|
|
8
10
|
exports.END_AGENT_EXECUTION = 'endAgentExecution';
|
|
9
11
|
exports.BUILT_IN_CHAT_ARGS = [
|
|
10
12
|
{
|
|
@@ -56,3 +58,87 @@ const getInspectAgentSessionQueryName = (agentName) => {
|
|
|
56
58
|
return `inspect${(0, upperFirst_js_1.default)(agentName)}`;
|
|
57
59
|
};
|
|
58
60
|
exports.getInspectAgentSessionQueryName = getInspectAgentSessionQueryName;
|
|
61
|
+
const removeBuiltInArgs = (args) => {
|
|
62
|
+
return args.filter(arg => !exports.BUILT_IN_CHAT_ARG_NAMES.includes(arg.argName));
|
|
63
|
+
};
|
|
64
|
+
exports.removeBuiltInArgs = removeBuiltInArgs;
|
|
65
|
+
const createArgs = (agent) => {
|
|
66
|
+
let apiArguments = (0, uniqBy_js_1.default)(agent.api.arguments ?? [], arg => arg.argName);
|
|
67
|
+
if (agent.api.type === 'chat') {
|
|
68
|
+
apiArguments = (0, exports.removeBuiltInArgs)(apiArguments).concat(exports.BUILT_IN_CHAT_ARGS);
|
|
69
|
+
}
|
|
70
|
+
return apiArguments.length > 0
|
|
71
|
+
? {
|
|
72
|
+
type: 'object',
|
|
73
|
+
properties: apiArguments.reduce((acc, argument) => {
|
|
74
|
+
acc[argument.argName] = {
|
|
75
|
+
type: argument.argType === 'sessionId' ? 'string' : argument.argType
|
|
76
|
+
};
|
|
77
|
+
return acc;
|
|
78
|
+
}, {}),
|
|
79
|
+
required: apiArguments.filter(arg => arg.required).map(arg => arg.argName)
|
|
80
|
+
}
|
|
81
|
+
: undefined;
|
|
82
|
+
};
|
|
83
|
+
exports.createArgs = createArgs;
|
|
84
|
+
function addAiQueries(projectSchema) {
|
|
85
|
+
const agents = projectSchema['ai-experimental']?.agents;
|
|
86
|
+
if (!agents) {
|
|
87
|
+
return projectSchema;
|
|
88
|
+
}
|
|
89
|
+
const newSchema = {
|
|
90
|
+
...projectSchema,
|
|
91
|
+
queries: { ...projectSchema.queries },
|
|
92
|
+
mutations: { ...projectSchema.mutations }
|
|
93
|
+
};
|
|
94
|
+
for (const [agentName, agent] of Object.entries(agents)) {
|
|
95
|
+
// Get valid return types based on states that could possibly be the end state
|
|
96
|
+
// TODO In the future the agent will have a return type defined and we will instead validate
|
|
97
|
+
// that all the return states will return the correct shape.
|
|
98
|
+
const returnStates = [...(0, exports.getAgentEndStates)(agent, true)];
|
|
99
|
+
const returnTypes = (0, uniq_js_1.default)(returnStates.map(stateId => {
|
|
100
|
+
const { execution } = agent.states[stateId];
|
|
101
|
+
if (execution.type === 'chat') {
|
|
102
|
+
return 'TSChatResponse';
|
|
103
|
+
}
|
|
104
|
+
if (execution.type === 'generate') {
|
|
105
|
+
return execution.outputShape ? execution.outputShape : 'string';
|
|
106
|
+
}
|
|
107
|
+
return 'JSON';
|
|
108
|
+
}));
|
|
109
|
+
const shape = returnTypes.length === 0 ? 'string' : returnTypes.length === 1 ? returnTypes[0] : 'JSON';
|
|
110
|
+
if (newSchema.mutations[agentName] !== undefined) {
|
|
111
|
+
throw new Error(`Schema already has a mutation with the name ${agentName}`);
|
|
112
|
+
}
|
|
113
|
+
newSchema.mutations[agentName] = {
|
|
114
|
+
description: agent.description,
|
|
115
|
+
args: (0, exports.createArgs)(agent),
|
|
116
|
+
shape,
|
|
117
|
+
resolver: {
|
|
118
|
+
name: 'ai:runAgent',
|
|
119
|
+
agentName
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
if (shape === 'TSChatResponse') {
|
|
123
|
+
newSchema.queries[(0, exports.getInspectAgentSessionQueryName)(agentName)] ||= {
|
|
124
|
+
description: `Inspect a session for the ${agentName} agent`,
|
|
125
|
+
args: {
|
|
126
|
+
type: 'object',
|
|
127
|
+
properties: {
|
|
128
|
+
sessionId: {
|
|
129
|
+
type: 'string'
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
required: ['sessionId']
|
|
133
|
+
},
|
|
134
|
+
shape: 'TSAgentSession',
|
|
135
|
+
resolver: {
|
|
136
|
+
name: 'ai:inspectAgentSession',
|
|
137
|
+
agentName
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return newSchema;
|
|
143
|
+
}
|
|
144
|
+
exports.addAiQueries = addAiQueries;
|
package/dist/cjs/src/index.js
CHANGED
|
@@ -58,3 +58,5 @@ __exportStar(require("./util/merge"), exports);
|
|
|
58
58
|
__exportStar(require("./util/patch-schema"), exports);
|
|
59
59
|
__exportStar(require("./util/shapes"), exports);
|
|
60
60
|
__exportStar(require("./constants"), exports);
|
|
61
|
+
__exportStar(require("./runtime-schema"), exports);
|
|
62
|
+
__exportStar(require("./service-dependencies"), exports);
|
|
@@ -3,9 +3,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.hasUnequalRelationships = exports.isEqualRelationship = exports.findExistingRelationships = exports.getRelationship = exports.getLegacyRelationship = exports.getRelationshipShapeIds = exports.getRelationshipShapes = exports.getRelationshipShapeRefs = exports.getRelationshipSchema = void 0;
|
|
6
|
+
exports.addRelatedFields = exports.hasUnequalRelationships = exports.isEqualRelationship = exports.findExistingRelationships = exports.getRelationship = exports.getLegacyRelationship = exports.getRelationshipShapeIds = exports.getRelationshipShapes = exports.getRelationshipShapeRefs = exports.getRelationshipSchema = void 0;
|
|
7
7
|
const util_1 = require("@takeshape/util");
|
|
8
8
|
const find_js_1 = __importDefault(require("lodash/find.js"));
|
|
9
|
+
const camelCase_js_1 = __importDefault(require("lodash/camelCase.js"));
|
|
10
|
+
const uniq_js_1 = __importDefault(require("lodash/uniq.js"));
|
|
9
11
|
const types_1 = require("./types");
|
|
10
12
|
const refs_1 = require("./refs");
|
|
11
13
|
const unions_1 = require("./unions");
|
|
@@ -235,3 +237,86 @@ function hasUnequalRelationships(relationships) {
|
|
|
235
237
|
}));
|
|
236
238
|
}
|
|
237
239
|
exports.hasUnequalRelationships = hasUnequalRelationships;
|
|
240
|
+
function getRelatedShapeIds(relationships) {
|
|
241
|
+
return (0, uniq_js_1.default)(relationships.map(rel => (rel.hasBackreference ? rel.shapeId : undefined)).filter(util_1.isDefined));
|
|
242
|
+
}
|
|
243
|
+
function getShapes(projectSchema, shapeIds) {
|
|
244
|
+
return shapeIds.map(shapeId => (0, shapes_1.getShapeById)(projectSchema, shapeId)).filter(util_1.isDefined);
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Adds backreference fields to the schema.
|
|
248
|
+
*/
|
|
249
|
+
function addRelatedFields(projectSchema, allRelationships) {
|
|
250
|
+
for (const [shapeId, shapeRelationships] of Object.entries(allRelationships)) {
|
|
251
|
+
const shape = (0, shapes_1.getShapeById)(projectSchema, shapeId);
|
|
252
|
+
if (shape && (0, types_1.isObjectSchema)(shape.schema)) {
|
|
253
|
+
const relatedShapeIds = getRelatedShapeIds(shapeRelationships);
|
|
254
|
+
const relatedShapeNames = getShapes(projectSchema, relatedShapeIds).map(shape => shape.name);
|
|
255
|
+
if (relatedShapeNames.length) {
|
|
256
|
+
let shapeName;
|
|
257
|
+
if (relatedShapeNames.length === 1) {
|
|
258
|
+
// If only one back reference exists, _references is a regular shape
|
|
259
|
+
shapeName = relatedShapeNames[0];
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
// If many back references exist, _references will be a union of referring shapes
|
|
263
|
+
shapeName = `${shape.name}Reference`;
|
|
264
|
+
projectSchema.shapes[shapeName] = {
|
|
265
|
+
id: shapeName,
|
|
266
|
+
name: shapeName,
|
|
267
|
+
title: shapeName,
|
|
268
|
+
schema: {
|
|
269
|
+
oneOf: relatedShapeNames.map(name => ({ '@ref': `local:${name}` }))
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
// _references, a list of all backreferences across all fields on this shape.
|
|
274
|
+
// It lists all the items that have references to the current item.
|
|
275
|
+
// It is for convenience.
|
|
276
|
+
if (shapeRelationships.some(rel => rel.hasBackreference)) {
|
|
277
|
+
shape.schema.properties._references = {
|
|
278
|
+
'@args': `TSListArgs<local:${shapeName}>`,
|
|
279
|
+
'@ref': `PaginatedList<local:${shapeName}>`,
|
|
280
|
+
'@resolver': {
|
|
281
|
+
name: 'shapedb:list',
|
|
282
|
+
service: 'shapedb',
|
|
283
|
+
args: {
|
|
284
|
+
ops: [
|
|
285
|
+
{ path: '$', mapping: '$args' },
|
|
286
|
+
{ path: `baseWhere._references.eq`, mapping: '$source._id' },
|
|
287
|
+
{ path: `baseWhere._shapeId.in`, value: relatedShapeIds }
|
|
288
|
+
]
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
// Create a schema for the backreference on the referred-to shape
|
|
295
|
+
for (const relationship of shapeRelationships) {
|
|
296
|
+
const relatedShape = (0, shapes_1.getShapeById)(projectSchema, relationship.shapeId);
|
|
297
|
+
if (relatedShape && relationship.hasBackreference) {
|
|
298
|
+
const { relatedName } = relationship;
|
|
299
|
+
const relatedFieldName = relatedName ? relatedName : `${(0, camelCase_js_1.default)(relatedShape.name)}Set`;
|
|
300
|
+
const filterField = relatedName ? relationship.path.concat('_id').join('.') : '_references';
|
|
301
|
+
shape.schema.properties[relatedFieldName] = {
|
|
302
|
+
'@args': `TSListArgs<local:${relatedShape.name}>`,
|
|
303
|
+
'@ref': `PaginatedList<local:${relatedShape.name}>`,
|
|
304
|
+
'@resolver': {
|
|
305
|
+
name: 'shapedb:list',
|
|
306
|
+
service: 'shapedb',
|
|
307
|
+
args: {
|
|
308
|
+
ops: [
|
|
309
|
+
{ path: '$', mapping: '$args' },
|
|
310
|
+
{ path: `baseWhere.${filterField}.eq`, mapping: '$source._id' },
|
|
311
|
+
{ path: `baseWhere._shapeId.eq`, value: relatedShape.id }
|
|
312
|
+
]
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
return projectSchema;
|
|
321
|
+
}
|
|
322
|
+
exports.addRelatedFields = addRelatedFields;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.buildRuntimeSchema = exports.applyDefaultsAndFlatten = exports.applyLegacyCompatibilityTweaks = void 0;
|
|
7
|
+
const errors_1 = require("@takeshape/errors");
|
|
8
|
+
const compose_js_1 = __importDefault(require("lodash/fp/compose.js"));
|
|
9
|
+
const util_1 = require("@takeshape/util");
|
|
10
|
+
const set_js_1 = __importDefault(require("lodash/set.js"));
|
|
11
|
+
const isError_js_1 = __importDefault(require("lodash/isError.js"));
|
|
12
|
+
const types_1 = require("./types");
|
|
13
|
+
const schema_util_1 = require("./schema-util");
|
|
14
|
+
const relationships_1 = require("./relationships");
|
|
15
|
+
const flatten_templates_1 = require("./flatten-templates");
|
|
16
|
+
const agents_1 = require("./agents");
|
|
17
|
+
const service_dependencies_1 = require("./service-dependencies");
|
|
18
|
+
function applyLegacyCompatibilityTweaks(projectSchema) {
|
|
19
|
+
const newSchema = (0, util_1.deepClone)(projectSchema);
|
|
20
|
+
let hasSearchableShapes = false;
|
|
21
|
+
for (const [shapeName, shape] of Object.entries(newSchema.shapes)) {
|
|
22
|
+
if ((0, types_1.isModelShape)(shape)) {
|
|
23
|
+
hasSearchableShapes = true;
|
|
24
|
+
// Magic _contentTypeId field used for V1 compatibility
|
|
25
|
+
(0, set_js_1.default)(shape, ['schema', 'properties', '_contentTypeId'], { type: 'string' });
|
|
26
|
+
(0, set_js_1.default)(shape, ['schema', 'properties', '_contentTypeName'], { type: 'string' });
|
|
27
|
+
if (shape.model?.type !== 'single') {
|
|
28
|
+
newSchema.queries[`search${shapeName}Index`] = {
|
|
29
|
+
shape: `SearchResults<${shapeName}>`,
|
|
30
|
+
resolver: {
|
|
31
|
+
name: 'takeshape:search',
|
|
32
|
+
service: 'takeshape',
|
|
33
|
+
shapeName
|
|
34
|
+
},
|
|
35
|
+
args: `TSSearchArgs<${shapeName}>`
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (shapeName === 'Asset') {
|
|
40
|
+
// Magic s3Key field to provide V1 compatibility with old projects until the field is
|
|
41
|
+
// formally removed and users are notified
|
|
42
|
+
(0, set_js_1.default)(shape, ['schema', 'properties', 's3Key'], {
|
|
43
|
+
title: 's3 key',
|
|
44
|
+
type: 'string',
|
|
45
|
+
'@mapping': 'shapedb:Asset.Hk6FQuz5',
|
|
46
|
+
'@deprecationReason': 'Use path instead'
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (hasSearchableShapes) {
|
|
51
|
+
// A placeholder shape for the TSSearchable interface
|
|
52
|
+
newSchema.shapes.TSSearchable = (0, schema_util_1.createShape)('TSSearchable', { type: 'object', properties: {} });
|
|
53
|
+
newSchema.queries.search = {
|
|
54
|
+
shape: 'SearchResults<TSSearchable>',
|
|
55
|
+
resolver: {
|
|
56
|
+
name: 'takeshape:search',
|
|
57
|
+
service: 'takeshape'
|
|
58
|
+
},
|
|
59
|
+
args: 'TSSearchArgs<TSSearchable>'
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
(0, relationships_1.addRelatedFields)(newSchema, (0, relationships_1.findExistingRelationships)(projectSchema, projectSchema.shapes));
|
|
63
|
+
return newSchema;
|
|
64
|
+
}
|
|
65
|
+
exports.applyLegacyCompatibilityTweaks = applyLegacyCompatibilityTweaks;
|
|
66
|
+
exports.applyDefaultsAndFlatten = (0, compose_js_1.default)(flatten_templates_1.flattenTemplates, applyLegacyCompatibilityTweaks, schema_util_1.applyDefaultsToSchema, agents_1.addAiQueries);
|
|
67
|
+
function buildRuntimeSchema(projectSchema, serviceLayers, log) {
|
|
68
|
+
try {
|
|
69
|
+
const projectSchemaWithDependencies = (0, service_dependencies_1.resolveSchemaShapeDependencies)(projectSchema, serviceLayers);
|
|
70
|
+
return (0, exports.applyDefaultsAndFlatten)(projectSchemaWithDependencies);
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
const error = new errors_1.SchemaBuildError('An error occurred while building the schema', {
|
|
74
|
+
cause: (0, isError_js_1.default)(err) ? err : undefined,
|
|
75
|
+
schema: projectSchema
|
|
76
|
+
});
|
|
77
|
+
log('build runtime error', error);
|
|
78
|
+
throw error;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
exports.buildRuntimeSchema = buildRuntimeSchema;
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.resolveSchemaShapeDependencies = exports.collectReferencedShapeNames = void 0;
|
|
7
|
+
const util_1 = require("@takeshape/util");
|
|
8
|
+
const get_js_1 = __importDefault(require("lodash/get.js"));
|
|
9
|
+
const set_js_1 = __importDefault(require("lodash/set.js"));
|
|
10
|
+
const isObject_js_1 = __importDefault(require("lodash/isObject.js"));
|
|
11
|
+
const pick_js_1 = __importDefault(require("lodash/pick.js"));
|
|
12
|
+
const types_1 = require("./types");
|
|
13
|
+
const refs_1 = require("./refs");
|
|
14
|
+
const interfaces_1 = require("./interfaces");
|
|
15
|
+
const schema_util_1 = require("./schema-util");
|
|
16
|
+
function getGraphQLServiceShapeMap(layers) {
|
|
17
|
+
return Object.assign({}, ...Object.values(layers).map(layer => layer.schema?.shapes ?? {}));
|
|
18
|
+
}
|
|
19
|
+
function schemaExtendsShape(context, shapeName, schema) {
|
|
20
|
+
return ((0, types_1.isExtendsSchema)(schema) &&
|
|
21
|
+
schema.extends.some((item) => (0, refs_1.getRefShapeName)(context, item) === shapeName));
|
|
22
|
+
}
|
|
23
|
+
function getMissingPropertyRefs(projectSchema, getNamespace) {
|
|
24
|
+
const propertyRefs = (0, refs_1.getAllPropertyRefs)(projectSchema);
|
|
25
|
+
return propertyRefs.filter(ref => {
|
|
26
|
+
const path = (0, refs_1.propertyRefItemToPath)(getNamespace, ref);
|
|
27
|
+
return !(0, get_js_1.default)(projectSchema, path);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
function refToQuery(serviceSchemas, ref) {
|
|
31
|
+
const serviceSchema = serviceSchemas[ref.serviceId].schema;
|
|
32
|
+
if (serviceSchema) {
|
|
33
|
+
if (ref.shapeName === 'Query' || ref.shapeName === 'Mutation') {
|
|
34
|
+
const operation = ref.shapeName === 'Query' ? 'queries' : 'mutations';
|
|
35
|
+
return serviceSchema[operation][ref.propertyName];
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function getShapeRefs(services, serviceSchemas, propertyRefs) {
|
|
40
|
+
const results = [];
|
|
41
|
+
for (const ref of propertyRefs) {
|
|
42
|
+
const query = refToQuery(serviceSchemas, ref);
|
|
43
|
+
const layerSchema = serviceSchemas[ref.serviceId]?.schema;
|
|
44
|
+
if (query && layerSchema) {
|
|
45
|
+
const layerWithService = {
|
|
46
|
+
...layerSchema,
|
|
47
|
+
services: (0, pick_js_1.default)(services, [ref.serviceId]) // include own service so refs have isValidService: true
|
|
48
|
+
};
|
|
49
|
+
results.push(...(0, schema_util_1.getAllRefsInQuery)(layerWithService, [], query));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return results;
|
|
53
|
+
}
|
|
54
|
+
function interfacesToShapeNames(projectSchema, shapeRefArray) {
|
|
55
|
+
return shapeRefArray.map(shapeRef => (0, refs_1.refItemToNamespacedShapeName)((0, refs_1.refExpressionToRefItem)(projectSchema, shapeRef)));
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Add all referenced shape names to the refSet meant to be used as a callback to visitSchemaProperties
|
|
59
|
+
*/
|
|
60
|
+
function collectReferencedShapeNames(context, shapeNames) {
|
|
61
|
+
const addRef = (refItem) => {
|
|
62
|
+
shapeNames.add((0, refs_1.refItemToNamespacedShapeName)(refItem));
|
|
63
|
+
};
|
|
64
|
+
const collect = (schema) => {
|
|
65
|
+
const args = schema['@args'];
|
|
66
|
+
if (args && (0, isObject_js_1.default)(args) && (0, types_1.isObjectSchema)(args)) {
|
|
67
|
+
Object.values(args.properties).forEach(collect);
|
|
68
|
+
}
|
|
69
|
+
const argsRefItem = (0, schema_util_1.getArgsReference)(context, schema);
|
|
70
|
+
if (argsRefItem) {
|
|
71
|
+
addRef(argsRefItem);
|
|
72
|
+
}
|
|
73
|
+
const refItem = (0, refs_1.getRef)(context, schema);
|
|
74
|
+
if (refItem) {
|
|
75
|
+
addRef(refItem);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
return collect;
|
|
79
|
+
}
|
|
80
|
+
exports.collectReferencedShapeNames = collectReferencedShapeNames;
|
|
81
|
+
/**
|
|
82
|
+
* Returns a schema with all of its dependencies resolved.
|
|
83
|
+
* SHOULD only return the minimum set of remote dependencies required to enable
|
|
84
|
+
* the local shape definitions.
|
|
85
|
+
*/
|
|
86
|
+
function resolveSchemaShapeDependencies(projectSchema, serviceLayers) {
|
|
87
|
+
const newSchema = (0, util_1.deepClone)(projectSchema);
|
|
88
|
+
if ((0, types_1.isProjectSchemaWithServices)(projectSchema)) {
|
|
89
|
+
const newShapeMap = {};
|
|
90
|
+
const requiredShapeNames = new Set((0, schema_util_1.getAllNamespaceShapes)(projectSchema));
|
|
91
|
+
const getNamespace = (0, refs_1.createGetNamespace)(projectSchema);
|
|
92
|
+
const missingPropertyRefs = getMissingPropertyRefs(projectSchema, getNamespace);
|
|
93
|
+
if (requiredShapeNames.size || missingPropertyRefs.length) {
|
|
94
|
+
const remoteShapeMap = getGraphQLServiceShapeMap(serviceLayers);
|
|
95
|
+
// Add shape references from queries
|
|
96
|
+
(0, util_1.addAll)(requiredShapeNames, getShapeRefs(projectSchema.services, serviceLayers, missingPropertyRefs)
|
|
97
|
+
.filter(schema_util_1.isValidRefItem)
|
|
98
|
+
.map(refs_1.refItemToNamespacedShapeName));
|
|
99
|
+
// Add referenced queries and mutations
|
|
100
|
+
for (const ref of missingPropertyRefs) {
|
|
101
|
+
const query = refToQuery(serviceLayers, ref);
|
|
102
|
+
if (query) {
|
|
103
|
+
(0, set_js_1.default)(newSchema, (0, refs_1.propertyRefItemToPath)(getNamespace, ref), query);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Gather all the remote dependencies that our local schema requires.
|
|
107
|
+
// If the required shape exists in the remote shape map, visit the
|
|
108
|
+
// properties on the remote shape's schema and ensure they are required
|
|
109
|
+
// as well.
|
|
110
|
+
const collectDependencies = (shapeNames) => {
|
|
111
|
+
for (const name of shapeNames) {
|
|
112
|
+
const localShape = newSchema.shapes[name];
|
|
113
|
+
const remoteShape = remoteShapeMap[name];
|
|
114
|
+
// Don't check for dependencies if the shape is already in our schema unless it extends a remote shape
|
|
115
|
+
// getNamespacedShapeNameList already collected those dependencies
|
|
116
|
+
if ((!localShape || (localShape && schemaExtendsShape(projectSchema, name, localShape.schema))) &&
|
|
117
|
+
remoteShape) {
|
|
118
|
+
(0, schema_util_1.visitSchemaProperties)(remoteShape.schema, [remoteShape.name, 'schema'], collectReferencedShapeNames({ services: newSchema.services }, shapeNames));
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
collectDependencies(requiredShapeNames);
|
|
123
|
+
// Collect interfaces that requiredShapeNames implement
|
|
124
|
+
const interfaceNames = new Set();
|
|
125
|
+
const requiredShapes = (0, util_1.mapSet)(requiredShapeNames, shapeName => newSchema.shapes[shapeName] ?? remoteShapeMap[shapeName]);
|
|
126
|
+
for (const shape of requiredShapes) {
|
|
127
|
+
if (shape?.interfaces) {
|
|
128
|
+
(0, util_1.addAll)(interfaceNames, interfacesToShapeNames(projectSchema, shape.interfaces));
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
// Collect implementations for interfaces in requiredShapeNames
|
|
132
|
+
const implementationNames = new Set();
|
|
133
|
+
const implementations = (0, interfaces_1.getImplementationShapeNameMap)({ ...newSchema.shapes, ...remoteShapeMap });
|
|
134
|
+
for (const shape of requiredShapes) {
|
|
135
|
+
if ((0, interfaces_1.isInterfaceShape)(shape) && implementations[shape.name]) {
|
|
136
|
+
(0, util_1.addAll)(implementationNames, implementations[shape.name]);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
// Collect the dependencies for the interfaces and implementations
|
|
140
|
+
collectDependencies(interfaceNames);
|
|
141
|
+
collectDependencies(implementationNames);
|
|
142
|
+
(0, util_1.addAll)(requiredShapeNames, interfaceNames);
|
|
143
|
+
(0, util_1.addAll)(requiredShapeNames, implementationNames);
|
|
144
|
+
// Populate a ShapeMap with the remote shapes we've gathered
|
|
145
|
+
// A combined context which prefers remote shapes for use when merging/inlining
|
|
146
|
+
const mergingContext = { services: newSchema.services, shapes: { ...newSchema.shapes, ...remoteShapeMap } };
|
|
147
|
+
for (const name of requiredShapeNames) {
|
|
148
|
+
const localShape = newSchema.shapes[name];
|
|
149
|
+
const remoteShape = remoteShapeMap[name];
|
|
150
|
+
if (localShape && remoteShape && schemaExtendsShape(mergingContext, name, localShape.schema)) {
|
|
151
|
+
// Merge and inline combined shape when a local shape extends a remote shape
|
|
152
|
+
newShapeMap[name] = {
|
|
153
|
+
...localShape,
|
|
154
|
+
schema: (0, refs_1.dereferenceObjectSchema)(mergingContext, newSchema.shapes[name].schema)
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
else if (localShape ?? remoteShape) {
|
|
158
|
+
newShapeMap[name] = localShape ?? remoteShape;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
// Assign remote shapes to the new schema, mutating the new schema
|
|
163
|
+
Object.assign(newSchema.shapes, (0, interfaces_1.pruneUnusedInterfaces)(newSchema, newShapeMap));
|
|
164
|
+
}
|
|
165
|
+
return newSchema;
|
|
166
|
+
}
|
|
167
|
+
exports.resolveSchemaShapeDependencies = resolveSchemaShapeDependencies;
|
|
@@ -3,48 +3,53 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.patchSchema =
|
|
7
|
-
const forIn_js_1 = __importDefault(require("lodash/forIn.js"));
|
|
6
|
+
exports.patchSchema = void 0;
|
|
8
7
|
const omit_js_1 = __importDefault(require("lodash/omit.js"));
|
|
9
|
-
const
|
|
8
|
+
const get_js_1 = __importDefault(require("lodash/get.js"));
|
|
9
|
+
const set_js_1 = __importDefault(require("lodash/fp/set.js"));
|
|
10
|
+
const unset_js_1 = __importDefault(require("lodash/unset.js"));
|
|
11
|
+
/**
|
|
12
|
+
* Array of lodash.get paths to keys that are merged when applying a schema update.
|
|
13
|
+
*/
|
|
14
|
+
const schemaUpdateMergedKeys = [
|
|
15
|
+
'queries',
|
|
16
|
+
'mutations',
|
|
17
|
+
'shapes',
|
|
18
|
+
'workflows',
|
|
19
|
+
'forms',
|
|
20
|
+
'services',
|
|
21
|
+
'ai-experimental.agents'
|
|
22
|
+
];
|
|
10
23
|
function shallowMerge(original, update) {
|
|
11
24
|
const result = { ...original };
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
result[key] = obj;
|
|
21
|
-
}
|
|
22
|
-
});
|
|
25
|
+
for (const [key, obj] of Object.entries(update)) {
|
|
26
|
+
// Null is a sentinel value to indicate delete
|
|
27
|
+
if (obj === null) {
|
|
28
|
+
(0, unset_js_1.default)(result, key);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
result[key] = obj;
|
|
32
|
+
}
|
|
23
33
|
}
|
|
24
34
|
return result;
|
|
25
35
|
}
|
|
26
|
-
exports.shallowMerge = shallowMerge;
|
|
27
36
|
/**
|
|
28
|
-
* Apply a schema update to a schema.
|
|
29
|
-
* Resulting schema is not assumed to be valid and should
|
|
37
|
+
* Apply a schema update to a schema. This can operate on a schema with frozen properties,
|
|
38
|
+
* such as one produced by immer. Resulting schema is not assumed to be valid and should
|
|
39
|
+
* be validated if appropriate.
|
|
30
40
|
*/
|
|
31
|
-
function patchSchema(projectSchema,
|
|
41
|
+
function patchSchema(projectSchema, schemaUpdate) {
|
|
32
42
|
// Patch old schema with update
|
|
33
|
-
|
|
43
|
+
let updatedSchema = {
|
|
34
44
|
...projectSchema,
|
|
35
|
-
...(0, omit_js_1.default)(
|
|
45
|
+
...(0, omit_js_1.default)(schemaUpdate, schemaUpdateMergedKeys)
|
|
36
46
|
};
|
|
37
47
|
for (const key of schemaUpdateMergedKeys) {
|
|
38
|
-
|
|
39
|
-
|
|
48
|
+
const update = (0, get_js_1.default)(schemaUpdate, key);
|
|
49
|
+
if (update) {
|
|
50
|
+
updatedSchema = (0, set_js_1.default)(key, shallowMerge((0, get_js_1.default)(projectSchema, key) ?? {}, update), updatedSchema);
|
|
40
51
|
}
|
|
41
52
|
}
|
|
42
|
-
if (update['ai-experimental']?.agents) {
|
|
43
|
-
const ai = {
|
|
44
|
-
agents: shallowMerge(projectSchema['ai-experimental']?.agents, update['ai-experimental'].agents)
|
|
45
|
-
};
|
|
46
|
-
updatedSchema['ai-experimental'] = ai;
|
|
47
|
-
}
|
|
48
53
|
return updatedSchema;
|
|
49
54
|
}
|
|
50
55
|
exports.patchSchema = patchSchema;
|
package/dist/cjs/src/validate.js
CHANGED
|
@@ -141,6 +141,9 @@ function enumerateBasicResolvers(resolver, path) {
|
|
|
141
141
|
visit(resolver, path);
|
|
142
142
|
return results;
|
|
143
143
|
}
|
|
144
|
+
const isValidAgentMutation = (projectSchema, mutationName) => {
|
|
145
|
+
return Boolean(projectSchema['ai-experimental']?.agents?.[mutationName]);
|
|
146
|
+
};
|
|
144
147
|
const validateAIToolConfig = (projectSchema, getNamespace, tool, basePath) => {
|
|
145
148
|
const toolRef = (0, ai_tools_1.getToolRef)(tool);
|
|
146
149
|
const path = typeof tool === 'string' ? basePath : basePath.concat('ref');
|
|
@@ -164,6 +167,9 @@ const validateAIToolConfig = (projectSchema, getNamespace, tool, basePath) => {
|
|
|
164
167
|
};
|
|
165
168
|
}
|
|
166
169
|
const property = (0, get_js_1.default)(projectSchema, propertyPath);
|
|
170
|
+
if (propertyPath[0] === 'mutations' && isValidAgentMutation(projectSchema, propertyPath[1])) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
167
173
|
if (!property) {
|
|
168
174
|
return {
|
|
169
175
|
type: 'notFound',
|
package/dist/esm/src/agents.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import upperFirst from 'lodash/upperFirst.js';
|
|
2
|
+
import uniq from 'lodash/uniq.js';
|
|
3
|
+
import uniqBy from 'lodash/uniqBy.js';
|
|
2
4
|
export const END_AGENT_EXECUTION = 'endAgentExecution';
|
|
3
5
|
export const BUILT_IN_CHAT_ARGS = [
|
|
4
6
|
{
|
|
@@ -47,3 +49,84 @@ export const getAgentEndStates = (agent, includeSuspend = false) => {
|
|
|
47
49
|
export const getInspectAgentSessionQueryName = (agentName) => {
|
|
48
50
|
return `inspect${upperFirst(agentName)}`;
|
|
49
51
|
};
|
|
52
|
+
export const removeBuiltInArgs = (args) => {
|
|
53
|
+
return args.filter(arg => !BUILT_IN_CHAT_ARG_NAMES.includes(arg.argName));
|
|
54
|
+
};
|
|
55
|
+
export const createArgs = (agent) => {
|
|
56
|
+
let apiArguments = uniqBy(agent.api.arguments ?? [], arg => arg.argName);
|
|
57
|
+
if (agent.api.type === 'chat') {
|
|
58
|
+
apiArguments = removeBuiltInArgs(apiArguments).concat(BUILT_IN_CHAT_ARGS);
|
|
59
|
+
}
|
|
60
|
+
return apiArguments.length > 0
|
|
61
|
+
? {
|
|
62
|
+
type: 'object',
|
|
63
|
+
properties: apiArguments.reduce((acc, argument) => {
|
|
64
|
+
acc[argument.argName] = {
|
|
65
|
+
type: argument.argType === 'sessionId' ? 'string' : argument.argType
|
|
66
|
+
};
|
|
67
|
+
return acc;
|
|
68
|
+
}, {}),
|
|
69
|
+
required: apiArguments.filter(arg => arg.required).map(arg => arg.argName)
|
|
70
|
+
}
|
|
71
|
+
: undefined;
|
|
72
|
+
};
|
|
73
|
+
export function addAiQueries(projectSchema) {
|
|
74
|
+
const agents = projectSchema['ai-experimental']?.agents;
|
|
75
|
+
if (!agents) {
|
|
76
|
+
return projectSchema;
|
|
77
|
+
}
|
|
78
|
+
const newSchema = {
|
|
79
|
+
...projectSchema,
|
|
80
|
+
queries: { ...projectSchema.queries },
|
|
81
|
+
mutations: { ...projectSchema.mutations }
|
|
82
|
+
};
|
|
83
|
+
for (const [agentName, agent] of Object.entries(agents)) {
|
|
84
|
+
// Get valid return types based on states that could possibly be the end state
|
|
85
|
+
// TODO In the future the agent will have a return type defined and we will instead validate
|
|
86
|
+
// that all the return states will return the correct shape.
|
|
87
|
+
const returnStates = [...getAgentEndStates(agent, true)];
|
|
88
|
+
const returnTypes = uniq(returnStates.map(stateId => {
|
|
89
|
+
const { execution } = agent.states[stateId];
|
|
90
|
+
if (execution.type === 'chat') {
|
|
91
|
+
return 'TSChatResponse';
|
|
92
|
+
}
|
|
93
|
+
if (execution.type === 'generate') {
|
|
94
|
+
return execution.outputShape ? execution.outputShape : 'string';
|
|
95
|
+
}
|
|
96
|
+
return 'JSON';
|
|
97
|
+
}));
|
|
98
|
+
const shape = returnTypes.length === 0 ? 'string' : returnTypes.length === 1 ? returnTypes[0] : 'JSON';
|
|
99
|
+
if (newSchema.mutations[agentName] !== undefined) {
|
|
100
|
+
throw new Error(`Schema already has a mutation with the name ${agentName}`);
|
|
101
|
+
}
|
|
102
|
+
newSchema.mutations[agentName] = {
|
|
103
|
+
description: agent.description,
|
|
104
|
+
args: createArgs(agent),
|
|
105
|
+
shape,
|
|
106
|
+
resolver: {
|
|
107
|
+
name: 'ai:runAgent',
|
|
108
|
+
agentName
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
if (shape === 'TSChatResponse') {
|
|
112
|
+
newSchema.queries[getInspectAgentSessionQueryName(agentName)] ||= {
|
|
113
|
+
description: `Inspect a session for the ${agentName} agent`,
|
|
114
|
+
args: {
|
|
115
|
+
type: 'object',
|
|
116
|
+
properties: {
|
|
117
|
+
sessionId: {
|
|
118
|
+
type: 'string'
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
required: ['sessionId']
|
|
122
|
+
},
|
|
123
|
+
shape: 'TSAgentSession',
|
|
124
|
+
resolver: {
|
|
125
|
+
name: 'ai:inspectAgentSession',
|
|
126
|
+
agentName
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return newSchema;
|
|
132
|
+
}
|
package/dist/esm/src/index.js
CHANGED