@ax-llm/ax 12.0.0 → 12.0.2

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.cjs CHANGED
@@ -1270,6 +1270,7 @@ var AxBaseAI = class {
1270
1270
  if (chatReq.functions && chatReq.functions.length > 0) {
1271
1271
  functions = chatReq.functions.map((fn2) => this.cleanupFunctionSchema(fn2));
1272
1272
  }
1273
+ validateChatPrompt(chatReq.chatPrompt);
1273
1274
  const req = {
1274
1275
  ...chatReq,
1275
1276
  model,
@@ -1611,6 +1612,31 @@ function setChatResponseEvents(res, span, excludeContentFromTrace) {
1611
1612
  });
1612
1613
  }
1613
1614
  }
1615
+ function validateAxMessageArray(values) {
1616
+ for (let i = 0; i < values.length; i++) {
1617
+ const message = values[i];
1618
+ if (!message || typeof message !== "object") {
1619
+ throw new Error(
1620
+ `AxMessage array validation failed: Item at index ${i} is not a valid message object`
1621
+ );
1622
+ }
1623
+ if ("content" in message && typeof message.content === "string" && message.content.trim() === "") {
1624
+ throw new Error(
1625
+ `AxMessage array validation failed: Item at index ${i} has empty content`
1626
+ );
1627
+ }
1628
+ }
1629
+ }
1630
+ function validateChatPrompt(chatPrompt) {
1631
+ for (let i = 0; i < chatPrompt.length; i++) {
1632
+ const message = chatPrompt[i];
1633
+ if (message && "content" in message && typeof message.content === "string" && message.content.trim() === "") {
1634
+ throw new Error(
1635
+ `Chat prompt validation failed: Message at index ${i} has empty content`
1636
+ );
1637
+ }
1638
+ }
1639
+ }
1614
1640
  function validateModels(models) {
1615
1641
  const keys = /* @__PURE__ */ new Set();
1616
1642
  for (const model of models) {
@@ -3387,7 +3413,9 @@ var AxAIGoogleGeminiImpl = class {
3387
3413
  const contents = req.chatPrompt.filter((p) => p.role !== "system").map((msg, i) => {
3388
3414
  switch (msg.role) {
3389
3415
  case "user": {
3390
- const parts = Array.isArray(msg.content) ? msg.content.map((c, i2) => {
3416
+ const parts = Array.isArray(
3417
+ msg.content
3418
+ ) ? msg.content.map((c, i2) => {
3391
3419
  switch (c.type) {
3392
3420
  case "text":
3393
3421
  return { text: c.text };
@@ -3448,12 +3476,14 @@ var AxAIGoogleGeminiImpl = class {
3448
3476
  }
3449
3477
  ];
3450
3478
  return {
3451
- role: "function",
3479
+ role: "model",
3452
3480
  parts
3453
3481
  };
3454
3482
  }
3455
3483
  default:
3456
- throw new Error("Invalid role");
3484
+ throw new Error(
3485
+ `Invalid role: ${JSON.stringify(msg)} (index: ${i})`
3486
+ );
3457
3487
  }
3458
3488
  });
3459
3489
  let tools = [];
@@ -5629,10 +5659,15 @@ var MemoryImpl = class {
5629
5659
  name,
5630
5660
  functionCalls
5631
5661
  }) {
5632
- if (!content && (!functionCalls || functionCalls.length === 0)) {
5662
+ const isContentEmpty = typeof content === "string" && content.trim() === "";
5663
+ if (isContentEmpty && (!functionCalls || functionCalls.length === 0)) {
5633
5664
  return;
5634
5665
  }
5635
- this.addMemory({ content, name, role: "assistant", functionCalls });
5666
+ if (isContentEmpty) {
5667
+ this.addMemory({ name, role: "assistant", functionCalls });
5668
+ } else {
5669
+ this.addMemory({ content, name, role: "assistant", functionCalls });
5670
+ }
5636
5671
  }
5637
5672
  addResult({
5638
5673
  content,
@@ -5654,7 +5689,7 @@ var MemoryImpl = class {
5654
5689
  if (!lastItem || lastItem.chat.role !== "assistant") {
5655
5690
  this.addResultMessage({ content, name, functionCalls });
5656
5691
  } else {
5657
- if ("content" in lastItem.chat && content) {
5692
+ if ("content" in lastItem.chat && typeof content === "string" && content.trim() !== "") {
5658
5693
  lastItem.chat.content = content;
5659
5694
  }
5660
5695
  if ("name" in lastItem.chat && name) {
@@ -7785,7 +7820,7 @@ var SignatureParser = class {
7785
7820
  'Add class names in quotes. Example: class "positive, negative, neutral"'
7786
7821
  );
7787
7822
  }
7788
- const options = classNamesString.split(/[,\s]+/).map((s2) => s2.trim()).filter((s2) => s2.length > 0);
7823
+ const options = classNamesString.split(/[,|]/).map((s2) => s2.trim()).filter((s2) => s2.length > 0);
7789
7824
  if (options.length === 0) {
7790
7825
  throw new SignatureValidationError(
7791
7826
  `Output field "${name}": Empty class list provided`,
@@ -7794,24 +7829,6 @@ var SignatureParser = class {
7794
7829
  'Provide at least one class option. Example: "positive, negative"'
7795
7830
  );
7796
7831
  }
7797
- if (options.length === 1) {
7798
- throw new SignatureValidationError(
7799
- `Output field "${name}": Class type needs at least 2 options`,
7800
- this.position,
7801
- this.getErrorContext(),
7802
- 'Add more class options or use "string" type instead. Example: "positive, negative, neutral"'
7803
- );
7804
- }
7805
- for (const option of options) {
7806
- if (!/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(option)) {
7807
- throw new SignatureValidationError(
7808
- `Output field "${name}": Invalid class option "${option}"`,
7809
- this.position,
7810
- this.getErrorContext(),
7811
- "Class options must start with a letter and contain only letters, numbers, underscores, or hyphens"
7812
- );
7813
- }
7814
- }
7815
7832
  type = { name: "class", isArray, options };
7816
7833
  } else {
7817
7834
  try {
@@ -8109,6 +8126,8 @@ var AxSignature = class _AxSignature {
8109
8126
  outputFields;
8110
8127
  sigHash;
8111
8128
  sigString;
8129
+ // Validation caching - stores hash when validation last passed
8130
+ validatedAtHash;
8112
8131
  constructor(signature) {
8113
8132
  if (!signature) {
8114
8133
  this.inputFields = [];
@@ -8150,6 +8169,9 @@ var AxSignature = class _AxSignature {
8150
8169
  );
8151
8170
  this.sigHash = signature.hash();
8152
8171
  this.sigString = signature.toString();
8172
+ if (signature.validatedAtHash === this.sigHash) {
8173
+ this.validatedAtHash = this.sigHash;
8174
+ }
8153
8175
  } else {
8154
8176
  throw new AxSignatureValidationError(
8155
8177
  "Invalid signature argument type",
@@ -8196,14 +8218,34 @@ var AxSignature = class _AxSignature {
8196
8218
  );
8197
8219
  }
8198
8220
  this.description = desc;
8221
+ this.invalidateValidationCache();
8199
8222
  this.updateHash();
8200
8223
  };
8201
8224
  addInputField = (field) => {
8202
8225
  try {
8203
8226
  const parsedField = this.parseField(field);
8204
8227
  validateField(parsedField, "input");
8228
+ for (const existingField of this.inputFields) {
8229
+ if (existingField.name === parsedField.name) {
8230
+ throw new AxSignatureValidationError(
8231
+ `Duplicate input field name: "${parsedField.name}"`,
8232
+ parsedField.name,
8233
+ "Each field name must be unique within the signature"
8234
+ );
8235
+ }
8236
+ }
8237
+ for (const outputField of this.outputFields) {
8238
+ if (outputField.name === parsedField.name) {
8239
+ throw new AxSignatureValidationError(
8240
+ `Field name "${parsedField.name}" appears in both inputs and outputs`,
8241
+ parsedField.name,
8242
+ "Use different names for input and output fields to avoid confusion"
8243
+ );
8244
+ }
8245
+ }
8205
8246
  this.inputFields.push(parsedField);
8206
- this.updateHash();
8247
+ this.invalidateValidationCache();
8248
+ this.updateHashLight();
8207
8249
  } catch (error) {
8208
8250
  if (error instanceof AxSignatureValidationError) {
8209
8251
  throw error;
@@ -8218,8 +8260,27 @@ var AxSignature = class _AxSignature {
8218
8260
  try {
8219
8261
  const parsedField = this.parseField(field);
8220
8262
  validateField(parsedField, "output");
8263
+ for (const existingField of this.outputFields) {
8264
+ if (existingField.name === parsedField.name) {
8265
+ throw new AxSignatureValidationError(
8266
+ `Duplicate output field name: "${parsedField.name}"`,
8267
+ parsedField.name,
8268
+ "Each field name must be unique within the signature"
8269
+ );
8270
+ }
8271
+ }
8272
+ for (const inputField of this.inputFields) {
8273
+ if (inputField.name === parsedField.name) {
8274
+ throw new AxSignatureValidationError(
8275
+ `Field name "${parsedField.name}" appears in both inputs and outputs`,
8276
+ parsedField.name,
8277
+ "Use different names for input and output fields to avoid confusion"
8278
+ );
8279
+ }
8280
+ }
8221
8281
  this.outputFields.push(parsedField);
8222
- this.updateHash();
8282
+ this.invalidateValidationCache();
8283
+ this.updateHashLight();
8223
8284
  } catch (error) {
8224
8285
  if (error instanceof AxSignatureValidationError) {
8225
8286
  throw error;
@@ -8245,6 +8306,7 @@ var AxSignature = class _AxSignature {
8245
8306
  return parsed;
8246
8307
  });
8247
8308
  this.inputFields = parsedFields;
8309
+ this.invalidateValidationCache();
8248
8310
  this.updateHash();
8249
8311
  } catch (error) {
8250
8312
  if (error instanceof AxSignatureValidationError) {
@@ -8270,6 +8332,7 @@ var AxSignature = class _AxSignature {
8270
8332
  return parsed;
8271
8333
  });
8272
8334
  this.outputFields = parsedFields;
8335
+ this.invalidateValidationCache();
8273
8336
  this.updateHash();
8274
8337
  } catch (error) {
8275
8338
  if (error instanceof AxSignatureValidationError) {
@@ -8283,6 +8346,9 @@ var AxSignature = class _AxSignature {
8283
8346
  getInputFields = () => this.inputFields;
8284
8347
  getOutputFields = () => this.outputFields;
8285
8348
  getDescription = () => this.description;
8349
+ invalidateValidationCache = () => {
8350
+ this.validatedAtHash = void 0;
8351
+ };
8286
8352
  toTitle = (name) => {
8287
8353
  let result = name.replace(/_/g, " ");
8288
8354
  result = result.replace(/([A-Z]|[0-9]+)/g, " $1").trim();
@@ -8319,6 +8385,30 @@ var AxSignature = class _AxSignature {
8319
8385
  };
8320
8386
  return schema;
8321
8387
  };
8388
+ updateHashLight = () => {
8389
+ try {
8390
+ this.getInputFields().forEach((field) => {
8391
+ validateField(field, "input");
8392
+ });
8393
+ this.getOutputFields().forEach((field) => {
8394
+ validateField(field, "output");
8395
+ });
8396
+ this.sigHash = (0, import_crypto3.createHash)("sha256").update(this.description ?? "").update(JSON.stringify(this.inputFields)).update(JSON.stringify(this.outputFields)).digest("hex");
8397
+ this.sigString = renderSignature(
8398
+ this.description,
8399
+ this.inputFields,
8400
+ this.outputFields
8401
+ );
8402
+ return [this.sigHash, this.sigString];
8403
+ } catch (error) {
8404
+ if (error instanceof AxSignatureValidationError) {
8405
+ throw error;
8406
+ }
8407
+ throw new AxSignatureValidationError(
8408
+ `Signature validation failed: ${error instanceof Error ? error.message : "Unknown error"}`
8409
+ );
8410
+ }
8411
+ };
8322
8412
  updateHash = () => {
8323
8413
  try {
8324
8414
  this.getInputFields().forEach((field) => {
@@ -8391,6 +8481,19 @@ var AxSignature = class _AxSignature {
8391
8481
  );
8392
8482
  }
8393
8483
  }
8484
+ validate = () => {
8485
+ if (this.validatedAtHash === this.sigHash) {
8486
+ return true;
8487
+ }
8488
+ try {
8489
+ this.updateHash();
8490
+ this.validatedAtHash = this.sigHash;
8491
+ return true;
8492
+ } catch (error) {
8493
+ this.validatedAtHash = void 0;
8494
+ throw error;
8495
+ }
8496
+ };
8394
8497
  hash = () => this.sigHash;
8395
8498
  toString = () => this.sigString;
8396
8499
  toJSON = () => {
@@ -8416,7 +8519,7 @@ function renderField(field) {
8416
8519
  result += "[]";
8417
8520
  }
8418
8521
  if (field.type.name === "class" && field.type.options) {
8419
- result += ` "${field.type.options.join(", ")}"`;
8522
+ result += ` "${field.type.options.join(" | ")}"`;
8420
8523
  }
8421
8524
  }
8422
8525
  if (field.description && field.type?.name !== "class") {
@@ -8548,13 +8651,6 @@ function validateFieldType(field, context3) {
8548
8651
  'Provide class options. Example: class "positive, negative, neutral"'
8549
8652
  );
8550
8653
  }
8551
- if (type.options.length === 1) {
8552
- throw new AxSignatureValidationError(
8553
- "Class type needs at least 2 options",
8554
- field.name,
8555
- 'Add more class options or use "string" type instead'
8556
- );
8557
- }
8558
8654
  for (const option of type.options) {
8559
8655
  if (!option || option.trim().length === 0) {
8560
8656
  throw new AxSignatureValidationError(
@@ -8564,11 +8660,11 @@ function validateFieldType(field, context3) {
8564
8660
  );
8565
8661
  }
8566
8662
  const trimmedOption = option.trim();
8567
- if (!/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(trimmedOption)) {
8663
+ if (trimmedOption.includes(",") || trimmedOption.includes("|")) {
8568
8664
  throw new AxSignatureValidationError(
8569
8665
  `Invalid class option "${trimmedOption}"`,
8570
8666
  field.name,
8571
- "Class options must start with a letter and contain only letters, numbers, underscores, or hyphens"
8667
+ "Class options cannot contain commas (,) or pipes (|) as they are used to separate options"
8572
8668
  );
8573
8669
  }
8574
8670
  }
@@ -8612,12 +8708,13 @@ var AxProgramWithSignature = class {
8612
8708
  children;
8613
8709
  constructor(signature, options) {
8614
8710
  this.signature = new AxSignature(signature);
8615
- this.sigHash = this.signature?.hash();
8616
- this.children = new AxInstanceRegistry();
8617
- this.key = { id: this.constructor.name };
8618
8711
  if (options?.description) {
8619
8712
  this.signature.setDescription(options.description);
8620
8713
  }
8714
+ this.signature.validate();
8715
+ this.sigHash = this.signature?.hash();
8716
+ this.children = new AxInstanceRegistry();
8717
+ this.key = { id: this.constructor.name };
8621
8718
  }
8622
8719
  getSignature() {
8623
8720
  return this.signature;
@@ -9185,6 +9282,7 @@ Content: ${result.content}`
9185
9282
  }
9186
9283
  let prompt;
9187
9284
  if (Array.isArray(values)) {
9285
+ validateAxMessageArray(values);
9188
9286
  prompt = this.promptTemplate.render(values, {
9189
9287
  examples: this.examples,
9190
9288
  demos: this.demos