@ax-llm/ax 11.0.67 → 12.0.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/index.js CHANGED
@@ -6560,6 +6560,11 @@ var extractValues = (sig, values, content) => {
6560
6560
  const xstate = { extractedFields: [], streamedIndex: {}, s: -1 };
6561
6561
  streamingExtractValues(sig, values, xstate, content);
6562
6562
  streamingExtractFinalValue(sig, values, xstate, content);
6563
+ for (const field of sig.getOutputFields()) {
6564
+ if (field.isInternal) {
6565
+ delete values[field.name];
6566
+ }
6567
+ }
6563
6568
  };
6564
6569
  var checkMissingRequiredFields = (xstate, values, currentIndex) => {
6565
6570
  const missingFields = [];
@@ -7285,93 +7290,218 @@ var AxInstanceRegistry = class {
7285
7290
  // dsp/sig.ts
7286
7291
  import { createHash } from "crypto";
7287
7292
 
7293
+ // dsp/globals.ts
7294
+ var axGlobals = {
7295
+ signatureStrict: true
7296
+ // Controls reservedNames enforcement in signature parsing/validation
7297
+ };
7298
+
7288
7299
  // dsp/parser.ts
7300
+ var SignatureValidationError = class extends Error {
7301
+ constructor(message, position, context3, suggestion) {
7302
+ super(message);
7303
+ this.position = position;
7304
+ this.context = context3;
7305
+ this.suggestion = suggestion;
7306
+ this.name = "SignatureValidationError";
7307
+ }
7308
+ };
7289
7309
  var SignatureParser = class {
7290
7310
  input;
7291
7311
  position;
7292
7312
  currentFieldName = null;
7313
+ currentSection = "description";
7293
7314
  constructor(input) {
7294
- this.input = input;
7315
+ this.input = input.trim();
7295
7316
  this.position = 0;
7317
+ if (!this.input) {
7318
+ throw new SignatureValidationError(
7319
+ "Empty signature provided",
7320
+ 0,
7321
+ "",
7322
+ 'A signature must contain at least input and output fields separated by "->". Example: "userQuery:string -> aiResponse:string"'
7323
+ );
7324
+ }
7296
7325
  }
7297
7326
  parse() {
7298
7327
  try {
7299
7328
  this.skipWhitespace();
7300
7329
  const optionalDesc = this.parseParsedString();
7301
7330
  this.skipWhitespace();
7331
+ this.currentSection = "inputs";
7302
7332
  const inputs = this.parseFieldList(
7303
7333
  this.parseInputField.bind(this),
7304
7334
  "input"
7305
7335
  );
7306
7336
  this.skipWhitespace();
7307
7337
  if (this.position >= this.input.length) {
7308
- throw new Error(
7309
- 'Incomplete signature: Missing output section. Expected "->" followed by output fields'
7338
+ throw new SignatureValidationError(
7339
+ "Incomplete signature: Missing output section",
7340
+ this.position,
7341
+ this.getErrorContext(),
7342
+ 'Add "->" followed by output fields. Example: "-> responseText:string"'
7310
7343
  );
7311
7344
  }
7312
- this.expect("->");
7345
+ this.expectArrow();
7313
7346
  this.skipWhitespace();
7314
7347
  if (this.position >= this.input.length) {
7315
- throw new Error(
7316
- 'Incomplete signature: No output fields specified after "->"'
7348
+ throw new SignatureValidationError(
7349
+ 'Incomplete signature: No output fields specified after "->"',
7350
+ this.position,
7351
+ this.getErrorContext(),
7352
+ 'Add at least one output field. Example: "-> responseText:string"'
7317
7353
  );
7318
7354
  }
7355
+ this.currentSection = "outputs";
7319
7356
  const outputs = this.parseFieldList(
7320
7357
  this.parseOutputField.bind(this),
7321
7358
  "output"
7322
7359
  );
7360
+ this.skipWhitespace();
7361
+ if (this.position < this.input.length) {
7362
+ const remaining = this.input.slice(this.position);
7363
+ throw new SignatureValidationError(
7364
+ `Unexpected content after signature: "${remaining}"`,
7365
+ this.position,
7366
+ this.getErrorContext(),
7367
+ "Remove any extra content after the output fields"
7368
+ );
7369
+ }
7370
+ this.validateParsedSignature({
7371
+ desc: optionalDesc?.trim(),
7372
+ inputs,
7373
+ outputs
7374
+ });
7323
7375
  return {
7324
7376
  desc: optionalDesc?.trim(),
7325
7377
  inputs,
7326
7378
  outputs
7327
7379
  };
7328
7380
  } catch (error) {
7381
+ if (error instanceof SignatureValidationError) {
7382
+ throw error;
7383
+ }
7329
7384
  const errorMessage = error instanceof Error ? error.message : "Unknown error";
7330
- const context3 = this.getErrorContext();
7331
- throw new Error(`${errorMessage}
7332
- ${context3}`);
7385
+ throw new SignatureValidationError(
7386
+ errorMessage,
7387
+ this.position,
7388
+ this.getErrorContext()
7389
+ );
7390
+ }
7391
+ }
7392
+ validateParsedSignature(signature) {
7393
+ const inputNames = /* @__PURE__ */ new Set();
7394
+ for (const field of signature.inputs) {
7395
+ if (inputNames.has(field.name)) {
7396
+ throw new SignatureValidationError(
7397
+ `Duplicate input field name: "${field.name}"`,
7398
+ 0,
7399
+ "",
7400
+ "Each field name must be unique within the signature"
7401
+ );
7402
+ }
7403
+ inputNames.add(field.name);
7404
+ }
7405
+ const outputNames = /* @__PURE__ */ new Set();
7406
+ for (const field of signature.outputs) {
7407
+ if (outputNames.has(field.name)) {
7408
+ throw new SignatureValidationError(
7409
+ `Duplicate output field name: "${field.name}"`,
7410
+ 0,
7411
+ "",
7412
+ "Each field name must be unique within the signature"
7413
+ );
7414
+ }
7415
+ outputNames.add(field.name);
7416
+ }
7417
+ for (const outputField of signature.outputs) {
7418
+ if (inputNames.has(outputField.name)) {
7419
+ throw new SignatureValidationError(
7420
+ `Field name "${outputField.name}" appears in both inputs and outputs`,
7421
+ 0,
7422
+ "",
7423
+ "Use different names for input and output fields to avoid confusion"
7424
+ );
7425
+ }
7426
+ }
7427
+ if (signature.inputs.length === 0) {
7428
+ throw new SignatureValidationError(
7429
+ "Signature must have at least one input field",
7430
+ 0,
7431
+ "",
7432
+ 'Add an input field before "->". Example: "userInput:string -> ..."'
7433
+ );
7434
+ }
7435
+ if (signature.outputs.length === 0) {
7436
+ throw new SignatureValidationError(
7437
+ "Signature must have at least one output field",
7438
+ 0,
7439
+ "",
7440
+ 'Add an output field after "->". Example: "... -> responseText:string"'
7441
+ );
7333
7442
  }
7334
7443
  }
7335
7444
  getErrorContext() {
7336
- const start = Math.max(0, this.position - 20);
7337
- const end = Math.min(this.input.length, this.position + 20);
7445
+ const start = Math.max(0, this.position - 25);
7446
+ const end = Math.min(this.input.length, this.position + 25);
7338
7447
  const before = this.input.slice(start, this.position);
7339
7448
  const after = this.input.slice(this.position, end);
7340
7449
  const pointer = " ".repeat(before.length) + "^";
7341
- return `Near position ${this.position}:
7342
- ${before}${after}
7343
- ${pointer}`;
7450
+ const lines = [
7451
+ `Position ${this.position} in signature:`,
7452
+ `"${before}${after}"`,
7453
+ ` ${pointer}`
7454
+ ];
7455
+ return lines.join("\n");
7344
7456
  }
7345
7457
  parseFieldList(parseFieldFn, section) {
7346
7458
  const fields = [];
7347
7459
  this.skipWhitespace();
7348
7460
  if (this.position >= this.input.length) {
7349
- throw new Error(`Empty ${section} section: Expected at least one field`);
7461
+ throw new SignatureValidationError(
7462
+ `Empty ${section} section: Expected at least one field`,
7463
+ this.position,
7464
+ this.getErrorContext(),
7465
+ `Add a ${section} field. Example: ${section === "input" ? "userInput:string" : "responseText:string"}`
7466
+ );
7350
7467
  }
7351
7468
  try {
7352
7469
  fields.push(parseFieldFn());
7353
7470
  } catch (error) {
7354
- throw new Error(
7355
- `Invalid first ${section} field: ${error instanceof Error ? error.message : "Unknown error"}`
7471
+ if (error instanceof SignatureValidationError) {
7472
+ throw error;
7473
+ }
7474
+ throw new SignatureValidationError(
7475
+ `Invalid first ${section} field: ${error instanceof Error ? error.message : "Unknown error"}`,
7476
+ this.position,
7477
+ this.getErrorContext()
7356
7478
  );
7357
7479
  }
7358
7480
  this.skipWhitespace();
7359
7481
  while (this.position < this.input.length) {
7360
- if (this.input[this.position] === "-" && this.input[this.position + 1] === ">") {
7482
+ if (this.input[this.position] === "-" && this.position + 1 < this.input.length && this.input[this.position + 1] === ">") {
7361
7483
  break;
7362
7484
  }
7363
7485
  if (this.match(",")) {
7364
7486
  this.skipWhitespace();
7365
7487
  if (this.position >= this.input.length) {
7366
- throw new Error(
7367
- `Unexpected end of input after comma in ${section} section`
7488
+ throw new SignatureValidationError(
7489
+ `Unexpected end of input after comma in ${section} section`,
7490
+ this.position,
7491
+ this.getErrorContext(),
7492
+ `Add another ${section} field after the comma`
7368
7493
  );
7369
7494
  }
7370
7495
  try {
7371
7496
  fields.push(parseFieldFn());
7372
7497
  } catch (error) {
7373
- throw new Error(
7374
- `Invalid ${section} field after comma: ${error instanceof Error ? error.message : "Unknown error"}`
7498
+ if (error instanceof SignatureValidationError) {
7499
+ throw error;
7500
+ }
7501
+ throw new SignatureValidationError(
7502
+ `Invalid ${section} field after comma: ${error instanceof Error ? error.message : "Unknown error"}`,
7503
+ this.position,
7504
+ this.getErrorContext()
7375
7505
  );
7376
7506
  }
7377
7507
  this.skipWhitespace();
@@ -7388,6 +7518,7 @@ ${pointer}`;
7388
7518
  this.skipWhitespace();
7389
7519
  const name = this.parseParsedIdentifier();
7390
7520
  this.currentFieldName = name;
7521
+ this.validateFieldName(name, "input");
7391
7522
  let isOptional = void 0;
7392
7523
  while (true) {
7393
7524
  if (this.match("?")) {
@@ -7395,8 +7526,11 @@ ${pointer}`;
7395
7526
  continue;
7396
7527
  }
7397
7528
  if (this.match("!")) {
7398
- throw new Error(
7399
- `Input field "${name}" does not support the internal marker "!"`
7529
+ throw new SignatureValidationError(
7530
+ `Input field "${name}" cannot use the internal marker "!"`,
7531
+ this.position - 1,
7532
+ this.getErrorContext(),
7533
+ "Internal markers (!) are only allowed on output fields"
7400
7534
  );
7401
7535
  }
7402
7536
  break;
@@ -7406,17 +7540,33 @@ ${pointer}`;
7406
7540
  if (this.match(":")) {
7407
7541
  this.skipWhitespace();
7408
7542
  if (/^class\b/.test(this.input.slice(this.position))) {
7409
- throw new Error(
7410
- `Input field "${name}" does not support the "class" type`
7543
+ throw new SignatureValidationError(
7544
+ `Input field "${name}" cannot use the "class" type`,
7545
+ this.position,
7546
+ this.getErrorContext(),
7547
+ 'Class types are only allowed on output fields. Use "string" type for input classifications'
7411
7548
  );
7412
7549
  } else {
7413
7550
  try {
7414
7551
  const typeName = this.parseTypeNotClass();
7415
7552
  const isArray = this.match("[]");
7416
7553
  type = { name: typeName, isArray };
7554
+ if ((typeName === "image" || typeName === "audio") && isArray) {
7555
+ throw new SignatureValidationError(
7556
+ `Input field "${name}": Arrays of ${typeName} are not supported`,
7557
+ this.position,
7558
+ this.getErrorContext(),
7559
+ `Use a single ${typeName} type instead: "${typeName}"`
7560
+ );
7561
+ }
7417
7562
  } catch (error) {
7418
- throw new Error(
7419
- `Input field "${name}": ${error instanceof Error ? error.message : "Unknown error"}`
7563
+ if (error instanceof SignatureValidationError) {
7564
+ throw error;
7565
+ }
7566
+ throw new SignatureValidationError(
7567
+ `Input field "${name}": ${error instanceof Error ? error.message : "Unknown error"}`,
7568
+ this.position,
7569
+ this.getErrorContext()
7420
7570
  );
7421
7571
  }
7422
7572
  }
@@ -7437,6 +7587,7 @@ ${pointer}`;
7437
7587
  this.skipWhitespace();
7438
7588
  const name = this.parseParsedIdentifier();
7439
7589
  this.currentFieldName = name;
7590
+ this.validateFieldName(name, "output");
7440
7591
  let isOptional = false;
7441
7592
  let isInternal = false;
7442
7593
  while (true) {
@@ -7459,25 +7610,86 @@ ${pointer}`;
7459
7610
  this.skipWhitespace();
7460
7611
  const classNamesString = this.parseParsedString();
7461
7612
  if (!classNamesString) {
7462
- throw new Error(
7463
- `Output field "${name}": Expected class names in quotes after "class" type. Example: class "MyClass1, MyClass2"`
7613
+ throw new SignatureValidationError(
7614
+ `Output field "${name}": Missing class options after "class" type`,
7615
+ this.position,
7616
+ this.getErrorContext(),
7617
+ 'Add class names in quotes. Example: class "positive, negative, neutral"'
7464
7618
  );
7465
7619
  }
7466
7620
  const options = classNamesString.split(/[,\s]+/).map((s2) => s2.trim()).filter((s2) => s2.length > 0);
7467
7621
  if (options.length === 0) {
7468
- throw new Error(
7469
- `Output field "${name}": Empty class list provided. At least one class name is required`
7622
+ throw new SignatureValidationError(
7623
+ `Output field "${name}": Empty class list provided`,
7624
+ this.position,
7625
+ this.getErrorContext(),
7626
+ 'Provide at least one class option. Example: "positive, negative"'
7470
7627
  );
7471
7628
  }
7629
+ if (options.length === 1) {
7630
+ throw new SignatureValidationError(
7631
+ `Output field "${name}": Class type needs at least 2 options`,
7632
+ this.position,
7633
+ this.getErrorContext(),
7634
+ 'Add more class options or use "string" type instead. Example: "positive, negative, neutral"'
7635
+ );
7636
+ }
7637
+ for (const option of options) {
7638
+ if (!/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(option)) {
7639
+ throw new SignatureValidationError(
7640
+ `Output field "${name}": Invalid class option "${option}"`,
7641
+ this.position,
7642
+ this.getErrorContext(),
7643
+ "Class options must start with a letter and contain only letters, numbers, underscores, or hyphens"
7644
+ );
7645
+ }
7646
+ }
7472
7647
  type = { name: "class", isArray, options };
7473
7648
  } else {
7474
7649
  try {
7475
7650
  const typeName = this.parseTypeNotClass();
7476
7651
  const isArray = this.match("[]");
7477
7652
  type = { name: typeName, isArray };
7653
+ if (typeName === "image" && isArray) {
7654
+ throw new SignatureValidationError(
7655
+ `Output field "${name}": Arrays of images are not supported`,
7656
+ this.position,
7657
+ this.getErrorContext(),
7658
+ 'Use a single image type instead: "image"'
7659
+ );
7660
+ }
7661
+ if (typeName === "audio" && isArray) {
7662
+ throw new SignatureValidationError(
7663
+ `Output field "${name}": Arrays of audio are not supported`,
7664
+ this.position,
7665
+ this.getErrorContext(),
7666
+ 'Use a single audio type instead: "audio"'
7667
+ );
7668
+ }
7669
+ if (typeName === "image") {
7670
+ throw new SignatureValidationError(
7671
+ `Output field "${name}": Image type is not supported in output fields`,
7672
+ this.position,
7673
+ this.getErrorContext(),
7674
+ "Image types can only be used in input fields"
7675
+ );
7676
+ }
7677
+ if (typeName === "audio") {
7678
+ throw new SignatureValidationError(
7679
+ `Output field "${name}": Audio type is not supported in output fields`,
7680
+ this.position,
7681
+ this.getErrorContext(),
7682
+ "Audio types can only be used in input fields"
7683
+ );
7684
+ }
7478
7685
  } catch (error) {
7479
- throw new Error(
7480
- `Output field "${name}": ${error instanceof Error ? error.message : "Unknown error"}`
7686
+ if (error instanceof SignatureValidationError) {
7687
+ throw error;
7688
+ }
7689
+ throw new SignatureValidationError(
7690
+ `Output field "${name}": ${error instanceof Error ? error.message : "Unknown error"}`,
7691
+ this.position,
7692
+ this.getErrorContext()
7481
7693
  );
7482
7694
  }
7483
7695
  }
@@ -7492,6 +7704,69 @@ ${pointer}`;
7492
7704
  isInternal
7493
7705
  };
7494
7706
  }
7707
+ validateFieldName(name, fieldType) {
7708
+ if (axGlobals.signatureStrict) {
7709
+ const reservedNames = [
7710
+ "text",
7711
+ "object",
7712
+ "image",
7713
+ "string",
7714
+ "number",
7715
+ "boolean",
7716
+ "json",
7717
+ "array",
7718
+ "datetime",
7719
+ "date",
7720
+ "time",
7721
+ "type",
7722
+ "class",
7723
+ "input",
7724
+ "output",
7725
+ "data",
7726
+ "value",
7727
+ "result",
7728
+ "response",
7729
+ "request",
7730
+ "item",
7731
+ "element"
7732
+ ];
7733
+ if (reservedNames.includes(name.toLowerCase())) {
7734
+ const suggestions = fieldType === "input" ? ["userInput", "questionText", "documentContent", "messageText"] : ["responseText", "analysisResult", "categoryType", "summaryText"];
7735
+ throw new SignatureValidationError(
7736
+ `Field name "${name}" is too generic`,
7737
+ this.position,
7738
+ this.getErrorContext(),
7739
+ `Use a more descriptive name. Examples: ${suggestions.join(", ")}`
7740
+ );
7741
+ }
7742
+ }
7743
+ const camelCaseRegex = /^[a-z][a-zA-Z0-9]*$/;
7744
+ const snakeCaseRegex = /^[a-z]+(_[a-z0-9]+)*$/;
7745
+ if (!camelCaseRegex.test(name) && !snakeCaseRegex.test(name)) {
7746
+ throw new SignatureValidationError(
7747
+ `Invalid field name "${name}"`,
7748
+ this.position,
7749
+ this.getErrorContext(),
7750
+ 'Field names must be in camelCase (e.g., "userInput") or snake_case (e.g., "user_input")'
7751
+ );
7752
+ }
7753
+ if (name.length < 2) {
7754
+ throw new SignatureValidationError(
7755
+ `Field name "${name}" is too short`,
7756
+ this.position,
7757
+ this.getErrorContext(),
7758
+ "Field names must be at least 2 characters long"
7759
+ );
7760
+ }
7761
+ if (name.length > 50) {
7762
+ throw new SignatureValidationError(
7763
+ `Field name "${name}" is too long (${name.length} characters)`,
7764
+ this.position,
7765
+ this.getErrorContext(),
7766
+ "Field names should be 50 characters or less"
7767
+ );
7768
+ }
7769
+ }
7495
7770
  parseTypeNotClass() {
7496
7771
  const types = [
7497
7772
  "string",
@@ -7506,13 +7781,42 @@ ${pointer}`;
7506
7781
  ];
7507
7782
  const foundType = types.find((type) => this.match(type));
7508
7783
  if (!foundType) {
7509
- const currentWord = this.input.slice(this.position).match(/^\w+/)?.[0] || "empty";
7510
- throw new Error(
7511
- `Invalid type "${currentWord}". Expected one of: ${types.join(", ")}`
7784
+ const currentWord = this.input.slice(this.position).match(/^\w+/)?.[0] || "";
7785
+ const suggestion = this.suggestType(currentWord);
7786
+ const baseMessage = `Invalid type "${currentWord || "empty"}"`;
7787
+ const suggestionPart = suggestion ? `. Did you mean "${suggestion}"?` : "";
7788
+ const fullMessage = `${baseMessage}${suggestionPart}`;
7789
+ throw new SignatureValidationError(
7790
+ fullMessage,
7791
+ this.position,
7792
+ this.getErrorContext(),
7793
+ `Expected one of: ${types.join(", ")}`
7512
7794
  );
7513
7795
  }
7514
7796
  return foundType;
7515
7797
  }
7798
+ suggestType(input) {
7799
+ const suggestions = {
7800
+ str: "string",
7801
+ text: "string",
7802
+ int: "number",
7803
+ integer: "number",
7804
+ float: "number",
7805
+ double: "number",
7806
+ bool: "boolean",
7807
+ object: "json",
7808
+ dict: "json",
7809
+ timestamp: "datetime",
7810
+ time: "datetime",
7811
+ img: "image",
7812
+ picture: "image",
7813
+ sound: "audio",
7814
+ voice: "audio",
7815
+ classification: "class",
7816
+ category: "class"
7817
+ };
7818
+ return suggestions[input.toLowerCase()] || null;
7819
+ }
7516
7820
  parseParsedIdentifier() {
7517
7821
  this.skipWhitespace();
7518
7822
  const match = /^[a-zA-Z_][a-zA-Z_0-9]*/.exec(
@@ -7523,9 +7827,28 @@ ${pointer}`;
7523
7827
  return match[0];
7524
7828
  }
7525
7829
  const invalidMatch = /^\S+/.exec(this.input.slice(this.position));
7526
- const invalidId = invalidMatch ? invalidMatch[0] : "empty";
7527
- throw new Error(
7528
- `Invalid identifier "${invalidId}". Identifiers must start with a letter or underscore and contain only letters, numbers, or underscores`
7830
+ const invalidId = invalidMatch ? invalidMatch[0] : "";
7831
+ if (invalidId === "") {
7832
+ throw new SignatureValidationError(
7833
+ "Expected field name but found end of input",
7834
+ this.position,
7835
+ this.getErrorContext(),
7836
+ "Add a field name. Field names must start with a letter or underscore"
7837
+ );
7838
+ }
7839
+ if (/^\d/.test(invalidId)) {
7840
+ throw new SignatureValidationError(
7841
+ `Invalid field name "${invalidId}" - cannot start with a number`,
7842
+ this.position,
7843
+ this.getErrorContext(),
7844
+ 'Field names must start with a letter or underscore. Example: "userInput" or "_internal"'
7845
+ );
7846
+ }
7847
+ throw new SignatureValidationError(
7848
+ `Invalid field name "${invalidId}"`,
7849
+ this.position,
7850
+ this.getErrorContext(),
7851
+ "Field names must start with a letter or underscore and contain only letters, numbers, or underscores"
7529
7852
  );
7530
7853
  }
7531
7854
  parseParsedString() {
@@ -7534,7 +7857,7 @@ ${pointer}`;
7534
7857
  if (this.match(quoteChar)) {
7535
7858
  let content = "";
7536
7859
  let escaped = false;
7537
- let startPos = this.position;
7860
+ const startPos = this.position - 1;
7538
7861
  while (this.position < this.input.length) {
7539
7862
  const char = this.input[this.position];
7540
7863
  this.position++;
@@ -7549,9 +7872,15 @@ ${pointer}`;
7549
7872
  content += char;
7550
7873
  }
7551
7874
  }
7552
- const partialString = this.input.slice(startPos, this.position);
7553
- throw new Error(
7554
- `Unterminated string starting at position ${startPos}: "${partialString}..."`
7875
+ const partialString = this.input.slice(
7876
+ startPos,
7877
+ Math.min(this.position, startPos + 20)
7878
+ );
7879
+ throw new SignatureValidationError(
7880
+ `Unterminated string starting at position ${startPos}`,
7881
+ startPos,
7882
+ this.getErrorContext(),
7883
+ `Add closing ${quoteChar} to complete the string: ${partialString}${quoteChar}`
7555
7884
  );
7556
7885
  }
7557
7886
  }
@@ -7579,11 +7908,15 @@ ${pointer}`;
7579
7908
  }
7580
7909
  return false;
7581
7910
  }
7582
- expect(str) {
7583
- if (!this.match(str)) {
7911
+ expectArrow() {
7912
+ if (!this.match("->")) {
7584
7913
  const found = this.input.slice(this.position, this.position + 10);
7585
- throw new Error(
7586
- `Expected "${str}" but found "${found}..." at position ${this.position}`
7914
+ const suggestion = found.includes(">") ? 'Use "->" (dash followed by greater-than)' : found.includes("-") ? 'Add ">" after the dash' : 'Add "->" to separate input and output fields';
7915
+ throw new SignatureValidationError(
7916
+ `Expected "->" but found "${found}..."`,
7917
+ this.position,
7918
+ this.getErrorContext(),
7919
+ suggestion
7587
7920
  );
7588
7921
  }
7589
7922
  }
@@ -7594,6 +7927,14 @@ function parseSignature(input) {
7594
7927
  }
7595
7928
 
7596
7929
  // dsp/sig.ts
7930
+ var AxSignatureValidationError = class extends Error {
7931
+ constructor(message, fieldName, suggestion) {
7932
+ super(message);
7933
+ this.fieldName = fieldName;
7934
+ this.suggestion = suggestion;
7935
+ this.name = "AxSignatureValidationError";
7936
+ }
7937
+ };
7597
7938
  var AxSignature = class _AxSignature {
7598
7939
  description;
7599
7940
  inputFields;
@@ -7613,8 +7954,18 @@ var AxSignature = class _AxSignature {
7613
7954
  try {
7614
7955
  sig = parseSignature(signature);
7615
7956
  } catch (e) {
7616
- throw new Error(
7617
- `Invalid Signature: ${e.message} (${signature})`
7957
+ if (e instanceof Error) {
7958
+ const suggestion = "suggestion" in e && typeof e.suggestion === "string" ? e.suggestion : 'Please check the signature format. Example: "userInput:string -> responseText:string"';
7959
+ throw new AxSignatureValidationError(
7960
+ `Invalid Signature: ${e.message}`,
7961
+ void 0,
7962
+ suggestion
7963
+ );
7964
+ }
7965
+ throw new AxSignatureValidationError(
7966
+ `Invalid Signature: ${signature}`,
7967
+ void 0,
7968
+ 'Please check the signature format. Example: "userInput:string -> responseText:string"'
7618
7969
  );
7619
7970
  }
7620
7971
  this.description = sig.desc;
@@ -7632,12 +7983,20 @@ var AxSignature = class _AxSignature {
7632
7983
  this.sigHash = signature.hash();
7633
7984
  this.sigString = signature.toString();
7634
7985
  } else {
7635
- throw new Error("invalid signature argument: " + signature);
7986
+ throw new AxSignatureValidationError(
7987
+ "Invalid signature argument type",
7988
+ void 0,
7989
+ "Signature must be a string or another AxSignature instance"
7990
+ );
7636
7991
  }
7637
7992
  }
7638
7993
  parseParsedField = (field) => {
7639
7994
  if (!field.name || field.name.length === 0) {
7640
- throw new Error("Field name is required.");
7995
+ throw new AxSignatureValidationError(
7996
+ "Field name is required",
7997
+ field.name,
7998
+ 'Every field must have a descriptive name. Example: "userInput", "responseText"'
7999
+ );
7641
8000
  }
7642
8001
  const title = this.toTitle(field.name);
7643
8002
  return {
@@ -7652,29 +8011,106 @@ var AxSignature = class _AxSignature {
7652
8011
  parseField = (field) => {
7653
8012
  const title = !field.title || field.title.length === 0 ? this.toTitle(field.name) : field.title;
7654
8013
  if (field.type && (!field.type.name || field.type.name.length === 0)) {
7655
- throw new Error("Field type name is required: " + field.name);
8014
+ throw new AxSignatureValidationError(
8015
+ "Field type name is required",
8016
+ field.name,
8017
+ "Specify a valid type. Available types: string, number, boolean, json, image, audio, date, datetime, class, code"
8018
+ );
7656
8019
  }
7657
8020
  return { ...field, title };
7658
8021
  };
7659
8022
  setDescription = (desc) => {
8023
+ if (typeof desc !== "string") {
8024
+ throw new AxSignatureValidationError(
8025
+ "Description must be a string",
8026
+ void 0,
8027
+ "Provide a string description for the signature"
8028
+ );
8029
+ }
7660
8030
  this.description = desc;
7661
8031
  this.updateHash();
7662
8032
  };
7663
8033
  addInputField = (field) => {
7664
- this.inputFields.push(this.parseField(field));
7665
- this.updateHash();
8034
+ try {
8035
+ const parsedField = this.parseField(field);
8036
+ validateField(parsedField, "input");
8037
+ this.inputFields.push(parsedField);
8038
+ this.updateHash();
8039
+ } catch (error) {
8040
+ if (error instanceof AxSignatureValidationError) {
8041
+ throw error;
8042
+ }
8043
+ throw new AxSignatureValidationError(
8044
+ `Failed to add input field "${field.name}": ${error instanceof Error ? error.message : "Unknown error"}`,
8045
+ field.name
8046
+ );
8047
+ }
7666
8048
  };
7667
8049
  addOutputField = (field) => {
7668
- this.outputFields.push(this.parseField(field));
7669
- this.updateHash();
8050
+ try {
8051
+ const parsedField = this.parseField(field);
8052
+ validateField(parsedField, "output");
8053
+ this.outputFields.push(parsedField);
8054
+ this.updateHash();
8055
+ } catch (error) {
8056
+ if (error instanceof AxSignatureValidationError) {
8057
+ throw error;
8058
+ }
8059
+ throw new AxSignatureValidationError(
8060
+ `Failed to add output field "${field.name}": ${error instanceof Error ? error.message : "Unknown error"}`,
8061
+ field.name
8062
+ );
8063
+ }
7670
8064
  };
7671
8065
  setInputFields = (fields) => {
7672
- this.inputFields = fields.map((v) => this.parseField(v));
7673
- this.updateHash();
8066
+ if (!Array.isArray(fields)) {
8067
+ throw new AxSignatureValidationError(
8068
+ "Input fields must be an array",
8069
+ void 0,
8070
+ "Provide an array of field objects"
8071
+ );
8072
+ }
8073
+ try {
8074
+ const parsedFields = fields.map((v) => {
8075
+ const parsed = this.parseField(v);
8076
+ validateField(parsed, "input");
8077
+ return parsed;
8078
+ });
8079
+ this.inputFields = parsedFields;
8080
+ this.updateHash();
8081
+ } catch (error) {
8082
+ if (error instanceof AxSignatureValidationError) {
8083
+ throw error;
8084
+ }
8085
+ throw new AxSignatureValidationError(
8086
+ `Failed to set input fields: ${error instanceof Error ? error.message : "Unknown error"}`
8087
+ );
8088
+ }
7674
8089
  };
7675
8090
  setOutputFields = (fields) => {
7676
- this.outputFields = fields.map((v) => this.parseField(v));
7677
- this.updateHash();
8091
+ if (!Array.isArray(fields)) {
8092
+ throw new AxSignatureValidationError(
8093
+ "Output fields must be an array",
8094
+ void 0,
8095
+ "Provide an array of field objects"
8096
+ );
8097
+ }
8098
+ try {
8099
+ const parsedFields = fields.map((v) => {
8100
+ const parsed = this.parseField(v);
8101
+ validateField(parsed, "output");
8102
+ return parsed;
8103
+ });
8104
+ this.outputFields = parsedFields;
8105
+ this.updateHash();
8106
+ } catch (error) {
8107
+ if (error instanceof AxSignatureValidationError) {
8108
+ throw error;
8109
+ }
8110
+ throw new AxSignatureValidationError(
8111
+ `Failed to set output fields: ${error instanceof Error ? error.message : "Unknown error"}`
8112
+ );
8113
+ }
7678
8114
  };
7679
8115
  getInputFields = () => this.inputFields;
7680
8116
  getOutputFields = () => this.outputFields;
@@ -7716,23 +8152,77 @@ var AxSignature = class _AxSignature {
7716
8152
  return schema;
7717
8153
  };
7718
8154
  updateHash = () => {
7719
- this.getInputFields().forEach((field) => {
7720
- validateField(field);
7721
- });
7722
- this.getOutputFields().forEach((field) => {
7723
- validateField(field);
7724
- if (field.type?.name === "image") {
7725
- throw new Error("Image type is not supported in output fields.");
8155
+ try {
8156
+ this.getInputFields().forEach((field) => {
8157
+ validateField(field, "input");
8158
+ });
8159
+ this.getOutputFields().forEach((field) => {
8160
+ validateField(field, "output");
8161
+ });
8162
+ this.validateSignatureConsistency();
8163
+ this.sigHash = createHash("sha256").update(this.description ?? "").update(JSON.stringify(this.inputFields)).update(JSON.stringify(this.outputFields)).digest("hex");
8164
+ this.sigString = renderSignature(
8165
+ this.description,
8166
+ this.inputFields,
8167
+ this.outputFields
8168
+ );
8169
+ return [this.sigHash, this.sigString];
8170
+ } catch (error) {
8171
+ if (error instanceof AxSignatureValidationError) {
8172
+ throw error;
7726
8173
  }
7727
- });
7728
- this.sigHash = createHash("sha256").update(this.description ?? "").update(JSON.stringify(this.inputFields)).update(JSON.stringify(this.outputFields)).digest("hex");
7729
- this.sigString = renderSignature(
7730
- this.description,
7731
- this.inputFields,
7732
- this.outputFields
7733
- );
7734
- return [this.sigHash, this.sigString];
8174
+ throw new AxSignatureValidationError(
8175
+ `Signature validation failed: ${error instanceof Error ? error.message : "Unknown error"}`
8176
+ );
8177
+ }
7735
8178
  };
8179
+ validateSignatureConsistency() {
8180
+ const inputNames = /* @__PURE__ */ new Set();
8181
+ for (const field of this.inputFields) {
8182
+ if (inputNames.has(field.name)) {
8183
+ throw new AxSignatureValidationError(
8184
+ `Duplicate input field name: "${field.name}"`,
8185
+ field.name,
8186
+ "Each field name must be unique within the signature"
8187
+ );
8188
+ }
8189
+ inputNames.add(field.name);
8190
+ }
8191
+ const outputNames = /* @__PURE__ */ new Set();
8192
+ for (const field of this.outputFields) {
8193
+ if (outputNames.has(field.name)) {
8194
+ throw new AxSignatureValidationError(
8195
+ `Duplicate output field name: "${field.name}"`,
8196
+ field.name,
8197
+ "Each field name must be unique within the signature"
8198
+ );
8199
+ }
8200
+ outputNames.add(field.name);
8201
+ }
8202
+ for (const outputField of this.outputFields) {
8203
+ if (inputNames.has(outputField.name)) {
8204
+ throw new AxSignatureValidationError(
8205
+ `Field name "${outputField.name}" appears in both inputs and outputs`,
8206
+ outputField.name,
8207
+ "Use different names for input and output fields to avoid confusion"
8208
+ );
8209
+ }
8210
+ }
8211
+ if (this.inputFields.length === 0) {
8212
+ throw new AxSignatureValidationError(
8213
+ "Signature must have at least one input field",
8214
+ void 0,
8215
+ 'Add an input field. Example: "userInput:string -> ..."'
8216
+ );
8217
+ }
8218
+ if (this.outputFields.length === 0) {
8219
+ throw new AxSignatureValidationError(
8220
+ "Signature must have at least one output field",
8221
+ void 0,
8222
+ 'Add an output field. Example: "... -> responseText:string"'
8223
+ );
8224
+ }
8225
+ }
7736
8226
  hash = () => this.sigHash;
7737
8227
  toString = () => this.sigString;
7738
8228
  toJSON = () => {
@@ -7749,54 +8239,194 @@ function renderField(field) {
7749
8239
  if (field.isOptional) {
7750
8240
  result += "?";
7751
8241
  }
8242
+ if (field.isInternal) {
8243
+ result += "!";
8244
+ }
7752
8245
  if (field.type) {
7753
8246
  result += ":" + field.type.name;
7754
8247
  if (field.type.isArray) {
7755
8248
  result += "[]";
7756
8249
  }
8250
+ if (field.type.name === "class" && field.type.options) {
8251
+ result += ` "${field.type.options.join(", ")}"`;
8252
+ }
7757
8253
  }
7758
- if (field.description) {
8254
+ if (field.description && field.type?.name !== "class") {
7759
8255
  result += ` "${field.description}"`;
7760
8256
  }
7761
8257
  return result;
7762
8258
  }
7763
8259
  function renderSignature(description, inputFields, outputFields) {
7764
- const descriptionPart = description ? `"${description}"` : "";
8260
+ const descriptionPart = description ? `"${description}" ` : "";
7765
8261
  const inputFieldsRendered = inputFields.map(renderField).join(", ");
7766
8262
  const outputFieldsRendered = outputFields.map(renderField).join(", ");
7767
- return `${descriptionPart} ${inputFieldsRendered} -> ${outputFieldsRendered}`;
8263
+ return `${descriptionPart}${inputFieldsRendered} -> ${outputFieldsRendered}`;
7768
8264
  }
7769
8265
  function isValidCase(inputString) {
7770
8266
  const camelCaseRegex = /^[a-z][a-zA-Z0-9]*$/;
7771
8267
  const snakeCaseRegex = /^[a-z]+(_[a-z0-9]+)*$/;
7772
8268
  return camelCaseRegex.test(inputString) || snakeCaseRegex.test(inputString);
7773
8269
  }
7774
- function validateField(field) {
8270
+ function validateField(field, context3) {
7775
8271
  if (!field.name || field.name.length === 0) {
7776
- throw new Error("Field name cannot be blank");
8272
+ throw new AxSignatureValidationError(
8273
+ "Field name cannot be blank",
8274
+ field.name,
8275
+ "Every field must have a descriptive name"
8276
+ );
7777
8277
  }
7778
8278
  if (!isValidCase(field.name)) {
7779
- throw new Error(
7780
- `Invalid field name '${field.name}', it must be camel case or snake case: `
8279
+ throw new AxSignatureValidationError(
8280
+ `Invalid field name '${field.name}' - must be camelCase or snake_case`,
8281
+ field.name,
8282
+ 'Use camelCase (e.g., "userInput") or snake_case (e.g., "user_input")'
7781
8283
  );
7782
8284
  }
7783
- if ([
7784
- "text",
7785
- "object",
7786
- "image",
7787
- "string",
7788
- "number",
7789
- "boolean",
7790
- "json",
7791
- "array",
7792
- "datetime",
7793
- "date",
7794
- "time",
7795
- "type",
7796
- "class"
7797
- ].includes(field.name)) {
7798
- throw new Error(
7799
- `Invalid field name '${field.name}', please make it more descriptive (eg. companyDescription)`
8285
+ if (axGlobals.signatureStrict) {
8286
+ const reservedNames = [
8287
+ "text",
8288
+ "object",
8289
+ "image",
8290
+ "string",
8291
+ "number",
8292
+ "boolean",
8293
+ "json",
8294
+ "array",
8295
+ "datetime",
8296
+ "date",
8297
+ "time",
8298
+ "type",
8299
+ "class",
8300
+ "input",
8301
+ "output",
8302
+ "data",
8303
+ "value",
8304
+ "result",
8305
+ "response",
8306
+ "request",
8307
+ "item",
8308
+ "element"
8309
+ ];
8310
+ if (reservedNames.includes(field.name.toLowerCase())) {
8311
+ const suggestions = context3 === "input" ? [
8312
+ "userInput",
8313
+ "questionText",
8314
+ "documentContent",
8315
+ "messageText",
8316
+ "queryString"
8317
+ ] : [
8318
+ "responseText",
8319
+ "analysisResult",
8320
+ "categoryType",
8321
+ "summaryText",
8322
+ "outputData"
8323
+ ];
8324
+ throw new AxSignatureValidationError(
8325
+ `Field name '${field.name}' is too generic`,
8326
+ field.name,
8327
+ `Use a more descriptive name. Examples for ${context3} fields: ${suggestions.join(", ")}`
8328
+ );
8329
+ }
8330
+ }
8331
+ if (field.name.length < 2) {
8332
+ throw new AxSignatureValidationError(
8333
+ `Field name '${field.name}' is too short`,
8334
+ field.name,
8335
+ "Field names must be at least 2 characters long"
8336
+ );
8337
+ }
8338
+ if (field.name.length > 50) {
8339
+ throw new AxSignatureValidationError(
8340
+ `Field name '${field.name}' is too long (${field.name.length} characters)`,
8341
+ field.name,
8342
+ "Field names should be 50 characters or less"
8343
+ );
8344
+ }
8345
+ if (field.type) {
8346
+ validateFieldType(field, context3);
8347
+ }
8348
+ }
8349
+ function validateFieldType(field, context3) {
8350
+ if (!field.type) return;
8351
+ const { type } = field;
8352
+ if (type.name === "image" || type.name === "audio") {
8353
+ if (context3 === "output") {
8354
+ throw new AxSignatureValidationError(
8355
+ `${type.name} type is not supported in output fields`,
8356
+ field.name,
8357
+ `${type.name} types can only be used in input fields`
8358
+ );
8359
+ }
8360
+ if (type.isArray) {
8361
+ throw new AxSignatureValidationError(
8362
+ `Arrays of ${type.name} are not supported`,
8363
+ field.name,
8364
+ `Use a single ${type.name} type instead`
8365
+ );
8366
+ }
8367
+ }
8368
+ if (type.name === "class") {
8369
+ if (context3 === "input") {
8370
+ throw new AxSignatureValidationError(
8371
+ "Class type is not supported in input fields",
8372
+ field.name,
8373
+ 'Class types are only allowed on output fields. Use "string" type for input classifications'
8374
+ );
8375
+ }
8376
+ if (!type.options || type.options.length === 0) {
8377
+ throw new AxSignatureValidationError(
8378
+ "Class type requires options",
8379
+ field.name,
8380
+ 'Provide class options. Example: class "positive, negative, neutral"'
8381
+ );
8382
+ }
8383
+ if (type.options.length === 1) {
8384
+ throw new AxSignatureValidationError(
8385
+ "Class type needs at least 2 options",
8386
+ field.name,
8387
+ 'Add more class options or use "string" type instead'
8388
+ );
8389
+ }
8390
+ for (const option of type.options) {
8391
+ if (!option || option.trim().length === 0) {
8392
+ throw new AxSignatureValidationError(
8393
+ "Empty class option found",
8394
+ field.name,
8395
+ "All class options must be non-empty strings"
8396
+ );
8397
+ }
8398
+ const trimmedOption = option.trim();
8399
+ if (!/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(trimmedOption)) {
8400
+ throw new AxSignatureValidationError(
8401
+ `Invalid class option "${trimmedOption}"`,
8402
+ field.name,
8403
+ "Class options must start with a letter and contain only letters, numbers, underscores, or hyphens"
8404
+ );
8405
+ }
8406
+ }
8407
+ const uniqueOptions = new Set(
8408
+ type.options.map((opt) => opt.trim().toLowerCase())
8409
+ );
8410
+ if (uniqueOptions.size !== type.options.length) {
8411
+ throw new AxSignatureValidationError(
8412
+ "Duplicate class options found",
8413
+ field.name,
8414
+ "Each class option must be unique (case-insensitive)"
8415
+ );
8416
+ }
8417
+ }
8418
+ if (type.name === "code" && type.isArray) {
8419
+ throw new AxSignatureValidationError(
8420
+ "Arrays of code are not commonly supported",
8421
+ field.name,
8422
+ "Consider using a single code field or an array of strings instead"
8423
+ );
8424
+ }
8425
+ if (field.isInternal && context3 === "input") {
8426
+ throw new AxSignatureValidationError(
8427
+ "Internal marker (!) is not allowed on input fields",
8428
+ field.name,
8429
+ "Internal markers are only allowed on output fields"
7800
8430
  );
7801
8431
  }
7802
8432
  }
@@ -11529,13 +12159,18 @@ var AxMockAIService = class {
11529
12159
  }
11530
12160
  };
11531
12161
  getLastUsedChatModel() {
11532
- throw new Error("Method not implemented.");
12162
+ return this.config.modelInfo?.name ?? "mock-model";
11533
12163
  }
11534
12164
  getLastUsedEmbedModel() {
11535
- throw new Error("Method not implemented.");
12165
+ return this.config.embedModelInfo?.name ?? "mock-embed-model";
11536
12166
  }
11537
12167
  getLastUsedModelConfig() {
11538
- throw new Error("Method not implemented.");
12168
+ return this.config.modelInfo ? {
12169
+ maxTokens: this.config.modelInfo.maxTokens,
12170
+ temperature: 0.7,
12171
+ // Default temperature
12172
+ stream: this.config.features?.streaming ?? false
12173
+ } : void 0;
11539
12174
  }
11540
12175
  getName() {
11541
12176
  return this.config.name ?? "mock-ai-service";
@@ -13938,6 +14573,7 @@ export {
13938
14573
  axAITogetherDefaultConfig,
13939
14574
  axBaseAIDefaultConfig,
13940
14575
  axBaseAIDefaultCreativeConfig,
14576
+ axGlobals,
13941
14577
  axModelInfoAnthropic,
13942
14578
  axModelInfoCohere,
13943
14579
  axModelInfoDeepSeek,