@takeshape/schema 11.63.7 → 11.66.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.
@@ -0,0 +1,323 @@
1
+ import jsep from 'jsep';
2
+ // Default operator precedence from https://github.com/EricSmekens/jsep/blob/master/src/jsep.js#L55
3
+ const DEFAULT_PRECEDENCE = {
4
+ '||': 1,
5
+ '&&': 2,
6
+ '|': 3,
7
+ '^': 4,
8
+ '&': 5,
9
+ '==': 6,
10
+ '!=': 6,
11
+ '===': 6,
12
+ '!==': 6,
13
+ '<': 7,
14
+ '>': 7,
15
+ '<=': 7,
16
+ '>=': 7,
17
+ '<<': 8,
18
+ '>>': 8,
19
+ '>>>': 8,
20
+ '+': 9,
21
+ '-': 9,
22
+ '*': 10,
23
+ '/': 10,
24
+ '%': 10
25
+ };
26
+ /**
27
+ * Evaluation code from JSEP project, under MIT License.
28
+ * Copyright (c) 2013 Stephen Oney, http://jsep.from.so/
29
+ */
30
+ const binops = {
31
+ // '|'(a, b) {
32
+ // return a | b;
33
+ // },
34
+ // '^'(a, b) {
35
+ // return a ^ b;
36
+ // },
37
+ // '&'(a, b) {
38
+ // return a & b;
39
+ // },
40
+ '=='(a, b) {
41
+ // biome-ignore lint/suspicious/noDoubleEquals: <explanation>
42
+ return a == b;
43
+ },
44
+ '!='(a, b) {
45
+ // biome-ignore lint/suspicious/noDoubleEquals: <explanation>
46
+ return a != b;
47
+ },
48
+ '==='(a, b) {
49
+ return a === b;
50
+ },
51
+ '!=='(a, b) {
52
+ return a !== b;
53
+ },
54
+ '<'(a, b) {
55
+ return a < b;
56
+ },
57
+ '>'(a, b) {
58
+ return a > b;
59
+ },
60
+ '<='(a, b) {
61
+ return a <= b;
62
+ },
63
+ '>='(a, b) {
64
+ return a >= b;
65
+ },
66
+ // '<<'(a, b) {
67
+ // return a << b;
68
+ // },
69
+ // '>>'(a, b) {
70
+ // return a >> b;
71
+ // },
72
+ // '>>>'(a, b) {
73
+ // return a >>> b;
74
+ // },
75
+ '+'(a, b) {
76
+ // eslint-disable-next-line @typescript-eslint/restrict-plus-operands
77
+ return a + b;
78
+ },
79
+ '-'(a, b) {
80
+ return a - b;
81
+ },
82
+ '*'(a, b) {
83
+ return a * b;
84
+ },
85
+ '/'(a, b) {
86
+ return a / b;
87
+ },
88
+ '%'(a, b) {
89
+ return a % b;
90
+ }
91
+ };
92
+ const unops = {
93
+ '-'(a) {
94
+ return -a;
95
+ },
96
+ '+'(a) {
97
+ return Number(a);
98
+ },
99
+ // '~'(a) {
100
+ // return ~a;
101
+ // },
102
+ '!'(a) {
103
+ return !a;
104
+ }
105
+ };
106
+ function evaluateArray(list, context) {
107
+ return list.map((v) => (v ? evaluate(v, context) : undefined));
108
+ }
109
+ function isObject(x) {
110
+ return Boolean(x) && typeof x === 'object';
111
+ }
112
+ export const METHODS_NOT_SUPPORTED = 'Methods are not supported in expressions';
113
+ export const THIS_NOT_SUPPORTED = 'This is not supported in expressions';
114
+ function evaluateMember(node, context) {
115
+ const object = evaluate(node.object, context);
116
+ let key;
117
+ if (node.computed) {
118
+ key = evaluate(node.property, context);
119
+ }
120
+ else {
121
+ key = node.property.name;
122
+ }
123
+ if (typeof key === 'string' && /^__proto__|prototype|constructor$/.test(key)) {
124
+ throw Error(`Access to member "${key}" disallowed.`);
125
+ }
126
+ if (isObject(object) && Object.hasOwn(object, key)) {
127
+ return [object, object[key]];
128
+ }
129
+ }
130
+ function evaluate(_node, context) {
131
+ const node = _node;
132
+ switch (node.type) {
133
+ case 'ArrayExpression':
134
+ return evaluateArray(node.elements, context);
135
+ case 'CallExpression': {
136
+ if (node.callee.type === 'MemberExpression') {
137
+ throw Error(METHODS_NOT_SUPPORTED);
138
+ }
139
+ const fn = evaluate(node.callee, context);
140
+ if (typeof fn !== 'function') {
141
+ return undefined;
142
+ }
143
+ return fn.apply(null, evaluateArray(node.arguments, context));
144
+ }
145
+ case 'ConditionalExpression':
146
+ return evaluate(node.test, context) ? evaluate(node.consequent, context) : evaluate(node.alternate, context);
147
+ case 'Identifier':
148
+ return context[node.name];
149
+ case 'Literal':
150
+ return node.value;
151
+ case 'BinaryExpression': {
152
+ if (node.operator === '||') {
153
+ return evaluate(node.left, context) || evaluate(node.right, context);
154
+ }
155
+ if (node.operator === '&&') {
156
+ return evaluate(node.left, context) && evaluate(node.right, context);
157
+ }
158
+ const op = binops[node.operator];
159
+ if (!op) {
160
+ throw new Error(`Unsupported operator ${node.operator}`);
161
+ }
162
+ return op(evaluate(node.left, context), evaluate(node.right, context));
163
+ }
164
+ case 'UnaryExpression': {
165
+ const op = unops[node.operator];
166
+ if (!op) {
167
+ throw new Error(`Unsupported operator ${node.operator}`);
168
+ }
169
+ return op(evaluate(node.argument, context));
170
+ }
171
+ case 'MemberExpression':
172
+ return evaluateMember(node, context)?.[1];
173
+ case 'ThisExpression':
174
+ return context;
175
+ // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
176
+ default:
177
+ return undefined;
178
+ }
179
+ }
180
+ export function parseExpression(expression) {
181
+ return jsep(expression);
182
+ }
183
+ function validateAST(options, rootNode) {
184
+ const validate = (_node, parent, parentKey) => {
185
+ const node = _node;
186
+ // eslint-disable-next-line default-case
187
+ switch (node.type) {
188
+ case 'ArrayExpression':
189
+ return node.elements.flatMap((v) => (v ? validate(v, node, 'elements') : []));
190
+ case 'CallExpression': {
191
+ if (node.callee.type === 'MemberExpression') {
192
+ return [{ message: METHODS_NOT_SUPPORTED }];
193
+ }
194
+ return [
195
+ ...validate(node.callee, node, 'callee'),
196
+ ...node.arguments.flatMap((v) => (v ? validate(v, node, 'arguments') : []))
197
+ ];
198
+ }
199
+ case 'ConditionalExpression':
200
+ return [
201
+ ...validate(node.test, node, 'test'),
202
+ ...validate(node.consequent, node, 'consequent'),
203
+ ...validate(node.alternate, node, 'alternate')
204
+ ];
205
+ case 'Identifier': {
206
+ const errors = [];
207
+ if (parent?.type === 'CallExpression' && parentKey === 'callee' && options.allowedFunctions) {
208
+ if (!options.allowedFunctions.includes(node.name)) {
209
+ errors.push({ message: `Unknown function "${node.name}"` });
210
+ }
211
+ }
212
+ else {
213
+ if (parent?.type === 'MemberExpression' && !parent.computed && parentKey === 'property') {
214
+ return errors;
215
+ }
216
+ if (options.allowedVars && !options.allowedVars.includes(node.name)) {
217
+ errors.push({ message: `Unknown variable "${node.name}"` });
218
+ }
219
+ }
220
+ return errors;
221
+ }
222
+ case 'Literal':
223
+ return [];
224
+ case 'BinaryExpression': {
225
+ const op = binops[node.operator];
226
+ if (!op) {
227
+ throw new Error(`Unsupported operator ${node.operator}`);
228
+ }
229
+ return [...validate(node.left, node, 'left'), ...validate(node.right, node, 'right')];
230
+ }
231
+ case 'UnaryExpression': {
232
+ const op = unops[node.operator];
233
+ if (!op) {
234
+ return [{ message: `Unsupported operator ${node.operator}` }];
235
+ }
236
+ return validate(node.argument, node, 'argument');
237
+ }
238
+ case 'MemberExpression':
239
+ return [
240
+ ...validate(node.object, node, 'object'),
241
+ ...(node.computed ? validate(node.property, node, 'property') : [])
242
+ ];
243
+ case 'ThisExpression':
244
+ return [{ message: THIS_NOT_SUPPORTED }];
245
+ }
246
+ };
247
+ return validate(rootNode, undefined, undefined);
248
+ }
249
+ const contextKeys = [
250
+ 'previousStateOutput',
251
+ 'currentStateId',
252
+ 'previousStateId',
253
+ 'stateOutputs',
254
+ 'currentStateOutput',
255
+ 'sessionMemory',
256
+ 'claims',
257
+ 'args',
258
+ 'vars'
259
+ ];
260
+ export function validateExpression(expression) {
261
+ try {
262
+ const ast = parseExpression(expression);
263
+ const errors = validateAST({
264
+ allowedVars: contextKeys,
265
+ allowedFunctions: ['contains']
266
+ }, ast);
267
+ if (errors.length) {
268
+ return {
269
+ valid: false,
270
+ errors: errors.map((e) => e.message)
271
+ };
272
+ }
273
+ return { valid: true };
274
+ }
275
+ catch (e) {
276
+ return { valid: false, errors: [e.message] };
277
+ }
278
+ }
279
+ export function compileExpression(expression) {
280
+ const ast = parseExpression(expression);
281
+ return (context) => evaluate(ast, context);
282
+ }
283
+ export function expressionToString(_node, parent) {
284
+ if (!_node) {
285
+ return '';
286
+ }
287
+ const node = _node;
288
+ if (node.type === 'BinaryExpression') {
289
+ const wrap = parent?.type === 'BinaryExpression' && DEFAULT_PRECEDENCE[parent.operator] > DEFAULT_PRECEDENCE[node.operator];
290
+ const str = `${expressionToString(node.left, node)} ${node.operator} ${expressionToString(node.right, node)}`;
291
+ return wrap ? `(${str})` : str;
292
+ }
293
+ if (node.type === 'CallExpression') {
294
+ const args = node.arguments.map((arg) => expressionToString(arg, node));
295
+ return `${expressionToString(node.callee, node)}(${args.join(', ')})`;
296
+ }
297
+ if (node.type === 'UnaryExpression') {
298
+ return node.operator + expressionToString(node.argument, node);
299
+ }
300
+ if (node.type === 'MemberExpression') {
301
+ if (node.computed) {
302
+ return `${expressionToString(node.object, node)}[${expressionToString(node.property, node)}]`;
303
+ }
304
+ return `${expressionToString(node.object, node)}.${expressionToString(node.property, node)}`;
305
+ }
306
+ if (node.type === 'ArrayExpression') {
307
+ const arr = node.elements.map((element) => expressionToString(element, node)).join(',');
308
+ return `[${arr}]`;
309
+ }
310
+ if (node.type === 'Literal') {
311
+ return node.raw;
312
+ }
313
+ if (node.type === 'Identifier') {
314
+ return node.name;
315
+ }
316
+ if (node.type === 'ConditionalExpression') {
317
+ return `${expressionToString(node.test, node)} ? ${expressionToString(node.consequent, node)} : ${expressionToString(node.alternate, node)}`;
318
+ }
319
+ if (node.type === 'ThisExpression') {
320
+ return 'this';
321
+ }
322
+ return '';
323
+ }
@@ -22,7 +22,7 @@ import { isLatestProjectSchemaJSON } from "../project-schema/index.js";
22
22
  import { atRefToRefItem, createGetNamespace, getRefShapeName, parsePropertyRef, propertyRefItemToPath, propertyRefItemToResolverPath, refItemToAtRef, refItemToNamespacedShapeName, refItemToShape } from "../refs.js";
23
23
  import { getRelationship } from "../relationships.js";
24
24
  import { scalars } from "../scalars.js";
25
- import { getAllRefs } from "../schema-util.js";
25
+ import { getAllRefs, isBuiltinMutation, isBuiltinQuery } from "../schema-util.js";
26
26
  import authSchemas from '../schemas/auth-schemas.json' with { type: 'json' };
27
27
  import { allProjectSchemas } from "../schemas/index.js";
28
28
  import { isValidTemplate } from "../template-shapes/index.js";
@@ -30,6 +30,7 @@ import { legacyProjectSchemaImportOptionalProps, projectSchemaImportOptionalProp
30
30
  import { isAIResolver, isBasicResolver, isComposeResolver, isExtendsSchema, isObjectSchema } from "../types/utils.js";
31
31
  import { isUnionSchema } from "../unions.js";
32
32
  import { getToolRef } from "../util/ai-tools.js";
33
+ import { validateExpression } from "../util/expressions.js";
33
34
  import { getShape } from "../util/shapes.js";
34
35
  import { CURRENT_SCHEMA_VERSION, LEGACY_API_VERSION, LEGACY_SCHEMA_VERSION } from "../versions.js";
35
36
  import { defaultWorkflow } from "../workflows.js";
@@ -162,6 +163,10 @@ const validateAIToolConfig = (projectSchema, getNamespace, tool, basePath) => {
162
163
  if (parsed.serviceId !== 'local') {
163
164
  return;
164
165
  }
166
+ if ((parsed.shapeName === 'Query' && isBuiltinQuery(parsed.propertyName)) ||
167
+ (parsed.shapeName === 'Mutation' && isBuiltinMutation(parsed.propertyName))) {
168
+ return;
169
+ }
165
170
  const propertyPath = propertyRefItemToPath(getNamespace, parsed);
166
171
  if (propertyPath[0] !== 'queries' && propertyPath[0] !== 'mutations') {
167
172
  return {
@@ -834,6 +839,45 @@ function validateAgents(projectSchema) {
834
839
  else {
835
840
  stateNames.add(state.name);
836
841
  }
842
+ if (state.variables) {
843
+ state.variables.forEach((variable, variableIndex) => {
844
+ variable.steps.forEach((step, stepIndex) => {
845
+ const stepPath = [...statePath, 'variables', variableIndex, 'steps', stepIndex];
846
+ if (step.condition) {
847
+ const conditionValidation = validateExpression(step.condition);
848
+ if (!conditionValidation.valid) {
849
+ const common = {
850
+ path: [...stepPath, 'condition'],
851
+ type: 'conflict'
852
+ };
853
+ errors.push(...conditionValidation.errors.map((message) => ({ ...common, message })));
854
+ }
855
+ }
856
+ const exprValidation = validateExpression(step.expression);
857
+ if (!exprValidation.valid) {
858
+ const common = {
859
+ path: [...stepPath, 'expression'],
860
+ type: 'conflict'
861
+ };
862
+ errors.push(...exprValidation.errors.map((message) => ({ ...common, message })));
863
+ }
864
+ });
865
+ });
866
+ }
867
+ if (state.transition) {
868
+ state.transition.forEach((transition, transitionIndex) => {
869
+ if (transition.condition) {
870
+ const conditionValidation = validateExpression(transition.condition);
871
+ if (!conditionValidation.valid) {
872
+ const common = {
873
+ path: [...statePath, 'transition', transitionIndex, 'expression'],
874
+ type: 'conflict'
875
+ };
876
+ errors.push(...conditionValidation.errors.map((message) => ({ ...common, message })));
877
+ }
878
+ }
879
+ });
880
+ }
837
881
  if (state.execution.type === 'generate' || state.execution.type === 'chat') {
838
882
  if (!state.execution.tools) {
839
883
  continue;
@@ -199,9 +199,6 @@
199
199
  "start": {
200
200
  "transition": [
201
201
  {
202
- "condition": {
203
- "type": "none"
204
- },
205
202
  "destination": "bbb"
206
203
  }
207
204
  ]
@@ -219,13 +216,10 @@
219
216
  "name": "input",
220
217
  "steps": [
221
218
  {
222
- "type": "stateOutput",
223
- "stateId": "ccc",
224
- "path": "dogName"
219
+ "expression": "stateOutputs['ccc'].dogName"
225
220
  },
226
221
  {
227
- "type": "graphqlArg",
228
- "argName": "input"
222
+ "expression": "args.input"
229
223
  }
230
224
  ]
231
225
  }
@@ -233,13 +227,10 @@
233
227
  "execution": {
234
228
  "type": "graphql",
235
229
  "query": "query ($input: String!) {\n getDogList(terms: $input) {\n items {\n name\n color\n }\n }\n}\n",
236
- "path": "getDogList.items"
230
+ "path": "getDogList.items[0]"
237
231
  },
238
232
  "transition": [
239
233
  {
240
- "condition": {
241
- "type": "none"
242
- },
243
234
  "destination": "ccc"
244
235
  }
245
236
  ]
@@ -247,11 +238,19 @@
247
238
  "ccc": {
248
239
  "name": "answer",
249
240
  "variables": [
241
+ {
242
+ "name": "input",
243
+ "steps": [
244
+ {
245
+ "expression": "args.input"
246
+ }
247
+ ]
248
+ },
250
249
  {
251
250
  "name": "results",
252
251
  "steps": [
253
252
  {
254
- "type": "previousStateOutput"
253
+ "expression": "previousStateOutput"
255
254
  }
256
255
  ]
257
256
  }
@@ -268,24 +267,14 @@
268
267
  },
269
268
  "transition": [
270
269
  {
271
- "condition": {
272
- "type": "stateOutput",
273
- "stateId": "ccc",
274
- "path": "answered"
275
- },
270
+ "condition": "stateOutputs['ccc'].answered",
276
271
  "destination": "ddd"
277
272
  },
278
273
  {
279
- "condition": {
280
- "type": "none"
281
- },
282
274
  "limit": 3,
283
275
  "destination": "bbb"
284
276
  },
285
277
  {
286
- "condition": {
287
- "type": "none"
288
- },
289
278
  "destination": "eee"
290
279
  }
291
280
  ]
@@ -297,8 +286,7 @@
297
286
  "name": "results",
298
287
  "steps": [
299
288
  {
300
- "type": "previousStateOutput",
301
- "path": "message"
289
+ "expression": "previousStateOutput.message"
302
290
  }
303
291
  ]
304
292
  }
@@ -321,8 +309,7 @@
321
309
  "name": "results",
322
310
  "steps": [
323
311
  {
324
- "type": "previousStateOutput",
325
- "path": "message"
312
+ "expression": "previousStateOutput.message"
326
313
  }
327
314
  ]
328
315
  }
@@ -348,9 +335,6 @@
348
335
  "start": {
349
336
  "transition": [
350
337
  {
351
- "condition": {
352
- "type": "none"
353
- },
354
338
  "destination": "3pjuyB47X"
355
339
  }
356
340
  ]
@@ -369,17 +353,10 @@
369
353
  },
370
354
  "transition": [
371
355
  {
372
- "condition": {
373
- "type": "stringContains",
374
- "string": "ALL_DONE",
375
- "path": "content"
376
- },
356
+ "condition": "contains(currentStateOutput.content, 'ALL_DONE')",
377
357
  "destination": "endAgentExecution"
378
358
  },
379
359
  {
380
- "condition": {
381
- "type": "none"
382
- },
383
360
  "destination": "3pjuyB47X",
384
361
  "suspend": true
385
362
  }
@@ -181,9 +181,6 @@
181
181
  "start": {
182
182
  "transition": [
183
183
  {
184
- "condition": {
185
- "type": "none"
186
- },
187
184
  "destination": "bbb"
188
185
  }
189
186
  ]
@@ -201,13 +198,10 @@
201
198
  "name": "input",
202
199
  "steps": [
203
200
  {
204
- "type": "stateOutput",
205
- "stateId": "ccc",
206
- "path": "dogName"
201
+ "expression": "stateOutputs['ccc'].dogName"
207
202
  },
208
203
  {
209
- "type": "graphqlArg",
210
- "argName": "input"
204
+ "expression": "args.input"
211
205
  }
212
206
  ]
213
207
  }
@@ -215,16 +209,32 @@
215
209
  "execution": {
216
210
  "type": "graphql",
217
211
  "query": "query ($input: String!) {\n getDogList(terms: $input) {\n items {\n name\n color\n }\n }\n}\n",
218
- "path": "getDogList.items"
212
+ "path": "getDogList.items[0]"
219
213
  },
220
- "transition": [{ "condition": { "type": "none" }, "destination": "ccc" }]
214
+ "transition": [
215
+ {
216
+ "destination": "ccc"
217
+ }
218
+ ]
221
219
  },
222
220
  "ccc": {
223
221
  "name": "answer",
224
222
  "variables": [
223
+ {
224
+ "name": "input",
225
+ "steps": [
226
+ {
227
+ "expression": "args.input"
228
+ }
229
+ ]
230
+ },
225
231
  {
226
232
  "name": "results",
227
- "steps": [{ "type": "previousStateOutput" }]
233
+ "steps": [
234
+ {
235
+ "expression": "previousStateOutput"
236
+ }
237
+ ]
228
238
  }
229
239
  ],
230
240
  "execution": {
@@ -239,19 +249,16 @@
239
249
  },
240
250
  "transition": [
241
251
  {
242
- "condition": {
243
- "type": "stateOutput",
244
- "stateId": "ccc",
245
- "path": "answered"
246
- },
252
+ "condition": "stateOutputs['ccc'].answered",
247
253
  "destination": "ddd"
248
254
  },
249
255
  {
250
- "condition": { "type": "none" },
251
256
  "limit": 3,
252
257
  "destination": "bbb"
253
258
  },
254
- { "condition": { "type": "none" }, "destination": "eee" }
259
+ {
260
+ "destination": "eee"
261
+ }
255
262
  ]
256
263
  },
257
264
  "ddd": {
@@ -259,7 +266,11 @@
259
266
  "variables": [
260
267
  {
261
268
  "name": "results",
262
- "steps": [{ "type": "previousStateOutput", "path": "message" }]
269
+ "steps": [
270
+ {
271
+ "expression": "previousStateOutput.message"
272
+ }
273
+ ]
263
274
  }
264
275
  ],
265
276
  "execution": {
@@ -278,7 +289,11 @@
278
289
  "variables": [
279
290
  {
280
291
  "name": "results",
281
- "steps": [{ "type": "previousStateOutput", "path": "message" }]
292
+ "steps": [
293
+ {
294
+ "expression": "previousStateOutput.message"
295
+ }
296
+ ]
282
297
  }
283
298
  ],
284
299
  "execution": {
@@ -302,9 +317,6 @@
302
317
  "start": {
303
318
  "transition": [
304
319
  {
305
- "condition": {
306
- "type": "none"
307
- },
308
320
  "destination": "3pjuyB47X"
309
321
  }
310
322
  ]
@@ -323,17 +335,10 @@
323
335
  },
324
336
  "transition": [
325
337
  {
326
- "condition": {
327
- "type": "stringContains",
328
- "string": "ALL_DONE",
329
- "path": "content"
330
- },
338
+ "condition": "contains(currentStateOutput.content, 'ALL_DONE')",
331
339
  "destination": "endAgentExecution"
332
340
  },
333
341
  {
334
- "condition": {
335
- "type": "none"
336
- },
337
342
  "destination": "3pjuyB47X",
338
343
  "suspend": true
339
344
  }