@discomedia/utils 1.0.68 → 1.0.69

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 (34) hide show
  1. package/dist/index-frontend.cjs +40 -185
  2. package/dist/index-frontend.cjs.map +1 -1
  3. package/dist/index-frontend.mjs +38 -186
  4. package/dist/index-frontend.mjs.map +1 -1
  5. package/dist/index.cjs +40 -185
  6. package/dist/index.cjs.map +1 -1
  7. package/dist/index.mjs +38 -186
  8. package/dist/index.mjs.map +1 -1
  9. package/dist/package.json +1 -1
  10. package/dist/test.js +82 -194
  11. package/dist/test.js.map +1 -1
  12. package/dist/types/index-frontend.d.ts +1 -0
  13. package/dist/types/index-frontend.d.ts.map +1 -1
  14. package/dist/types/index.d.ts +1 -0
  15. package/dist/types/index.d.ts.map +1 -1
  16. package/dist/types/llm-config.d.ts +1 -1
  17. package/dist/types/llm-config.d.ts.map +1 -1
  18. package/dist/types/llm-images.d.ts.map +1 -1
  19. package/dist/types/llm-openai.d.ts +4 -16
  20. package/dist/types/llm-openai.d.ts.map +1 -1
  21. package/dist/types/types/llm-types.d.ts +6 -1
  22. package/dist/types/types/llm-types.d.ts.map +1 -1
  23. package/dist/types-frontend/index-frontend.d.ts +1 -0
  24. package/dist/types-frontend/index-frontend.d.ts.map +1 -1
  25. package/dist/types-frontend/index.d.ts +1 -0
  26. package/dist/types-frontend/index.d.ts.map +1 -1
  27. package/dist/types-frontend/llm-config.d.ts +1 -1
  28. package/dist/types-frontend/llm-config.d.ts.map +1 -1
  29. package/dist/types-frontend/llm-images.d.ts.map +1 -1
  30. package/dist/types-frontend/llm-openai.d.ts +4 -16
  31. package/dist/types-frontend/llm-openai.d.ts.map +1 -1
  32. package/dist/types-frontend/types/llm-types.d.ts +6 -1
  33. package/dist/types-frontend/types/llm-types.d.ts.map +1 -1
  34. package/package.json +1 -1
package/dist/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.0.68",
6
+ "version": "1.0.69",
7
7
  "author": "Disco Media",
8
8
  "description": "Utility functions used in Disco Media apps",
9
9
  "always-build-npm": true,
package/dist/test.js CHANGED
@@ -366,6 +366,29 @@ function getLastFullTradingDate(currentDate = new Date()) {
366
366
  return getLastFullTradingDateImpl(currentDate);
367
367
  }
368
368
 
369
+ /**
370
+ * Represents OpenAI models
371
+ */
372
+ const OPENAI_MODELS = [
373
+ 'gpt-5',
374
+ 'gpt-5-mini',
375
+ 'gpt-5.4-mini',
376
+ 'gpt-5-nano',
377
+ 'gpt-5.1',
378
+ 'gpt-5.4',
379
+ 'gpt-5.5',
380
+ 'gpt-5.5-pro',
381
+ 'gpt-5.2',
382
+ 'gpt-5.2-pro',
383
+ 'gpt-5.1-codex',
384
+ 'gpt-5.1-codex-max',
385
+ ];
386
+ /**
387
+ * Type guard to check if a model is a supported direct OpenAI model.
388
+ */
389
+ function isOpenAIModel(model) {
390
+ return OPENAI_MODELS.includes(model);
391
+ }
369
392
  /**
370
393
  * Type guard to check if a model is an OpenRouter model
371
394
  */
@@ -14143,57 +14166,12 @@ function zodTextFormat(zodObject, name, props) {
14143
14166
  }
14144
14167
 
14145
14168
  // llm-openai-config.ts
14146
- const DEFAULT_MODEL = 'gpt-4.1-mini';
14169
+ const DEFAULT_MODEL = 'gpt-5-mini';
14147
14170
  const GPT_5_HIGH_CONTEXT_THRESHOLD_TOKENS = 272_000;
14148
14171
  const GPT_5_HIGH_CONTEXT_INPUT_MULTIPLIER = 2;
14149
14172
  const GPT_5_HIGH_CONTEXT_OUTPUT_MULTIPLIER = 1.5;
14150
14173
  /** Token costs in USD per 1M tokens. Last updated May 2026. */
14151
14174
  const openAiModelCosts = {
14152
- 'gpt-4o': {
14153
- inputCost: 2.5 / 1_000_000,
14154
- cacheHitCost: 1.25 / 1_000_000,
14155
- outputCost: 10 / 1_000_000,
14156
- },
14157
- 'gpt-4o-mini': {
14158
- inputCost: 0.15 / 1_000_000,
14159
- cacheHitCost: 0.075 / 1_000_000,
14160
- outputCost: 0.6 / 1_000_000,
14161
- },
14162
- 'o1-mini': {
14163
- inputCost: 1.1 / 1_000_000,
14164
- cacheHitCost: 0.55 / 1_000_000,
14165
- outputCost: 4.4 / 1_000_000,
14166
- },
14167
- 'o1': {
14168
- inputCost: 15 / 1_000_000,
14169
- cacheHitCost: 7.5 / 1_000_000,
14170
- outputCost: 60 / 1_000_000,
14171
- },
14172
- 'o3-mini': {
14173
- inputCost: 1.1 / 1_000_000,
14174
- cacheHitCost: 0.55 / 1_000_000,
14175
- outputCost: 4.4 / 1_000_000,
14176
- },
14177
- 'o3': {
14178
- inputCost: 2 / 1_000_000,
14179
- cacheHitCost: 0.5 / 1_000_000,
14180
- outputCost: 8 / 1_000_000,
14181
- },
14182
- 'gpt-4.1': {
14183
- inputCost: 2 / 1_000_000,
14184
- cacheHitCost: 0.5 / 1_000_000,
14185
- outputCost: 8 / 1_000_000,
14186
- },
14187
- 'gpt-4.1-mini': {
14188
- inputCost: 0.4 / 1_000_000,
14189
- cacheHitCost: 0.1 / 1_000_000,
14190
- outputCost: 1.6 / 1_000_000,
14191
- },
14192
- 'gpt-4.1-nano': {
14193
- inputCost: 0.1 / 1_000_000,
14194
- cacheHitCost: 0.025 / 1_000_000,
14195
- outputCost: 0.4 / 1_000_000,
14196
- },
14197
14175
  'gpt-5': {
14198
14176
  inputCost: 1.25 / 1_000_000,
14199
14177
  cacheHitCost: 0.125 / 1_000_000,
@@ -14224,10 +14202,6 @@ const openAiModelCosts = {
14224
14202
  cacheHitCost: 0.25 / 1_000_000,
14225
14203
  outputCost: 15 / 1_000_000,
14226
14204
  },
14227
- 'gpt-5.4-pro': {
14228
- inputCost: 30 / 1_000_000,
14229
- outputCost: 180 / 1_000_000,
14230
- },
14231
14205
  'gpt-5.5': {
14232
14206
  inputCost: 5 / 1_000_000,
14233
14207
  cacheHitCost: 0.5 / 1_000_000,
@@ -14256,11 +14230,6 @@ const openAiModelCosts = {
14256
14230
  cacheHitCost: 0.125 / 1_000_000,
14257
14231
  outputCost: 10 / 1_000_000,
14258
14232
  },
14259
- 'o4-mini': {
14260
- inputCost: 1.1 / 1_000_000,
14261
- cacheHitCost: 0.275 / 1_000_000,
14262
- outputCost: 4.4 / 1_000_000,
14263
- },
14264
14233
  };
14265
14234
  const deepseekModelCosts = {
14266
14235
  'deepseek-chat': {
@@ -14275,8 +14244,7 @@ const deepseekModelCosts = {
14275
14244
  },
14276
14245
  };
14277
14246
  function shouldUseGPT5HighContextPricing(model, inputTokens) {
14278
- return ((model === 'gpt-5.4' || model === 'gpt-5.4-pro' || model === 'gpt-5.5') &&
14279
- inputTokens > GPT_5_HIGH_CONTEXT_THRESHOLD_TOKENS);
14247
+ return (model === 'gpt-5.4' || model === 'gpt-5.5') && inputTokens > GPT_5_HIGH_CONTEXT_THRESHOLD_TOKENS;
14280
14248
  }
14281
14249
  /** Image generation costs in USD per image. Based on OpenAI pricing as of Feb 2025. */
14282
14250
  const openAiImageCosts = {
@@ -14717,101 +14685,6 @@ async function parseResponse(content, responseFormat) {
14717
14685
  }
14718
14686
 
14719
14687
  // llm-openai.ts
14720
- const isSupportedModel = (model) => {
14721
- return [
14722
- 'gpt-4o-mini',
14723
- 'gpt-4o',
14724
- 'o1-mini',
14725
- 'o1',
14726
- 'o3-mini',
14727
- 'gpt-4.1',
14728
- 'gpt-4.1-mini',
14729
- 'gpt-4.1-nano',
14730
- 'gpt-5',
14731
- 'gpt-5-mini',
14732
- 'gpt-5.4-mini',
14733
- 'gpt-5-nano',
14734
- 'gpt-5.1',
14735
- 'gpt-5.4',
14736
- 'gpt-5.4-pro',
14737
- 'gpt-5.5',
14738
- 'gpt-5.5-pro',
14739
- 'gpt-5.2',
14740
- 'gpt-5.2-pro',
14741
- 'gpt-5.1-codex',
14742
- 'gpt-5.1-codex-max',
14743
- 'o4-mini',
14744
- 'o3',
14745
- ].includes(model);
14746
- };
14747
- /**
14748
- * Checks if the given model supports the temperature parameter. Reasoning models (o1*, o3*, o4*) do not support temperature.
14749
- * @param model The model to check.
14750
- * @returns True if the model supports the temperature parameter, false otherwise.
14751
- */
14752
- function supportsTemperature(model) {
14753
- // Reasoning models don't support temperature
14754
- // GPT-5 models also do not support temperature
14755
- const reasoningAndGPT5Models = [
14756
- 'o1',
14757
- 'o1-mini',
14758
- 'o3-mini',
14759
- 'o4-mini',
14760
- 'o3',
14761
- 'gpt-5',
14762
- 'gpt-5-mini',
14763
- 'gpt-5.4-mini',
14764
- 'gpt-5-nano',
14765
- 'gpt-5.1',
14766
- 'gpt-5.4',
14767
- 'gpt-5.4-pro',
14768
- 'gpt-5.5',
14769
- 'gpt-5.5-pro',
14770
- 'gpt-5.2',
14771
- 'gpt-5.2-pro',
14772
- 'gpt-5.1-codex',
14773
- 'gpt-5.1-codex-max',
14774
- ];
14775
- return !reasoningAndGPT5Models.includes(model);
14776
- }
14777
- /**
14778
- * Checks if the given model is a reasoning model. Reasoning models have different tool choice constraints.
14779
- * @param model The model to check.
14780
- * @returns True if the model is a reasoning model, false otherwise.
14781
- */
14782
- function isReasoningModel(model) {
14783
- const reasoningModels = ['o1', 'o1-mini', 'o3-mini', 'o4-mini', 'o3'];
14784
- return reasoningModels.includes(model);
14785
- }
14786
- /**
14787
- * Checks if the given model is a GPT-5 model. GPT-5 models don't support tool_choice other than 'auto'.
14788
- * @param model The model to check.
14789
- * @returns True if the model is a GPT-5 model, false otherwise.
14790
- */
14791
- function isGPT5Model(model) {
14792
- const gpt5Models = [
14793
- 'gpt-5',
14794
- 'gpt-5-mini',
14795
- 'gpt-5.4-mini',
14796
- 'gpt-5-nano',
14797
- 'gpt-5.1',
14798
- 'gpt-5.4',
14799
- 'gpt-5.4-pro',
14800
- 'gpt-5.5',
14801
- 'gpt-5.5-pro',
14802
- 'gpt-5.2',
14803
- 'gpt-5.2-pro',
14804
- 'gpt-5.1-codex',
14805
- 'gpt-5.1-codex-max',
14806
- ];
14807
- return gpt5Models.includes(model);
14808
- }
14809
- function supportsStructuredOutputs(model) {
14810
- return normalizeModelName(model) !== 'gpt-5.4-pro';
14811
- }
14812
- function supportsDistillation(model) {
14813
- return normalizeModelName(model) !== 'gpt-5.4-pro';
14814
- }
14815
14688
  function isZodSchema(schema) {
14816
14689
  return typeof schema === 'object' && schema !== null && 'safeParse' in schema;
14817
14690
  }
@@ -14845,7 +14718,7 @@ function buildJsonSchemaFormat(schema, schemaName, schemaDescription, schemaStri
14845
14718
  * - Built-in tools (web search, file search, computer use, code interpreter, image generation)
14846
14719
  * - Background processing
14847
14720
  * - Conversation state management
14848
- * - Reasoning support for o-series models
14721
+ * - GPT-5 reasoning controls
14849
14722
  *
14850
14723
  * @example
14851
14724
  * // Basic text response
@@ -14866,6 +14739,9 @@ function buildJsonSchemaFormat(schema, schemaName, schemaDescription, schemaStri
14866
14739
  */
14867
14740
  const makeResponsesAPICall = async (input, options = {}) => {
14868
14741
  const normalizedModel = normalizeModelName(options.model || DEFAULT_MODEL);
14742
+ if (!isOpenAIModel(normalizedModel)) {
14743
+ throw new Error(`Unsupported OpenAI model: ${normalizedModel}. Please use a supported GPT-5 model.`);
14744
+ }
14869
14745
  const apiKey = options.apiKey || process.env.OPENAI_API_KEY;
14870
14746
  if (!apiKey) {
14871
14747
  throw new Error('OpenAI API key is not provided and OPENAI_API_KEY environment variable is not set');
@@ -14880,12 +14756,6 @@ const makeResponsesAPICall = async (input, options = {}) => {
14880
14756
  input,
14881
14757
  ...cleanOptions,
14882
14758
  };
14883
- if (requestBody.text?.format?.type === 'json_schema' && !supportsStructuredOutputs(normalizedModel)) {
14884
- throw new Error(`Model ${normalizedModel} does not support structured outputs`);
14885
- }
14886
- if (requestBody.store && !supportsDistillation(normalizedModel)) {
14887
- throw new Error(`Model ${normalizedModel} does not support distillation`);
14888
- }
14889
14759
  // Make the API call to the Responses endpoint
14890
14760
  const response = await openai.responses.create(requestBody);
14891
14761
  const cacheHitTokens = response.usage?.input_tokens_details?.cached_tokens || 0;
@@ -14992,8 +14862,8 @@ async function makeLLMCall(input, options = {}) {
14992
14862
  const { apiKey, model = DEFAULT_MODEL, responseFormat = 'text', schema, schemaName = 'response', schemaDescription, schemaStrict, tools, useCodeInterpreter = false, useWebSearch = false, imageBase64, imageDetail = 'high', context, } = options;
14993
14863
  // Validate model
14994
14864
  const normalizedModel = normalizeModelName(model);
14995
- if (!isSupportedModel(normalizedModel)) {
14996
- throw new Error(`Unsupported model: ${normalizedModel}. Please use one of the supported models.`);
14865
+ if (!isOpenAIModel(normalizedModel)) {
14866
+ throw new Error(`Unsupported OpenAI model: ${normalizedModel}. Please use a supported GPT-5 model.`);
14997
14867
  }
14998
14868
  // Process input for conversation context and image analysis
14999
14869
  let processedInput;
@@ -15062,10 +14932,6 @@ async function makeLLMCall(input, options = {}) {
15062
14932
  parallel_tool_calls: false,
15063
14933
  tools,
15064
14934
  };
15065
- // Only include temperature if the model supports it
15066
- if (supportsTemperature(normalizedModel)) {
15067
- responsesOptions.temperature = 0.2;
15068
- }
15069
14935
  // Configure response format
15070
14936
  if (schema) {
15071
14937
  responsesOptions.text = {
@@ -15081,41 +14947,17 @@ async function makeLLMCall(input, options = {}) {
15081
14947
  // Configure built-in tools
15082
14948
  if (useCodeInterpreter) {
15083
14949
  responsesOptions.tools = [{ type: 'code_interpreter', container: { type: 'auto' } }];
15084
- // For reasoning models, we can't force tool choice - they only support 'auto'
15085
- if (!isReasoningModel(normalizedModel)) {
15086
- responsesOptions.tool_choice = { type: 'code_interpreter' };
15087
- }
15088
14950
  responsesOptions.include = ['code_interpreter_call.outputs'];
15089
14951
  }
15090
14952
  if (useWebSearch) {
15091
14953
  responsesOptions.tools = [{ type: 'web_search_preview' }];
15092
- // For reasoning models and GPT-5 models, we can't force tool choice - they only support 'auto'
15093
- if (!isReasoningModel(normalizedModel) && !isGPT5Model(normalizedModel)) {
15094
- responsesOptions.tool_choice = { type: 'web_search_preview' };
15095
- }
15096
14954
  }
15097
14955
  return await makeResponsesAPICall(processedInput, responsesOptions);
15098
14956
  }
15099
14957
 
15100
14958
  const DEFAULT_IMAGE_MODEL = 'gpt-image-1.5';
15101
14959
  const resolveImageModel = (model) => model ?? DEFAULT_IMAGE_MODEL;
15102
- const MULTIMODAL_VISION_MODELS = new Set([
15103
- 'gpt-4o-mini',
15104
- 'gpt-4o',
15105
- 'gpt-5',
15106
- 'gpt-5-mini',
15107
- 'gpt-5.4-mini',
15108
- 'gpt-5-nano',
15109
- 'gpt-5.1',
15110
- 'gpt-5.4',
15111
- 'gpt-5.4-pro',
15112
- 'gpt-5.5',
15113
- 'gpt-5.5-pro',
15114
- 'gpt-5.2',
15115
- 'gpt-5.2-pro',
15116
- 'gpt-5.1-codex',
15117
- 'gpt-5.1-codex-max',
15118
- ]);
14960
+ const MULTIMODAL_VISION_MODELS = new Set(OPENAI_MODELS);
15119
14961
  /**
15120
14962
  * Makes a call to the OpenAI Images API to generate images based on a text prompt.
15121
14963
  *
@@ -22399,7 +22241,7 @@ async function testLLM() {
22399
22241
  console.log('Skipping OpenAI LLM tests: OPENAI_API_KEY not set');
22400
22242
  return;
22401
22243
  }
22402
- const models = ['gpt-5.5'];
22244
+ const models = ['gpt-5-mini'];
22403
22245
  for (const model of models) {
22404
22246
  console.log(`\nTesting model: ${model}`);
22405
22247
  // 1. Basic call
@@ -22415,14 +22257,59 @@ async function testLLM() {
22415
22257
  }
22416
22258
  console.log(`Response: ${JSON.stringify(json.response)}`);
22417
22259
  // 3. Web search
22418
- const searchPrompt = 'Use web search to identify the official OpenAI model ID for GPT-5.5. Respond with the model ID only.';
22260
+ const searchPrompt = `Use web search to identify the official OpenAI model ID for ${model}. Respond with the model ID only.`;
22419
22261
  const tool = await disco.llm.call(searchPrompt, { model, useWebSearch: true });
22420
- if (!tool.response || !tool.response.includes('gpt-5.5')) {
22421
- throw new Error(`Expected web search response to include gpt-5.5, received: ${tool.response}`);
22262
+ if (!tool.response || !tool.response.includes(model)) {
22263
+ throw new Error(`Expected web search response to include ${model}, received: ${tool.response}`);
22422
22264
  }
22423
22265
  console.log(`Response: ${tool.response}`);
22424
22266
  }
22425
22267
  }
22268
+ function testOpenAIModelDeprecation() {
22269
+ const supportedModels = [
22270
+ 'gpt-5',
22271
+ 'gpt-5-mini',
22272
+ 'gpt-5.4-mini',
22273
+ 'gpt-5-nano',
22274
+ 'gpt-5.1',
22275
+ 'gpt-5.4',
22276
+ 'gpt-5.5',
22277
+ 'gpt-5.5-pro',
22278
+ 'gpt-5.2',
22279
+ 'gpt-5.2-pro',
22280
+ 'gpt-5.1-codex',
22281
+ 'gpt-5.1-codex-max',
22282
+ ];
22283
+ for (const model of supportedModels) {
22284
+ if (!isOpenAIModel(model)) {
22285
+ throw new Error(`Expected ${model} to be accepted as a direct OpenAI model`);
22286
+ }
22287
+ }
22288
+ const deprecatedModels = [
22289
+ 'gpt-4o-mini',
22290
+ 'gpt-4o',
22291
+ 'o1-mini',
22292
+ 'o1',
22293
+ 'o3-mini',
22294
+ 'gpt-4.1',
22295
+ 'gpt-4.1-mini',
22296
+ 'o4-mini',
22297
+ 'gpt-4.1-nano',
22298
+ 'o3',
22299
+ 'gpt-5.4-pro',
22300
+ ];
22301
+ for (const model of deprecatedModels) {
22302
+ if (isOpenAIModel(model)) {
22303
+ throw new Error(`Expected ${model} to be deprecated from direct OpenAI support`);
22304
+ }
22305
+ }
22306
+ if (OPENAI_MODELS.length !== supportedModels.length) {
22307
+ throw new Error(`Expected ${supportedModels.length} direct OpenAI models, received ${OPENAI_MODELS.length}`);
22308
+ }
22309
+ console.log('\n[OpenAI] Model deprecation test');
22310
+ console.log(` Default model: ${DEFAULT_MODEL}`);
22311
+ console.log(` Supported direct OpenAI models: ${OPENAI_MODELS.join(', ')}`);
22312
+ }
22426
22313
  async function testLLMStructuredOutputWithZod() {
22427
22314
  if (!process.env.OPENAI_API_KEY) {
22428
22315
  console.log('Skipping OpenAI structured output Zod test: OPENAI_API_KEY not set');
@@ -22461,6 +22348,7 @@ async function testLLMStructuredOutputWithZod() {
22461
22348
  console.log(' Usage:', result.usage);
22462
22349
  }
22463
22350
  async function runActiveTests() {
22351
+ testOpenAIModelDeprecation();
22464
22352
  await testLLM();
22465
22353
  await testLLMStructuredOutputWithZod();
22466
22354
  }