@discomedia/utils 1.0.46 → 1.0.51

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.cjs CHANGED
@@ -449,9 +449,10 @@ function getLastFullTradingDateImpl(currentDate = new Date()) {
449
449
  if (calendar.isEarlyCloseDay(prevMarketDay)) {
450
450
  prevCloseMinutes = MARKET_CONFIG.TIMES.EARLY_CLOSE.hour * 60 + MARKET_CONFIG.TIMES.EARLY_CLOSE.minute;
451
451
  }
452
- const year = prevMarketDay.getUTCFullYear();
453
- const month = prevMarketDay.getUTCMonth();
454
- const day = prevMarketDay.getUTCDate();
452
+ const prevNYDate = toNYTime(prevMarketDay);
453
+ const year = prevNYDate.getUTCFullYear();
454
+ const month = prevNYDate.getUTCMonth();
455
+ const day = prevNYDate.getUTCDate();
455
456
  const closeHour = Math.floor(prevCloseMinutes / 60);
456
457
  const closeMinute = prevCloseMinutes % 60;
457
458
  return fromNYTime(new Date(Date.UTC(year, month, day, closeHour, closeMinute, 0, 0)));
@@ -965,6 +966,61 @@ function countTradingDays(startDate, endDate = new Date()) {
965
966
  minutes: Math.round(minutes),
966
967
  };
967
968
  }
969
+ /**
970
+ * Returns the trading day N days back from a reference date, along with its market open time.
971
+ * Trading days are counted as full or half trading days (days that end count as 1 full trading day).
972
+ *
973
+ * @param options - Object with:
974
+ * - referenceDate: Date to count back from (default: now)
975
+ * - days: Number of trading days to go back (must be >= 1)
976
+ * @returns Object containing:
977
+ * - date: Trading date in YYYY-MM-DD format
978
+ * - marketOpenISO: Market open time as ISO string (e.g., "2025-11-15T13:30:00.000Z")
979
+ * - unixTimestamp: Market open time as Unix timestamp in seconds
980
+ * @example
981
+ * ```typescript
982
+ * // Get the trading day 1 day back (most recent full trading day)
983
+ * const result = getTradingDaysBack({ days: 1 });
984
+ * console.log(result.date); // "2025-11-01"
985
+ * console.log(result.marketOpenISO); // "2025-11-01T13:30:00.000Z"
986
+ * console.log(result.unixTimestamp); // 1730466600
987
+ *
988
+ * // Get the trading day 5 days back from a specific date
989
+ * const result2 = getTradingDaysBack({
990
+ * referenceDate: new Date('2025-11-15T12:00:00-05:00'),
991
+ * days: 5
992
+ * });
993
+ * ```
994
+ */
995
+ function getTradingDaysBack(options) {
996
+ const calendar = new MarketCalendar();
997
+ const refDate = options.referenceDate || new Date();
998
+ const daysBack = options.days;
999
+ if (daysBack < 1) {
1000
+ throw new Error('days must be at least 1');
1001
+ }
1002
+ // Start from the last full trading date relative to reference
1003
+ let targetDate = getLastFullTradingDateImpl(refDate);
1004
+ // Go back the specified number of days (we're already at day 1, so go back days-1 more)
1005
+ for (let i = 1; i < daysBack; i++) {
1006
+ targetDate = calendar.getPreviousMarketDay(targetDate);
1007
+ }
1008
+ // Get market open time for this date
1009
+ const marketTimes = getMarketTimes(targetDate);
1010
+ if (!marketTimes.open) {
1011
+ throw new Error(`No market open time for target date`);
1012
+ }
1013
+ // Format the date string (YYYY-MM-DD) in NY time
1014
+ const nyDate = toNYTime(marketTimes.open);
1015
+ const dateStr = `${nyDate.getUTCFullYear()}-${String(nyDate.getUTCMonth() + 1).padStart(2, '0')}-${String(nyDate.getUTCDate()).padStart(2, '0')}`;
1016
+ const marketOpenISO = marketTimes.open.toISOString();
1017
+ const unixTimestamp = Math.floor(marketTimes.open.getTime() / 1000);
1018
+ return {
1019
+ date: dateStr,
1020
+ marketOpenISO,
1021
+ unixTimestamp,
1022
+ };
1023
+ }
968
1024
  // Export MARKET_TIMES for compatibility
969
1025
  const MARKET_TIMES = {
970
1026
  TIMEZONE: MARKET_CONFIG.TIMEZONE,
@@ -1087,6 +1143,10 @@ function isOpenRouterModel(model) {
1087
1143
  'openai/gpt-5-mini',
1088
1144
  'openai/gpt-5-nano',
1089
1145
  'openai/gpt-5.1',
1146
+ 'openai/gpt-5.2',
1147
+ 'openai/gpt-5.2-pro',
1148
+ 'openai/gpt-5.1-codex',
1149
+ 'openai/gpt-5.1-codex-max',
1090
1150
  'openai/gpt-oss-120b',
1091
1151
  'z.ai/glm-4.5',
1092
1152
  'z.ai/glm-4.5-air',
@@ -2452,7 +2512,7 @@ const safeJSON = (text) => {
2452
2512
  // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2453
2513
  const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
2454
2514
 
2455
- const VERSION = '6.9.1'; // x-release-please-version
2515
+ const VERSION = '6.15.0'; // x-release-please-version
2456
2516
 
2457
2517
  // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2458
2518
  const isRunningInBrowser = () => {
@@ -8293,6 +8353,19 @@ class Responses extends APIResource {
8293
8353
  cancel(responseID, options) {
8294
8354
  return this._client.post(path `/responses/${responseID}/cancel`, options);
8295
8355
  }
8356
+ /**
8357
+ * Compact conversation
8358
+ *
8359
+ * @example
8360
+ * ```ts
8361
+ * const compactedResponse = await client.responses.compact({
8362
+ * model: 'gpt-5.2',
8363
+ * });
8364
+ * ```
8365
+ */
8366
+ compact(body, options) {
8367
+ return this._client.post('/responses/compact', { body, ...options });
8368
+ }
8296
8369
  }
8297
8370
  Responses.InputItems = InputItems;
8298
8371
  Responses.InputTokens = InputTokens;
@@ -9435,6 +9508,22 @@ const openAiModelCosts = {
9435
9508
  inputCost: 1.25 / 1_000_000,
9436
9509
  outputCost: 10 / 1_000_000,
9437
9510
  },
9511
+ 'gpt-5.2': {
9512
+ inputCost: 1.5 / 1_000_000,
9513
+ outputCost: 12 / 1_000_000,
9514
+ },
9515
+ 'gpt-5.2-pro': {
9516
+ inputCost: 3 / 1_000_000,
9517
+ outputCost: 24 / 1_000_000,
9518
+ },
9519
+ 'gpt-5.1-codex': {
9520
+ inputCost: 1.1 / 1_000_000,
9521
+ outputCost: 8.8 / 1_000_000,
9522
+ },
9523
+ 'gpt-5.1-codex-max': {
9524
+ inputCost: 1.8 / 1_000_000,
9525
+ outputCost: 14.4 / 1_000_000,
9526
+ },
9438
9527
  'o4-mini': {
9439
9528
  inputCost: 1.1 / 1_000_000,
9440
9529
  outputCost: 4.4 / 1_000_000,
@@ -9455,6 +9544,7 @@ const deepseekModelCosts = {
9455
9544
  /** Image generation costs in USD per image. Based on OpenAI pricing as of Feb 2025. */
9456
9545
  const openAiImageCosts = {
9457
9546
  'gpt-image-1': 0.0075, // $0.0075 per image for gpt-image-1
9547
+ 'gpt-image-1.5': 0.0075, // Assumes parity pricing with gpt-image-1 until OpenAI publishes updated rates
9458
9548
  };
9459
9549
  /**
9460
9550
  * Calculates the cost of generating images using OpenAI's Images API.
@@ -9464,10 +9554,12 @@ const openAiImageCosts = {
9464
9554
  * @returns The cost of generating the images in USD.
9465
9555
  */
9466
9556
  function calculateImageCost(model, imageCount) {
9467
- if (typeof imageCount !== 'number' || imageCount <= 0) {
9557
+ if (typeof model !== 'string' || typeof imageCount !== 'number' || imageCount <= 0) {
9468
9558
  return 0;
9469
9559
  }
9470
9560
  const costPerImage = openAiImageCosts[model];
9561
+ if (!costPerImage)
9562
+ return 0;
9471
9563
  return imageCount * costPerImage;
9472
9564
  }
9473
9565
  /**
@@ -9896,6 +9988,10 @@ const isSupportedModel = (model) => {
9896
9988
  'gpt-5-mini',
9897
9989
  'gpt-5-nano',
9898
9990
  'gpt-5.1',
9991
+ 'gpt-5.2',
9992
+ 'gpt-5.2-pro',
9993
+ 'gpt-5.1-codex',
9994
+ 'gpt-5.1-codex-max',
9899
9995
  'o4-mini',
9900
9996
  'o3',
9901
9997
  ].includes(model);
@@ -9908,7 +10004,21 @@ const isSupportedModel = (model) => {
9908
10004
  function supportsTemperature(model) {
9909
10005
  // Reasoning models don't support temperature
9910
10006
  // GPT-5 models also do not support temperature
9911
- const reasoningAndGPT5Models = ['o1', 'o1-mini', 'o3-mini', 'o4-mini', 'o3', 'gpt-5', 'gpt-5-mini', 'gpt-5-nano', 'gpt-5.1'];
10007
+ const reasoningAndGPT5Models = [
10008
+ 'o1',
10009
+ 'o1-mini',
10010
+ 'o3-mini',
10011
+ 'o4-mini',
10012
+ 'o3',
10013
+ 'gpt-5',
10014
+ 'gpt-5-mini',
10015
+ 'gpt-5-nano',
10016
+ 'gpt-5.1',
10017
+ 'gpt-5.2',
10018
+ 'gpt-5.2-pro',
10019
+ 'gpt-5.1-codex',
10020
+ 'gpt-5.1-codex-max',
10021
+ ];
9912
10022
  return !reasoningAndGPT5Models.includes(model);
9913
10023
  }
9914
10024
  /**
@@ -9926,7 +10036,16 @@ function isReasoningModel(model) {
9926
10036
  * @returns True if the model is a GPT-5 model, false otherwise.
9927
10037
  */
9928
10038
  function isGPT5Model(model) {
9929
- const gpt5Models = ['gpt-5', 'gpt-5-mini', 'gpt-5-nano', 'gpt-5.1'];
10039
+ const gpt5Models = [
10040
+ 'gpt-5',
10041
+ 'gpt-5-mini',
10042
+ 'gpt-5-nano',
10043
+ 'gpt-5.1',
10044
+ 'gpt-5.2',
10045
+ 'gpt-5.2-pro',
10046
+ 'gpt-5.1-codex',
10047
+ 'gpt-5.1-codex-max',
10048
+ ];
9930
10049
  return gpt5Models.includes(model);
9931
10050
  }
9932
10051
  /**
@@ -10167,6 +10286,20 @@ async function makeLLMCall(input, options = {}) {
10167
10286
  return await makeResponsesAPICall(processedInput, responsesOptions);
10168
10287
  }
10169
10288
 
10289
+ const DEFAULT_IMAGE_MODEL = 'gpt-image-1.5';
10290
+ const resolveImageModel = (model) => model ?? DEFAULT_IMAGE_MODEL;
10291
+ const MULTIMODAL_VISION_MODELS = new Set([
10292
+ 'gpt-4o-mini',
10293
+ 'gpt-4o',
10294
+ 'gpt-5',
10295
+ 'gpt-5-mini',
10296
+ 'gpt-5-nano',
10297
+ 'gpt-5.1',
10298
+ 'gpt-5.2',
10299
+ 'gpt-5.2-pro',
10300
+ 'gpt-5.1-codex',
10301
+ 'gpt-5.1-codex-max',
10302
+ ]);
10170
10303
  /**
10171
10304
  * Makes a call to the OpenAI Images API to generate images based on a text prompt.
10172
10305
  *
@@ -10203,7 +10336,12 @@ async function makeLLMCall(input, options = {}) {
10203
10336
  * @throws Error if the API call fails or invalid parameters are provided
10204
10337
  */
10205
10338
  async function makeImagesCall(prompt, options = {}) {
10206
- const { size = 'auto', outputFormat = 'webp', compression = 50, quality = 'high', count = 1, background = 'auto', moderation = 'auto', apiKey } = options;
10339
+ const { model, size = 'auto', outputFormat = 'webp', compression = 50, quality = 'high', count = 1, background = 'auto', moderation = 'auto', apiKey, visionModel, } = options;
10340
+ const imageModel = resolveImageModel(model);
10341
+ const supportedVisionModel = visionModel && MULTIMODAL_VISION_MODELS.has(visionModel) ? visionModel : undefined;
10342
+ if (visionModel && !supportedVisionModel) {
10343
+ console.warn(`Vision model ${visionModel} is not recognized as a multimodal OpenAI model. Ignoring for image usage metadata.`);
10344
+ }
10207
10345
  // Get API key
10208
10346
  const effectiveApiKey = apiKey || process.env.OPENAI_API_KEY;
10209
10347
  if (!effectiveApiKey) {
@@ -10224,7 +10362,7 @@ async function makeImagesCall(prompt, options = {}) {
10224
10362
  });
10225
10363
  // Build the request parameters using OpenAI's type
10226
10364
  const requestParams = {
10227
- model: 'gpt-image-1',
10365
+ model: imageModel,
10228
10366
  prompt,
10229
10367
  n: count || 1,
10230
10368
  size: size || 'auto',
@@ -10248,7 +10386,7 @@ async function makeImagesCall(prompt, options = {}) {
10248
10386
  throw new Error('No images returned from OpenAI Images API');
10249
10387
  }
10250
10388
  // Calculate cost
10251
- const cost = calculateImageCost('gpt-image-1', count || 1);
10389
+ const cost = calculateImageCost(imageModel, count || 1);
10252
10390
  // Return the response with enhanced usage information
10253
10391
  const enhancedResponse = {
10254
10392
  ...response,
@@ -10261,8 +10399,9 @@ async function makeImagesCall(prompt, options = {}) {
10261
10399
  total_tokens: 0,
10262
10400
  }),
10263
10401
  provider: 'openai',
10264
- model: 'gpt-image-1',
10402
+ model: imageModel,
10265
10403
  cost,
10404
+ ...(supportedVisionModel ? { visionModel: supportedVisionModel } : {}),
10266
10405
  },
10267
10406
  };
10268
10407
  return enhancedResponse;
@@ -19389,6 +19528,7 @@ const disco = {
19389
19528
  getNYTimeZone: getNYTimeZone,
19390
19529
  getTradingDate: getTradingDate,
19391
19530
  getTradingStartAndEndDates: getTradingStartAndEndDates,
19531
+ getTradingDaysBack: getTradingDaysBack,
19392
19532
  isMarketDay: isMarketDay,
19393
19533
  isWithinMarketHours: isWithinMarketHours,
19394
19534
  countTradingDays: countTradingDays,