190proof 1.0.118 → 1.0.120

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/README.md CHANGED
@@ -323,6 +323,19 @@ interface ParsedResponseMessage {
323
323
  }
324
324
  ```
325
325
 
326
+ ### `setLogger(sink | null)`
327
+
328
+ 190proof logs each call and retry to the console. Route those lines to your own logger, or pass `null` to silence them (useful when 190proof is a dependency of a library):
329
+
330
+ ```typescript
331
+ import { setLogger } from "190proof";
332
+
333
+ setLogger(null); // silent
334
+ setLogger({ log: myLog.info, warn: myLog.warn, error: myLog.error });
335
+ ```
336
+
337
+ Errors thrown by `callWithRetries` never carry the HTTP request (and so never the API key); provider status and response body stay on `error.response`.
338
+
326
339
  ### `parseModelString(model)`
327
340
 
328
341
  Parses a model string into its provider and model ID components.
package/dist/index.d.mts CHANGED
@@ -359,6 +359,26 @@ interface GenericPayload {
359
359
  signal?: AbortSignal;
360
360
  }
361
361
 
362
+ /** Where 190proof's own log lines go. Defaults to the console. */
363
+ interface LogSink {
364
+ log(message: string, ...args: any[]): void;
365
+ warn(message: string, ...args: any[]): void;
366
+ error(message: string, ...args: any[]): void;
367
+ }
368
+ /**
369
+ * Route 190proof's logging to your own logger, or pass null to silence it
370
+ * (useful when embedding the SDK in a library).
371
+ */
372
+ declare function setLogger(next: LogSink | null): void;
373
+ /**
374
+ * HTTP client errors (axios) carry the full request config, API-key headers
375
+ * included; logging or rethrowing one as a `cause` leaks the key into every
376
+ * log that prints it. Rebuild a plain Error with only what callers use:
377
+ * message, name, code, and the response status + body. Non-HTTP errors pass
378
+ * through untouched.
379
+ */
380
+ declare function redactError<T>(err: T): T | Error;
381
+
362
382
  /**
363
383
  * In-process memory of OpenRouter models that rejected image input (the
364
384
  * routing-layer 404 "No endpoints found that support image input"). Payloads
@@ -382,4 +402,4 @@ declare function parseModelString(model: string): {
382
402
  };
383
403
  declare function callWithRetries(id: string | string[], aiPayload: GenericPayload, aiConfig?: OpenAIConfig | AnthropicAIConfig, retries?: number, chunkTimeoutMs?: number): Promise<ParsedResponseMessage>;
384
404
 
385
- export { type AnyModel, ClaudeModel, type FunctionCall, type FunctionDefinition, GPTModel, GeminiModel, type GenericMessage, type GenericPayload, GroqModel, MIN_STREAM_ATTEMPT_MS, OPENROUTER_NONSTREAM_TIMEOUT_MS, OPENROUTER_STREAM_TIMEOUT_MS, type OpenAIConfig, OpenRouterModel, type OpenRouterProviderPreferences, type ParsedResponseMessage, type Provider, type ToolResult, callWithRetries, openRouterImageRejectedModels, parseModelString };
405
+ export { type AnyModel, ClaudeModel, type FunctionCall, type FunctionDefinition, GPTModel, GeminiModel, type GenericMessage, type GenericPayload, GroqModel, type LogSink, MIN_STREAM_ATTEMPT_MS, OPENROUTER_NONSTREAM_TIMEOUT_MS, OPENROUTER_STREAM_TIMEOUT_MS, type OpenAIConfig, OpenRouterModel, type OpenRouterProviderPreferences, type ParsedResponseMessage, type Provider, type ToolResult, callWithRetries, openRouterImageRejectedModels, parseModelString, redactError, setLogger };
package/dist/index.d.ts CHANGED
@@ -359,6 +359,26 @@ interface GenericPayload {
359
359
  signal?: AbortSignal;
360
360
  }
361
361
 
362
+ /** Where 190proof's own log lines go. Defaults to the console. */
363
+ interface LogSink {
364
+ log(message: string, ...args: any[]): void;
365
+ warn(message: string, ...args: any[]): void;
366
+ error(message: string, ...args: any[]): void;
367
+ }
368
+ /**
369
+ * Route 190proof's logging to your own logger, or pass null to silence it
370
+ * (useful when embedding the SDK in a library).
371
+ */
372
+ declare function setLogger(next: LogSink | null): void;
373
+ /**
374
+ * HTTP client errors (axios) carry the full request config, API-key headers
375
+ * included; logging or rethrowing one as a `cause` leaks the key into every
376
+ * log that prints it. Rebuild a plain Error with only what callers use:
377
+ * message, name, code, and the response status + body. Non-HTTP errors pass
378
+ * through untouched.
379
+ */
380
+ declare function redactError<T>(err: T): T | Error;
381
+
362
382
  /**
363
383
  * In-process memory of OpenRouter models that rejected image input (the
364
384
  * routing-layer 404 "No endpoints found that support image input"). Payloads
@@ -382,4 +402,4 @@ declare function parseModelString(model: string): {
382
402
  };
383
403
  declare function callWithRetries(id: string | string[], aiPayload: GenericPayload, aiConfig?: OpenAIConfig | AnthropicAIConfig, retries?: number, chunkTimeoutMs?: number): Promise<ParsedResponseMessage>;
384
404
 
385
- export { type AnyModel, ClaudeModel, type FunctionCall, type FunctionDefinition, GPTModel, GeminiModel, type GenericMessage, type GenericPayload, GroqModel, MIN_STREAM_ATTEMPT_MS, OPENROUTER_NONSTREAM_TIMEOUT_MS, OPENROUTER_STREAM_TIMEOUT_MS, type OpenAIConfig, OpenRouterModel, type OpenRouterProviderPreferences, type ParsedResponseMessage, type Provider, type ToolResult, callWithRetries, openRouterImageRejectedModels, parseModelString };
405
+ export { type AnyModel, ClaudeModel, type FunctionCall, type FunctionDefinition, GPTModel, GeminiModel, type GenericMessage, type GenericPayload, GroqModel, type LogSink, MIN_STREAM_ATTEMPT_MS, OPENROUTER_NONSTREAM_TIMEOUT_MS, OPENROUTER_STREAM_TIMEOUT_MS, type OpenAIConfig, OpenRouterModel, type OpenRouterProviderPreferences, type ParsedResponseMessage, type Provider, type ToolResult, callWithRetries, openRouterImageRejectedModels, parseModelString, redactError, setLogger };
package/dist/index.js CHANGED
@@ -27,7 +27,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
27
27
  ));
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
29
 
30
- // index.ts
30
+ // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
33
  ClaudeModel: () => ClaudeModel,
@@ -40,11 +40,13 @@ __export(index_exports, {
40
40
  OpenRouterModel: () => OpenRouterModel,
41
41
  callWithRetries: () => callWithRetries,
42
42
  openRouterImageRejectedModels: () => openRouterImageRejectedModels,
43
- parseModelString: () => parseModelString
43
+ parseModelString: () => parseModelString,
44
+ redactError: () => redactError,
45
+ setLogger: () => setLogger
44
46
  });
45
47
  module.exports = __toCommonJS(index_exports);
46
48
 
47
- // interfaces.ts
49
+ // src/interfaces.ts
48
50
  var ClaudeModel = /* @__PURE__ */ ((ClaudeModel2) => {
49
51
  ClaudeModel2["HAIKU_3"] = "claude-3-haiku-20240307";
50
52
  ClaudeModel2["SONNET_3"] = "claude-3-sonnet-20240229";
@@ -103,7 +105,7 @@ var GeminiModel = /* @__PURE__ */ ((GeminiModel2) => {
103
105
  return GeminiModel2;
104
106
  })(GeminiModel || {});
105
107
 
106
- // logger.ts
108
+ // src/logger.ts
107
109
  function formatIdentifier(identifier) {
108
110
  if (Array.isArray(identifier)) {
109
111
  return identifier.map((id) => `[${id}]`).join(" ");
@@ -113,14 +115,34 @@ function formatIdentifier(identifier) {
113
115
  function formatMessage(level, identifier, message) {
114
116
  return `[${level}] ${formatIdentifier(identifier)} ${message}`;
115
117
  }
118
+ var sink = console;
119
+ function setLogger(next) {
120
+ sink = next;
121
+ }
116
122
  function log(identifier, message, ...args) {
117
- console.log(formatMessage("LOG", identifier, message), ...args);
123
+ sink == null ? void 0 : sink.log(formatMessage("LOG", identifier, message), ...args);
118
124
  }
119
125
  function warn(identifier, message, ...args) {
120
- console.warn(formatMessage("WARN", identifier, message), ...args);
126
+ sink == null ? void 0 : sink.warn(formatMessage("WARN", identifier, message), ...args);
121
127
  }
122
128
  function error(identifier, message, ...args) {
123
- console.error(formatMessage("ERROR", identifier, message), ...args);
129
+ sink == null ? void 0 : sink.error(formatMessage("ERROR", identifier, message), ...args);
130
+ }
131
+ function redactError(err) {
132
+ const e = err;
133
+ if (!e || typeof e !== "object" || !(e.config || e.request || e.isAxiosError)) {
134
+ return err;
135
+ }
136
+ const clean = new Error(e.message);
137
+ clean.name = e.name;
138
+ if (e.code !== void 0) clean.code = e.code;
139
+ if (e.status !== void 0) clean.status = e.status;
140
+ if (e.response) {
141
+ clean.response = { status: e.response.status, statusText: e.response.statusText, data: e.response.data };
142
+ }
143
+ if (e.data !== void 0) clean.data = e.data;
144
+ if (e.cause) clean.cause = redactError(e.cause);
145
+ return clean;
124
146
  }
125
147
  var logger_default = {
126
148
  log,
@@ -128,11 +150,11 @@ var logger_default = {
128
150
  error
129
151
  };
130
152
 
131
- // index.ts
153
+ // src/index.ts
132
154
  var import_client_bedrock_runtime = require("@aws-sdk/client-bedrock-runtime");
133
155
  var import_axios = __toESM(require("axios"));
134
156
 
135
- // utils.ts
157
+ // src/utils.ts
136
158
  function timeout(ms) {
137
159
  return new Promise((resolve) => setTimeout(resolve, ms));
138
160
  }
@@ -142,7 +164,7 @@ function isHeicImage(name, mime) {
142
164
  return ["heic", "heif", "heics"].includes(extension) || !!(mime && ["image/heic", "image/heif", "image/heic-sequence"].includes(mime));
143
165
  }
144
166
 
145
- // index.ts
167
+ // src/index.ts
146
168
  var sharp = require("sharp");
147
169
  var decode = require("heic-decode");
148
170
  function anySignal(signals) {
@@ -180,7 +202,7 @@ async function withRetries(identifier, apiName, fn, options = {}) {
180
202
  logger_default.error(
181
203
  identifier,
182
204
  `Retry #${attempt} error: ${error3.message}`,
183
- ((_b = error3.response) == null ? void 0 : _b.data) || error3
205
+ ((_b = error3.response) == null ? void 0 : _b.data) || redactError(error3)
184
206
  );
185
207
  }
186
208
  await timeout(baseDelayMs * attempt);
@@ -190,7 +212,7 @@ async function withRetries(identifier, apiName, fn, options = {}) {
190
212
  const error2 = new Error(
191
213
  `Failed to call ${apiName} API after ${retries} attempts: ${detail}`
192
214
  );
193
- error2.cause = lastError;
215
+ error2.cause = redactError(lastError);
194
216
  throw error2;
195
217
  }
196
218
  function parseStreamedResponse(identifier, paragraph, toolCallAccumulators, allowedFunctionNames, reasoning) {
@@ -660,7 +682,7 @@ async function callOpenAiWithRetries(id, openAiPayload, openAiConfig, retries =
660
682
  logger_default.error(
661
683
  id,
662
684
  `Retry #${attempt} error: ${error2.message}`,
663
- ((_a = error2.response) == null ? void 0 : _a.data) || error2.data || error2
685
+ ((_a = error2.response) == null ? void 0 : _a.data) || error2.data || redactError(error2)
664
686
  );
665
687
  if (((_b = error2.data) == null ? void 0 : _b.code) === "content_policy_violation") {
666
688
  logger_default.log(id, "Removing images due to content policy violation");
@@ -1218,7 +1240,7 @@ async function callGoogleAIWithRetries(id, payload, retries = 5, requestTimeoutM
1218
1240
  const fetchError = new Error(
1219
1241
  "Google AI could not fetch the provided image URL(s)."
1220
1242
  );
1221
- fetchError.cause = error2;
1243
+ fetchError.cause = redactError(error2);
1222
1244
  fetchError.googleFetchFailure = true;
1223
1245
  throw fetchError;
1224
1246
  }
@@ -1565,6 +1587,14 @@ async function callOpenRouterStream(id, payload, streamTimeoutMs = OPENROUTER_ST
1565
1587
  let finishReason = null;
1566
1588
  let sawDone = false;
1567
1589
  let dataChunks = 0;
1590
+ const RAW_HEAD_MAX = 3e3;
1591
+ const RAW_TAIL_MAX = 1500;
1592
+ let rawHead = "";
1593
+ let rawTail = "";
1594
+ let generationId;
1595
+ const unreadKeys = /* @__PURE__ */ new Set();
1596
+ const KNOWN_DELTA_KEYS = /* @__PURE__ */ new Set(["role", "content", "reasoning", "reasoning_details", "tool_calls"]);
1597
+ const KNOWN_CHOICE_KEYS = /* @__PURE__ */ new Set(["index", "delta", "finish_reason", "native_finish_reason", "logprobs"]);
1568
1598
  try {
1569
1599
  armStallTimer();
1570
1600
  const response = await fetch(openRouterEndpoint(), {
@@ -1616,6 +1646,11 @@ async function callOpenRouterStream(id, payload, streamTimeoutMs = OPENROUTER_ST
1616
1646
  sawDone = true;
1617
1647
  break outer;
1618
1648
  }
1649
+ if (rawHead.length < RAW_HEAD_MAX) {
1650
+ rawHead += dataStr.slice(0, RAW_HEAD_MAX - rawHead.length) + "\n";
1651
+ } else {
1652
+ rawTail = (rawTail + dataStr + "\n").slice(-RAW_TAIL_MAX);
1653
+ }
1619
1654
  let json;
1620
1655
  try {
1621
1656
  json = JSON.parse(dataStr);
@@ -1637,6 +1672,7 @@ async function callOpenRouterStream(id, payload, streamTimeoutMs = OPENROUTER_ST
1637
1672
  throw error2;
1638
1673
  }
1639
1674
  if (json.provider) provider = json.provider;
1675
+ if (json.id && !generationId) generationId = json.id;
1640
1676
  let useful = false;
1641
1677
  if (json.usage) {
1642
1678
  usage = json.usage;
@@ -1645,6 +1681,12 @@ async function callOpenRouterStream(id, payload, streamTimeoutMs = OPENROUTER_ST
1645
1681
  const choice = (_c = json.choices) == null ? void 0 : _c[0];
1646
1682
  if (choice) {
1647
1683
  const delta = (_d = choice.delta) != null ? _d : {};
1684
+ for (const k of Object.keys(choice)) {
1685
+ if (!KNOWN_CHOICE_KEYS.has(k) && choice[k] != null) unreadKeys.add(`choice.${k}`);
1686
+ }
1687
+ for (const k of Object.keys(delta)) {
1688
+ if (!KNOWN_DELTA_KEYS.has(k) && delta[k] != null && delta[k] !== "") unreadKeys.add(`delta.${k}`);
1689
+ }
1648
1690
  if (delta.content) {
1649
1691
  paragraph += delta.content;
1650
1692
  useful = true;
@@ -1701,7 +1743,12 @@ async function callOpenRouterStream(id, payload, streamTimeoutMs = OPENROUTER_ST
1701
1743
  usage,
1702
1744
  paragraph: paragraph.slice(0, 500),
1703
1745
  reasoningChars: reasoning.length,
1704
- toolCalls
1746
+ toolCalls,
1747
+ generationId,
1748
+ dataChunks,
1749
+ unreadKeys: [...unreadKeys],
1750
+ rawHead,
1751
+ rawTail: rawTail || void 0
1705
1752
  })
1706
1753
  });
1707
1754
  } catch (error2) {
@@ -1976,7 +2023,7 @@ async function callWithRetries(id, aiPayload, aiConfig, retries = 5, chunkTimeou
1976
2023
  (_e = result.provider) != null ? _e : result.provider = provider;
1977
2024
  return result;
1978
2025
  } catch (error2) {
1979
- if ((_f = aiPayload.signal) == null ? void 0 : _f.aborted) throw error2;
2026
+ if ((_f = aiPayload.signal) == null ? void 0 : _f.aborted) throw redactError(error2);
1980
2027
  if (aiPayload.fallbackModel) {
1981
2028
  logger_default.error(
1982
2029
  id,
@@ -1998,7 +2045,7 @@ async function callWithRetries(id, aiPayload, aiConfig, retries = 5, chunkTimeou
1998
2045
  chunkTimeoutMs
1999
2046
  );
2000
2047
  }
2001
- throw error2;
2048
+ throw redactError(error2);
2002
2049
  }
2003
2050
  }
2004
2051
  // Annotate the CommonJS export names for ESM import in node:
@@ -2013,6 +2060,8 @@ async function callWithRetries(id, aiPayload, aiConfig, retries = 5, chunkTimeou
2013
2060
  OpenRouterModel,
2014
2061
  callWithRetries,
2015
2062
  openRouterImageRejectedModels,
2016
- parseModelString
2063
+ parseModelString,
2064
+ redactError,
2065
+ setLogger
2017
2066
  });
2018
2067
  //# sourceMappingURL=index.js.map