@adaptic/lumic-utils 1.0.25 → 1.0.26

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 (22) hide show
  1. package/dist/{apollo-client.client-D6jG5B1n.js → apollo-client.client-CtjgIfRT.js} +3 -3
  2. package/dist/{apollo-client.client-D6jG5B1n.js.map → apollo-client.client-CtjgIfRT.js.map} +1 -1
  3. package/dist/{apollo-client.client-DLW-p46Y.js → apollo-client.client-Uv0-ZrFd.js} +4 -4
  4. package/dist/{apollo-client.client-DLW-p46Y.js.map → apollo-client.client-Uv0-ZrFd.js.map} +1 -1
  5. package/dist/{apollo-client.server-CXLiLmSz.js → apollo-client.server-DaXmxoBl.js} +3 -3
  6. package/dist/{apollo-client.server-CXLiLmSz.js.map → apollo-client.server-DaXmxoBl.js.map} +1 -1
  7. package/dist/{apollo-client.server-Cx30LaNh.js → apollo-client.server-JYHXy9ib.js} +3 -3
  8. package/dist/{apollo-client.server-Cx30LaNh.js.map → apollo-client.server-JYHXy9ib.js.map} +1 -1
  9. package/dist/{index-CqnZ-XiI.js → index-Bu-2kk3p.js} +2 -2
  10. package/dist/{index-CqnZ-XiI.js.map → index-Bu-2kk3p.js.map} +1 -1
  11. package/dist/{index-ChygDqeG.js → index-DgFDhFuO.js} +190 -82
  12. package/dist/{index-Bvc61lYS.js.map → index-DgFDhFuO.js.map} +1 -1
  13. package/dist/{index-D2TPDKw0.js → index-HopiPnjc.js} +2 -2
  14. package/dist/{index-D2TPDKw0.js.map → index-HopiPnjc.js.map} +1 -1
  15. package/dist/{index-Bvc61lYS.js → index-z7Y1nTVX.js} +190 -82
  16. package/dist/{index-ChygDqeG.js.map → index-z7Y1nTVX.js.map} +1 -1
  17. package/dist/index.cjs +1 -1
  18. package/dist/index.mjs +1 -1
  19. package/dist/test.cjs +1 -1
  20. package/dist/test.mjs +1 -1
  21. package/dist/types/functions/llm-deepseek.d.ts +4 -0
  22. package/package.json +1 -1
@@ -1648,8 +1648,17 @@ async function parseResponse(content, responseFormat, options = {}) {
1648
1648
  getLumicLogger().info(`Code block for type ${detectedType} detected and removed. Cleaned content: ${cleanedContent}`);
1649
1649
  }
1650
1650
  }
1651
- // Multiple JSON parsing strategies
1652
- // Default pipeline: direct parse -> extract from brackets -> remove leading/trailing text -> fixBrokenJson (string manipulation) -> FAIL
1651
+ // Whether the cleaned content structurally resembles JSON. Used to gate the
1652
+ // lenient fixBrokenJson strategy, which will otherwise coerce arbitrary
1653
+ // prose into a bogus object/array.
1654
+ const inputResemblesJson = cleanedContent.startsWith('{') || cleanedContent.startsWith('[');
1655
+ // Multiple JSON parsing strategies.
1656
+ // Default pipeline: direct parse -> extract from brackets -> remove
1657
+ // leading/trailing text -> GATED fixBrokenJson -> FAIL. fixBrokenJson is
1658
+ // deliberately gated (Strategy 4): its output is accepted only when the
1659
+ // input looked like JSON AND the repaired value round-trips through
1660
+ // JSON.stringify/JSON.parse, so a "successful" repair of non-JSON text is
1661
+ // rejected instead of silently returned as garbage.
1653
1662
  const jsonParsingStrategies = [
1654
1663
  // Strategy 1: Direct parsing
1655
1664
  () => {
@@ -1683,45 +1692,65 @@ async function parseResponse(content, responseFormat, options = {}) {
1683
1692
  return null;
1684
1693
  }
1685
1694
  },
1686
- // Strategy 4: Use fixBrokenJson (string manipulation only, no AI)
1695
+ // Strategy 4: Gated fixBrokenJson (string manipulation only, no AI)
1687
1696
  () => {
1688
- return fixBrokenJson(cleanedContent);
1697
+ if (!inputResemblesJson) {
1698
+ return null;
1699
+ }
1700
+ const fixed = fixBrokenJson(cleanedContent);
1701
+ if (fixed === null) {
1702
+ return null;
1703
+ }
1704
+ try {
1705
+ // Round-trip guard: ensures the repaired value is genuinely
1706
+ // JSON-serializable before we trust it.
1707
+ return JSON.parse(JSON.stringify(fixed));
1708
+ }
1709
+ catch {
1710
+ return null;
1711
+ }
1689
1712
  },
1690
1713
  ];
1691
1714
  // Try each parsing strategy
1692
1715
  for (const strategy of jsonParsingStrategies) {
1693
- const result = await strategy();
1716
+ const result = strategy();
1694
1717
  if (result !== null) {
1695
- return result;
1718
+ return finalizeJsonResult(result, responseFormat);
1696
1719
  }
1697
1720
  }
1698
1721
  // Strategy 5: Use AI fixing (only if explicitly enabled)
1699
1722
  if (enableAiFix) {
1700
1723
  getLumicLogger().warn('Using AI-powered JSON fixing. This adds cost and latency. Consider improving JSON generation instead.');
1724
+ let aiFixedJson = null;
1701
1725
  try {
1702
- const aiFixedJson = await fixJsonWithAI(cleanedContent);
1703
- if (aiFixedJson !== null) {
1704
- // Validate the AI-fixed JSON by attempting to stringify and re-parse it
1705
- // This ensures it's actually valid JSON and not just something that passed fixJsonWithAI
1706
- try {
1707
- const validated = JSON.parse(JSON.stringify(aiFixedJson));
1708
- return validated;
1709
- }
1710
- catch {
1711
- // AI returned something that looks like JSON but isn't valid
1712
- // Increment recursion depth and try parsing the AI response
1713
- getLumicLogger().warn('AI fixing returned invalid JSON, attempting recursive parse...');
1714
- return parseResponse(JSON.stringify(aiFixedJson), responseFormat, {
1715
- ...options,
1716
- _recursionDepth: recursionDepth + 1,
1717
- });
1718
- }
1719
- }
1726
+ aiFixedJson = await fixJsonWithAI(cleanedContent);
1720
1727
  }
1721
1728
  catch (error) {
1722
1729
  const errorMessage = error instanceof Error ? error.message : 'Unknown error';
1723
1730
  getLumicLogger().error(`AI JSON fixing failed: ${errorMessage}`);
1724
- // Continue to final error below
1731
+ // Fall through to the final error below.
1732
+ }
1733
+ if (aiFixedJson !== null) {
1734
+ let validated;
1735
+ try {
1736
+ // Validate the AI-fixed JSON by attempting to stringify and re-parse
1737
+ // it. This ensures it is actually valid JSON, not just something that
1738
+ // passed fixJsonWithAI.
1739
+ validated = JSON.parse(JSON.stringify(aiFixedJson));
1740
+ }
1741
+ catch {
1742
+ // AI returned something that looks like JSON but isn't valid.
1743
+ // Increment recursion depth and try parsing the AI response.
1744
+ getLumicLogger().warn('AI fixing returned invalid JSON, attempting recursive parse...');
1745
+ return parseResponse(JSON.stringify(aiFixedJson), responseFormat, {
1746
+ ...options,
1747
+ _recursionDepth: recursionDepth + 1,
1748
+ });
1749
+ }
1750
+ // Schema validation (json_schema format) happens here, OUTSIDE the
1751
+ // JSON.parse try/catch, so a schema mismatch propagates as a thrown
1752
+ // JsonParseError rather than being mistaken for invalid JSON.
1753
+ return finalizeJsonResult(validated, responseFormat);
1725
1754
  }
1726
1755
  }
1727
1756
  // If all strategies fail, throw an error
@@ -1732,6 +1761,106 @@ async function parseResponse(content, responseFormat, options = {}) {
1732
1761
  return content;
1733
1762
  }
1734
1763
  }
1764
+ /**
1765
+ * Reports the JSON type of a runtime value for schema-validation diagnostics.
1766
+ *
1767
+ * @param value The value whose JSON type should be described.
1768
+ * @returns One of `'null' | 'array' | 'object' | 'string' | 'number' | 'boolean' | 'undefined'`.
1769
+ */
1770
+ function jsonTypeOf(value) {
1771
+ if (value === null)
1772
+ return 'null';
1773
+ if (Array.isArray(value))
1774
+ return 'array';
1775
+ return typeof value;
1776
+ }
1777
+ /**
1778
+ * Extracts a declared primitive `type` string from a property schema, if present.
1779
+ *
1780
+ * @param propertySchema The (untyped) per-property JSON-Schema fragment.
1781
+ * @returns The declared type string, or null when none is declared.
1782
+ */
1783
+ function extractSchemaType(propertySchema) {
1784
+ if (typeof propertySchema === 'object' && propertySchema !== null && 'type' in propertySchema) {
1785
+ const declared = propertySchema.type;
1786
+ return typeof declared === 'string' ? declared : null;
1787
+ }
1788
+ return null;
1789
+ }
1790
+ /**
1791
+ * Checks whether a runtime value satisfies a declared JSON-Schema primitive
1792
+ * type. Unknown/unsupported type keywords are treated permissively (they never
1793
+ * cause a rejection), so this validator only ever rejects clear mismatches.
1794
+ *
1795
+ * @param value The runtime value to check.
1796
+ * @param expectedType The declared JSON-Schema type keyword.
1797
+ * @returns True when the value matches (or the keyword is unsupported).
1798
+ */
1799
+ function valueMatchesJsonType(value, expectedType) {
1800
+ switch (expectedType) {
1801
+ case 'string':
1802
+ return typeof value === 'string';
1803
+ case 'number':
1804
+ return typeof value === 'number';
1805
+ case 'integer':
1806
+ return typeof value === 'number' && Number.isInteger(value);
1807
+ case 'boolean':
1808
+ return typeof value === 'boolean';
1809
+ case 'object':
1810
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
1811
+ case 'array':
1812
+ return Array.isArray(value);
1813
+ case 'null':
1814
+ return value === null;
1815
+ default:
1816
+ return true;
1817
+ }
1818
+ }
1819
+ /**
1820
+ * Validates a parsed value against a `json_schema` object schema. Enforces that
1821
+ * the value is a plain object, that every `required` property is present, and
1822
+ * that present properties whose schema declares a primitive `type` match it.
1823
+ *
1824
+ * @param value The parsed value to validate.
1825
+ * @param schema The object schema supplied on the response format.
1826
+ * @throws {JsonParseError} When the value violates the schema.
1827
+ */
1828
+ function validateJsonSchema(value, schema) {
1829
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
1830
+ throw new JsonParseError(`JSON schema validation failed: expected an object but received ${jsonTypeOf(value)}.`);
1831
+ }
1832
+ const record = value;
1833
+ const missing = (schema.required ?? []).filter((key) => !(key in record));
1834
+ if (missing.length > 0) {
1835
+ throw new JsonParseError(`JSON schema validation failed: missing required properties: ${missing.join(', ')}.`);
1836
+ }
1837
+ for (const [key, propertySchema] of Object.entries(schema.properties)) {
1838
+ if (!(key in record))
1839
+ continue;
1840
+ const expectedType = extractSchemaType(propertySchema);
1841
+ if (expectedType !== null && !valueMatchesJsonType(record[key], expectedType)) {
1842
+ throw new JsonParseError(`JSON schema validation failed: property "${key}" expected type "${expectedType}" but received ${jsonTypeOf(record[key])}.`);
1843
+ }
1844
+ }
1845
+ }
1846
+ /**
1847
+ * Finalizes a successfully-parsed JSON value. When the caller supplied a
1848
+ * `json_schema` response format, the value is validated against that schema
1849
+ * before being returned so schema violations surface as a thrown
1850
+ * {@link JsonParseError} instead of flowing silently downstream. For plain
1851
+ * `json` formats the value is returned unchanged.
1852
+ *
1853
+ * @param value The parsed value produced by a parsing strategy.
1854
+ * @param responseFormat The originally requested response format.
1855
+ * @returns The value narrowed to `T`.
1856
+ * @throws {JsonParseError} When a supplied json_schema is not satisfied.
1857
+ */
1858
+ function finalizeJsonResult(value, responseFormat) {
1859
+ if (typeof responseFormat === 'object' && responseFormat?.type === 'json_schema') {
1860
+ validateJsonSchema(value, responseFormat.schema);
1861
+ }
1862
+ return value;
1863
+ }
1735
1864
 
1736
1865
  /**
1737
1866
  * Default timeout values (in milliseconds) for external service calls.
@@ -9068,6 +9197,10 @@ async function createDeepseekCompletion(content, responseFormat, options = {}) {
9068
9197
  * @param responseFormat The format of the response. Defaults to 'json'.
9069
9198
  * @param options Configuration options including model ('deepseek-chat' or 'deepseek-reasoner'), tools, and apiKey.
9070
9199
  * @return A promise that resolves to the response from the Deepseek API.
9200
+ * @throws {Error} If the requested capability (JSON output / tool calling) is
9201
+ * unsupported by the model, or if the underlying API call fails. This matches
9202
+ * the OpenAI and Anthropic providers, which surface failures by throwing
9203
+ * rather than returning a success-shaped response carrying an error payload.
9071
9204
  */
9072
9205
  const makeDeepseekCall = async (content, responseFormat = 'json', options = {}) => {
9073
9206
  // Set default model if not provided
@@ -9078,43 +9211,15 @@ const makeDeepseekCall = async (content, responseFormat = 'json', options = {})
9078
9211
  mergedOptions.model = DEFAULT_DEEPSEEK_OPTIONS.defaultModel;
9079
9212
  }
9080
9213
  const modelName = normalizeModelName(mergedOptions.model);
9081
- // Check if the requested response format is compatible with the model
9214
+ // Check if the requested response format is compatible with the model.
9215
+ // Throw rather than returning a fake-success LLMResponse: a caller that
9216
+ // asked for JSON must not silently receive an { error } payload typed as T.
9082
9217
  if (responseFormat !== 'text' && !supportsJsonOutput(modelName)) {
9083
- getLumicLogger().warn(`Model ${modelName} does not support JSON output. Will return error in the response.`);
9084
- return {
9085
- response: {
9086
- error: `Model ${modelName} does not support JSON output format.`
9087
- },
9088
- usage: {
9089
- prompt_tokens: 0,
9090
- completion_tokens: 0,
9091
- reasoning_tokens: 0,
9092
- provider: 'deepseek',
9093
- model: modelName,
9094
- cached_tokens: 0,
9095
- cost: 0,
9096
- },
9097
- tool_calls: undefined,
9098
- };
9218
+ throw new Error(`Model ${modelName} does not support JSON output format.`);
9099
9219
  }
9100
- // Check if tools are requested with a model that doesn't support them
9220
+ // Check if tools are requested with a model that doesn't support them.
9101
9221
  if (mergedOptions.tools && mergedOptions.tools.length > 0 && !supportsToolCalling(modelName)) {
9102
- getLumicLogger().warn(`Model ${modelName} does not support tool calling. Will return error in the response.`);
9103
- return {
9104
- response: {
9105
- error: `Model ${modelName} does not support tool calling.`
9106
- },
9107
- usage: {
9108
- prompt_tokens: 0,
9109
- completion_tokens: 0,
9110
- reasoning_tokens: 0,
9111
- provider: 'deepseek',
9112
- model: modelName,
9113
- cached_tokens: 0,
9114
- cost: 0,
9115
- },
9116
- tool_calls: undefined,
9117
- };
9222
+ throw new Error(`Model ${modelName} does not support tool calling.`);
9118
9223
  }
9119
9224
  try {
9120
9225
  const completion = await createDeepseekCompletion(content, responseFormat, mergedOptions);
@@ -9164,23 +9269,13 @@ const makeDeepseekCall = async (content, responseFormat = 'json', options = {})
9164
9269
  };
9165
9270
  }
9166
9271
  catch (error) {
9167
- // If there's an error due to incompatible features, return a structured error
9272
+ // Mirror the OpenAI/Anthropic providers: log with sanitized context and
9273
+ // rethrow so callers observe the failure. Returning a success-shaped
9274
+ // response with an { error } payload here previously let hard failures
9275
+ // (auth, timeout, rate-limit exhaustion, unparseable output) masquerade as
9276
+ // successful completions downstream.
9168
9277
  getLumicLogger().error(`Error in Deepseek API call: ${sanitizeError(error)}`);
9169
- return {
9170
- response: {
9171
- error: sanitizeError(error)
9172
- },
9173
- usage: {
9174
- prompt_tokens: 0,
9175
- completion_tokens: 0,
9176
- reasoning_tokens: 0,
9177
- provider: 'deepseek',
9178
- model: modelName,
9179
- cached_tokens: 0,
9180
- cost: 0,
9181
- },
9182
- tool_calls: undefined,
9183
- };
9278
+ throw error;
9184
9279
  }
9185
9280
  };
9186
9281
 
@@ -10114,14 +10209,27 @@ async function downloadFile(s3Client, bucketName, s3Key, localFilePath) {
10114
10209
  async function unzipFile(zipPath, destPath) {
10115
10210
  const zip = new AdmZip(zipPath);
10116
10211
  try {
10117
- zip.extractAllToAsync(destPath, true);
10118
- const stats = await getDirectoryStats(destPath);
10119
- return stats;
10212
+ // extractAllToAsync is fire-and-forget: it returns void and reports
10213
+ // failures through its callback. The previous call neither awaited it nor
10214
+ // observed the callback, so getDirectoryStats raced an in-flight (or
10215
+ // failed) extraction and any extraction error was silently dropped. Wrap
10216
+ // it in a Promise so the extraction is fully awaited and errors surface.
10217
+ await new Promise((resolve, reject) => {
10218
+ zip.extractAllToAsync(destPath, true, false, (error) => {
10219
+ if (error) {
10220
+ reject(error);
10221
+ }
10222
+ else {
10223
+ resolve();
10224
+ }
10225
+ });
10226
+ });
10227
+ return await getDirectoryStats(destPath);
10120
10228
  }
10121
10229
  catch (error) {
10122
10230
  const errorMessage = error instanceof Error ? error.message : String(error);
10123
10231
  getLumicLogger().error(`Error unzipping file: ${errorMessage}`);
10124
- throw error;
10232
+ throw new ZipError(`Failed to extract archive "${zipPath}" to "${destPath}": ${errorMessage}`, error);
10125
10233
  }
10126
10234
  }
10127
10235
  async function getDirectoryStats(dirPath) {
@@ -23075,11 +23183,11 @@ let poolConfig = DEFAULT_POOL_CONFIG;
23075
23183
  async function loadApolloModules() {
23076
23184
  if (typeof window === "undefined" || process.env.AWS_EXECUTION_ENV) {
23077
23185
  // Server-side (or Lambda): load the CommonJS‑based implementation.
23078
- return (await Promise.resolve().then(function () { return require('./apollo-client.server-Cx30LaNh.js'); }));
23186
+ return (await Promise.resolve().then(function () { return require('./apollo-client.server-JYHXy9ib.js'); }));
23079
23187
  }
23080
23188
  else {
23081
23189
  // Client-side: load the ESM‑based implementation.
23082
- return (await Promise.resolve().then(function () { return require('./apollo-client.client-D6jG5B1n.js'); }));
23190
+ return (await Promise.resolve().then(function () { return require('./apollo-client.client-CtjgIfRT.js'); }));
23083
23191
  }
23084
23192
  }
23085
23193
  /**
@@ -81790,4 +81898,4 @@ exports.withCorrelationId = withCorrelationId;
81790
81898
  exports.withMetrics = withMetrics;
81791
81899
  exports.withRateLimit = withRateLimit;
81792
81900
  exports.withRetry = withRetry;
81793
- //# sourceMappingURL=index-ChygDqeG.js.map
81901
+ //# sourceMappingURL=index-DgFDhFuO.js.map