@ax-llm/ax 11.0.67 → 12.0.1

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
@@ -1098,6 +1098,7 @@ var AxBaseAI = class {
1098
1098
  if (chatReq.functions && chatReq.functions.length > 0) {
1099
1099
  functions = chatReq.functions.map((fn2) => this.cleanupFunctionSchema(fn2));
1100
1100
  }
1101
+ validateChatPrompt(chatReq.chatPrompt);
1101
1102
  const req = {
1102
1103
  ...chatReq,
1103
1104
  model,
@@ -1439,6 +1440,31 @@ function setChatResponseEvents(res, span, excludeContentFromTrace) {
1439
1440
  });
1440
1441
  }
1441
1442
  }
1443
+ function validateAxMessageArray(values) {
1444
+ for (let i = 0; i < values.length; i++) {
1445
+ const message = values[i];
1446
+ if (!message || typeof message !== "object") {
1447
+ throw new Error(
1448
+ `AxMessage array validation failed: Item at index ${i} is not a valid message object`
1449
+ );
1450
+ }
1451
+ if ("content" in message && typeof message.content === "string" && message.content.trim() === "") {
1452
+ throw new Error(
1453
+ `AxMessage array validation failed: Item at index ${i} has empty content`
1454
+ );
1455
+ }
1456
+ }
1457
+ }
1458
+ function validateChatPrompt(chatPrompt) {
1459
+ for (let i = 0; i < chatPrompt.length; i++) {
1460
+ const message = chatPrompt[i];
1461
+ if (message && "content" in message && typeof message.content === "string" && message.content.trim() === "") {
1462
+ throw new Error(
1463
+ `Chat prompt validation failed: Message at index ${i} has empty content`
1464
+ );
1465
+ }
1466
+ }
1467
+ }
1442
1468
  function validateModels(models) {
1443
1469
  const keys = /* @__PURE__ */ new Set();
1444
1470
  for (const model of models) {
@@ -3215,7 +3241,9 @@ var AxAIGoogleGeminiImpl = class {
3215
3241
  const contents = req.chatPrompt.filter((p) => p.role !== "system").map((msg, i) => {
3216
3242
  switch (msg.role) {
3217
3243
  case "user": {
3218
- const parts = Array.isArray(msg.content) ? msg.content.map((c, i2) => {
3244
+ const parts = Array.isArray(
3245
+ msg.content
3246
+ ) ? msg.content.map((c, i2) => {
3219
3247
  switch (c.type) {
3220
3248
  case "text":
3221
3249
  return { text: c.text };
@@ -3276,12 +3304,14 @@ var AxAIGoogleGeminiImpl = class {
3276
3304
  }
3277
3305
  ];
3278
3306
  return {
3279
- role: "function",
3307
+ role: "model",
3280
3308
  parts
3281
3309
  };
3282
3310
  }
3283
3311
  default:
3284
- throw new Error("Invalid role");
3312
+ throw new Error(
3313
+ `Invalid role: ${JSON.stringify(msg)} (index: ${i})`
3314
+ );
3285
3315
  }
3286
3316
  });
3287
3317
  let tools = [];
@@ -6560,6 +6590,11 @@ var extractValues = (sig, values, content) => {
6560
6590
  const xstate = { extractedFields: [], streamedIndex: {}, s: -1 };
6561
6591
  streamingExtractValues(sig, values, xstate, content);
6562
6592
  streamingExtractFinalValue(sig, values, xstate, content);
6593
+ for (const field of sig.getOutputFields()) {
6594
+ if (field.isInternal) {
6595
+ delete values[field.name];
6596
+ }
6597
+ }
6563
6598
  };
6564
6599
  var checkMissingRequiredFields = (xstate, values, currentIndex) => {
6565
6600
  const missingFields = [];
@@ -7285,93 +7320,218 @@ var AxInstanceRegistry = class {
7285
7320
  // dsp/sig.ts
7286
7321
  import { createHash } from "crypto";
7287
7322
 
7323
+ // dsp/globals.ts
7324
+ var axGlobals = {
7325
+ signatureStrict: true
7326
+ // Controls reservedNames enforcement in signature parsing/validation
7327
+ };
7328
+
7288
7329
  // dsp/parser.ts
7330
+ var SignatureValidationError = class extends Error {
7331
+ constructor(message, position, context3, suggestion) {
7332
+ super(message);
7333
+ this.position = position;
7334
+ this.context = context3;
7335
+ this.suggestion = suggestion;
7336
+ this.name = "SignatureValidationError";
7337
+ }
7338
+ };
7289
7339
  var SignatureParser = class {
7290
7340
  input;
7291
7341
  position;
7292
7342
  currentFieldName = null;
7343
+ currentSection = "description";
7293
7344
  constructor(input) {
7294
- this.input = input;
7345
+ this.input = input.trim();
7295
7346
  this.position = 0;
7347
+ if (!this.input) {
7348
+ throw new SignatureValidationError(
7349
+ "Empty signature provided",
7350
+ 0,
7351
+ "",
7352
+ 'A signature must contain at least input and output fields separated by "->". Example: "userQuery:string -> aiResponse:string"'
7353
+ );
7354
+ }
7296
7355
  }
7297
7356
  parse() {
7298
7357
  try {
7299
7358
  this.skipWhitespace();
7300
7359
  const optionalDesc = this.parseParsedString();
7301
7360
  this.skipWhitespace();
7361
+ this.currentSection = "inputs";
7302
7362
  const inputs = this.parseFieldList(
7303
7363
  this.parseInputField.bind(this),
7304
7364
  "input"
7305
7365
  );
7306
7366
  this.skipWhitespace();
7307
7367
  if (this.position >= this.input.length) {
7308
- throw new Error(
7309
- 'Incomplete signature: Missing output section. Expected "->" followed by output fields'
7368
+ throw new SignatureValidationError(
7369
+ "Incomplete signature: Missing output section",
7370
+ this.position,
7371
+ this.getErrorContext(),
7372
+ 'Add "->" followed by output fields. Example: "-> responseText:string"'
7310
7373
  );
7311
7374
  }
7312
- this.expect("->");
7375
+ this.expectArrow();
7313
7376
  this.skipWhitespace();
7314
7377
  if (this.position >= this.input.length) {
7315
- throw new Error(
7316
- 'Incomplete signature: No output fields specified after "->"'
7378
+ throw new SignatureValidationError(
7379
+ 'Incomplete signature: No output fields specified after "->"',
7380
+ this.position,
7381
+ this.getErrorContext(),
7382
+ 'Add at least one output field. Example: "-> responseText:string"'
7317
7383
  );
7318
7384
  }
7385
+ this.currentSection = "outputs";
7319
7386
  const outputs = this.parseFieldList(
7320
7387
  this.parseOutputField.bind(this),
7321
7388
  "output"
7322
7389
  );
7390
+ this.skipWhitespace();
7391
+ if (this.position < this.input.length) {
7392
+ const remaining = this.input.slice(this.position);
7393
+ throw new SignatureValidationError(
7394
+ `Unexpected content after signature: "${remaining}"`,
7395
+ this.position,
7396
+ this.getErrorContext(),
7397
+ "Remove any extra content after the output fields"
7398
+ );
7399
+ }
7400
+ this.validateParsedSignature({
7401
+ desc: optionalDesc?.trim(),
7402
+ inputs,
7403
+ outputs
7404
+ });
7323
7405
  return {
7324
7406
  desc: optionalDesc?.trim(),
7325
7407
  inputs,
7326
7408
  outputs
7327
7409
  };
7328
7410
  } catch (error) {
7411
+ if (error instanceof SignatureValidationError) {
7412
+ throw error;
7413
+ }
7329
7414
  const errorMessage = error instanceof Error ? error.message : "Unknown error";
7330
- const context3 = this.getErrorContext();
7331
- throw new Error(`${errorMessage}
7332
- ${context3}`);
7415
+ throw new SignatureValidationError(
7416
+ errorMessage,
7417
+ this.position,
7418
+ this.getErrorContext()
7419
+ );
7420
+ }
7421
+ }
7422
+ validateParsedSignature(signature) {
7423
+ const inputNames = /* @__PURE__ */ new Set();
7424
+ for (const field of signature.inputs) {
7425
+ if (inputNames.has(field.name)) {
7426
+ throw new SignatureValidationError(
7427
+ `Duplicate input field name: "${field.name}"`,
7428
+ 0,
7429
+ "",
7430
+ "Each field name must be unique within the signature"
7431
+ );
7432
+ }
7433
+ inputNames.add(field.name);
7434
+ }
7435
+ const outputNames = /* @__PURE__ */ new Set();
7436
+ for (const field of signature.outputs) {
7437
+ if (outputNames.has(field.name)) {
7438
+ throw new SignatureValidationError(
7439
+ `Duplicate output field name: "${field.name}"`,
7440
+ 0,
7441
+ "",
7442
+ "Each field name must be unique within the signature"
7443
+ );
7444
+ }
7445
+ outputNames.add(field.name);
7446
+ }
7447
+ for (const outputField of signature.outputs) {
7448
+ if (inputNames.has(outputField.name)) {
7449
+ throw new SignatureValidationError(
7450
+ `Field name "${outputField.name}" appears in both inputs and outputs`,
7451
+ 0,
7452
+ "",
7453
+ "Use different names for input and output fields to avoid confusion"
7454
+ );
7455
+ }
7456
+ }
7457
+ if (signature.inputs.length === 0) {
7458
+ throw new SignatureValidationError(
7459
+ "Signature must have at least one input field",
7460
+ 0,
7461
+ "",
7462
+ 'Add an input field before "->". Example: "userInput:string -> ..."'
7463
+ );
7464
+ }
7465
+ if (signature.outputs.length === 0) {
7466
+ throw new SignatureValidationError(
7467
+ "Signature must have at least one output field",
7468
+ 0,
7469
+ "",
7470
+ 'Add an output field after "->". Example: "... -> responseText:string"'
7471
+ );
7333
7472
  }
7334
7473
  }
7335
7474
  getErrorContext() {
7336
- const start = Math.max(0, this.position - 20);
7337
- const end = Math.min(this.input.length, this.position + 20);
7475
+ const start = Math.max(0, this.position - 25);
7476
+ const end = Math.min(this.input.length, this.position + 25);
7338
7477
  const before = this.input.slice(start, this.position);
7339
7478
  const after = this.input.slice(this.position, end);
7340
7479
  const pointer = " ".repeat(before.length) + "^";
7341
- return `Near position ${this.position}:
7342
- ${before}${after}
7343
- ${pointer}`;
7480
+ const lines = [
7481
+ `Position ${this.position} in signature:`,
7482
+ `"${before}${after}"`,
7483
+ ` ${pointer}`
7484
+ ];
7485
+ return lines.join("\n");
7344
7486
  }
7345
7487
  parseFieldList(parseFieldFn, section) {
7346
7488
  const fields = [];
7347
7489
  this.skipWhitespace();
7348
7490
  if (this.position >= this.input.length) {
7349
- throw new Error(`Empty ${section} section: Expected at least one field`);
7491
+ throw new SignatureValidationError(
7492
+ `Empty ${section} section: Expected at least one field`,
7493
+ this.position,
7494
+ this.getErrorContext(),
7495
+ `Add a ${section} field. Example: ${section === "input" ? "userInput:string" : "responseText:string"}`
7496
+ );
7350
7497
  }
7351
7498
  try {
7352
7499
  fields.push(parseFieldFn());
7353
7500
  } catch (error) {
7354
- throw new Error(
7355
- `Invalid first ${section} field: ${error instanceof Error ? error.message : "Unknown error"}`
7501
+ if (error instanceof SignatureValidationError) {
7502
+ throw error;
7503
+ }
7504
+ throw new SignatureValidationError(
7505
+ `Invalid first ${section} field: ${error instanceof Error ? error.message : "Unknown error"}`,
7506
+ this.position,
7507
+ this.getErrorContext()
7356
7508
  );
7357
7509
  }
7358
7510
  this.skipWhitespace();
7359
7511
  while (this.position < this.input.length) {
7360
- if (this.input[this.position] === "-" && this.input[this.position + 1] === ">") {
7512
+ if (this.input[this.position] === "-" && this.position + 1 < this.input.length && this.input[this.position + 1] === ">") {
7361
7513
  break;
7362
7514
  }
7363
7515
  if (this.match(",")) {
7364
7516
  this.skipWhitespace();
7365
7517
  if (this.position >= this.input.length) {
7366
- throw new Error(
7367
- `Unexpected end of input after comma in ${section} section`
7518
+ throw new SignatureValidationError(
7519
+ `Unexpected end of input after comma in ${section} section`,
7520
+ this.position,
7521
+ this.getErrorContext(),
7522
+ `Add another ${section} field after the comma`
7368
7523
  );
7369
7524
  }
7370
7525
  try {
7371
7526
  fields.push(parseFieldFn());
7372
7527
  } catch (error) {
7373
- throw new Error(
7374
- `Invalid ${section} field after comma: ${error instanceof Error ? error.message : "Unknown error"}`
7528
+ if (error instanceof SignatureValidationError) {
7529
+ throw error;
7530
+ }
7531
+ throw new SignatureValidationError(
7532
+ `Invalid ${section} field after comma: ${error instanceof Error ? error.message : "Unknown error"}`,
7533
+ this.position,
7534
+ this.getErrorContext()
7375
7535
  );
7376
7536
  }
7377
7537
  this.skipWhitespace();
@@ -7388,6 +7548,7 @@ ${pointer}`;
7388
7548
  this.skipWhitespace();
7389
7549
  const name = this.parseParsedIdentifier();
7390
7550
  this.currentFieldName = name;
7551
+ this.validateFieldName(name, "input");
7391
7552
  let isOptional = void 0;
7392
7553
  while (true) {
7393
7554
  if (this.match("?")) {
@@ -7395,8 +7556,11 @@ ${pointer}`;
7395
7556
  continue;
7396
7557
  }
7397
7558
  if (this.match("!")) {
7398
- throw new Error(
7399
- `Input field "${name}" does not support the internal marker "!"`
7559
+ throw new SignatureValidationError(
7560
+ `Input field "${name}" cannot use the internal marker "!"`,
7561
+ this.position - 1,
7562
+ this.getErrorContext(),
7563
+ "Internal markers (!) are only allowed on output fields"
7400
7564
  );
7401
7565
  }
7402
7566
  break;
@@ -7406,17 +7570,33 @@ ${pointer}`;
7406
7570
  if (this.match(":")) {
7407
7571
  this.skipWhitespace();
7408
7572
  if (/^class\b/.test(this.input.slice(this.position))) {
7409
- throw new Error(
7410
- `Input field "${name}" does not support the "class" type`
7573
+ throw new SignatureValidationError(
7574
+ `Input field "${name}" cannot use the "class" type`,
7575
+ this.position,
7576
+ this.getErrorContext(),
7577
+ 'Class types are only allowed on output fields. Use "string" type for input classifications'
7411
7578
  );
7412
7579
  } else {
7413
7580
  try {
7414
7581
  const typeName = this.parseTypeNotClass();
7415
7582
  const isArray = this.match("[]");
7416
7583
  type = { name: typeName, isArray };
7584
+ if ((typeName === "image" || typeName === "audio") && isArray) {
7585
+ throw new SignatureValidationError(
7586
+ `Input field "${name}": Arrays of ${typeName} are not supported`,
7587
+ this.position,
7588
+ this.getErrorContext(),
7589
+ `Use a single ${typeName} type instead: "${typeName}"`
7590
+ );
7591
+ }
7417
7592
  } catch (error) {
7418
- throw new Error(
7419
- `Input field "${name}": ${error instanceof Error ? error.message : "Unknown error"}`
7593
+ if (error instanceof SignatureValidationError) {
7594
+ throw error;
7595
+ }
7596
+ throw new SignatureValidationError(
7597
+ `Input field "${name}": ${error instanceof Error ? error.message : "Unknown error"}`,
7598
+ this.position,
7599
+ this.getErrorContext()
7420
7600
  );
7421
7601
  }
7422
7602
  }
@@ -7437,6 +7617,7 @@ ${pointer}`;
7437
7617
  this.skipWhitespace();
7438
7618
  const name = this.parseParsedIdentifier();
7439
7619
  this.currentFieldName = name;
7620
+ this.validateFieldName(name, "output");
7440
7621
  let isOptional = false;
7441
7622
  let isInternal = false;
7442
7623
  while (true) {
@@ -7459,25 +7640,86 @@ ${pointer}`;
7459
7640
  this.skipWhitespace();
7460
7641
  const classNamesString = this.parseParsedString();
7461
7642
  if (!classNamesString) {
7462
- throw new Error(
7463
- `Output field "${name}": Expected class names in quotes after "class" type. Example: class "MyClass1, MyClass2"`
7643
+ throw new SignatureValidationError(
7644
+ `Output field "${name}": Missing class options after "class" type`,
7645
+ this.position,
7646
+ this.getErrorContext(),
7647
+ 'Add class names in quotes. Example: class "positive, negative, neutral"'
7464
7648
  );
7465
7649
  }
7466
7650
  const options = classNamesString.split(/[,\s]+/).map((s2) => s2.trim()).filter((s2) => s2.length > 0);
7467
7651
  if (options.length === 0) {
7468
- throw new Error(
7469
- `Output field "${name}": Empty class list provided. At least one class name is required`
7652
+ throw new SignatureValidationError(
7653
+ `Output field "${name}": Empty class list provided`,
7654
+ this.position,
7655
+ this.getErrorContext(),
7656
+ 'Provide at least one class option. Example: "positive, negative"'
7470
7657
  );
7471
7658
  }
7659
+ if (options.length === 1) {
7660
+ throw new SignatureValidationError(
7661
+ `Output field "${name}": Class type needs at least 2 options`,
7662
+ this.position,
7663
+ this.getErrorContext(),
7664
+ 'Add more class options or use "string" type instead. Example: "positive, negative, neutral"'
7665
+ );
7666
+ }
7667
+ for (const option of options) {
7668
+ if (!/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(option)) {
7669
+ throw new SignatureValidationError(
7670
+ `Output field "${name}": Invalid class option "${option}"`,
7671
+ this.position,
7672
+ this.getErrorContext(),
7673
+ "Class options must start with a letter and contain only letters, numbers, underscores, or hyphens"
7674
+ );
7675
+ }
7676
+ }
7472
7677
  type = { name: "class", isArray, options };
7473
7678
  } else {
7474
7679
  try {
7475
7680
  const typeName = this.parseTypeNotClass();
7476
7681
  const isArray = this.match("[]");
7477
7682
  type = { name: typeName, isArray };
7683
+ if (typeName === "image" && isArray) {
7684
+ throw new SignatureValidationError(
7685
+ `Output field "${name}": Arrays of images are not supported`,
7686
+ this.position,
7687
+ this.getErrorContext(),
7688
+ 'Use a single image type instead: "image"'
7689
+ );
7690
+ }
7691
+ if (typeName === "audio" && isArray) {
7692
+ throw new SignatureValidationError(
7693
+ `Output field "${name}": Arrays of audio are not supported`,
7694
+ this.position,
7695
+ this.getErrorContext(),
7696
+ 'Use a single audio type instead: "audio"'
7697
+ );
7698
+ }
7699
+ if (typeName === "image") {
7700
+ throw new SignatureValidationError(
7701
+ `Output field "${name}": Image type is not supported in output fields`,
7702
+ this.position,
7703
+ this.getErrorContext(),
7704
+ "Image types can only be used in input fields"
7705
+ );
7706
+ }
7707
+ if (typeName === "audio") {
7708
+ throw new SignatureValidationError(
7709
+ `Output field "${name}": Audio type is not supported in output fields`,
7710
+ this.position,
7711
+ this.getErrorContext(),
7712
+ "Audio types can only be used in input fields"
7713
+ );
7714
+ }
7478
7715
  } catch (error) {
7479
- throw new Error(
7480
- `Output field "${name}": ${error instanceof Error ? error.message : "Unknown error"}`
7716
+ if (error instanceof SignatureValidationError) {
7717
+ throw error;
7718
+ }
7719
+ throw new SignatureValidationError(
7720
+ `Output field "${name}": ${error instanceof Error ? error.message : "Unknown error"}`,
7721
+ this.position,
7722
+ this.getErrorContext()
7481
7723
  );
7482
7724
  }
7483
7725
  }
@@ -7492,6 +7734,69 @@ ${pointer}`;
7492
7734
  isInternal
7493
7735
  };
7494
7736
  }
7737
+ validateFieldName(name, fieldType) {
7738
+ if (axGlobals.signatureStrict) {
7739
+ const reservedNames = [
7740
+ "text",
7741
+ "object",
7742
+ "image",
7743
+ "string",
7744
+ "number",
7745
+ "boolean",
7746
+ "json",
7747
+ "array",
7748
+ "datetime",
7749
+ "date",
7750
+ "time",
7751
+ "type",
7752
+ "class",
7753
+ "input",
7754
+ "output",
7755
+ "data",
7756
+ "value",
7757
+ "result",
7758
+ "response",
7759
+ "request",
7760
+ "item",
7761
+ "element"
7762
+ ];
7763
+ if (reservedNames.includes(name.toLowerCase())) {
7764
+ const suggestions = fieldType === "input" ? ["userInput", "questionText", "documentContent", "messageText"] : ["responseText", "analysisResult", "categoryType", "summaryText"];
7765
+ throw new SignatureValidationError(
7766
+ `Field name "${name}" is too generic`,
7767
+ this.position,
7768
+ this.getErrorContext(),
7769
+ `Use a more descriptive name. Examples: ${suggestions.join(", ")}`
7770
+ );
7771
+ }
7772
+ }
7773
+ const camelCaseRegex = /^[a-z][a-zA-Z0-9]*$/;
7774
+ const snakeCaseRegex = /^[a-z]+(_[a-z0-9]+)*$/;
7775
+ if (!camelCaseRegex.test(name) && !snakeCaseRegex.test(name)) {
7776
+ throw new SignatureValidationError(
7777
+ `Invalid field name "${name}"`,
7778
+ this.position,
7779
+ this.getErrorContext(),
7780
+ 'Field names must be in camelCase (e.g., "userInput") or snake_case (e.g., "user_input")'
7781
+ );
7782
+ }
7783
+ if (name.length < 2) {
7784
+ throw new SignatureValidationError(
7785
+ `Field name "${name}" is too short`,
7786
+ this.position,
7787
+ this.getErrorContext(),
7788
+ "Field names must be at least 2 characters long"
7789
+ );
7790
+ }
7791
+ if (name.length > 50) {
7792
+ throw new SignatureValidationError(
7793
+ `Field name "${name}" is too long (${name.length} characters)`,
7794
+ this.position,
7795
+ this.getErrorContext(),
7796
+ "Field names should be 50 characters or less"
7797
+ );
7798
+ }
7799
+ }
7495
7800
  parseTypeNotClass() {
7496
7801
  const types = [
7497
7802
  "string",
@@ -7506,13 +7811,42 @@ ${pointer}`;
7506
7811
  ];
7507
7812
  const foundType = types.find((type) => this.match(type));
7508
7813
  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(", ")}`
7814
+ const currentWord = this.input.slice(this.position).match(/^\w+/)?.[0] || "";
7815
+ const suggestion = this.suggestType(currentWord);
7816
+ const baseMessage = `Invalid type "${currentWord || "empty"}"`;
7817
+ const suggestionPart = suggestion ? `. Did you mean "${suggestion}"?` : "";
7818
+ const fullMessage = `${baseMessage}${suggestionPart}`;
7819
+ throw new SignatureValidationError(
7820
+ fullMessage,
7821
+ this.position,
7822
+ this.getErrorContext(),
7823
+ `Expected one of: ${types.join(", ")}`
7512
7824
  );
7513
7825
  }
7514
7826
  return foundType;
7515
7827
  }
7828
+ suggestType(input) {
7829
+ const suggestions = {
7830
+ str: "string",
7831
+ text: "string",
7832
+ int: "number",
7833
+ integer: "number",
7834
+ float: "number",
7835
+ double: "number",
7836
+ bool: "boolean",
7837
+ object: "json",
7838
+ dict: "json",
7839
+ timestamp: "datetime",
7840
+ time: "datetime",
7841
+ img: "image",
7842
+ picture: "image",
7843
+ sound: "audio",
7844
+ voice: "audio",
7845
+ classification: "class",
7846
+ category: "class"
7847
+ };
7848
+ return suggestions[input.toLowerCase()] || null;
7849
+ }
7516
7850
  parseParsedIdentifier() {
7517
7851
  this.skipWhitespace();
7518
7852
  const match = /^[a-zA-Z_][a-zA-Z_0-9]*/.exec(
@@ -7523,9 +7857,28 @@ ${pointer}`;
7523
7857
  return match[0];
7524
7858
  }
7525
7859
  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`
7860
+ const invalidId = invalidMatch ? invalidMatch[0] : "";
7861
+ if (invalidId === "") {
7862
+ throw new SignatureValidationError(
7863
+ "Expected field name but found end of input",
7864
+ this.position,
7865
+ this.getErrorContext(),
7866
+ "Add a field name. Field names must start with a letter or underscore"
7867
+ );
7868
+ }
7869
+ if (/^\d/.test(invalidId)) {
7870
+ throw new SignatureValidationError(
7871
+ `Invalid field name "${invalidId}" - cannot start with a number`,
7872
+ this.position,
7873
+ this.getErrorContext(),
7874
+ 'Field names must start with a letter or underscore. Example: "userInput" or "_internal"'
7875
+ );
7876
+ }
7877
+ throw new SignatureValidationError(
7878
+ `Invalid field name "${invalidId}"`,
7879
+ this.position,
7880
+ this.getErrorContext(),
7881
+ "Field names must start with a letter or underscore and contain only letters, numbers, or underscores"
7529
7882
  );
7530
7883
  }
7531
7884
  parseParsedString() {
@@ -7534,7 +7887,7 @@ ${pointer}`;
7534
7887
  if (this.match(quoteChar)) {
7535
7888
  let content = "";
7536
7889
  let escaped = false;
7537
- let startPos = this.position;
7890
+ const startPos = this.position - 1;
7538
7891
  while (this.position < this.input.length) {
7539
7892
  const char = this.input[this.position];
7540
7893
  this.position++;
@@ -7549,9 +7902,15 @@ ${pointer}`;
7549
7902
  content += char;
7550
7903
  }
7551
7904
  }
7552
- const partialString = this.input.slice(startPos, this.position);
7553
- throw new Error(
7554
- `Unterminated string starting at position ${startPos}: "${partialString}..."`
7905
+ const partialString = this.input.slice(
7906
+ startPos,
7907
+ Math.min(this.position, startPos + 20)
7908
+ );
7909
+ throw new SignatureValidationError(
7910
+ `Unterminated string starting at position ${startPos}`,
7911
+ startPos,
7912
+ this.getErrorContext(),
7913
+ `Add closing ${quoteChar} to complete the string: ${partialString}${quoteChar}`
7555
7914
  );
7556
7915
  }
7557
7916
  }
@@ -7579,11 +7938,15 @@ ${pointer}`;
7579
7938
  }
7580
7939
  return false;
7581
7940
  }
7582
- expect(str) {
7583
- if (!this.match(str)) {
7941
+ expectArrow() {
7942
+ if (!this.match("->")) {
7584
7943
  const found = this.input.slice(this.position, this.position + 10);
7585
- throw new Error(
7586
- `Expected "${str}" but found "${found}..." at position ${this.position}`
7944
+ const suggestion = found.includes(">") ? 'Use "->" (dash followed by greater-than)' : found.includes("-") ? 'Add ">" after the dash' : 'Add "->" to separate input and output fields';
7945
+ throw new SignatureValidationError(
7946
+ `Expected "->" but found "${found}..."`,
7947
+ this.position,
7948
+ this.getErrorContext(),
7949
+ suggestion
7587
7950
  );
7588
7951
  }
7589
7952
  }
@@ -7594,6 +7957,14 @@ function parseSignature(input) {
7594
7957
  }
7595
7958
 
7596
7959
  // dsp/sig.ts
7960
+ var AxSignatureValidationError = class extends Error {
7961
+ constructor(message, fieldName, suggestion) {
7962
+ super(message);
7963
+ this.fieldName = fieldName;
7964
+ this.suggestion = suggestion;
7965
+ this.name = "AxSignatureValidationError";
7966
+ }
7967
+ };
7597
7968
  var AxSignature = class _AxSignature {
7598
7969
  description;
7599
7970
  inputFields;
@@ -7613,8 +7984,18 @@ var AxSignature = class _AxSignature {
7613
7984
  try {
7614
7985
  sig = parseSignature(signature);
7615
7986
  } catch (e) {
7616
- throw new Error(
7617
- `Invalid Signature: ${e.message} (${signature})`
7987
+ if (e instanceof Error) {
7988
+ const suggestion = "suggestion" in e && typeof e.suggestion === "string" ? e.suggestion : 'Please check the signature format. Example: "userInput:string -> responseText:string"';
7989
+ throw new AxSignatureValidationError(
7990
+ `Invalid Signature: ${e.message}`,
7991
+ void 0,
7992
+ suggestion
7993
+ );
7994
+ }
7995
+ throw new AxSignatureValidationError(
7996
+ `Invalid Signature: ${signature}`,
7997
+ void 0,
7998
+ 'Please check the signature format. Example: "userInput:string -> responseText:string"'
7618
7999
  );
7619
8000
  }
7620
8001
  this.description = sig.desc;
@@ -7632,12 +8013,20 @@ var AxSignature = class _AxSignature {
7632
8013
  this.sigHash = signature.hash();
7633
8014
  this.sigString = signature.toString();
7634
8015
  } else {
7635
- throw new Error("invalid signature argument: " + signature);
8016
+ throw new AxSignatureValidationError(
8017
+ "Invalid signature argument type",
8018
+ void 0,
8019
+ "Signature must be a string or another AxSignature instance"
8020
+ );
7636
8021
  }
7637
8022
  }
7638
8023
  parseParsedField = (field) => {
7639
8024
  if (!field.name || field.name.length === 0) {
7640
- throw new Error("Field name is required.");
8025
+ throw new AxSignatureValidationError(
8026
+ "Field name is required",
8027
+ field.name,
8028
+ 'Every field must have a descriptive name. Example: "userInput", "responseText"'
8029
+ );
7641
8030
  }
7642
8031
  const title = this.toTitle(field.name);
7643
8032
  return {
@@ -7652,29 +8041,106 @@ var AxSignature = class _AxSignature {
7652
8041
  parseField = (field) => {
7653
8042
  const title = !field.title || field.title.length === 0 ? this.toTitle(field.name) : field.title;
7654
8043
  if (field.type && (!field.type.name || field.type.name.length === 0)) {
7655
- throw new Error("Field type name is required: " + field.name);
8044
+ throw new AxSignatureValidationError(
8045
+ "Field type name is required",
8046
+ field.name,
8047
+ "Specify a valid type. Available types: string, number, boolean, json, image, audio, date, datetime, class, code"
8048
+ );
7656
8049
  }
7657
8050
  return { ...field, title };
7658
8051
  };
7659
8052
  setDescription = (desc) => {
8053
+ if (typeof desc !== "string") {
8054
+ throw new AxSignatureValidationError(
8055
+ "Description must be a string",
8056
+ void 0,
8057
+ "Provide a string description for the signature"
8058
+ );
8059
+ }
7660
8060
  this.description = desc;
7661
8061
  this.updateHash();
7662
8062
  };
7663
8063
  addInputField = (field) => {
7664
- this.inputFields.push(this.parseField(field));
7665
- this.updateHash();
8064
+ try {
8065
+ const parsedField = this.parseField(field);
8066
+ validateField(parsedField, "input");
8067
+ this.inputFields.push(parsedField);
8068
+ this.updateHash();
8069
+ } catch (error) {
8070
+ if (error instanceof AxSignatureValidationError) {
8071
+ throw error;
8072
+ }
8073
+ throw new AxSignatureValidationError(
8074
+ `Failed to add input field "${field.name}": ${error instanceof Error ? error.message : "Unknown error"}`,
8075
+ field.name
8076
+ );
8077
+ }
7666
8078
  };
7667
8079
  addOutputField = (field) => {
7668
- this.outputFields.push(this.parseField(field));
7669
- this.updateHash();
8080
+ try {
8081
+ const parsedField = this.parseField(field);
8082
+ validateField(parsedField, "output");
8083
+ this.outputFields.push(parsedField);
8084
+ this.updateHash();
8085
+ } catch (error) {
8086
+ if (error instanceof AxSignatureValidationError) {
8087
+ throw error;
8088
+ }
8089
+ throw new AxSignatureValidationError(
8090
+ `Failed to add output field "${field.name}": ${error instanceof Error ? error.message : "Unknown error"}`,
8091
+ field.name
8092
+ );
8093
+ }
7670
8094
  };
7671
8095
  setInputFields = (fields) => {
7672
- this.inputFields = fields.map((v) => this.parseField(v));
7673
- this.updateHash();
8096
+ if (!Array.isArray(fields)) {
8097
+ throw new AxSignatureValidationError(
8098
+ "Input fields must be an array",
8099
+ void 0,
8100
+ "Provide an array of field objects"
8101
+ );
8102
+ }
8103
+ try {
8104
+ const parsedFields = fields.map((v) => {
8105
+ const parsed = this.parseField(v);
8106
+ validateField(parsed, "input");
8107
+ return parsed;
8108
+ });
8109
+ this.inputFields = parsedFields;
8110
+ this.updateHash();
8111
+ } catch (error) {
8112
+ if (error instanceof AxSignatureValidationError) {
8113
+ throw error;
8114
+ }
8115
+ throw new AxSignatureValidationError(
8116
+ `Failed to set input fields: ${error instanceof Error ? error.message : "Unknown error"}`
8117
+ );
8118
+ }
7674
8119
  };
7675
8120
  setOutputFields = (fields) => {
7676
- this.outputFields = fields.map((v) => this.parseField(v));
7677
- this.updateHash();
8121
+ if (!Array.isArray(fields)) {
8122
+ throw new AxSignatureValidationError(
8123
+ "Output fields must be an array",
8124
+ void 0,
8125
+ "Provide an array of field objects"
8126
+ );
8127
+ }
8128
+ try {
8129
+ const parsedFields = fields.map((v) => {
8130
+ const parsed = this.parseField(v);
8131
+ validateField(parsed, "output");
8132
+ return parsed;
8133
+ });
8134
+ this.outputFields = parsedFields;
8135
+ this.updateHash();
8136
+ } catch (error) {
8137
+ if (error instanceof AxSignatureValidationError) {
8138
+ throw error;
8139
+ }
8140
+ throw new AxSignatureValidationError(
8141
+ `Failed to set output fields: ${error instanceof Error ? error.message : "Unknown error"}`
8142
+ );
8143
+ }
7678
8144
  };
7679
8145
  getInputFields = () => this.inputFields;
7680
8146
  getOutputFields = () => this.outputFields;
@@ -7716,23 +8182,77 @@ var AxSignature = class _AxSignature {
7716
8182
  return schema;
7717
8183
  };
7718
8184
  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.");
8185
+ try {
8186
+ this.getInputFields().forEach((field) => {
8187
+ validateField(field, "input");
8188
+ });
8189
+ this.getOutputFields().forEach((field) => {
8190
+ validateField(field, "output");
8191
+ });
8192
+ this.validateSignatureConsistency();
8193
+ this.sigHash = createHash("sha256").update(this.description ?? "").update(JSON.stringify(this.inputFields)).update(JSON.stringify(this.outputFields)).digest("hex");
8194
+ this.sigString = renderSignature(
8195
+ this.description,
8196
+ this.inputFields,
8197
+ this.outputFields
8198
+ );
8199
+ return [this.sigHash, this.sigString];
8200
+ } catch (error) {
8201
+ if (error instanceof AxSignatureValidationError) {
8202
+ throw error;
7726
8203
  }
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];
8204
+ throw new AxSignatureValidationError(
8205
+ `Signature validation failed: ${error instanceof Error ? error.message : "Unknown error"}`
8206
+ );
8207
+ }
7735
8208
  };
8209
+ validateSignatureConsistency() {
8210
+ const inputNames = /* @__PURE__ */ new Set();
8211
+ for (const field of this.inputFields) {
8212
+ if (inputNames.has(field.name)) {
8213
+ throw new AxSignatureValidationError(
8214
+ `Duplicate input field name: "${field.name}"`,
8215
+ field.name,
8216
+ "Each field name must be unique within the signature"
8217
+ );
8218
+ }
8219
+ inputNames.add(field.name);
8220
+ }
8221
+ const outputNames = /* @__PURE__ */ new Set();
8222
+ for (const field of this.outputFields) {
8223
+ if (outputNames.has(field.name)) {
8224
+ throw new AxSignatureValidationError(
8225
+ `Duplicate output field name: "${field.name}"`,
8226
+ field.name,
8227
+ "Each field name must be unique within the signature"
8228
+ );
8229
+ }
8230
+ outputNames.add(field.name);
8231
+ }
8232
+ for (const outputField of this.outputFields) {
8233
+ if (inputNames.has(outputField.name)) {
8234
+ throw new AxSignatureValidationError(
8235
+ `Field name "${outputField.name}" appears in both inputs and outputs`,
8236
+ outputField.name,
8237
+ "Use different names for input and output fields to avoid confusion"
8238
+ );
8239
+ }
8240
+ }
8241
+ if (this.inputFields.length === 0) {
8242
+ throw new AxSignatureValidationError(
8243
+ "Signature must have at least one input field",
8244
+ void 0,
8245
+ 'Add an input field. Example: "userInput:string -> ..."'
8246
+ );
8247
+ }
8248
+ if (this.outputFields.length === 0) {
8249
+ throw new AxSignatureValidationError(
8250
+ "Signature must have at least one output field",
8251
+ void 0,
8252
+ 'Add an output field. Example: "... -> responseText:string"'
8253
+ );
8254
+ }
8255
+ }
7736
8256
  hash = () => this.sigHash;
7737
8257
  toString = () => this.sigString;
7738
8258
  toJSON = () => {
@@ -7749,54 +8269,194 @@ function renderField(field) {
7749
8269
  if (field.isOptional) {
7750
8270
  result += "?";
7751
8271
  }
8272
+ if (field.isInternal) {
8273
+ result += "!";
8274
+ }
7752
8275
  if (field.type) {
7753
8276
  result += ":" + field.type.name;
7754
8277
  if (field.type.isArray) {
7755
8278
  result += "[]";
7756
8279
  }
8280
+ if (field.type.name === "class" && field.type.options) {
8281
+ result += ` "${field.type.options.join(", ")}"`;
8282
+ }
7757
8283
  }
7758
- if (field.description) {
8284
+ if (field.description && field.type?.name !== "class") {
7759
8285
  result += ` "${field.description}"`;
7760
8286
  }
7761
8287
  return result;
7762
8288
  }
7763
8289
  function renderSignature(description, inputFields, outputFields) {
7764
- const descriptionPart = description ? `"${description}"` : "";
8290
+ const descriptionPart = description ? `"${description}" ` : "";
7765
8291
  const inputFieldsRendered = inputFields.map(renderField).join(", ");
7766
8292
  const outputFieldsRendered = outputFields.map(renderField).join(", ");
7767
- return `${descriptionPart} ${inputFieldsRendered} -> ${outputFieldsRendered}`;
8293
+ return `${descriptionPart}${inputFieldsRendered} -> ${outputFieldsRendered}`;
7768
8294
  }
7769
8295
  function isValidCase(inputString) {
7770
8296
  const camelCaseRegex = /^[a-z][a-zA-Z0-9]*$/;
7771
8297
  const snakeCaseRegex = /^[a-z]+(_[a-z0-9]+)*$/;
7772
8298
  return camelCaseRegex.test(inputString) || snakeCaseRegex.test(inputString);
7773
8299
  }
7774
- function validateField(field) {
8300
+ function validateField(field, context3) {
7775
8301
  if (!field.name || field.name.length === 0) {
7776
- throw new Error("Field name cannot be blank");
8302
+ throw new AxSignatureValidationError(
8303
+ "Field name cannot be blank",
8304
+ field.name,
8305
+ "Every field must have a descriptive name"
8306
+ );
7777
8307
  }
7778
8308
  if (!isValidCase(field.name)) {
7779
- throw new Error(
7780
- `Invalid field name '${field.name}', it must be camel case or snake case: `
8309
+ throw new AxSignatureValidationError(
8310
+ `Invalid field name '${field.name}' - must be camelCase or snake_case`,
8311
+ field.name,
8312
+ 'Use camelCase (e.g., "userInput") or snake_case (e.g., "user_input")'
7781
8313
  );
7782
8314
  }
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)`
8315
+ if (axGlobals.signatureStrict) {
8316
+ const reservedNames = [
8317
+ "text",
8318
+ "object",
8319
+ "image",
8320
+ "string",
8321
+ "number",
8322
+ "boolean",
8323
+ "json",
8324
+ "array",
8325
+ "datetime",
8326
+ "date",
8327
+ "time",
8328
+ "type",
8329
+ "class",
8330
+ "input",
8331
+ "output",
8332
+ "data",
8333
+ "value",
8334
+ "result",
8335
+ "response",
8336
+ "request",
8337
+ "item",
8338
+ "element"
8339
+ ];
8340
+ if (reservedNames.includes(field.name.toLowerCase())) {
8341
+ const suggestions = context3 === "input" ? [
8342
+ "userInput",
8343
+ "questionText",
8344
+ "documentContent",
8345
+ "messageText",
8346
+ "queryString"
8347
+ ] : [
8348
+ "responseText",
8349
+ "analysisResult",
8350
+ "categoryType",
8351
+ "summaryText",
8352
+ "outputData"
8353
+ ];
8354
+ throw new AxSignatureValidationError(
8355
+ `Field name '${field.name}' is too generic`,
8356
+ field.name,
8357
+ `Use a more descriptive name. Examples for ${context3} fields: ${suggestions.join(", ")}`
8358
+ );
8359
+ }
8360
+ }
8361
+ if (field.name.length < 2) {
8362
+ throw new AxSignatureValidationError(
8363
+ `Field name '${field.name}' is too short`,
8364
+ field.name,
8365
+ "Field names must be at least 2 characters long"
8366
+ );
8367
+ }
8368
+ if (field.name.length > 50) {
8369
+ throw new AxSignatureValidationError(
8370
+ `Field name '${field.name}' is too long (${field.name.length} characters)`,
8371
+ field.name,
8372
+ "Field names should be 50 characters or less"
8373
+ );
8374
+ }
8375
+ if (field.type) {
8376
+ validateFieldType(field, context3);
8377
+ }
8378
+ }
8379
+ function validateFieldType(field, context3) {
8380
+ if (!field.type) return;
8381
+ const { type } = field;
8382
+ if (type.name === "image" || type.name === "audio") {
8383
+ if (context3 === "output") {
8384
+ throw new AxSignatureValidationError(
8385
+ `${type.name} type is not supported in output fields`,
8386
+ field.name,
8387
+ `${type.name} types can only be used in input fields`
8388
+ );
8389
+ }
8390
+ if (type.isArray) {
8391
+ throw new AxSignatureValidationError(
8392
+ `Arrays of ${type.name} are not supported`,
8393
+ field.name,
8394
+ `Use a single ${type.name} type instead`
8395
+ );
8396
+ }
8397
+ }
8398
+ if (type.name === "class") {
8399
+ if (context3 === "input") {
8400
+ throw new AxSignatureValidationError(
8401
+ "Class type is not supported in input fields",
8402
+ field.name,
8403
+ 'Class types are only allowed on output fields. Use "string" type for input classifications'
8404
+ );
8405
+ }
8406
+ if (!type.options || type.options.length === 0) {
8407
+ throw new AxSignatureValidationError(
8408
+ "Class type requires options",
8409
+ field.name,
8410
+ 'Provide class options. Example: class "positive, negative, neutral"'
8411
+ );
8412
+ }
8413
+ if (type.options.length === 1) {
8414
+ throw new AxSignatureValidationError(
8415
+ "Class type needs at least 2 options",
8416
+ field.name,
8417
+ 'Add more class options or use "string" type instead'
8418
+ );
8419
+ }
8420
+ for (const option of type.options) {
8421
+ if (!option || option.trim().length === 0) {
8422
+ throw new AxSignatureValidationError(
8423
+ "Empty class option found",
8424
+ field.name,
8425
+ "All class options must be non-empty strings"
8426
+ );
8427
+ }
8428
+ const trimmedOption = option.trim();
8429
+ if (!/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(trimmedOption)) {
8430
+ throw new AxSignatureValidationError(
8431
+ `Invalid class option "${trimmedOption}"`,
8432
+ field.name,
8433
+ "Class options must start with a letter and contain only letters, numbers, underscores, or hyphens"
8434
+ );
8435
+ }
8436
+ }
8437
+ const uniqueOptions = new Set(
8438
+ type.options.map((opt) => opt.trim().toLowerCase())
8439
+ );
8440
+ if (uniqueOptions.size !== type.options.length) {
8441
+ throw new AxSignatureValidationError(
8442
+ "Duplicate class options found",
8443
+ field.name,
8444
+ "Each class option must be unique (case-insensitive)"
8445
+ );
8446
+ }
8447
+ }
8448
+ if (type.name === "code" && type.isArray) {
8449
+ throw new AxSignatureValidationError(
8450
+ "Arrays of code are not commonly supported",
8451
+ field.name,
8452
+ "Consider using a single code field or an array of strings instead"
8453
+ );
8454
+ }
8455
+ if (field.isInternal && context3 === "input") {
8456
+ throw new AxSignatureValidationError(
8457
+ "Internal marker (!) is not allowed on input fields",
8458
+ field.name,
8459
+ "Internal markers are only allowed on output fields"
7800
8460
  );
7801
8461
  }
7802
8462
  }
@@ -8387,6 +9047,7 @@ Content: ${result.content}`
8387
9047
  }
8388
9048
  let prompt;
8389
9049
  if (Array.isArray(values)) {
9050
+ validateAxMessageArray(values);
8390
9051
  prompt = this.promptTemplate.render(values, {
8391
9052
  examples: this.examples,
8392
9053
  demos: this.demos
@@ -11529,13 +12190,18 @@ var AxMockAIService = class {
11529
12190
  }
11530
12191
  };
11531
12192
  getLastUsedChatModel() {
11532
- throw new Error("Method not implemented.");
12193
+ return this.config.modelInfo?.name ?? "mock-model";
11533
12194
  }
11534
12195
  getLastUsedEmbedModel() {
11535
- throw new Error("Method not implemented.");
12196
+ return this.config.embedModelInfo?.name ?? "mock-embed-model";
11536
12197
  }
11537
12198
  getLastUsedModelConfig() {
11538
- throw new Error("Method not implemented.");
12199
+ return this.config.modelInfo ? {
12200
+ maxTokens: this.config.modelInfo.maxTokens,
12201
+ temperature: 0.7,
12202
+ // Default temperature
12203
+ stream: this.config.features?.streaming ?? false
12204
+ } : void 0;
11539
12205
  }
11540
12206
  getName() {
11541
12207
  return this.config.name ?? "mock-ai-service";
@@ -13938,6 +14604,7 @@ export {
13938
14604
  axAITogetherDefaultConfig,
13939
14605
  axBaseAIDefaultConfig,
13940
14606
  axBaseAIDefaultCreativeConfig,
14607
+ axGlobals,
13941
14608
  axModelInfoAnthropic,
13942
14609
  axModelInfoCohere,
13943
14610
  axModelInfoDeepSeek,