@ax-llm/ax 10.0.42 → 10.0.44

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
@@ -76,22 +76,29 @@ var AxSpanKindValues = /* @__PURE__ */ ((AxSpanKindValues2) => {
76
76
  // util/apicall.ts
77
77
  import path from "path";
78
78
  import {
79
+ ReadableStream,
79
80
  TextDecoderStream as TextDecoderStreamNative
80
81
  } from "stream/web";
81
82
  import "@opentelemetry/api";
82
83
 
83
84
  // util/sse.ts
84
- import { TransformStream } from "stream/web";
85
- var SSEParser = class extends TransformStream {
86
- constructor(dataParser = JSON.parse) {
85
+ import { TransformStream as TransformStream2 } from "stream/web";
86
+ var SSEParser = class extends TransformStream2 {
87
+ buffer = "";
88
+ currentEvent = { rawData: "" };
89
+ dataParser;
90
+ onError;
91
+ constructor(options = {}) {
87
92
  super({
88
93
  transform: (chunk, controller) => this.handleChunk(chunk, controller),
89
94
  flush: (controller) => this.handleFlush(controller)
90
95
  });
91
- this.dataParser = dataParser;
96
+ this.dataParser = options.dataParser || JSON.parse;
97
+ this.onError = options.onError || ((error, rawData) => {
98
+ console.warn("Failed to parse event data:", error);
99
+ console.log("Raw data that failed to parse:", rawData);
100
+ });
92
101
  }
93
- buffer = "";
94
- currentEvent = { rawData: "" };
95
102
  handleChunk(chunk, controller) {
96
103
  this.buffer += chunk;
97
104
  this.processBuffer(controller);
@@ -99,24 +106,28 @@ var SSEParser = class extends TransformStream {
99
106
  handleFlush(controller) {
100
107
  this.processBuffer(controller);
101
108
  if (this.currentEvent.rawData) {
102
- this.emitEvent(controller);
109
+ this.processEvent(controller);
103
110
  }
104
111
  }
105
112
  processBuffer(controller) {
106
- const lines = this.buffer.split(/\r\n|\r|\n/);
113
+ const normalizedBuffer = this.buffer.replace(/\r\n|\r/g, "\n");
114
+ const lines = normalizedBuffer.split("\n");
107
115
  this.buffer = lines.pop() || "";
108
116
  for (const line of lines) {
109
- if (line.trim() === "") {
110
- this.emitEvent(controller);
117
+ if (line === "") {
118
+ this.processEvent(controller);
111
119
  } else {
112
120
  this.parseLine(line);
113
121
  }
114
122
  }
115
123
  }
116
124
  parseLine(line) {
125
+ if (line.startsWith(":")) {
126
+ return;
127
+ }
117
128
  const colonIndex = line.indexOf(":");
118
129
  if (colonIndex === -1) {
119
- this.currentEvent.rawData += this.currentEvent.rawData ? "\n" + line.trim() : line.trim();
130
+ this.currentEvent.rawData += (this.currentEvent.rawData && !this.currentEvent.rawData.endsWith("\n") ? "\n" : "") + line.trim();
120
131
  return;
121
132
  }
122
133
  const field = line.slice(0, colonIndex).trim();
@@ -126,7 +137,7 @@ var SSEParser = class extends TransformStream {
126
137
  this.currentEvent.event = value;
127
138
  break;
128
139
  case "data":
129
- this.currentEvent.rawData += this.currentEvent.rawData ? "\n" + value : value;
140
+ this.currentEvent.rawData += (this.currentEvent.rawData && !this.currentEvent.rawData.endsWith("\n") ? "\n" : "") + value;
130
141
  break;
131
142
  case "id":
132
143
  this.currentEvent.id = value;
@@ -140,21 +151,20 @@ var SSEParser = class extends TransformStream {
140
151
  }
141
152
  }
142
153
  }
143
- emitEvent(controller) {
154
+ processEvent(controller) {
144
155
  if (this.currentEvent.rawData) {
145
- if (this.currentEvent.rawData.trim() === "[DONE]" || this.currentEvent.rawData.trim().startsWith("[")) {
156
+ if (!this.currentEvent.event) {
157
+ this.currentEvent.event = "message";
158
+ }
159
+ if (this.currentEvent.rawData.trim() === "[DONE]") {
160
+ this.currentEvent = { rawData: "" };
146
161
  return;
147
- } else {
148
- try {
149
- const parsedData = this.dataParser(this.currentEvent.rawData);
150
- controller.enqueue(parsedData);
151
- } catch (e) {
152
- console.warn("Failed to parse event data:", e);
153
- console.log(
154
- "Raw data that failed to parse:",
155
- this.currentEvent.rawData
156
- );
157
- }
162
+ }
163
+ try {
164
+ const parsedData = this.dataParser(this.currentEvent.rawData);
165
+ controller.enqueue(parsedData);
166
+ } catch (e) {
167
+ this.onError(e, this.currentEvent.rawData);
158
168
  }
159
169
  this.currentEvent = { rawData: "" };
160
170
  }
@@ -163,7 +173,7 @@ var SSEParser = class extends TransformStream {
163
173
 
164
174
  // util/stream.ts
165
175
  import {
166
- TransformStream as TransformStream2
176
+ TransformStream as TransformStream3
167
177
  } from "stream/web";
168
178
  var TextDecodeTransformer = class {
169
179
  decoder;
@@ -186,59 +196,312 @@ var TextDecodeTransformer = class {
186
196
  }
187
197
  }
188
198
  };
189
- var TextDecoderStreamPolyfill = class extends TransformStream2 {
199
+ var TextDecoderStreamPolyfill = class extends TransformStream3 {
190
200
  constructor() {
191
201
  super(new TextDecodeTransformer());
192
202
  }
193
203
  };
194
204
 
195
205
  // util/apicall.ts
206
+ var defaultRetryConfig = {
207
+ maxRetries: 3,
208
+ initialDelayMs: 1e3,
209
+ maxDelayMs: 6e4,
210
+ // Increased to 60 seconds
211
+ backoffFactor: 2,
212
+ retryableStatusCodes: [500, 408, 429, 502, 503, 504]
213
+ };
214
+ var defaultTimeoutMs = 3e4;
196
215
  var textDecoderStream = TextDecoderStreamNative ?? TextDecoderStreamPolyfill;
216
+ var AxAIServiceError = class extends Error {
217
+ constructor(message, url, requestBody, context = {}) {
218
+ super(message);
219
+ this.url = url;
220
+ this.requestBody = requestBody;
221
+ this.context = context;
222
+ this.name = "AxAIServiceError";
223
+ this.timestamp = (/* @__PURE__ */ new Date()).toISOString();
224
+ this.errorId = crypto.randomUUID();
225
+ }
226
+ timestamp;
227
+ errorId;
228
+ toString() {
229
+ return `${this.name} [${this.errorId}]: ${this.message}
230
+ Timestamp: ${this.timestamp}
231
+ URL: ${this.url}${this.requestBody ? `
232
+ Request Body: ${JSON.stringify(this.requestBody, null, 2)}` : ""}${this.context ? `
233
+ Context: ${JSON.stringify(this.context, null, 2)}` : ""}`;
234
+ }
235
+ toJSON() {
236
+ return {
237
+ name: this.name,
238
+ errorId: this.errorId,
239
+ message: this.message,
240
+ timestamp: this.timestamp,
241
+ url: this.url,
242
+ requestBody: this.requestBody,
243
+ context: this.context,
244
+ stack: this.stack
245
+ };
246
+ }
247
+ };
248
+ var AxAIServiceStatusError = class extends AxAIServiceError {
249
+ constructor(status, statusText, url, requestBody, context) {
250
+ super(`HTTP ${status} - ${statusText}`, url, requestBody, {
251
+ httpStatus: status,
252
+ httpStatusText: statusText,
253
+ ...context
254
+ });
255
+ this.status = status;
256
+ this.statusText = statusText;
257
+ this.name = "AxAIServiceStatusError";
258
+ }
259
+ };
260
+ var AxAIServiceNetworkError = class extends AxAIServiceError {
261
+ constructor(originalError, url, requestBody, context) {
262
+ super(`Network Error: ${originalError.message}`, url, requestBody, {
263
+ originalErrorName: originalError.name,
264
+ originalErrorStack: originalError.stack,
265
+ ...context
266
+ });
267
+ this.originalError = originalError;
268
+ this.name = "AxAIServiceNetworkError";
269
+ this.stack = originalError.stack;
270
+ }
271
+ };
272
+ var AxAIServiceResponseError = class extends AxAIServiceError {
273
+ constructor(message, url, requestBody, context) {
274
+ super(message, url, requestBody, context);
275
+ this.name = "AxAIServiceResponseError";
276
+ }
277
+ };
278
+ var AxAIServiceStreamTerminatedError = class extends AxAIServiceError {
279
+ constructor(url, requestBody, lastChunk, context) {
280
+ super("Stream terminated unexpectedly by remote host", url, requestBody, {
281
+ lastChunk,
282
+ ...context
283
+ });
284
+ this.lastChunk = lastChunk;
285
+ this.name = "AxAIServiceStreamTerminatedError";
286
+ }
287
+ };
288
+ var AxAIServiceTimeoutError = class extends AxAIServiceError {
289
+ constructor(url, timeoutMs, requestBody, context) {
290
+ super(`Request timeout after ${timeoutMs}ms`, url, requestBody, {
291
+ timeoutMs,
292
+ ...context
293
+ });
294
+ this.name = "AxAIServiceTimeoutError";
295
+ }
296
+ };
297
+ var AxAIServiceAuthenticationError = class extends AxAIServiceError {
298
+ constructor(url, requestBody, context) {
299
+ super("Authentication failed", url, requestBody, context);
300
+ this.name = "AxAIServiceAuthenticationError";
301
+ }
302
+ };
303
+ function calculateRetryDelay(attempt, config) {
304
+ const delay = Math.min(
305
+ config.maxDelayMs,
306
+ config.initialDelayMs * Math.pow(config.backoffFactor, attempt)
307
+ );
308
+ return delay * (0.75 + Math.random() * 0.5);
309
+ }
310
+ function createRequestMetrics() {
311
+ return {
312
+ startTime: Date.now(),
313
+ retryCount: 0
314
+ };
315
+ }
316
+ function updateRetryMetrics(metrics) {
317
+ metrics.retryCount++;
318
+ metrics.lastRetryTime = Date.now();
319
+ }
197
320
  var apiCall = async (api, json) => {
321
+ const retryConfig = { ...defaultRetryConfig, ...api.retry };
322
+ const timeoutMs = api.timeout ?? defaultTimeoutMs;
323
+ const metrics = createRequestMetrics();
198
324
  const baseUrl = new URL(process.env["PROXY"] ?? api.url);
199
325
  const apiPath = path.join(baseUrl.pathname, api.name ?? "/", baseUrl.search);
200
326
  const apiUrl = new URL(apiPath, baseUrl);
327
+ const requestId = crypto.randomUUID();
201
328
  if (api.span?.isRecording()) {
202
329
  api.span.setAttributes({
203
330
  "http.request.method": api.put ? "PUT" : "POST",
204
- "url.full": apiUrl.href
331
+ "url.full": apiUrl.href,
332
+ "request.id": requestId,
333
+ "request.startTime": metrics.startTime
205
334
  });
206
335
  }
207
- let res;
208
- try {
209
- res = await (api.fetch ?? fetch)(apiUrl, {
210
- method: api.put ? "PUT" : "POST",
211
- headers: {
212
- "Content-Type": "application/json",
213
- ...api.headers
214
- },
215
- body: JSON.stringify(json)
216
- });
217
- if (res.status >= 400) {
218
- const reqBody = JSON.stringify(json, null, 2);
219
- throw new Error(
220
- `API Request Error: ${res.status}, ${res.statusText}
221
- :Request Body: ${reqBody}`
222
- );
223
- }
224
- if (!api.stream) {
225
- const resJson = await res.json();
226
- return resJson;
227
- }
228
- if (!res.body) {
229
- throw new Error("Response body is null");
230
- }
231
- const st = res.body.pipeThrough(new textDecoderStream()).pipeThrough(new SSEParser());
232
- return st;
233
- } catch (e) {
234
- if (api.span?.isRecording()) {
235
- api.span.recordException(e);
336
+ let attempt = 0;
337
+ while (true) {
338
+ const controller = new AbortController();
339
+ let timeoutId = setTimeout(() => {
340
+ controller.abort("Request timeout");
341
+ }, timeoutMs);
342
+ try {
343
+ const res = await (api.fetch ?? fetch)(apiUrl, {
344
+ method: api.put ? "PUT" : "POST",
345
+ headers: {
346
+ "Content-Type": "application/json",
347
+ "X-Request-ID": requestId,
348
+ "X-Retry-Count": attempt.toString(),
349
+ ...api.headers
350
+ },
351
+ body: JSON.stringify(json),
352
+ signal: controller.signal
353
+ });
354
+ clearTimeout(timeoutId);
355
+ if (res.status === 401 || res.status === 403) {
356
+ throw new AxAIServiceAuthenticationError(apiUrl.href, json, { metrics });
357
+ }
358
+ if (res.status >= 400 && attempt < retryConfig.maxRetries && retryConfig.retryableStatusCodes.includes(res.status)) {
359
+ const delay = calculateRetryDelay(attempt, retryConfig);
360
+ attempt++;
361
+ updateRetryMetrics(metrics);
362
+ if (api.span?.isRecording()) {
363
+ api.span.addEvent("retry", {
364
+ attempt,
365
+ delay,
366
+ status: res.status,
367
+ "metrics.startTime": metrics.startTime,
368
+ "metrics.retryCount": metrics.retryCount,
369
+ "metrics.lastRetryTime": metrics.lastRetryTime
370
+ });
371
+ }
372
+ clearTimeout(timeoutId);
373
+ continue;
374
+ }
375
+ if (res.status >= 400) {
376
+ throw new AxAIServiceStatusError(
377
+ res.status,
378
+ res.statusText,
379
+ apiUrl.href,
380
+ json,
381
+ { metrics }
382
+ );
383
+ }
384
+ if (!api.stream) {
385
+ const resJson = await res.json();
386
+ if (api.span?.isRecording()) {
387
+ api.span.setAttributes({
388
+ "response.time": Date.now() - metrics.startTime,
389
+ "response.retries": metrics.retryCount
390
+ });
391
+ }
392
+ return resJson;
393
+ }
394
+ if (!res.body) {
395
+ throw new AxAIServiceResponseError(
396
+ "Response body is null",
397
+ apiUrl.href,
398
+ json,
399
+ { metrics }
400
+ );
401
+ }
402
+ let lastChunk;
403
+ let chunkCount = 0;
404
+ const trackingStream = new TransformStream({
405
+ transform(chunk, controller2) {
406
+ lastChunk = chunk;
407
+ chunkCount++;
408
+ metrics.streamChunks = chunkCount;
409
+ metrics.lastChunkTime = Date.now();
410
+ controller2.enqueue(chunk);
411
+ },
412
+ flush(controller2) {
413
+ if (api.span?.isRecording()) {
414
+ api.span.setAttributes({
415
+ "stream.chunks": chunkCount,
416
+ "stream.duration": Date.now() - metrics.startTime,
417
+ "response.retries": metrics.retryCount
418
+ });
419
+ }
420
+ controller2.terminate();
421
+ }
422
+ });
423
+ const wrappedStream = new ReadableStream({
424
+ start(controller2) {
425
+ const reader = res.body.pipeThrough(new textDecoderStream()).pipeThrough(new SSEParser()).pipeThrough(trackingStream).getReader();
426
+ async function read() {
427
+ try {
428
+ while (true) {
429
+ const { done, value } = await reader.read();
430
+ if (done) {
431
+ controller2.close();
432
+ break;
433
+ } else {
434
+ controller2.enqueue(value);
435
+ }
436
+ }
437
+ } catch (e) {
438
+ const error = e;
439
+ const streamMetrics = {
440
+ ...metrics,
441
+ streamDuration: Date.now() - metrics.startTime
442
+ };
443
+ if (error.name === "AbortError" || error.message?.includes("aborted")) {
444
+ controller2.error(
445
+ new AxAIServiceStreamTerminatedError(
446
+ apiUrl.href,
447
+ json,
448
+ lastChunk,
449
+ { streamMetrics }
450
+ )
451
+ );
452
+ } else {
453
+ controller2.error(
454
+ new AxAIServiceResponseError(
455
+ `Stream processing error: ${error.message}`,
456
+ apiUrl.href,
457
+ json,
458
+ { streamMetrics }
459
+ )
460
+ );
461
+ }
462
+ } finally {
463
+ reader.releaseLock();
464
+ }
465
+ }
466
+ read();
467
+ }
468
+ });
469
+ return wrappedStream;
470
+ } catch (error) {
471
+ clearTimeout(timeoutId);
472
+ if (error instanceof Error && error.name === "AbortError") {
473
+ throw new AxAIServiceTimeoutError(apiUrl.href, timeoutMs, json, {
474
+ metrics
475
+ });
476
+ }
477
+ if (api.span?.isRecording()) {
478
+ api.span.recordException(error);
479
+ api.span.setAttributes({
480
+ "error.time": Date.now() - metrics.startTime,
481
+ "error.retries": metrics.retryCount
482
+ });
483
+ }
484
+ if (error instanceof AxAIServiceNetworkError && attempt < retryConfig.maxRetries) {
485
+ const delay = calculateRetryDelay(attempt, retryConfig);
486
+ attempt++;
487
+ updateRetryMetrics(metrics);
488
+ if (api.span?.isRecording()) {
489
+ api.span.addEvent("retry", {
490
+ attempt,
491
+ delay,
492
+ error: error.message,
493
+ "metrics.startTime": metrics.startTime,
494
+ "metrics.retryCount": metrics.retryCount,
495
+ "metrics.lastRetryTime": metrics.lastRetryTime
496
+ });
497
+ }
498
+ continue;
499
+ }
500
+ if (error instanceof AxAIServiceError) {
501
+ error.context["metrics"] = metrics;
502
+ }
503
+ throw error;
236
504
  }
237
- const reqBody = JSON.stringify(json, null, 2);
238
- throw new Error(
239
- `API Response Error: ${apiUrl.href}, ${e}
240
- Request Body: ${reqBody}`
241
- );
242
505
  }
243
506
  };
244
507
 
@@ -275,7 +538,7 @@ var ColorLog = class {
275
538
 
276
539
  // util/transform.ts
277
540
  import {
278
- TransformStream as TransformStream3
541
+ TransformStream as TransformStream4
279
542
  } from "stream/web";
280
543
  var TypeTransformer = class {
281
544
  buffer;
@@ -298,7 +561,7 @@ var TypeTransformer = class {
298
561
  controller.terminate();
299
562
  }
300
563
  };
301
- var RespTransformStream = class extends TransformStream3 {
564
+ var RespTransformStream = class extends TransformStream4 {
302
565
  constructor(transformFn, doneCallback) {
303
566
  super(new TypeTransformer(transformFn, doneCallback));
304
567
  }
@@ -3261,7 +3524,7 @@ var AxAI = class {
3261
3524
  };
3262
3525
 
3263
3526
  // dsp/generate.ts
3264
- import { ReadableStream } from "stream/web";
3527
+ import { ReadableStream as ReadableStream2 } from "stream/web";
3265
3528
  import { SpanKind as SpanKind2 } from "@opentelemetry/api";
3266
3529
 
3267
3530
  // ai/util.ts
@@ -3488,9 +3751,6 @@ var assertStreamingAssertions = (asserts, values, xstate, content, final) => {
3488
3751
  }
3489
3752
  };
3490
3753
 
3491
- // dsp/extract.ts
3492
- import JSON5 from "json5";
3493
-
3494
3754
  // dsp/datetime.ts
3495
3755
  import moment from "moment-timezone";
3496
3756
 
@@ -3521,104 +3781,143 @@ import { createHash } from "crypto";
3521
3781
  var SignatureParser = class {
3522
3782
  input;
3523
3783
  position;
3784
+ currentFieldName = null;
3524
3785
  constructor(input) {
3525
3786
  this.input = input;
3526
3787
  this.position = 0;
3527
3788
  }
3528
3789
  parse() {
3529
- this.skipWhitespace();
3530
- const optionalDesc = this.parseParsedString();
3531
- this.skipWhitespace();
3532
- const inputs = this.parseInputParsedFieldList();
3533
- this.skipWhitespace();
3534
- this.expect("->");
3535
- this.skipWhitespace();
3536
- const outputs = this.parseOutputParsedFieldList();
3537
- return {
3538
- desc: optionalDesc?.trim(),
3539
- inputs,
3540
- outputs
3541
- };
3542
- }
3543
- parseInputParsedFieldList() {
3544
- const fields = [];
3545
- fields.push(this.parseInputParsedField());
3546
- while (this.match(",")) {
3790
+ try {
3547
3791
  this.skipWhitespace();
3548
- fields.push(this.parseInputParsedField());
3549
- }
3550
- return fields;
3551
- }
3552
- parseOutputParsedFieldList() {
3553
- const fields = [];
3554
- fields.push(this.parseOutputParsedField());
3555
- while (this.match(",")) {
3792
+ const optionalDesc = this.parseParsedString();
3556
3793
  this.skipWhitespace();
3557
- fields.push(this.parseOutputParsedField());
3558
- }
3559
- return fields;
3560
- }
3561
- parseInputParsedField() {
3562
- this.skipWhitespace();
3563
- const name = this.parseParsedIdentifier();
3564
- const isOptional = this.match("?");
3565
- let type;
3566
- if (this.match(":")) {
3794
+ const inputs = this.parseFieldList(this.parseField.bind(this), "input");
3567
3795
  this.skipWhitespace();
3568
- const typeName = this.parseTypeNotClass();
3569
- const isArray = this.match("[]");
3570
- type = { name: typeName, isArray };
3796
+ if (this.position >= this.input.length) {
3797
+ throw new Error(
3798
+ 'Incomplete signature: Missing output section. Expected "->" followed by output fields'
3799
+ );
3800
+ }
3801
+ this.expect("->");
3802
+ this.skipWhitespace();
3803
+ if (this.position >= this.input.length) {
3804
+ throw new Error(
3805
+ 'Incomplete signature: No output fields specified after "->"'
3806
+ );
3807
+ }
3808
+ const outputs = this.parseFieldList(this.parseField.bind(this), "output");
3809
+ return {
3810
+ desc: optionalDesc?.trim(),
3811
+ inputs,
3812
+ outputs
3813
+ };
3814
+ } catch (error) {
3815
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
3816
+ const context = this.getErrorContext();
3817
+ throw new Error(`${errorMessage}
3818
+ ${context}`);
3819
+ }
3820
+ }
3821
+ getErrorContext() {
3822
+ const start = Math.max(0, this.position - 20);
3823
+ const end = Math.min(this.input.length, this.position + 20);
3824
+ const before = this.input.slice(start, this.position);
3825
+ const after = this.input.slice(this.position, end);
3826
+ const pointer = " ".repeat(before.length) + "^";
3827
+ return `Near position ${this.position}:
3828
+ ${before}${after}
3829
+ ${pointer}`;
3830
+ }
3831
+ parseFieldList(parseFieldFn, section) {
3832
+ const fields = [];
3833
+ this.skipWhitespace();
3834
+ if (this.position >= this.input.length) {
3835
+ throw new Error(`Empty ${section} section: Expected at least one field`);
3836
+ }
3837
+ try {
3838
+ fields.push(parseFieldFn());
3839
+ } catch (error) {
3840
+ throw new Error(
3841
+ `Invalid first ${section} field: ${error instanceof Error ? error.message : "Unknown error"}`
3842
+ );
3571
3843
  }
3572
3844
  this.skipWhitespace();
3573
- const desc = this.parseParsedString();
3574
- return {
3575
- name,
3576
- desc: desc?.trim(),
3577
- type,
3578
- isOptional
3579
- };
3845
+ while (this.position < this.input.length) {
3846
+ if (this.input[this.position] === "-" && this.input[this.position + 1] === ">") {
3847
+ break;
3848
+ }
3849
+ if (this.match(",")) {
3850
+ this.skipWhitespace();
3851
+ if (this.position >= this.input.length) {
3852
+ throw new Error(
3853
+ `Unexpected end of input after comma in ${section} section`
3854
+ );
3855
+ }
3856
+ try {
3857
+ fields.push(parseFieldFn());
3858
+ } catch (error) {
3859
+ throw new Error(
3860
+ `Invalid ${section} field after comma: ${error instanceof Error ? error.message : "Unknown error"}`
3861
+ );
3862
+ }
3863
+ this.skipWhitespace();
3864
+ } else {
3865
+ break;
3866
+ }
3867
+ }
3868
+ return fields;
3580
3869
  }
3581
- parseOutputParsedField() {
3870
+ parseField() {
3582
3871
  this.skipWhitespace();
3583
3872
  const name = this.parseParsedIdentifier();
3873
+ this.currentFieldName = name;
3584
3874
  const isOptional = this.match("?");
3875
+ let type;
3585
3876
  this.skipWhitespace();
3586
3877
  if (this.match(":")) {
3587
3878
  this.skipWhitespace();
3588
3879
  if (this.match("class")) {
3589
3880
  const isArray = this.match("[]");
3590
3881
  this.skipWhitespace();
3591
- const desc = this.parseParsedString();
3592
- if (!desc) {
3882
+ const desc2 = this.parseParsedString();
3883
+ if (!desc2) {
3593
3884
  throw new Error(
3594
- "Expected description containing class names after type 'class'"
3885
+ `Field "${name}": Expected class names in quotes after "class" type. Example: class "MyClass1, MyClass2"`
3595
3886
  );
3596
3887
  }
3597
- const classNames = desc.split(",").map((s) => s.trim());
3598
- return {
3599
- name,
3600
- type: { name: "class", isArray, classes: classNames },
3601
- isOptional
3602
- };
3888
+ const classes = desc2.split(/[,\s]+/).map((s) => s.trim()).filter((s) => s.length > 0);
3889
+ if (classes.length === 0) {
3890
+ throw new Error(
3891
+ `Field "${name}": Empty class list provided. At least one class name is required`
3892
+ );
3893
+ }
3894
+ type = { name: "class", isArray, classes };
3603
3895
  } else {
3604
- const typeName = this.parseTypeNotClass();
3605
- const isArray = this.match("[]");
3606
- this.skipWhitespace();
3607
- const desc = this.parseParsedString();
3608
- return {
3609
- name,
3610
- desc: desc?.trim(),
3611
- type: { name: typeName, isArray },
3612
- isOptional
3613
- };
3896
+ try {
3897
+ const typeName = this.parseTypeNotClass();
3898
+ const isArray = this.match("[]");
3899
+ type = { name: typeName, isArray };
3900
+ } catch (error) {
3901
+ throw new Error(
3902
+ `Field "${name}": ${error instanceof Error ? error.message : "Unknown error"}`
3903
+ );
3904
+ }
3614
3905
  }
3906
+ }
3907
+ this.skipWhitespace();
3908
+ const desc = this.parseParsedString();
3909
+ if (type?.name === "class") {
3910
+ return {
3911
+ name,
3912
+ desc: desc?.trim(),
3913
+ type,
3914
+ isOptional
3915
+ };
3615
3916
  } else {
3616
- this.skipWhitespace();
3617
- const desc = this.parseParsedString();
3618
3917
  return {
3619
3918
  name,
3620
3919
  desc: desc?.trim(),
3621
- type: void 0,
3920
+ type,
3622
3921
  isOptional
3623
3922
  };
3624
3923
  }
@@ -3634,14 +3933,17 @@ var SignatureParser = class {
3634
3933
  "datetime",
3635
3934
  "date"
3636
3935
  ];
3637
- for (const type of types) {
3638
- if (this.match(type)) {
3639
- return type;
3640
- }
3936
+ const foundType = types.find((type) => this.match(type));
3937
+ if (!foundType) {
3938
+ const currentWord = this.input.slice(this.position).match(/^\w+/)?.[0] || "empty";
3939
+ throw new Error(
3940
+ `Invalid type "${currentWord}". Expected one of: ${types.join(", ")}`
3941
+ );
3641
3942
  }
3642
- throw new Error(`Expected one of ${types.join(", ")}`);
3943
+ return foundType;
3643
3944
  }
3644
3945
  parseParsedIdentifier() {
3946
+ this.skipWhitespace();
3645
3947
  const match = /^[a-zA-Z_][a-zA-Z_0-9]*/.exec(
3646
3948
  this.input.slice(this.position)
3647
3949
  );
@@ -3649,40 +3951,69 @@ var SignatureParser = class {
3649
3951
  this.position += match[0].length;
3650
3952
  return match[0];
3651
3953
  }
3652
- throw new Error("Expected identifier");
3954
+ const invalidMatch = /^\S+/.exec(this.input.slice(this.position));
3955
+ const invalidId = invalidMatch ? invalidMatch[0] : "empty";
3956
+ throw new Error(
3957
+ `Invalid identifier "${invalidId}". Identifiers must start with a letter or underscore and contain only letters, numbers, or underscores`
3958
+ );
3653
3959
  }
3654
3960
  parseParsedString() {
3655
- if (this.match("'")) {
3656
- const endQuote = this.input.indexOf("'", this.position);
3657
- if (endQuote === -1) throw new Error("Unterminated string");
3658
- const content = this.input.slice(this.position, endQuote);
3659
- this.position = endQuote + 1;
3660
- return content;
3661
- } else if (this.match('"')) {
3662
- const endQuote = this.input.indexOf('"', this.position);
3663
- if (endQuote === -1) throw new Error("Unterminated string");
3664
- const content = this.input.slice(this.position, endQuote);
3665
- this.position = endQuote + 1;
3666
- return content;
3961
+ const quoteChars = ["'", '"'];
3962
+ for (const quoteChar of quoteChars) {
3963
+ if (this.match(quoteChar)) {
3964
+ let content = "";
3965
+ let escaped = false;
3966
+ let startPos = this.position;
3967
+ while (this.position < this.input.length) {
3968
+ const char = this.input[this.position];
3969
+ this.position++;
3970
+ if (escaped) {
3971
+ content += char;
3972
+ escaped = false;
3973
+ } else if (char === "\\") {
3974
+ escaped = true;
3975
+ } else if (char === quoteChar) {
3976
+ return content;
3977
+ } else {
3978
+ content += char;
3979
+ }
3980
+ }
3981
+ const partialString = this.input.slice(startPos, this.position);
3982
+ throw new Error(
3983
+ `Unterminated string starting at position ${startPos}: "${partialString}..."`
3984
+ );
3985
+ }
3667
3986
  }
3668
3987
  return void 0;
3669
3988
  }
3670
3989
  skipWhitespace() {
3671
- const match = /^[ \t\r\n]+/.exec(this.input.slice(this.position));
3990
+ const match = /^[\s\t\r\n]+/.exec(this.input.slice(this.position));
3672
3991
  if (match) {
3673
3992
  this.position += match[0].length;
3674
3993
  }
3675
3994
  }
3676
- match(str) {
3677
- if (this.input.startsWith(str, this.position)) {
3678
- this.position += str.length;
3679
- return true;
3995
+ match(strOrRegex) {
3996
+ let match;
3997
+ if (typeof strOrRegex === "string") {
3998
+ if (this.input.startsWith(strOrRegex, this.position)) {
3999
+ this.position += strOrRegex.length;
4000
+ return true;
4001
+ }
4002
+ } else {
4003
+ match = strOrRegex.exec(this.input.slice(this.position));
4004
+ if (match) {
4005
+ this.position += match[0].length;
4006
+ return true;
4007
+ }
3680
4008
  }
3681
4009
  return false;
3682
4010
  }
3683
4011
  expect(str) {
3684
4012
  if (!this.match(str)) {
3685
- throw new Error(`Expected "${str}"`);
4013
+ const found = this.input.slice(this.position, this.position + 10);
4014
+ throw new Error(
4015
+ `Expected "${str}" but found "${found}..." at position ${this.position}`
4016
+ );
3686
4017
  }
3687
4018
  }
3688
4019
  };
@@ -4916,7 +5247,7 @@ function validateAndParseFieldValue(field, fieldValue) {
4916
5247
  if (field.type?.name === "json") {
4917
5248
  try {
4918
5249
  const text = extractBlock(fieldValue);
4919
- value = JSON5.parse(text);
5250
+ value = JSON.parse(text);
4920
5251
  return value;
4921
5252
  } catch (e) {
4922
5253
  throw new ValidationError({
@@ -4929,7 +5260,7 @@ function validateAndParseFieldValue(field, fieldValue) {
4929
5260
  if (field.type?.isArray) {
4930
5261
  try {
4931
5262
  try {
4932
- value = JSON5.parse(fieldValue);
5263
+ value = JSON.parse(fieldValue);
4933
5264
  } catch {
4934
5265
  value = parseMarkdownList(fieldValue);
4935
5266
  }
@@ -4982,9 +5313,6 @@ var extractBlock = (input) => {
4982
5313
  return input;
4983
5314
  };
4984
5315
 
4985
- // dsp/functions.ts
4986
- import JSON52 from "json5";
4987
-
4988
5316
  // dsp/jsonschema.ts
4989
5317
  var validateJSONSchema = (schema) => {
4990
5318
  const errors = [];
@@ -5042,7 +5370,7 @@ var AxFunctionProcessor = class {
5042
5370
  executeFunction = async (fnSpec, func, options) => {
5043
5371
  let args;
5044
5372
  if (typeof func.args === "string" && func.args.length > 0) {
5045
- args = JSON52.parse(func.args);
5373
+ args = JSON.parse(func.args);
5046
5374
  } else {
5047
5375
  args = func.args;
5048
5376
  }
@@ -5211,7 +5539,7 @@ var AxGen = class extends AxProgramWithSignature {
5211
5539
  mem,
5212
5540
  options
5213
5541
  });
5214
- if (res instanceof ReadableStream) {
5542
+ if (res instanceof ReadableStream2) {
5215
5543
  yield* this.processStreamingResponse({
5216
5544
  ai,
5217
5545
  model,
@@ -5329,37 +5657,35 @@ var AxGen = class extends AxProgramWithSignature {
5329
5657
  functions
5330
5658
  }) {
5331
5659
  const values = {};
5332
- const result = res.results[0];
5333
- if (!result) {
5334
- throw new Error("No result found");
5335
- }
5336
- if (res.modelUsage) {
5337
- this.usage.push({ ...usageInfo, ...res.modelUsage });
5338
- }
5339
- mem.addResult(result, sessionId);
5340
- if (result.content) {
5341
- extractValues(this.signature, values, result.content);
5342
- assertAssertions(this.asserts, values);
5343
- }
5344
- if (result.functionCalls) {
5345
- const funcs = parseFunctionCalls(ai, result.functionCalls, values);
5346
- if (funcs) {
5347
- if (!functions) {
5348
- throw new Error("Functions are not defined");
5660
+ for (const result of res.results ?? []) {
5661
+ if (res.modelUsage) {
5662
+ this.usage.push({ ...usageInfo, ...res.modelUsage });
5663
+ }
5664
+ mem.addResult(result, sessionId);
5665
+ if (result.content) {
5666
+ extractValues(this.signature, values, result.content);
5667
+ assertAssertions(this.asserts, values);
5668
+ }
5669
+ if (result.functionCalls) {
5670
+ const funcs = parseFunctionCalls(ai, result.functionCalls, values);
5671
+ if (funcs) {
5672
+ if (!functions) {
5673
+ throw new Error("Functions are not defined");
5674
+ }
5675
+ const fx = await processFunctions(
5676
+ ai,
5677
+ functions,
5678
+ funcs,
5679
+ mem,
5680
+ sessionId,
5681
+ traceId
5682
+ );
5683
+ this.functionsExecuted = /* @__PURE__ */ new Set([...this.functionsExecuted, ...fx]);
5349
5684
  }
5350
- const fx = await processFunctions(
5351
- ai,
5352
- functions,
5353
- funcs,
5354
- mem,
5355
- sessionId,
5356
- traceId
5357
- );
5358
- this.functionsExecuted = /* @__PURE__ */ new Set([...this.functionsExecuted, ...fx]);
5359
5685
  }
5360
- }
5361
- if (result.finishReason === "length") {
5362
- throw new Error("Max tokens reached before completion");
5686
+ if (result.finishReason === "length") {
5687
+ throw new Error("Max tokens reached before completion");
5688
+ }
5363
5689
  }
5364
5690
  return { ...values };
5365
5691
  }
@@ -5739,6 +6065,25 @@ var AxBalancer = class _AxBalancer {
5739
6065
  try {
5740
6066
  return await this.currentService.chat(req, options);
5741
6067
  } catch (e) {
6068
+ if (!(e instanceof AxAIServiceError)) {
6069
+ throw e;
6070
+ }
6071
+ switch (e.constructor) {
6072
+ case AxAIServiceAuthenticationError:
6073
+ throw e;
6074
+ case AxAIServiceStatusError:
6075
+ break;
6076
+ case AxAIServiceNetworkError:
6077
+ break;
6078
+ case AxAIServiceResponseError:
6079
+ break;
6080
+ case AxAIServiceStreamTerminatedError:
6081
+ break;
6082
+ case AxAIServiceTimeoutError:
6083
+ break;
6084
+ default:
6085
+ throw e;
6086
+ }
5742
6087
  console.warn(`Service ${this.currentService.getName()} failed`);
5743
6088
  if (!this.getNextService()) {
5744
6089
  throw e;
@@ -7424,6 +7769,13 @@ export {
7424
7769
  AxAIOpenAIModel,
7425
7770
  AxAIReka,
7426
7771
  AxAIRekaModel,
7772
+ AxAIServiceAuthenticationError,
7773
+ AxAIServiceError,
7774
+ AxAIServiceNetworkError,
7775
+ AxAIServiceResponseError,
7776
+ AxAIServiceStatusError,
7777
+ AxAIServiceStreamTerminatedError,
7778
+ AxAIServiceTimeoutError,
7427
7779
  AxAITogether,
7428
7780
  AxAgent,
7429
7781
  AxApacheTika,