call-ai 0.7.0-dev-preview-8 → 0.7.0-dev-preview-10

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.
Files changed (2) hide show
  1. package/dist/api.js +65 -9
  2. package/package.json +1 -1
package/dist/api.js CHANGED
@@ -35,10 +35,26 @@ function callAI(prompt, options = {}) {
35
35
  // Make the fetch request and handle errors before creating the generator
36
36
  console.log(`[callAI:${PACKAGE_VERSION}] Making fetch request to: ${endpoint}`);
37
37
  console.log(`[callAI:${PACKAGE_VERSION}] With model: ${model}`);
38
+ console.log(`[callAI:${PACKAGE_VERSION}] Request headers:`, JSON.stringify(requestOptions.headers));
38
39
  let response;
39
40
  try {
40
41
  response = await fetch(endpoint, requestOptions);
41
42
  console.log(`[callAI:${PACKAGE_VERSION}] Fetch completed with status:`, response.status, response.statusText);
43
+ // Log all headers
44
+ console.log(`[callAI:${PACKAGE_VERSION}] Response headers:`);
45
+ response.headers.forEach((value, name) => {
46
+ console.log(`[callAI:${PACKAGE_VERSION}] ${name}: ${value}`);
47
+ });
48
+ // Clone response for diagnostic purposes only
49
+ const diagnosticResponse = response.clone();
50
+ try {
51
+ // Try to get the response as text for debugging
52
+ const responseText = await diagnosticResponse.text();
53
+ console.log(`[callAI:${PACKAGE_VERSION}] First 500 chars of response body:`, responseText.substring(0, 500) + (responseText.length > 500 ? '...' : ''));
54
+ }
55
+ catch (e) {
56
+ console.log(`[callAI:${PACKAGE_VERSION}] Could not read response body for diagnostics:`, e);
57
+ }
42
58
  }
43
59
  catch (fetchError) {
44
60
  console.error(`[callAI:${PACKAGE_VERSION}] Network error during fetch:`, fetchError);
@@ -47,6 +63,7 @@ function callAI(prompt, options = {}) {
47
63
  // Explicitly check for HTTP error status and log extensively
48
64
  console.log(`[callAI:${PACKAGE_VERSION}] Response.ok =`, response.ok);
49
65
  console.log(`[callAI:${PACKAGE_VERSION}] Response.status =`, response.status);
66
+ console.log(`[callAI:${PACKAGE_VERSION}] Response.type =`, response.type);
50
67
  // Enhanced error handling with more debugging - MUST check !response.ok
51
68
  if (!response.ok) {
52
69
  console.log(`[callAI:${PACKAGE_VERSION}] Detected error response with status:`, response.status);
@@ -462,8 +479,16 @@ async function extractClaudeResponse(response) {
462
479
  /**
463
480
  * Generator factory function for streaming API calls
464
481
  * This is called after the fetch is made and response is validated
482
+ *
483
+ * Note: Even though we checked response.ok before creating this generator,
484
+ * we need to be prepared for errors that may occur during streaming. Some APIs
485
+ * return a 200 OK initially but then deliver error information in the stream.
465
486
  */
466
487
  async function* createStreamingGenerator(response, options, schemaStrategy, model) {
488
+ console.log(`[callAI:${PACKAGE_VERSION}] Starting streaming generator with model: ${model}`);
489
+ console.log(`[callAI:${PACKAGE_VERSION}] Response status:`, response.status);
490
+ console.log(`[callAI:${PACKAGE_VERSION}] Response type:`, response.type);
491
+ console.log(`[callAI:${PACKAGE_VERSION}] Response Content-Type:`, response.headers.get('content-type'));
467
492
  try {
468
493
  // Handle streaming response
469
494
  if (!response.body) {
@@ -477,16 +502,26 @@ async function* createStreamingGenerator(response, options, schemaStrategy, mode
477
502
  while (true) {
478
503
  const { done, value } = await reader.read();
479
504
  if (done) {
505
+ console.log(`[callAI:${PACKAGE_VERSION}] Stream done=true after ${chunkCount} chunks`);
480
506
  if (options.debug) {
481
507
  console.log(`[callAI-streaming:complete v${PACKAGE_VERSION}] Stream finished after ${chunkCount} chunks`);
482
508
  }
483
509
  break;
484
510
  }
511
+ // Increment chunk counter before processing
512
+ chunkCount++;
485
513
  const chunk = decoder.decode(value);
514
+ console.log(`[callAI:${PACKAGE_VERSION}] Raw chunk #${chunkCount} (${chunk.length} bytes):`, chunk.length > 200 ? chunk.substring(0, 200) + '...' : chunk);
486
515
  const lines = chunk.split("\n").filter((line) => line.trim() !== "");
516
+ console.log(`[callAI:${PACKAGE_VERSION}] Chunk #${chunkCount} contains ${lines.length} non-empty lines`);
487
517
  for (const line of lines) {
518
+ console.log(`[callAI:${PACKAGE_VERSION}] Processing line:`, line.length > 100 ? line.substring(0, 100) + '...' : line);
488
519
  if (line.startsWith("data: ")) {
489
- // Simple debug logging of raw SSE events with no processing
520
+ let data = line.slice(6);
521
+ if (data === "[DONE]") {
522
+ console.log(`[callAI:${PACKAGE_VERSION}] Received [DONE] marker`);
523
+ break;
524
+ }
490
525
  if (options.debug) {
491
526
  console.log(`[callAI:raw] ${line}`);
492
527
  }
@@ -498,17 +533,38 @@ async function* createStreamingGenerator(response, options, schemaStrategy, mode
498
533
  try {
499
534
  const jsonLine = line.replace("data: ", "");
500
535
  if (!jsonLine.trim()) {
536
+ console.log(`[callAI:${PACKAGE_VERSION}] Empty JSON line after data: prefix`);
501
537
  continue;
502
538
  }
503
- chunkCount++;
539
+ console.log(`[callAI:${PACKAGE_VERSION}] JSON line (first 100 chars):`, jsonLine.length > 100 ? jsonLine.substring(0, 100) + '...' : jsonLine);
504
540
  // Parse the JSON chunk
505
- const json = JSON.parse(jsonLine);
506
- // Check for error in the parsed JSON response
507
- if (json.error) {
508
- // Use the standard error format as the rest of the library
509
- // We need to throw the error properly
510
- handleApiError(new Error(`API returned error: ${JSON.stringify(json.error)}`), "Streaming API call error", options.debug);
511
- // This code is unreachable as handleApiError throws
541
+ let json;
542
+ try {
543
+ json = JSON.parse(jsonLine);
544
+ console.log(`[callAI:${PACKAGE_VERSION}] Parsed JSON:`, JSON.stringify(json).length > 100 ?
545
+ JSON.stringify(json).substring(0, 100) + '...' :
546
+ JSON.stringify(json));
547
+ }
548
+ catch (parseError) {
549
+ console.error(`[callAI:${PACKAGE_VERSION}] JSON parse error:`, parseError);
550
+ console.error(`[callAI:${PACKAGE_VERSION}] Failed to parse:`, jsonLine);
551
+ continue;
552
+ }
553
+ // Enhanced error detection - check for BOTH error and json.error
554
+ // Some APIs return 200 OK but then deliver errors in the stream
555
+ if (json.error || (typeof json === 'object' && 'error' in json)) {
556
+ console.error(`[callAI:${PACKAGE_VERSION}] Detected error in streaming response:`, json);
557
+ // Create a detailed error object similar to our HTTP error handling
558
+ const errorMessage = json.error?.message ||
559
+ json.error?.toString() ||
560
+ JSON.stringify(json.error || json);
561
+ const detailedError = new Error(`API streaming error: ${errorMessage}`);
562
+ // Add error metadata
563
+ detailedError.status = json.error?.status || 400;
564
+ detailedError.statusText = json.error?.type || 'Bad Request';
565
+ detailedError.details = JSON.stringify(json.error || json);
566
+ console.error(`[callAI:${PACKAGE_VERSION}] Throwing stream error:`, detailedError);
567
+ throw detailedError;
512
568
  }
513
569
  // Handle tool use response - Claude with schema cases
514
570
  const isClaudeWithSchema = /claude/i.test(model) && schemaStrategy.strategy === "tool_mode";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "call-ai",
3
- "version": "0.7.0-dev-preview-8",
3
+ "version": "0.7.0-dev-preview-10",
4
4
  "description": "Lightweight library for making AI API calls with streaming support",
5
5
  "main": "dist/index.js",
6
6
  "browser": "dist/index.js",