@adaptic/lumic-utils 1.0.18 → 1.0.19

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.
@@ -2086,15 +2086,33 @@ function resetLLMCostTracker() {
2086
2086
  // llm-openai.ts
2087
2087
  /**
2088
2088
  * Determines if an LLM error should be retried.
2089
- * Only retries on rate limit errors (429).
2089
+ *
2090
+ * Retries on:
2091
+ * - 429 / rate limit errors (transient capacity)
2092
+ * - "could not parse the JSON body" 400s — observed once in production for a
2093
+ * single symbol on the very first conversation turn (Wave 86, 2026-04-11).
2094
+ * The exact same call site succeeds millions of times before and after, and
2095
+ * the prior fix commit `6eaef52` in this repo already eliminated the only
2096
+ * known SDK-v5 cause (passing `tools: undefined/null`). The remaining cases
2097
+ * are virtually always proxy/network corruption of the request body in
2098
+ * flight (request truncated mid-flight, TLS renegotiation, edge proxy
2099
+ * buffer reset). Retrying once with a fresh connection has a high
2100
+ * probability of recovering, and a deterministic SDK-side defect would
2101
+ * re-fail on retry (so we still surface it).
2090
2102
  */
2091
2103
  const isRetryableLLMError = (error) => {
2092
2104
  if (error instanceof Error) {
2093
2105
  const message = error.message;
2094
- // Retry only on rate limits (429)
2106
+ // Retry on rate limits (429)
2095
2107
  if (message.includes('429') || message.includes('rate limit') || message.includes('Rate limit')) {
2096
2108
  return true;
2097
2109
  }
2110
+ // Retry on transient body-corruption 400s. Match the exact OpenAI error
2111
+ // string to avoid retrying genuine client-side validation 400s (which
2112
+ // would re-fail forever and waste retry budget).
2113
+ if (message.includes('could not parse the JSON body of your request')) {
2114
+ return true;
2115
+ }
2098
2116
  }
2099
2117
  return false;
2100
2118
  };
@@ -2290,12 +2308,52 @@ async function createCompletion(content, responseFormat, options = DEFAULT_OPTIO
2290
2308
  if (responseFormatOption.type !== 'text') {
2291
2309
  queryOptions.response_format = responseFormatOption;
2292
2310
  }
2293
- const completion = await withRetry(() => openai.chat.completions.create(queryOptions), {
2294
- maxRetries: 3,
2295
- baseDelayMs: 2000,
2296
- maxDelayMs: 30000,
2297
- retryableErrors: isRetryableLLMError,
2298
- }, `OpenAI:${normalizedModel}`);
2311
+ let completion;
2312
+ try {
2313
+ completion = await withRetry(() => openai.chat.completions.create(queryOptions), {
2314
+ maxRetries: 3,
2315
+ baseDelayMs: 2000,
2316
+ maxDelayMs: 30000,
2317
+ retryableErrors: isRetryableLLMError,
2318
+ }, `OpenAI:${normalizedModel}`);
2319
+ }
2320
+ catch (error) {
2321
+ // Defensive observability: when the OpenAI SDK rejects our request,
2322
+ // emit a structured snapshot of the queryOptions shape (NOT content) so
2323
+ // a future recurrence of the rare "could not parse JSON body" 400 can be
2324
+ // diagnosed without having to reproduce locally. We deliberately log
2325
+ // metadata only — no message content, no API key — so this is safe even
2326
+ // for production prompts containing sensitive context.
2327
+ const errorMessage = error instanceof Error ? error.message : String(error);
2328
+ const totalContentChars = messages.reduce((sum, msg) => {
2329
+ if (typeof msg.content === 'string')
2330
+ return sum + msg.content.length;
2331
+ if (Array.isArray(msg.content)) {
2332
+ return sum + msg.content.reduce((s, part) => {
2333
+ if (typeof part === 'object' && part !== null && 'text' in part && typeof part.text === 'string') {
2334
+ return s + part.text.length;
2335
+ }
2336
+ return s;
2337
+ }, 0);
2338
+ }
2339
+ return sum;
2340
+ }, 0);
2341
+ getLumicLogger().error(`OpenAI ChatCompletion call failed for model ${normalizedModel}`, {
2342
+ model: normalizedModel,
2343
+ errorMessage,
2344
+ messageCount: messages.length,
2345
+ roleBreakdown: messages.reduce((acc, msg) => {
2346
+ acc[msg.role] = (acc[msg.role] ?? 0) + 1;
2347
+ return acc;
2348
+ }, {}),
2349
+ totalContentChars,
2350
+ toolCount: queryOptions.tools?.length ?? 0,
2351
+ hasTemperature: queryOptions.temperature !== undefined,
2352
+ hasResponseFormat: queryOptions.response_format !== undefined,
2353
+ hasMaxCompletionTokens: queryOptions.max_completion_tokens !== undefined,
2354
+ });
2355
+ throw error;
2356
+ }
2299
2357
  const response = {
2300
2358
  id: completion.id,
2301
2359
  content: completion.choices[0]?.message?.content || '',
@@ -7922,7 +7980,12 @@ function translateContextToAnthropic(context) {
7922
7980
  /** Convert string or content block array to a uniform content block array. */
7923
7981
  function toContentBlocks(content) {
7924
7982
  if (typeof content === 'string') {
7925
- return [{ type: 'text', text: content }];
7983
+ const textBlock = {
7984
+ type: 'text',
7985
+ text: content,
7986
+ citations: null,
7987
+ };
7988
+ return [textBlock];
7926
7989
  }
7927
7990
  return content;
7928
7991
  }
@@ -22713,11 +22776,11 @@ let poolConfig = DEFAULT_POOL_CONFIG;
22713
22776
  async function loadApolloModules() {
22714
22777
  if (typeof window === "undefined" || process.env.AWS_EXECUTION_ENV) {
22715
22778
  // Server-side (or Lambda): load the CommonJS‑based implementation.
22716
- return (await import('./apollo-client.server-C2gZgUkR.js'));
22779
+ return (await import('./apollo-client.server-Blxbp1Gf.js'));
22717
22780
  }
22718
22781
  else {
22719
22782
  // Client-side: load the ESM‑based implementation.
22720
- return (await import('./apollo-client.client-kEvzgHxw.js'));
22783
+ return (await import('./apollo-client.client-Dfi-rHW-.js'));
22721
22784
  }
22722
22785
  }
22723
22786
  /**
@@ -81241,4 +81304,4 @@ const lumic = {
81241
81304
  };
81242
81305
 
81243
81306
  export { GraphQLInterfaceType as $, print as A, getNamedType as B, isInputType as C, isRequiredArgument as D, isNamedType as E, GraphQLError as F, GraphQLNonNull as G, isOutputType as H, isRequiredInputField as I, isCompositeType as J, Kind as K, getNullableType as L, getEnterLeaveForKind as M, isNode as N, OperationTypeNode as O, didYouMean as P, naturalCompare as Q, suggestionList as R, specifiedScalarTypes as S, keyMap as T, isType as U, isNullableType as V, visit as W, visitInParallel as X, keyValMap as Y, assertObjectType as Z, GraphQLScalarType as _, isListType as a, validateGoogleSheetsRange as a$, GraphQLUnionType as a0, GraphQLInputObjectType as a1, assertNullableType as a2, assertInterfaceType as a3, mapValue as a4, isSpecifiedScalarType as a5, isPrintableAsBlockString as a6, printBlockString as a7, BREAK as a8, GRAPHQL_MAX_INT as a9, printSourceLocation as aA, resolveObjMapThunk as aB, resolveReadonlyArrayThunk as aC, valueFromASTUntyped as aD, version$4 as aE, versionInfo as aF, getAugmentedNamespace as aG, isDigit$1 as aH, isNameStart as aI, dedentBlockStringLines as aJ, isNameContinue as aK, setLumicLogger as aL, getLumicLogger as aM, sanitizeForLog as aN, sanitizeError as aO, sanitizeAWSAuth as aP, sanitizeObject as aQ, getSecrets as aR, resetSecrets as aS, requireSecret as aT, withRetry as aU, CircuitBreaker as aV, CircuitBreakerState as aW, CircuitBreakerOpenError as aX, DEFAULT_CIRCUIT_BREAKER_CONFIG as aY, validateSlackChannel as aZ, validateS3Key as a_, GRAPHQL_MIN_INT as aa, GraphQLFloat as ab, GraphQLInt as ac, Location as ad, Token as ae, assertAbstractType as af, assertCompositeType as ag, assertEnumType as ah, assertEnumValueName as ai, assertInputObjectType as aj, assertInputType as ak, assertLeafType as al, assertListType as am, assertNamedType as an, assertNonNullType as ao, assertOutputType as ap, assertScalarType as aq, assertType as ar, assertUnionType as as, assertWrappingType as at, formatError as au, getLocation as av, getVisitFn as aw, isWrappingType as ax, printError as ay, printLocation as az, isAbstractType as b, PDFError as b$, LLMCostTracker as b0, getLLMCostTracker as b1, setLLMCostTracker as b2, resetLLMCostTracker as b3, setMetricsCollector as b4, getMetricsCollector as b5, resetMetricsCollector as b6, withMetrics as b7, generateCorrelationId as b8, getCorrelationId as b9, openAIChatCompletionSchema as bA, openAIImageResponseSchema as bB, validateOpenAIChatCompletion as bC, safeValidateOpenAIChatCompletion as bD, perplexityResponseSchema as bE, validatePerplexityResponse as bF, safeValidatePerplexityResponse as bG, googleSheetsValueRangeSchema as bH, validateGoogleSheetsResponse as bI, safeValidateGoogleSheetsResponse as bJ, s3ListObjectsSchema as bK, s3GetObjectSchema as bL, lambdaInvokeResponseSchema as bM, validateS3ListObjects as bN, safeValidateS3ListObjects as bO, validateLambdaResponse as bP, safeValidateLambdaResponse as bQ, createValidator as bR, createSafeValidator as bS, LumicError as bT, SlackError as bU, LLMError as bV, AWSLambdaError as bW, AWSS3Error as bX, GoogleSheetsError as bY, PerplexityError as bZ, JsonParseError as b_, getCorrelationContext as ba, withCorrelationId as bb, getCorrelationHeaders as bc, TokenBucketRateLimiter as bd, RATE_LIMIT_PROFILES as be, getRateLimiter as bf, resetAllRateLimiters as bg, withRateLimit as bh, checkIntegrationHealth as bi, SUPPORTED_MODELS as bj, isValidModel as bk, getModelCapabilities as bl, getModelProvider as bm, MODEL_ALIASES as bn, OPENAI_COMPATIBLE_PROVIDERS as bo, PROVIDER_DEFAULT_MODELS as bp, LLM_DEFAULT_PROVIDER as bq, LLM_MINI_PROVIDER as br, LLM_NORMAL_PROVIDER as bs, LLM_ADVANCED_PROVIDER as bt, LLM_PROVIDER as bu, LLM_MODEL_MINI as bv, LLM_MODEL_NORMAL as bw, LLM_MODEL_ADVANCED as bx, makeAnthropicCall as by, makeOpenAICompatibleCall as bz, isInterfaceType as c, ZipError as c0, SLACK_TIMEOUT_MS as c1, PERPLEXITY_TIMEOUT_MS as c2, GOOGLE_SHEETS_TIMEOUT_MS as c3, LLM_TIMEOUT_MS as c4, AWS_LAMBDA_TIMEOUT_MS as c5, AWS_S3_TIMEOUT_MS as c6, OPENWEATHER_TIMEOUT_MS as c7, GENERIC_FETCH_TIMEOUT_MS as c8, isObjectType as d, assertName as e, devAssert as f, isObjectLike as g, defineArguments as h, isNonNullType as i, argsToArgsConfig as j, GraphQLBoolean as k, lumic as l, GraphQLString as m, instanceOf as n, inspect as o, isInputObjectType as p, isLeafType as q, isEnumType as r, GraphQLID as s, toObjMap as t, invariant as u, GraphQLObjectType as v, GraphQLEnumType as w, GraphQLList as x, isScalarType as y, isUnionType as z };
81244
- //# sourceMappingURL=index-UQOI_SLD.js.map
81307
+ //# sourceMappingURL=index-CSQmloZ-.js.map