@ax-llm/ax 12.0.16 → 12.0.17

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
@@ -1,71 +1,3 @@
1
- // ai/base.ts
2
- import crypto2 from "crypto";
3
- import { context, SpanKind } from "@opentelemetry/api";
4
-
5
- // trace/trace.ts
6
- var axSpanAttributes = {
7
- // LLM
8
- LLM_SYSTEM: "gen_ai.system",
9
- LLM_OPERATION_NAME: "gen_ai.operation.name",
10
- LLM_REQUEST_MODEL: "gen_ai.request.model",
11
- LLM_REQUEST_MAX_TOKENS: "gen_ai.request.max_tokens",
12
- LLM_REQUEST_TEMPERATURE: "gen_ai.request.temperature",
13
- LLM_REQUEST_TOP_K: "gen_ai.request.top_k",
14
- LLM_REQUEST_FREQUENCY_PENALTY: "gen_ai.request.frequency_penalty",
15
- LLM_REQUEST_PRESENCE_PENALTY: "gen_ai.request.presence_penalty",
16
- LLM_REQUEST_STOP_SEQUENCES: "gen_ai.request.stop_sequences",
17
- LLM_REQUEST_LLM_IS_STREAMING: "gen_ai.request.llm_is_streaming",
18
- LLM_REQUEST_TOP_P: "gen_ai.request.top_p",
19
- LLM_USAGE_INPUT_TOKENS: "gen_ai.usage.input_tokens",
20
- LLM_USAGE_OUTPUT_TOKENS: "gen_ai.usage.output_tokens",
21
- LLM_USAGE_TOTAL_TOKENS: "gen_ai.usage.total_tokens",
22
- LLM_USAGE_THOUGHTS_TOKENS: "gen_ai.usage.thoughts_tokens",
23
- // Vector DB
24
- DB_SYSTEM: "db.system",
25
- DB_TABLE: "db.table",
26
- DB_NAMESPACE: "db.namespace",
27
- DB_ID: "db.id",
28
- DB_QUERY_TEXT: "db.query.text",
29
- DB_VECTOR: "db.vector",
30
- DB_OPERATION_NAME: "db.operation.name",
31
- DB_VECTOR_QUERY_TOP_K: "db.vector.query.top_k",
32
- DB_QUERY_EMBEDDINGS: "db.query.embeddings",
33
- DB_QUERY_RESULT: "db.query.result",
34
- // Query Embeddings
35
- DB_QUERY_EMBEDDINGS_VECTOR: "db.query.embeddings.vector",
36
- // Query Result (canonical format)
37
- DB_QUERY_RESULT_ID: "db.query.result.id",
38
- DB_QUERY_RESULT_SCORE: "db.query.result.score",
39
- DB_QUERY_RESULT_DISTANCE: "db.query.result.distance",
40
- DB_QUERY_RESULT_METADATA: "db.query.result.metadata",
41
- DB_QUERY_RESULT_VECTOR: "db.query.result.vector",
42
- DB_QUERY_RESULT_DOCUMENT: "db.query.result.document"
43
- };
44
- var axSpanEvents = {
45
- GEN_AI_USER_MESSAGE: "gen_ai.user.message",
46
- GEN_AI_SYSTEM_MESSAGE: "gen_ai.system.message",
47
- GEN_AI_ASSISTANT_MESSAGE: "gen_ai.assistant.message",
48
- GEN_AI_TOOL_MESSAGE: "gen_ai.tool.message",
49
- // For tool messages in request & response tool calls
50
- GEN_AI_CHOICE: "gen_ai.choice",
51
- GEN_AI_USAGE: "gen_ai.usage"
52
- };
53
- var AxLLMRequestTypeValues = /* @__PURE__ */ ((AxLLMRequestTypeValues2) => {
54
- AxLLMRequestTypeValues2["COMPLETION"] = "completion";
55
- AxLLMRequestTypeValues2["CHAT"] = "chat";
56
- AxLLMRequestTypeValues2["RERANK"] = "rerank";
57
- AxLLMRequestTypeValues2["UNKNOWN"] = "unknown";
58
- return AxLLMRequestTypeValues2;
59
- })(AxLLMRequestTypeValues || {});
60
- var AxSpanKindValues = /* @__PURE__ */ ((AxSpanKindValues2) => {
61
- AxSpanKindValues2["WORKFLOW"] = "workflow";
62
- AxSpanKindValues2["TASK"] = "task";
63
- AxSpanKindValues2["AGENT"] = "agent";
64
- AxSpanKindValues2["TOOL"] = "tool";
65
- AxSpanKindValues2["UNKNOWN"] = "unknown";
66
- return AxSpanKindValues2;
67
- })(AxSpanKindValues || {});
68
-
69
1
  // util/apicall.ts
70
2
  import crypto from "crypto";
71
3
  import {
@@ -320,6 +252,33 @@ var AxAIServiceAuthenticationError = class extends AxAIServiceError {
320
252
  this.name = this.constructor.name;
321
253
  }
322
254
  };
255
+ var AxAIRefusalError = class extends Error {
256
+ constructor(refusalMessage, model, requestId) {
257
+ super(`Model refused to fulfill request: ${refusalMessage}`);
258
+ this.refusalMessage = refusalMessage;
259
+ this.model = model;
260
+ this.requestId = requestId;
261
+ this.name = "AxAIRefusalError";
262
+ this.timestamp = (/* @__PURE__ */ new Date()).toISOString();
263
+ this.errorId = crypto.randomUUID();
264
+ }
265
+ timestamp;
266
+ errorId;
267
+ toString() {
268
+ return [
269
+ `${this.name}: ${this.message}`,
270
+ `Refusal: ${this.refusalMessage}`,
271
+ this.model ? `Model: ${this.model}` : "",
272
+ this.requestId ? `Request ID: ${this.requestId}` : "",
273
+ `Timestamp: ${this.timestamp}`,
274
+ `Error ID: ${this.errorId}`
275
+ ].filter(Boolean).join("\n");
276
+ }
277
+ // For Node.js, override the custom inspect method so console.log shows our custom string.
278
+ [Symbol.for("nodejs.util.inspect.custom")](_depth, _options) {
279
+ return this.toString();
280
+ }
281
+ };
323
282
  async function safeReadResponseBody(response) {
324
283
  try {
325
284
  if (response.headers.get("content-type")?.includes("application/json")) {
@@ -623,6 +582,74 @@ var apiCall = async (api, json) => {
623
582
  }
624
583
  };
625
584
 
585
+ // ai/base.ts
586
+ import crypto2 from "crypto";
587
+ import { context, SpanKind } from "@opentelemetry/api";
588
+
589
+ // trace/trace.ts
590
+ var axSpanAttributes = {
591
+ // LLM
592
+ LLM_SYSTEM: "gen_ai.system",
593
+ LLM_OPERATION_NAME: "gen_ai.operation.name",
594
+ LLM_REQUEST_MODEL: "gen_ai.request.model",
595
+ LLM_REQUEST_MAX_TOKENS: "gen_ai.request.max_tokens",
596
+ LLM_REQUEST_TEMPERATURE: "gen_ai.request.temperature",
597
+ LLM_REQUEST_TOP_K: "gen_ai.request.top_k",
598
+ LLM_REQUEST_FREQUENCY_PENALTY: "gen_ai.request.frequency_penalty",
599
+ LLM_REQUEST_PRESENCE_PENALTY: "gen_ai.request.presence_penalty",
600
+ LLM_REQUEST_STOP_SEQUENCES: "gen_ai.request.stop_sequences",
601
+ LLM_REQUEST_LLM_IS_STREAMING: "gen_ai.request.llm_is_streaming",
602
+ LLM_REQUEST_TOP_P: "gen_ai.request.top_p",
603
+ LLM_USAGE_INPUT_TOKENS: "gen_ai.usage.input_tokens",
604
+ LLM_USAGE_OUTPUT_TOKENS: "gen_ai.usage.output_tokens",
605
+ LLM_USAGE_TOTAL_TOKENS: "gen_ai.usage.total_tokens",
606
+ LLM_USAGE_THOUGHTS_TOKENS: "gen_ai.usage.thoughts_tokens",
607
+ // Vector DB
608
+ DB_SYSTEM: "db.system",
609
+ DB_TABLE: "db.table",
610
+ DB_NAMESPACE: "db.namespace",
611
+ DB_ID: "db.id",
612
+ DB_QUERY_TEXT: "db.query.text",
613
+ DB_VECTOR: "db.vector",
614
+ DB_OPERATION_NAME: "db.operation.name",
615
+ DB_VECTOR_QUERY_TOP_K: "db.vector.query.top_k",
616
+ DB_QUERY_EMBEDDINGS: "db.query.embeddings",
617
+ DB_QUERY_RESULT: "db.query.result",
618
+ // Query Embeddings
619
+ DB_QUERY_EMBEDDINGS_VECTOR: "db.query.embeddings.vector",
620
+ // Query Result (canonical format)
621
+ DB_QUERY_RESULT_ID: "db.query.result.id",
622
+ DB_QUERY_RESULT_SCORE: "db.query.result.score",
623
+ DB_QUERY_RESULT_DISTANCE: "db.query.result.distance",
624
+ DB_QUERY_RESULT_METADATA: "db.query.result.metadata",
625
+ DB_QUERY_RESULT_VECTOR: "db.query.result.vector",
626
+ DB_QUERY_RESULT_DOCUMENT: "db.query.result.document"
627
+ };
628
+ var axSpanEvents = {
629
+ GEN_AI_USER_MESSAGE: "gen_ai.user.message",
630
+ GEN_AI_SYSTEM_MESSAGE: "gen_ai.system.message",
631
+ GEN_AI_ASSISTANT_MESSAGE: "gen_ai.assistant.message",
632
+ GEN_AI_TOOL_MESSAGE: "gen_ai.tool.message",
633
+ // For tool messages in request & response tool calls
634
+ GEN_AI_CHOICE: "gen_ai.choice",
635
+ GEN_AI_USAGE: "gen_ai.usage"
636
+ };
637
+ var AxLLMRequestTypeValues = /* @__PURE__ */ ((AxLLMRequestTypeValues2) => {
638
+ AxLLMRequestTypeValues2["COMPLETION"] = "completion";
639
+ AxLLMRequestTypeValues2["CHAT"] = "chat";
640
+ AxLLMRequestTypeValues2["RERANK"] = "rerank";
641
+ AxLLMRequestTypeValues2["UNKNOWN"] = "unknown";
642
+ return AxLLMRequestTypeValues2;
643
+ })(AxLLMRequestTypeValues || {});
644
+ var AxSpanKindValues = /* @__PURE__ */ ((AxSpanKindValues2) => {
645
+ AxSpanKindValues2["WORKFLOW"] = "workflow";
646
+ AxSpanKindValues2["TASK"] = "task";
647
+ AxSpanKindValues2["AGENT"] = "agent";
648
+ AxSpanKindValues2["TOOL"] = "tool";
649
+ AxSpanKindValues2["UNKNOWN"] = "unknown";
650
+ return AxSpanKindValues2;
651
+ })(AxSpanKindValues || {});
652
+
626
653
  // util/transform.ts
627
654
  import {
628
655
  TransformStream as TransformStream4
@@ -1988,7 +2015,13 @@ var AxAIAnthropicImpl = class {
1988
2015
  };
1989
2016
  createChatResp = (resp) => {
1990
2017
  if (resp.type === "error") {
1991
- throw new Error(`Anthropic Chat API Error: ${resp.error.message}`);
2018
+ throw new AxAIRefusalError(
2019
+ resp.error.message,
2020
+ void 0,
2021
+ // model not specified in error response
2022
+ void 0
2023
+ // requestId not specified in error response
2024
+ );
1992
2025
  }
1993
2026
  const finishReason = mapFinishReason(resp.stop_reason);
1994
2027
  const showThoughts = this.currentPromptConfig?.thinkingTokenBudget !== "none" && this.currentPromptConfig?.showThoughts !== false;
@@ -2044,7 +2077,13 @@ var AxAIAnthropicImpl = class {
2044
2077
  }
2045
2078
  if (resp.type === "error") {
2046
2079
  const { error } = resp;
2047
- throw new Error(error.message);
2080
+ throw new AxAIRefusalError(
2081
+ error.message,
2082
+ void 0,
2083
+ // model not specified in error event
2084
+ void 0
2085
+ // requestId not specified in error event
2086
+ );
2048
2087
  }
2049
2088
  const index = 0;
2050
2089
  if (resp.type === "message_start") {
@@ -2672,6 +2711,9 @@ var AxAIOpenAIImpl = class {
2672
2711
  totalTokens: usage.total_tokens
2673
2712
  } : void 0;
2674
2713
  const results = choices.map((choice) => {
2714
+ if (choice.message.refusal) {
2715
+ throw new AxAIRefusalError(choice.message.refusal, resp.model, resp.id);
2716
+ }
2675
2717
  const finishReason = mapFinishReason2(choice.finish_reason);
2676
2718
  const functionCalls = choice.message.tool_calls?.map(
2677
2719
  ({ id: id2, function: { arguments: params, name } }) => ({
@@ -2683,8 +2725,9 @@ var AxAIOpenAIImpl = class {
2683
2725
  return {
2684
2726
  index: choice.index,
2685
2727
  id: `${choice.index}`,
2686
- content: choice.message.content,
2728
+ content: choice.message.content ?? void 0,
2687
2729
  thought: choice.message.reasoning_content,
2730
+ annotations: choice.message.annotations,
2688
2731
  functionCalls,
2689
2732
  finishReason
2690
2733
  };
@@ -2711,11 +2754,16 @@ var AxAIOpenAIImpl = class {
2711
2754
  delta: {
2712
2755
  content,
2713
2756
  role,
2757
+ refusal,
2714
2758
  tool_calls: toolCalls,
2715
- reasoning_content: thought
2759
+ reasoning_content: thought,
2760
+ annotations
2716
2761
  },
2717
2762
  finish_reason: oaiFinishReason
2718
2763
  }) => {
2764
+ if (refusal) {
2765
+ throw new AxAIRefusalError(refusal, void 0, id);
2766
+ }
2719
2767
  const finishReason = mapFinishReason2(oaiFinishReason);
2720
2768
  const functionCalls = toolCalls?.map(({ id: _id, index: index2, function: { name, arguments: params } }) => {
2721
2769
  if (typeof _id === "string" && typeof index2 === "number" && !sstate.indexIdMap[index2]) {
@@ -2733,9 +2781,10 @@ var AxAIOpenAIImpl = class {
2733
2781
  }).filter((v) => v !== null);
2734
2782
  return {
2735
2783
  index,
2736
- content,
2784
+ content: content ?? void 0,
2737
2785
  role,
2738
2786
  thought,
2787
+ annotations,
2739
2788
  functionCalls,
2740
2789
  finishReason,
2741
2790
  id
@@ -3832,11 +3881,29 @@ var AxAIGoogleGeminiImpl = class {
3832
3881
  result.finishReason = "stop";
3833
3882
  break;
3834
3883
  case "SAFETY":
3835
- throw new Error("Finish reason: SAFETY");
3884
+ throw new AxAIRefusalError(
3885
+ "Content was blocked due to safety settings",
3886
+ void 0,
3887
+ // model not available in candidate
3888
+ void 0
3889
+ // requestId not available
3890
+ );
3836
3891
  case "RECITATION":
3837
- throw new Error("Finish reason: RECITATION");
3892
+ throw new AxAIRefusalError(
3893
+ "Content was blocked due to recitation policy",
3894
+ void 0,
3895
+ // model not available in candidate
3896
+ void 0
3897
+ // requestId not available
3898
+ );
3838
3899
  case "MALFORMED_FUNCTION_CALL":
3839
- throw new Error("Finish reason: MALFORMED_FUNCTION_CALL");
3900
+ throw new AxAIRefusalError(
3901
+ "Function call was malformed and blocked",
3902
+ void 0,
3903
+ // model not available in candidate
3904
+ void 0
3905
+ // requestId not available
3906
+ );
3840
3907
  }
3841
3908
  if (!candidate.content || !candidate.content.parts) {
3842
3909
  return result;
@@ -4714,7 +4781,7 @@ var AxAIOpenAIResponsesImpl = class {
4714
4781
  switch (item.type) {
4715
4782
  case "message":
4716
4783
  currentResult.id = item.id;
4717
- currentResult.content = contentToText(item.content);
4784
+ currentResult.content = contentToText(item.content, id);
4718
4785
  currentResult.finishReason = item.status === "completed" ? "stop" : "content_filter";
4719
4786
  break;
4720
4787
  case "reasoning":
@@ -4887,7 +4954,10 @@ var AxAIOpenAIResponsesImpl = class {
4887
4954
  switch (event.item.type) {
4888
4955
  case "message":
4889
4956
  baseResult.id = event.item.id;
4890
- baseResult.content = contentToText(event.item.content);
4957
+ baseResult.content = contentToText(
4958
+ event.item.content,
4959
+ event.item.id
4960
+ );
4891
4961
  break;
4892
4962
  case "function_call":
4893
4963
  baseResult.id = event.item.id;
@@ -5057,7 +5127,7 @@ var AxAIOpenAIResponsesImpl = class {
5057
5127
  break;
5058
5128
  case "response.content_part.added":
5059
5129
  baseResult.id = event.item_id;
5060
- baseResult.content = contentToText([event.part]);
5130
+ baseResult.content = contentToText([event.part], event.item_id);
5061
5131
  break;
5062
5132
  case "response.output_text.delta":
5063
5133
  baseResult.id = event.item_id;
@@ -5242,11 +5312,13 @@ var AxAIOpenAIResponsesImpl = class {
5242
5312
  return [apiConfig, reqValue];
5243
5313
  }
5244
5314
  };
5245
- var contentToText = (content) => {
5246
- return [
5247
- ...content.filter((c) => c.type === "output_text").map((c) => c.text),
5248
- ...content.filter((c) => c.type === "refusal").map((c) => c.refusal)
5249
- ].join("\n");
5315
+ var contentToText = (content, responseId) => {
5316
+ const refusalContent = content.filter((c) => c.type === "refusal");
5317
+ if (refusalContent.length > 0) {
5318
+ const refusalMessage = refusalContent.map((c) => c.refusal).join("\n");
5319
+ throw new AxAIRefusalError(refusalMessage, void 0, responseId);
5320
+ }
5321
+ return content.filter((c) => c.type === "output_text").map((c) => c.text).join("\n");
5250
5322
  };
5251
5323
 
5252
5324
  // ai/openai/responses_api_base.ts
@@ -5834,213 +5906,279 @@ import {
5834
5906
 
5835
5907
  // ai/validate.ts
5836
5908
  function axValidateChatRequestMessage(item) {
5909
+ const value = (v) => JSON.stringify(v, null, 2);
5837
5910
  if (!item) {
5838
- throw new Error("Chat request message item cannot be null or undefined");
5911
+ throw new Error(
5912
+ `Chat request message item cannot be null or undefined, received: ${value(item)}`
5913
+ );
5839
5914
  }
5840
- if (!item.role) {
5841
- throw new Error("Chat request message must have a role");
5915
+ const role = item?.role;
5916
+ if (!role) {
5917
+ throw new Error(
5918
+ `Chat request message must have a role, received: ${value(role)}`
5919
+ );
5842
5920
  }
5843
- switch (item.role) {
5844
- case "system":
5845
- if (!item.content || item.content.trim() === "") {
5921
+ switch (role) {
5922
+ case "system": {
5923
+ const systemItem = item;
5924
+ if (!systemItem.content || systemItem.content.trim() === "") {
5846
5925
  throw new Error(
5847
- "System message content cannot be empty or whitespace-only"
5926
+ `System message content cannot be empty or whitespace-only, received: ${value(systemItem.content)}`
5848
5927
  );
5849
5928
  }
5850
5929
  break;
5851
- case "user":
5852
- if (!item.content) {
5853
- throw new Error("User message content cannot be undefined");
5930
+ }
5931
+ case "user": {
5932
+ const userItem = item;
5933
+ if (!userItem.content) {
5934
+ throw new Error(
5935
+ `User message content cannot be undefined, received: ${value(userItem.content)}`
5936
+ );
5854
5937
  }
5855
- if (typeof item.content === "string") {
5856
- if (item.content.trim() === "") {
5938
+ if (typeof userItem.content === "string") {
5939
+ if (userItem.content.trim() === "") {
5857
5940
  throw new Error(
5858
- "User message content cannot be empty or whitespace-only"
5941
+ `User message content cannot be empty or whitespace-only, received: ${value(userItem.content)}`
5859
5942
  );
5860
5943
  }
5861
- } else if (Array.isArray(item.content)) {
5862
- if (item.content.length === 0) {
5863
- throw new Error("User message content array cannot be empty");
5944
+ } else if (Array.isArray(userItem.content)) {
5945
+ if (userItem.content.length === 0) {
5946
+ throw new Error(
5947
+ `User message content array cannot be empty, received: ${value(userItem.content)}`
5948
+ );
5864
5949
  }
5865
- for (let index = 0; index < item.content.length; index++) {
5866
- const contentItem = item.content[index];
5950
+ for (let index = 0; index < userItem.content.length; index++) {
5951
+ const contentItem = userItem.content[index];
5867
5952
  if (!contentItem || typeof contentItem !== "object") {
5868
5953
  throw new Error(
5869
- `User message content item at index ${index} must be an object`
5954
+ `User message content item at index ${index} must be an object, received: ${value(contentItem)}`
5870
5955
  );
5871
5956
  }
5872
- if (!contentItem.type) {
5957
+ const contentType = contentItem?.type;
5958
+ if (!contentType) {
5873
5959
  throw new Error(
5874
- `User message content item at index ${index} must have a type`
5960
+ `User message content item at index ${index} must have a type, received: ${value(contentType)}`
5875
5961
  );
5876
5962
  }
5877
- switch (contentItem.type) {
5878
- case "text":
5879
- if (!contentItem.text || contentItem.text.trim() === "") {
5963
+ switch (contentType) {
5964
+ case "text": {
5965
+ const textItem = contentItem;
5966
+ if (!textItem.text || textItem.text.trim() === "") {
5880
5967
  throw new Error(
5881
- `User message text content at index ${index} cannot be empty or whitespace-only`
5968
+ `User message text content at index ${index} cannot be empty or whitespace-only, received: ${value(textItem.text)}`
5882
5969
  );
5883
5970
  }
5884
5971
  break;
5885
- case "image":
5886
- if (!contentItem.image || contentItem.image.trim() === "") {
5972
+ }
5973
+ case "image": {
5974
+ const imageItem = contentItem;
5975
+ if (!imageItem.image || imageItem.image.trim() === "") {
5887
5976
  throw new Error(
5888
- `User message image content at index ${index} cannot be empty`
5977
+ `User message image content at index ${index} cannot be empty, received: ${value(imageItem.image)}`
5889
5978
  );
5890
5979
  }
5891
- if (!contentItem.mimeType || contentItem.mimeType.trim() === "") {
5980
+ if (!imageItem.mimeType || imageItem.mimeType.trim() === "") {
5892
5981
  throw new Error(
5893
- `User message image content at index ${index} must have a mimeType`
5982
+ `User message image content at index ${index} must have a mimeType, received: ${value(imageItem.mimeType)}`
5894
5983
  );
5895
5984
  }
5896
5985
  break;
5897
- case "audio":
5898
- if (!contentItem.data || contentItem.data.trim() === "") {
5986
+ }
5987
+ case "audio": {
5988
+ const audioItem = contentItem;
5989
+ if (!audioItem.data || audioItem.data.trim() === "") {
5899
5990
  throw new Error(
5900
- `User message audio content at index ${index} cannot be empty`
5991
+ `User message audio content at index ${index} cannot be empty, received: ${value(audioItem.data)}`
5901
5992
  );
5902
5993
  }
5903
5994
  break;
5995
+ }
5904
5996
  default:
5905
5997
  throw new Error(
5906
- `User message content item at index ${index} has unsupported type: ${contentItem.type}`
5998
+ `User message content item at index ${index} has unsupported type: ${value(contentType)}`
5907
5999
  );
5908
6000
  }
5909
6001
  }
5910
6002
  } else {
5911
6003
  throw new Error(
5912
- "User message content must be a string or array of content objects"
6004
+ `User message content must be a string or array of content objects, received: ${value(userItem.content)}`
5913
6005
  );
5914
6006
  }
5915
6007
  break;
5916
- case "assistant":
5917
- if (!item.content && !item.functionCalls) {
6008
+ }
6009
+ case "assistant": {
6010
+ const assistantItem = item;
6011
+ if (!assistantItem.content && !assistantItem.functionCalls) {
5918
6012
  throw new Error(
5919
- "Assistant message must have either content or function calls"
6013
+ `Assistant message must have either content or function calls, received content: ${value(assistantItem.content)}, functionCalls: ${value(assistantItem.functionCalls)}`
5920
6014
  );
5921
6015
  }
5922
- if (item.content && typeof item.content !== "string") {
5923
- throw new Error("Assistant message content must be a string");
6016
+ if (assistantItem.content && typeof assistantItem.content !== "string") {
6017
+ throw new Error(
6018
+ `Assistant message content must be a string, received: ${value(assistantItem.content)}`
6019
+ );
5924
6020
  }
5925
- if (item.functionCalls && !Array.isArray(item.functionCalls)) {
5926
- throw new Error("Assistant message function calls must be an array");
6021
+ if (assistantItem.functionCalls && !Array.isArray(assistantItem.functionCalls)) {
6022
+ throw new Error(
6023
+ `Assistant message function calls must be an array, received: ${value(assistantItem.functionCalls)}`
6024
+ );
5927
6025
  }
5928
6026
  break;
5929
- case "function":
5930
- if (!item.functionId || item.functionId.trim() === "") {
5931
- throw new Error("Function message must have a non-empty functionId");
6027
+ }
6028
+ case "function": {
6029
+ const functionItem = item;
6030
+ if (!functionItem.functionId || functionItem.functionId.trim() === "") {
6031
+ throw new Error(
6032
+ `Function message must have a non-empty functionId, received: ${value(functionItem.functionId)}`
6033
+ );
5932
6034
  }
5933
- if (item.result === void 0 || item.result === null) {
5934
- throw new Error("Function message must have a result");
6035
+ if (functionItem.result === void 0 || functionItem.result === null) {
6036
+ throw new Error(
6037
+ `Function message must have a result, received: ${value(functionItem.result)}`
6038
+ );
5935
6039
  }
5936
- if (typeof item.result !== "string") {
5937
- throw new Error("Function message result must be a string");
6040
+ if (typeof functionItem.result !== "string") {
6041
+ throw new Error(
6042
+ `Function message result must be a string, received: ${value(functionItem.result)}`
6043
+ );
5938
6044
  }
5939
6045
  break;
6046
+ }
5940
6047
  default:
5941
- throw new Error(
5942
- `Unsupported message role: ${item.role}`
5943
- );
6048
+ throw new Error(`Unsupported message role: ${value(role)}`);
5944
6049
  }
5945
6050
  }
5946
6051
  function axValidateChatResponseResult(results) {
6052
+ const value = (v) => JSON.stringify(v, null, 2);
5947
6053
  const resultsArray = Array.isArray(results) ? results : [results];
5948
6054
  if (resultsArray.length === 0) {
5949
- throw new Error("Chat response results cannot be empty");
6055
+ throw new Error(
6056
+ `Chat response results cannot be empty, received: ${value(resultsArray)}`
6057
+ );
5950
6058
  }
5951
6059
  for (let arrayIndex = 0; arrayIndex < resultsArray.length; arrayIndex++) {
5952
6060
  const result = resultsArray[arrayIndex];
5953
6061
  if (!result) {
5954
6062
  throw new Error(
5955
- `Chat response result at index ${arrayIndex} cannot be null or undefined`
6063
+ `Chat response result at index ${arrayIndex} cannot be null or undefined, received: ${value(result)}`
5956
6064
  );
5957
6065
  }
5958
6066
  if (typeof result.index !== "number") {
5959
6067
  throw new Error(
5960
- `Chat response result at index ${arrayIndex} must have a numeric index`
6068
+ `Chat response result at index ${arrayIndex} must have a numeric index, received: ${value(result.index)}`
5961
6069
  );
5962
6070
  }
5963
6071
  if (result.index < 0) {
5964
6072
  throw new Error(
5965
- `Chat response result at index ${arrayIndex} must have a non-negative index`
6073
+ `Chat response result at index ${arrayIndex} must have a non-negative index, received: ${value(result.index)}`
5966
6074
  );
5967
6075
  }
5968
6076
  if (!result.content && !result.thought && !result.functionCalls && !result.finishReason) {
5969
6077
  throw new Error(
5970
- `Chat response result at index ${arrayIndex} must have at least one of: content, thought, functionCalls, or finishReason`
6078
+ `Chat response result at index ${arrayIndex} must have at least one of: content, thought, functionCalls, or finishReason, received: ${value({ content: result.content, thought: result.thought, functionCalls: result.functionCalls, finishReason: result.finishReason })}`
5971
6079
  );
5972
6080
  }
5973
6081
  if (result.content !== void 0 && typeof result.content !== "string") {
5974
6082
  throw new Error(
5975
- `Chat response result content at index ${arrayIndex} must be a string`
6083
+ `Chat response result content at index ${arrayIndex} must be a string, received: ${value(result.content)}`
5976
6084
  );
5977
6085
  }
5978
6086
  if (result.thought !== void 0 && typeof result.thought !== "string") {
5979
6087
  throw new Error(
5980
- `Chat response result thought at index ${arrayIndex} must be a string`
6088
+ `Chat response result thought at index ${arrayIndex} must be a string, received: ${value(result.thought)}`
5981
6089
  );
5982
6090
  }
5983
6091
  if (result.name !== void 0) {
5984
6092
  if (typeof result.name !== "string") {
5985
6093
  throw new Error(
5986
- `Chat response result name at index ${arrayIndex} must be a string`
6094
+ `Chat response result name at index ${arrayIndex} must be a string, received: ${value(result.name)}`
5987
6095
  );
5988
6096
  }
5989
6097
  if (result.name.trim() === "") {
5990
6098
  throw new Error(
5991
- `Chat response result name at index ${arrayIndex} cannot be empty or whitespace-only`
6099
+ `Chat response result name at index ${arrayIndex} cannot be empty or whitespace-only, received: ${value(result.name)}`
5992
6100
  );
5993
6101
  }
5994
6102
  }
6103
+ if (result.annotations !== void 0) {
6104
+ if (!Array.isArray(result.annotations)) {
6105
+ throw new Error(
6106
+ `Chat response result annotations at index ${arrayIndex} must be an array, received: ${value(result.annotations)}`
6107
+ );
6108
+ }
6109
+ for (let i = 0; i < result.annotations.length; i++) {
6110
+ const annotation = result.annotations[i];
6111
+ if (!annotation || typeof annotation !== "object") {
6112
+ throw new Error(
6113
+ `Chat response result annotation at index ${arrayIndex}[${i}] must be an object, received: ${value(annotation)}`
6114
+ );
6115
+ }
6116
+ if (annotation.type !== "url_citation") {
6117
+ throw new Error(
6118
+ `Chat response result annotation at index ${arrayIndex}[${i}] must have type 'url_citation', received: ${value(annotation.type)}`
6119
+ );
6120
+ }
6121
+ if (!annotation.url_citation || typeof annotation.url_citation !== "object") {
6122
+ throw new Error(
6123
+ `Chat response result annotation at index ${arrayIndex}[${i}] must have a valid url_citation object, received: ${value(annotation.url_citation)}`
6124
+ );
6125
+ }
6126
+ if (typeof annotation.url_citation.url !== "string") {
6127
+ throw new Error(
6128
+ `Chat response result annotation at index ${arrayIndex}[${i}] url_citation.url must be a string, received: ${value(annotation.url_citation.url)}`
6129
+ );
6130
+ }
6131
+ }
6132
+ }
5995
6133
  if (result.id !== void 0) {
5996
6134
  if (typeof result.id !== "string") {
5997
6135
  throw new Error(
5998
- `Chat response result id at index ${arrayIndex} must be a string`
6136
+ `Chat response result id at index ${arrayIndex} must be a string, received: ${value(result.id)}`
5999
6137
  );
6000
6138
  }
6001
6139
  if (result.id.trim() === "") {
6002
6140
  throw new Error(
6003
- `Chat response result id at index ${arrayIndex} cannot be empty or whitespace-only`
6141
+ `Chat response result id at index ${arrayIndex} cannot be empty or whitespace-only, received: ${value(result.id)}`
6004
6142
  );
6005
6143
  }
6006
6144
  }
6007
6145
  if (result.functionCalls !== void 0) {
6008
6146
  if (!Array.isArray(result.functionCalls)) {
6009
6147
  throw new Error(
6010
- `Chat response result functionCalls at index ${arrayIndex} must be an array`
6148
+ `Chat response result functionCalls at index ${arrayIndex} must be an array, received: ${value(result.functionCalls)}`
6011
6149
  );
6012
6150
  }
6013
6151
  for (let callIndex = 0; callIndex < result.functionCalls.length; callIndex++) {
6014
6152
  const functionCall = result.functionCalls[callIndex];
6015
6153
  if (!functionCall) {
6016
6154
  throw new Error(
6017
- `Function call at index ${callIndex} in result ${arrayIndex} cannot be null or undefined`
6155
+ `Function call at index ${callIndex} in result ${arrayIndex} cannot be null or undefined, received: ${value(functionCall)}`
6018
6156
  );
6019
6157
  }
6020
6158
  if (!functionCall.id || typeof functionCall.id !== "string" || functionCall.id.trim() === "") {
6021
6159
  throw new Error(
6022
- `Function call at index ${callIndex} in result ${arrayIndex} must have a non-empty string id`
6160
+ `Function call at index ${callIndex} in result ${arrayIndex} must have a non-empty string id, received: ${value(functionCall.id)}`
6023
6161
  );
6024
6162
  }
6025
6163
  if (functionCall.type !== "function") {
6026
6164
  throw new Error(
6027
- `Function call at index ${callIndex} in result ${arrayIndex} must have type 'function'`
6165
+ `Function call at index ${callIndex} in result ${arrayIndex} must have type 'function', received: ${value(functionCall.type)}`
6028
6166
  );
6029
6167
  }
6030
6168
  if (!functionCall.function) {
6031
6169
  throw new Error(
6032
- `Function call at index ${callIndex} in result ${arrayIndex} must have a function object`
6170
+ `Function call at index ${callIndex} in result ${arrayIndex} must have a function object, received: ${value(functionCall.function)}`
6033
6171
  );
6034
6172
  }
6035
6173
  if (!functionCall.function.name || typeof functionCall.function.name !== "string" || functionCall.function.name.trim() === "") {
6036
6174
  throw new Error(
6037
- `Function call at index ${callIndex} in result ${arrayIndex} must have a non-empty function name`
6175
+ `Function call at index ${callIndex} in result ${arrayIndex} must have a non-empty function name, received: ${value(functionCall.function.name)}`
6038
6176
  );
6039
6177
  }
6040
6178
  if (functionCall.function.params !== void 0) {
6041
6179
  if (typeof functionCall.function.params !== "string" && typeof functionCall.function.params !== "object") {
6042
6180
  throw new Error(
6043
- `Function call params at index ${callIndex} in result ${arrayIndex} must be a string or object`
6181
+ `Function call params at index ${callIndex} in result ${arrayIndex} must be a string or object, received: ${value(functionCall.function.params)}`
6044
6182
  );
6045
6183
  }
6046
6184
  }
@@ -6056,7 +6194,7 @@ function axValidateChatResponseResult(results) {
6056
6194
  ];
6057
6195
  if (!validFinishReasons.includes(result.finishReason)) {
6058
6196
  throw new Error(
6059
- `Chat response result finishReason at index ${arrayIndex} must be one of: ${validFinishReasons.join(", ")}`
6197
+ `Chat response result finishReason at index ${arrayIndex} must be one of: ${validFinishReasons.join(", ")}, received: ${value(result.finishReason)}`
6060
6198
  );
6061
6199
  }
6062
6200
  }
@@ -16113,6 +16251,198 @@ var AxEvalUtil = {
16113
16251
  novelF1ScoreOptimized
16114
16252
  };
16115
16253
 
16254
+ // flow/flow.ts
16255
+ var AxFlow = class extends AxProgramWithSignature {
16256
+ nodes = /* @__PURE__ */ new Map();
16257
+ flowDefinition = [];
16258
+ nodeGenerators = /* @__PURE__ */ new Map();
16259
+ loopStack = [];
16260
+ constructor(signature = "userInput:string -> flowOutput:string") {
16261
+ super(signature);
16262
+ }
16263
+ /**
16264
+ * Declares a reusable computational node and its input/output signature.
16265
+ *
16266
+ * @param name - The name of the node
16267
+ * @param signature - An object where the key is a string representation of inputs
16268
+ * and the value is an object representing outputs
16269
+ * @returns this (for chaining)
16270
+ *
16271
+ * @example
16272
+ * ```typescript
16273
+ * flow.node('summarizer', { 'text:string': { summary: f.string() } })
16274
+ * ```
16275
+ */
16276
+ node(name, signature) {
16277
+ const [inputSignature, outputSignature] = Object.entries(signature)[0] ?? [
16278
+ "",
16279
+ {}
16280
+ ];
16281
+ if (!inputSignature || !outputSignature) {
16282
+ throw new Error(
16283
+ `Invalid signature for node '${name}': signature must have at least one input->output mapping`
16284
+ );
16285
+ }
16286
+ const outputFields = Object.entries(outputSignature).map(([key, value]) => {
16287
+ if (typeof value === "object" && value !== null && "type" in value) {
16288
+ const fieldType = value;
16289
+ let fieldString = `${key}:`;
16290
+ if (fieldType.isOptional) {
16291
+ const colonIndex = fieldString.lastIndexOf(":");
16292
+ fieldString = fieldString.slice(0, colonIndex) + "?" + fieldString.slice(colonIndex);
16293
+ }
16294
+ if (fieldType.isInternal) {
16295
+ const colonIndex = fieldString.lastIndexOf(":");
16296
+ fieldString = fieldString.slice(0, colonIndex) + "!" + fieldString.slice(colonIndex);
16297
+ }
16298
+ fieldString += fieldType.type;
16299
+ if (fieldType.isArray) {
16300
+ fieldString += "[]";
16301
+ }
16302
+ if (fieldType.type === "class" && fieldType.options) {
16303
+ fieldString += ` "${fieldType.options.join(", ")}"`;
16304
+ }
16305
+ if (fieldType.description && (fieldType.type !== "class" || !fieldType.options)) {
16306
+ fieldString += ` "${fieldType.description}"`;
16307
+ }
16308
+ return fieldString;
16309
+ }
16310
+ return `${key}:string`;
16311
+ }).join(", ");
16312
+ const signatureString = `${inputSignature} -> ${outputFields}`;
16313
+ this.nodes.set(name, {
16314
+ inputs: { [inputSignature]: true },
16315
+ outputs: outputSignature
16316
+ });
16317
+ this.nodeGenerators.set(name, new AxGen(signatureString));
16318
+ return this;
16319
+ }
16320
+ /**
16321
+ * Applies a synchronous transformation to the state object.
16322
+ *
16323
+ * @param transform - Function that takes the current state and returns a new state
16324
+ * @returns this (for chaining)
16325
+ *
16326
+ * @example
16327
+ * ```typescript
16328
+ * flow.map(state => ({ ...state, processedText: state.text.toLowerCase() }))
16329
+ * ```
16330
+ */
16331
+ map(transform) {
16332
+ this.flowDefinition.push((state) => {
16333
+ return transform(state);
16334
+ });
16335
+ return this;
16336
+ }
16337
+ /**
16338
+ * Executes a previously defined node.
16339
+ *
16340
+ * @param nodeName - The name of the node to execute (must exist in the nodes map)
16341
+ * @param mapping - Function that takes the current state and returns the input object required by the node
16342
+ * @param dynamicContext - Optional object to override the AI service or options for this specific step
16343
+ * @returns this (for chaining)
16344
+ *
16345
+ * @example
16346
+ * ```typescript
16347
+ * flow.execute('summarizer', state => ({ text: state.originalText }), { ai: cheapAI })
16348
+ * ```
16349
+ */
16350
+ execute(nodeName, mapping, dynamicContext) {
16351
+ if (!this.nodes.has(nodeName)) {
16352
+ throw new Error(
16353
+ `Node '${nodeName}' not found. Make sure to define it with .node() first.`
16354
+ );
16355
+ }
16356
+ const nodeGenerator = this.nodeGenerators.get(nodeName);
16357
+ if (!nodeGenerator) {
16358
+ throw new Error(`Node generator for '${nodeName}' not found.`);
16359
+ }
16360
+ this.flowDefinition.push(async (state, context3) => {
16361
+ const ai = dynamicContext?.ai ?? context3.mainAi;
16362
+ const options = dynamicContext?.options ?? context3.mainOptions;
16363
+ const nodeInputs = mapping(state);
16364
+ const result = await nodeGenerator.forward(ai, nodeInputs, options);
16365
+ return {
16366
+ ...state,
16367
+ [`${nodeName}Result`]: result
16368
+ };
16369
+ });
16370
+ return this;
16371
+ }
16372
+ /**
16373
+ * Marks the beginning of a loop block.
16374
+ *
16375
+ * @param condition - Function that takes the current state and returns a boolean
16376
+ * @returns this (for chaining)
16377
+ *
16378
+ * @example
16379
+ * ```typescript
16380
+ * flow.while(state => state.iterations < 3)
16381
+ * .map(state => ({ ...state, iterations: (state.iterations || 0) + 1 }))
16382
+ * .endWhile()
16383
+ * ```
16384
+ */
16385
+ while(condition) {
16386
+ const loopStartIndex = this.flowDefinition.length;
16387
+ this.loopStack.push(loopStartIndex);
16388
+ const placeholderStep = Object.assign(
16389
+ (state) => state,
16390
+ {
16391
+ _condition: condition,
16392
+ _isLoopStart: true
16393
+ }
16394
+ );
16395
+ this.flowDefinition.push(placeholderStep);
16396
+ return this;
16397
+ }
16398
+ /**
16399
+ * Marks the end of a loop block.
16400
+ *
16401
+ * @returns this (for chaining)
16402
+ */
16403
+ endWhile() {
16404
+ if (this.loopStack.length === 0) {
16405
+ throw new Error("endWhile() called without matching while()");
16406
+ }
16407
+ const loopStartIndex = this.loopStack.pop();
16408
+ const placeholderStep = this.flowDefinition[loopStartIndex];
16409
+ if (!placeholderStep || !("_isLoopStart" in placeholderStep)) {
16410
+ throw new Error("Loop start step not found or invalid");
16411
+ }
16412
+ const condition = placeholderStep._condition;
16413
+ const loopBodySteps = this.flowDefinition.splice(loopStartIndex + 1);
16414
+ this.flowDefinition[loopStartIndex] = async (state, context3) => {
16415
+ let currentState = state;
16416
+ while (condition(currentState)) {
16417
+ for (const step of loopBodySteps) {
16418
+ currentState = await step(currentState, context3);
16419
+ }
16420
+ }
16421
+ return currentState;
16422
+ };
16423
+ return this;
16424
+ }
16425
+ /**
16426
+ * Executes the flow with the given AI service and input values.
16427
+ *
16428
+ * @param ai - The AI service to use as the default for all steps
16429
+ * @param values - The input values for the flow
16430
+ * @param options - Optional forward options to use as defaults
16431
+ * @returns Promise that resolves to the final output
16432
+ */
16433
+ async forward(ai, values, options) {
16434
+ let state = { ...values };
16435
+ const context3 = {
16436
+ mainAi: ai,
16437
+ mainOptions: options
16438
+ };
16439
+ for (const step of this.flowDefinition) {
16440
+ state = await step(state, context3);
16441
+ }
16442
+ return state;
16443
+ }
16444
+ };
16445
+
16116
16446
  // ../../node_modules/uuid/dist/esm-node/rng.js
16117
16447
  import crypto4 from "crypto";
16118
16448
  var rnds8Pool = new Uint8Array(256);
@@ -16649,6 +16979,7 @@ export {
16649
16979
  AxAIOpenAIResponsesBase,
16650
16980
  AxAIOpenAIResponsesImpl,
16651
16981
  AxAIOpenAIResponsesModel,
16982
+ AxAIRefusalError,
16652
16983
  AxAIReka,
16653
16984
  AxAIRekaModel,
16654
16985
  AxAIServiceAbortedError,
@@ -16680,6 +17011,7 @@ export {
16680
17011
  AxDockerSession,
16681
17012
  AxEmbeddingAdapter,
16682
17013
  AxEvalUtil,
17014
+ AxFlow,
16683
17015
  AxFunctionError,
16684
17016
  AxFunctionProcessor,
16685
17017
  AxGen,