@discomedia/utils 1.0.24 → 1.0.25

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/dist/index.mjs CHANGED
@@ -2368,7 +2368,7 @@ const safeJSON = (text) => {
2368
2368
  // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2369
2369
  const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
2370
2370
 
2371
- const VERSION = '5.12.0'; // x-release-please-version
2371
+ const VERSION = '5.12.1'; // x-release-please-version
2372
2372
 
2373
2373
  // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2374
2374
  const isRunningInBrowser = () => {
@@ -4001,8 +4001,119 @@ let Messages$1 = class Messages extends APIResource {
4001
4001
  }
4002
4002
  };
4003
4003
 
4004
- function isRunnableFunctionWithParse(fn) {
4005
- return typeof fn.parse === 'function';
4004
+ function isChatCompletionFunctionTool(tool) {
4005
+ return tool !== undefined && 'function' in tool && tool.function !== undefined;
4006
+ }
4007
+ function isAutoParsableResponseFormat(response_format) {
4008
+ return response_format?.['$brand'] === 'auto-parseable-response-format';
4009
+ }
4010
+ function isAutoParsableTool$1(tool) {
4011
+ return tool?.['$brand'] === 'auto-parseable-tool';
4012
+ }
4013
+ function maybeParseChatCompletion(completion, params) {
4014
+ if (!params || !hasAutoParseableInput$1(params)) {
4015
+ return {
4016
+ ...completion,
4017
+ choices: completion.choices.map((choice) => {
4018
+ assertToolCallsAreChatCompletionFunctionToolCalls(choice.message.tool_calls);
4019
+ return {
4020
+ ...choice,
4021
+ message: {
4022
+ ...choice.message,
4023
+ parsed: null,
4024
+ ...(choice.message.tool_calls ?
4025
+ {
4026
+ tool_calls: choice.message.tool_calls,
4027
+ }
4028
+ : undefined),
4029
+ },
4030
+ };
4031
+ }),
4032
+ };
4033
+ }
4034
+ return parseChatCompletion(completion, params);
4035
+ }
4036
+ function parseChatCompletion(completion, params) {
4037
+ const choices = completion.choices.map((choice) => {
4038
+ if (choice.finish_reason === 'length') {
4039
+ throw new LengthFinishReasonError();
4040
+ }
4041
+ if (choice.finish_reason === 'content_filter') {
4042
+ throw new ContentFilterFinishReasonError();
4043
+ }
4044
+ assertToolCallsAreChatCompletionFunctionToolCalls(choice.message.tool_calls);
4045
+ return {
4046
+ ...choice,
4047
+ message: {
4048
+ ...choice.message,
4049
+ ...(choice.message.tool_calls ?
4050
+ {
4051
+ tool_calls: choice.message.tool_calls?.map((toolCall) => parseToolCall$1(params, toolCall)) ?? undefined,
4052
+ }
4053
+ : undefined),
4054
+ parsed: choice.message.content && !choice.message.refusal ?
4055
+ parseResponseFormat(params, choice.message.content)
4056
+ : null,
4057
+ },
4058
+ };
4059
+ });
4060
+ return { ...completion, choices };
4061
+ }
4062
+ function parseResponseFormat(params, content) {
4063
+ if (params.response_format?.type !== 'json_schema') {
4064
+ return null;
4065
+ }
4066
+ if (params.response_format?.type === 'json_schema') {
4067
+ if ('$parseRaw' in params.response_format) {
4068
+ const response_format = params.response_format;
4069
+ return response_format.$parseRaw(content);
4070
+ }
4071
+ return JSON.parse(content);
4072
+ }
4073
+ return null;
4074
+ }
4075
+ function parseToolCall$1(params, toolCall) {
4076
+ const inputTool = params.tools?.find((inputTool) => isChatCompletionFunctionTool(inputTool) && inputTool.function?.name === toolCall.function.name); // TS doesn't narrow based on isChatCompletionTool
4077
+ return {
4078
+ ...toolCall,
4079
+ function: {
4080
+ ...toolCall.function,
4081
+ parsed_arguments: isAutoParsableTool$1(inputTool) ? inputTool.$parseRaw(toolCall.function.arguments)
4082
+ : inputTool?.function.strict ? JSON.parse(toolCall.function.arguments)
4083
+ : null,
4084
+ },
4085
+ };
4086
+ }
4087
+ function shouldParseToolCall(params, toolCall) {
4088
+ if (!params || !('tools' in params) || !params.tools) {
4089
+ return false;
4090
+ }
4091
+ const inputTool = params.tools?.find((inputTool) => isChatCompletionFunctionTool(inputTool) && inputTool.function?.name === toolCall.function.name);
4092
+ return (isChatCompletionFunctionTool(inputTool) &&
4093
+ (isAutoParsableTool$1(inputTool) || inputTool?.function.strict || false));
4094
+ }
4095
+ function hasAutoParseableInput$1(params) {
4096
+ if (isAutoParsableResponseFormat(params.response_format)) {
4097
+ return true;
4098
+ }
4099
+ return (params.tools?.some((t) => isAutoParsableTool$1(t) || (t.type === 'function' && t.function.strict === true)) ?? false);
4100
+ }
4101
+ function assertToolCallsAreChatCompletionFunctionToolCalls(toolCalls) {
4102
+ for (const toolCall of toolCalls || []) {
4103
+ if (toolCall.type !== 'function') {
4104
+ throw new OpenAIError(`Currently only \`function\` tool calls are supported; Received \`${toolCall.type}\``);
4105
+ }
4106
+ }
4107
+ }
4108
+ function validateInputTools(tools) {
4109
+ for (const tool of tools ?? []) {
4110
+ if (tool.type !== 'function') {
4111
+ throw new OpenAIError(`Currently only \`function\` tool types support auto-parsing; Received \`${tool.type}\``);
4112
+ }
4113
+ if (tool.function.strict !== true) {
4114
+ throw new OpenAIError(`The \`${tool.function.name}\` tool is not marked with \`strict: true\`. Only strict function tools can be auto-parsed`);
4115
+ }
4116
+ }
4006
4117
  }
4007
4118
 
4008
4119
  const isAssistantMessage = (message) => {
@@ -4196,104 +4307,8 @@ _EventStream_connectedPromise = new WeakMap(), _EventStream_resolveConnectedProm
4196
4307
  return this._emit('error', new OpenAIError(String(error)));
4197
4308
  };
4198
4309
 
4199
- function isAutoParsableResponseFormat(response_format) {
4200
- return response_format?.['$brand'] === 'auto-parseable-response-format';
4201
- }
4202
- function isAutoParsableTool$1(tool) {
4203
- return tool?.['$brand'] === 'auto-parseable-tool';
4204
- }
4205
- function maybeParseChatCompletion(completion, params) {
4206
- if (!params || !hasAutoParseableInput$1(params)) {
4207
- return {
4208
- ...completion,
4209
- choices: completion.choices.map((choice) => ({
4210
- ...choice,
4211
- message: {
4212
- ...choice.message,
4213
- parsed: null,
4214
- ...(choice.message.tool_calls ?
4215
- {
4216
- tool_calls: choice.message.tool_calls,
4217
- }
4218
- : undefined),
4219
- },
4220
- })),
4221
- };
4222
- }
4223
- return parseChatCompletion(completion, params);
4224
- }
4225
- function parseChatCompletion(completion, params) {
4226
- const choices = completion.choices.map((choice) => {
4227
- if (choice.finish_reason === 'length') {
4228
- throw new LengthFinishReasonError();
4229
- }
4230
- if (choice.finish_reason === 'content_filter') {
4231
- throw new ContentFilterFinishReasonError();
4232
- }
4233
- return {
4234
- ...choice,
4235
- message: {
4236
- ...choice.message,
4237
- ...(choice.message.tool_calls ?
4238
- {
4239
- tool_calls: choice.message.tool_calls?.map((toolCall) => parseToolCall$1(params, toolCall)) ?? undefined,
4240
- }
4241
- : undefined),
4242
- parsed: choice.message.content && !choice.message.refusal ?
4243
- parseResponseFormat(params, choice.message.content)
4244
- : null,
4245
- },
4246
- };
4247
- });
4248
- return { ...completion, choices };
4249
- }
4250
- function parseResponseFormat(params, content) {
4251
- if (params.response_format?.type !== 'json_schema') {
4252
- return null;
4253
- }
4254
- if (params.response_format?.type === 'json_schema') {
4255
- if ('$parseRaw' in params.response_format) {
4256
- const response_format = params.response_format;
4257
- return response_format.$parseRaw(content);
4258
- }
4259
- return JSON.parse(content);
4260
- }
4261
- return null;
4262
- }
4263
- function parseToolCall$1(params, toolCall) {
4264
- const inputTool = params.tools?.find((inputTool) => inputTool.function?.name === toolCall.function.name);
4265
- return {
4266
- ...toolCall,
4267
- function: {
4268
- ...toolCall.function,
4269
- parsed_arguments: isAutoParsableTool$1(inputTool) ? inputTool.$parseRaw(toolCall.function.arguments)
4270
- : inputTool?.function.strict ? JSON.parse(toolCall.function.arguments)
4271
- : null,
4272
- },
4273
- };
4274
- }
4275
- function shouldParseToolCall(params, toolCall) {
4276
- if (!params) {
4277
- return false;
4278
- }
4279
- const inputTool = params.tools?.find((inputTool) => inputTool.function?.name === toolCall.function.name);
4280
- return isAutoParsableTool$1(inputTool) || inputTool?.function.strict || false;
4281
- }
4282
- function hasAutoParseableInput$1(params) {
4283
- if (isAutoParsableResponseFormat(params.response_format)) {
4284
- return true;
4285
- }
4286
- return (params.tools?.some((t) => isAutoParsableTool$1(t) || (t.type === 'function' && t.function.strict === true)) ?? false);
4287
- }
4288
- function validateInputTools(tools) {
4289
- for (const tool of tools ?? []) {
4290
- if (tool.type !== 'function') {
4291
- throw new OpenAIError(`Currently only \`function\` tool types support auto-parsing; Received \`${tool.type}\``);
4292
- }
4293
- if (tool.function.strict !== true) {
4294
- throw new OpenAIError(`The \`${tool.function.name}\` tool is not marked with \`strict: true\`. Only strict function tools can be auto-parsed`);
4295
- }
4296
- }
4310
+ function isRunnableFunctionWithParse(fn) {
4311
+ return typeof fn.parse === 'function';
4297
4312
  }
4298
4313
 
4299
4314
  var _AbstractChatCompletionRunner_instances, _AbstractChatCompletionRunner_getFinalContent, _AbstractChatCompletionRunner_getFinalMessage, _AbstractChatCompletionRunner_getFinalFunctionToolCall, _AbstractChatCompletionRunner_getFinalFunctionToolCallResult, _AbstractChatCompletionRunner_calculateTotalUsage, _AbstractChatCompletionRunner_validateParams, _AbstractChatCompletionRunner_stringifyFunctionCallResult;
@@ -4419,7 +4434,7 @@ class AbstractChatCompletionRunner extends EventStream {
4419
4434
  async _runTools(client, params, options) {
4420
4435
  const role = 'tool';
4421
4436
  const { tool_choice = 'auto', stream, ...restParams } = params;
4422
- const singleFunctionToCall = typeof tool_choice !== 'string' && tool_choice?.function?.name;
4437
+ const singleFunctionToCall = typeof tool_choice !== 'string' && tool_choice.type === 'function' && tool_choice?.function?.name;
4423
4438
  const { maxChatCompletions = DEFAULT_MAX_CHAT_COMPLETIONS } = options || {};
4424
4439
  // TODO(someday): clean this logic up
4425
4440
  const inputTools = params.tools.map((tool) => {
@@ -4537,7 +4552,7 @@ _AbstractChatCompletionRunner_instances = new WeakSet(), _AbstractChatCompletion
4537
4552
  for (let i = this.messages.length - 1; i >= 0; i--) {
4538
4553
  const message = this.messages[i];
4539
4554
  if (isAssistantMessage(message) && message?.tool_calls?.length) {
4540
- return message.tool_calls.at(-1)?.function;
4555
+ return message.tool_calls.filter((x) => x.type === 'function').at(-1)?.function;
4541
4556
  }
4542
4557
  }
4543
4558
  return;
@@ -5015,7 +5030,7 @@ class ChatCompletionStream extends AbstractChatCompletionRunner {
5015
5030
  throw new Error('tool call snapshot missing `type`');
5016
5031
  }
5017
5032
  if (toolCallSnapshot.type === 'function') {
5018
- const inputTool = __classPrivateFieldGet(this, _ChatCompletionStream_params, "f")?.tools?.find((tool) => tool.type === 'function' && tool.function.name === toolCallSnapshot.function.name);
5033
+ const inputTool = __classPrivateFieldGet(this, _ChatCompletionStream_params, "f")?.tools?.find((tool) => isChatCompletionFunctionTool(tool) && tool.function.name === toolCallSnapshot.function.name); // TS doesn't narrow based on isChatCompletionTool
5019
5034
  this._emit('tool_calls.function.arguments.done', {
5020
5035
  name: toolCallSnapshot.function.name,
5021
5036
  index: toolCallIndex,
@@ -8825,7 +8840,7 @@ OpenAI.Evals = Evals;
8825
8840
  OpenAI.Containers = Containers;
8826
8841
 
8827
8842
  // llm-openai-config.ts
8828
- const DEFAULT_MODEL$1 = 'gpt-4.1-mini';
8843
+ const DEFAULT_MODEL = 'gpt-4.1-mini';
8829
8844
  /** Token costs in USD per 1M tokens. Last updated Feb 2025. */
8830
8845
  const openAiModelCosts = {
8831
8846
  'gpt-4o': {
@@ -8864,6 +8879,18 @@ const openAiModelCosts = {
8864
8879
  inputCost: 0.1 / 1_000_000,
8865
8880
  outputCost: 0.4 / 1_000_000,
8866
8881
  },
8882
+ 'gpt-5': {
8883
+ inputCost: 1.25 / 1_000_000,
8884
+ outputCost: 10 / 1_000_000,
8885
+ },
8886
+ 'gpt-5-mini': {
8887
+ inputCost: 0.25 / 1_000_000,
8888
+ outputCost: 2 / 1_000_000,
8889
+ },
8890
+ 'gpt-5-nano': {
8891
+ inputCost: 0.05 / 1_000_000,
8892
+ outputCost: 0.4 / 1_000_000,
8893
+ },
8867
8894
  'o4-mini': {
8868
8895
  inputCost: 1.1 / 1_000_000,
8869
8896
  outputCost: 4.4 / 1_000_000,
@@ -8931,7 +8958,6 @@ function calculateCost(provider, model, inputTokens, outputTokens, reasoningToke
8931
8958
  return inputCost + outputCost + reasoningCost;
8932
8959
  }
8933
8960
 
8934
- const DEFAULT_MODEL = 'gpt-4.1-mini';
8935
8961
  /**
8936
8962
  * Fix a broken JSON string by attempting to extract and parse valid JSON content. This function is very lenient and will attempt to fix many types of JSON errors, including unbalanced brackets, missing or extra commas, improperly escaped $ signs, unquoted strings, trailing commas, missing closing brackets or braces, etc.
8937
8963
  * @param {string} jsonStr - The broken JSON string to fix
@@ -9176,9 +9202,7 @@ function initializeOpenAI(apiKey) {
9176
9202
  });
9177
9203
  }
9178
9204
  /**
9179
- * Fixes broken JSON by sending it to the OpenAI GPT-4.1-mini model as a chat completion.
9180
- * The GPT-4.1-mini model is a large language model that can understand and generate code,
9181
- * including JSON. The returned JSON is the fixed version of the input JSON.
9205
+ * Fixes broken JSON by sending it to OpenAI to fix it.
9182
9206
  * If the model fails to return valid JSON, an error is thrown.
9183
9207
  * @param jsonStr - the broken JSON to fix
9184
9208
  * @param apiKey - the OpenAI API key to use, or undefined to use the value of the OPENAI_API_KEY environment variable
@@ -9322,8 +9346,11 @@ const isSupportedModel = (model) => {
9322
9346
  'o3-mini',
9323
9347
  'gpt-4.1',
9324
9348
  'gpt-4.1-mini',
9325
- 'o4-mini',
9326
9349
  'gpt-4.1-nano',
9350
+ 'gpt-5',
9351
+ 'gpt-5-mini',
9352
+ 'gpt-5-nano',
9353
+ 'o4-mini',
9327
9354
  'o3',
9328
9355
  ].includes(model);
9329
9356
  };
@@ -9334,8 +9361,9 @@ const isSupportedModel = (model) => {
9334
9361
  */
9335
9362
  function supportsTemperature(model) {
9336
9363
  // Reasoning models don't support temperature
9337
- const reasoningModels = ['o1', 'o1-mini', 'o3-mini', 'o4-mini', 'o3'];
9338
- return !reasoningModels.includes(model);
9364
+ // GPT-5 models also do not support temperature
9365
+ const reasoningAndGPT5Models = ['o1', 'o1-mini', 'o3-mini', 'o4-mini', 'o3', 'gpt-5', 'gpt-5-mini', 'gpt-5-nano'];
9366
+ return !reasoningAndGPT5Models.includes(model);
9339
9367
  }
9340
9368
  /**
9341
9369
  * Checks if the given model is a reasoning model. Reasoning models have different tool choice constraints.
@@ -9346,6 +9374,15 @@ function isReasoningModel(model) {
9346
9374
  const reasoningModels = ['o1', 'o1-mini', 'o3-mini', 'o4-mini', 'o3'];
9347
9375
  return reasoningModels.includes(model);
9348
9376
  }
9377
+ /**
9378
+ * Checks if the given model is a GPT-5 model. GPT-5 models don't support tool_choice other than 'auto'.
9379
+ * @param model The model to check.
9380
+ * @returns True if the model is a GPT-5 model, false otherwise.
9381
+ */
9382
+ function isGPT5Model(model) {
9383
+ const gpt5Models = ['gpt-5', 'gpt-5-mini', 'gpt-5-nano'];
9384
+ return gpt5Models.includes(model);
9385
+ }
9349
9386
  /**
9350
9387
  * Makes a call to OpenAI's Responses API for more advanced use cases with built-in tools.
9351
9388
  *
@@ -9373,7 +9410,7 @@ function isReasoningModel(model) {
9373
9410
  * @throws Error if the API call fails
9374
9411
  */
9375
9412
  const makeResponsesAPICall = async (input, options = {}) => {
9376
- const normalizedModel = normalizeModelName(options.model || DEFAULT_MODEL$1);
9413
+ const normalizedModel = normalizeModelName(options.model || DEFAULT_MODEL);
9377
9414
  const apiKey = options.apiKey || process.env.OPENAI_API_KEY;
9378
9415
  if (!apiKey) {
9379
9416
  throw new Error('OpenAI API key is not provided and OPENAI_API_KEY environment variable is not set');
@@ -9484,7 +9521,7 @@ const makeResponsesAPICall = async (input, options = {}) => {
9484
9521
  * });
9485
9522
  */
9486
9523
  async function makeLLMCall(input, options = {}) {
9487
- const { apiKey, model = DEFAULT_MODEL$1, responseFormat = 'text', tools, useCodeInterpreter = false, useWebSearch = false, imageBase64, imageDetail = 'high', context, } = options;
9524
+ const { apiKey, model = DEFAULT_MODEL, responseFormat = 'text', tools, useCodeInterpreter = false, useWebSearch = false, imageBase64, imageDetail = 'high', context, } = options;
9488
9525
  // Validate model
9489
9526
  const normalizedModel = normalizeModelName(model);
9490
9527
  if (!isSupportedModel(normalizedModel)) {
@@ -9576,8 +9613,8 @@ async function makeLLMCall(input, options = {}) {
9576
9613
  }
9577
9614
  if (useWebSearch) {
9578
9615
  responsesOptions.tools = [{ type: 'web_search_preview' }];
9579
- // For reasoning models, we can't force tool choice - they only support 'auto'
9580
- if (!isReasoningModel(normalizedModel)) {
9616
+ // For reasoning models and GPT-5 models, we can't force tool choice - they only support 'auto'
9617
+ if (!isReasoningModel(normalizedModel) && !isGPT5Model(normalizedModel)) {
9581
9618
  responsesOptions.tool_choice = { type: 'web_search_preview' };
9582
9619
  }
9583
9620
  }