@discomedia/utils 1.0.68 → 1.0.70

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 +68 -208
  2. package/dist/index-frontend.cjs.map +1 -1
  3. package/dist/index-frontend.mjs +65 -209
  4. package/dist/index-frontend.mjs.map +1 -1
  5. package/dist/index.cjs +68 -208
  6. package/dist/index.cjs.map +1 -1
  7. package/dist/index.mjs +65 -209
  8. package/dist/index.mjs.map +1 -1
  9. package/dist/package.json +1 -1
  10. package/dist/test.js +119 -217
  11. package/dist/test.js.map +1 -1
  12. package/dist/types/index-frontend.d.ts +2 -0
  13. package/dist/types/index-frontend.d.ts.map +1 -1
  14. package/dist/types/index.d.ts +2 -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 +8 -2
  22. package/dist/types/types/llm-types.d.ts.map +1 -1
  23. package/dist/types-frontend/index-frontend.d.ts +2 -0
  24. package/dist/types-frontend/index-frontend.d.ts.map +1 -1
  25. package/dist/types-frontend/index.d.ts +2 -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 +8 -2
  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.70",
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,33 +366,59 @@ 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
+ }
392
+ /**
393
+ * Represents OpenRouter models
394
+ */
395
+ const OPENROUTER_MODELS = [
396
+ 'openai/gpt-5',
397
+ 'openai/gpt-5-mini',
398
+ 'openai/gpt-5.4-mini',
399
+ 'openai/gpt-5-nano',
400
+ 'openai/gpt-5.1',
401
+ 'openai/gpt-5.4',
402
+ 'openai/gpt-5.4-pro',
403
+ 'openai/gpt-5.5',
404
+ 'openai/gpt-5.5-pro',
405
+ 'openai/gpt-5.2',
406
+ 'openai/gpt-5.2-pro',
407
+ 'openai/gpt-5.1-codex',
408
+ 'openai/gpt-5.1-codex-max',
409
+ 'openai/gpt-oss-120b',
410
+ 'z.ai/glm-4.5',
411
+ 'z.ai/glm-4.5-air',
412
+ 'google/gemini-2.5-flash',
413
+ 'google/gemini-2.5-flash-lite',
414
+ 'deepseek/deepseek-r1-0528',
415
+ 'deepseek/deepseek-chat-v3-0324',
416
+ ];
369
417
  /**
370
418
  * Type guard to check if a model is an OpenRouter model
371
419
  */
372
420
  function isOpenRouterModel(model) {
373
- const openRouterModels = [
374
- 'openai/gpt-5',
375
- 'openai/gpt-5-mini',
376
- 'openai/gpt-5.4-mini',
377
- 'openai/gpt-5-nano',
378
- 'openai/gpt-5.1',
379
- 'openai/gpt-5.4',
380
- 'openai/gpt-5.4-pro',
381
- 'openai/gpt-5.5',
382
- 'openai/gpt-5.5-pro',
383
- 'openai/gpt-5.2',
384
- 'openai/gpt-5.2-pro',
385
- 'openai/gpt-5.1-codex',
386
- 'openai/gpt-5.1-codex-max',
387
- 'openai/gpt-oss-120b',
388
- 'z.ai/glm-4.5',
389
- 'z.ai/glm-4.5-air',
390
- 'google/gemini-2.5-flash',
391
- 'google/gemini-2.5-flash-lite',
392
- 'deepseek/deepseek-r1-0528',
393
- 'deepseek/deepseek-chat-v3-0324',
394
- ];
395
- return openRouterModels.includes(model);
421
+ return OPENROUTER_MODELS.includes(model);
396
422
  }
397
423
 
398
424
  function __classPrivateFieldSet(receiver, state, value, kind, f) {
@@ -14143,57 +14169,12 @@ function zodTextFormat(zodObject, name, props) {
14143
14169
  }
14144
14170
 
14145
14171
  // llm-openai-config.ts
14146
- const DEFAULT_MODEL = 'gpt-4.1-mini';
14172
+ const DEFAULT_MODEL = 'gpt-5-mini';
14147
14173
  const GPT_5_HIGH_CONTEXT_THRESHOLD_TOKENS = 272_000;
14148
14174
  const GPT_5_HIGH_CONTEXT_INPUT_MULTIPLIER = 2;
14149
14175
  const GPT_5_HIGH_CONTEXT_OUTPUT_MULTIPLIER = 1.5;
14150
14176
  /** Token costs in USD per 1M tokens. Last updated May 2026. */
14151
14177
  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
14178
  'gpt-5': {
14198
14179
  inputCost: 1.25 / 1_000_000,
14199
14180
  cacheHitCost: 0.125 / 1_000_000,
@@ -14224,10 +14205,6 @@ const openAiModelCosts = {
14224
14205
  cacheHitCost: 0.25 / 1_000_000,
14225
14206
  outputCost: 15 / 1_000_000,
14226
14207
  },
14227
- 'gpt-5.4-pro': {
14228
- inputCost: 30 / 1_000_000,
14229
- outputCost: 180 / 1_000_000,
14230
- },
14231
14208
  'gpt-5.5': {
14232
14209
  inputCost: 5 / 1_000_000,
14233
14210
  cacheHitCost: 0.5 / 1_000_000,
@@ -14256,11 +14233,6 @@ const openAiModelCosts = {
14256
14233
  cacheHitCost: 0.125 / 1_000_000,
14257
14234
  outputCost: 10 / 1_000_000,
14258
14235
  },
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
14236
  };
14265
14237
  const deepseekModelCosts = {
14266
14238
  'deepseek-chat': {
@@ -14275,8 +14247,7 @@ const deepseekModelCosts = {
14275
14247
  },
14276
14248
  };
14277
14249
  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);
14250
+ return (model === 'gpt-5.4' || model === 'gpt-5.5') && inputTokens > GPT_5_HIGH_CONTEXT_THRESHOLD_TOKENS;
14280
14251
  }
14281
14252
  /** Image generation costs in USD per image. Based on OpenAI pricing as of Feb 2025. */
14282
14253
  const openAiImageCosts = {
@@ -14717,101 +14688,6 @@ async function parseResponse(content, responseFormat) {
14717
14688
  }
14718
14689
 
14719
14690
  // 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
14691
  function isZodSchema(schema) {
14816
14692
  return typeof schema === 'object' && schema !== null && 'safeParse' in schema;
14817
14693
  }
@@ -14845,7 +14721,7 @@ function buildJsonSchemaFormat(schema, schemaName, schemaDescription, schemaStri
14845
14721
  * - Built-in tools (web search, file search, computer use, code interpreter, image generation)
14846
14722
  * - Background processing
14847
14723
  * - Conversation state management
14848
- * - Reasoning support for o-series models
14724
+ * - GPT-5 reasoning controls
14849
14725
  *
14850
14726
  * @example
14851
14727
  * // Basic text response
@@ -14866,6 +14742,9 @@ function buildJsonSchemaFormat(schema, schemaName, schemaDescription, schemaStri
14866
14742
  */
14867
14743
  const makeResponsesAPICall = async (input, options = {}) => {
14868
14744
  const normalizedModel = normalizeModelName(options.model || DEFAULT_MODEL);
14745
+ if (!isOpenAIModel(normalizedModel)) {
14746
+ throw new Error(`Unsupported OpenAI model: ${normalizedModel}. Please use a supported GPT-5 model.`);
14747
+ }
14869
14748
  const apiKey = options.apiKey || process.env.OPENAI_API_KEY;
14870
14749
  if (!apiKey) {
14871
14750
  throw new Error('OpenAI API key is not provided and OPENAI_API_KEY environment variable is not set');
@@ -14880,12 +14759,6 @@ const makeResponsesAPICall = async (input, options = {}) => {
14880
14759
  input,
14881
14760
  ...cleanOptions,
14882
14761
  };
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
14762
  // Make the API call to the Responses endpoint
14890
14763
  const response = await openai.responses.create(requestBody);
14891
14764
  const cacheHitTokens = response.usage?.input_tokens_details?.cached_tokens || 0;
@@ -14992,8 +14865,8 @@ async function makeLLMCall(input, options = {}) {
14992
14865
  const { apiKey, model = DEFAULT_MODEL, responseFormat = 'text', schema, schemaName = 'response', schemaDescription, schemaStrict, tools, useCodeInterpreter = false, useWebSearch = false, imageBase64, imageDetail = 'high', context, } = options;
14993
14866
  // Validate model
14994
14867
  const normalizedModel = normalizeModelName(model);
14995
- if (!isSupportedModel(normalizedModel)) {
14996
- throw new Error(`Unsupported model: ${normalizedModel}. Please use one of the supported models.`);
14868
+ if (!isOpenAIModel(normalizedModel)) {
14869
+ throw new Error(`Unsupported OpenAI model: ${normalizedModel}. Please use a supported GPT-5 model.`);
14997
14870
  }
14998
14871
  // Process input for conversation context and image analysis
14999
14872
  let processedInput;
@@ -15062,10 +14935,6 @@ async function makeLLMCall(input, options = {}) {
15062
14935
  parallel_tool_calls: false,
15063
14936
  tools,
15064
14937
  };
15065
- // Only include temperature if the model supports it
15066
- if (supportsTemperature(normalizedModel)) {
15067
- responsesOptions.temperature = 0.2;
15068
- }
15069
14938
  // Configure response format
15070
14939
  if (schema) {
15071
14940
  responsesOptions.text = {
@@ -15081,41 +14950,17 @@ async function makeLLMCall(input, options = {}) {
15081
14950
  // Configure built-in tools
15082
14951
  if (useCodeInterpreter) {
15083
14952
  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
14953
  responsesOptions.include = ['code_interpreter_call.outputs'];
15089
14954
  }
15090
14955
  if (useWebSearch) {
15091
14956
  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
14957
  }
15097
14958
  return await makeResponsesAPICall(processedInput, responsesOptions);
15098
14959
  }
15099
14960
 
15100
14961
  const DEFAULT_IMAGE_MODEL = 'gpt-image-1.5';
15101
14962
  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
- ]);
14963
+ const MULTIMODAL_VISION_MODELS = new Set(OPENAI_MODELS);
15119
14964
  /**
15120
14965
  * Makes a call to the OpenAI Images API to generate images based on a text prompt.
15121
14966
  *
@@ -22399,7 +22244,7 @@ async function testLLM() {
22399
22244
  console.log('Skipping OpenAI LLM tests: OPENAI_API_KEY not set');
22400
22245
  return;
22401
22246
  }
22402
- const models = ['gpt-5.5'];
22247
+ const models = ['gpt-5-mini'];
22403
22248
  for (const model of models) {
22404
22249
  console.log(`\nTesting model: ${model}`);
22405
22250
  // 1. Basic call
@@ -22415,14 +22260,70 @@ async function testLLM() {
22415
22260
  }
22416
22261
  console.log(`Response: ${JSON.stringify(json.response)}`);
22417
22262
  // 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.';
22263
+ const searchPrompt = `Use web search to identify the official OpenAI model ID for ${model}. Respond with the model ID only.`;
22419
22264
  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}`);
22265
+ if (!tool.response || !tool.response.includes(model)) {
22266
+ throw new Error(`Expected web search response to include ${model}, received: ${tool.response}`);
22422
22267
  }
22423
22268
  console.log(`Response: ${tool.response}`);
22424
22269
  }
22425
22270
  }
22271
+ function testOpenAIModelDeprecation() {
22272
+ const supportedModels = [
22273
+ 'gpt-5',
22274
+ 'gpt-5-mini',
22275
+ 'gpt-5.4-mini',
22276
+ 'gpt-5-nano',
22277
+ 'gpt-5.1',
22278
+ 'gpt-5.4',
22279
+ 'gpt-5.5',
22280
+ 'gpt-5.5-pro',
22281
+ 'gpt-5.2',
22282
+ 'gpt-5.2-pro',
22283
+ 'gpt-5.1-codex',
22284
+ 'gpt-5.1-codex-max',
22285
+ ];
22286
+ for (const model of supportedModels) {
22287
+ if (!isOpenAIModel(model)) {
22288
+ throw new Error(`Expected ${model} to be accepted as a direct OpenAI model`);
22289
+ }
22290
+ }
22291
+ const deprecatedModels = [
22292
+ 'gpt-4o-mini',
22293
+ 'gpt-4o',
22294
+ 'o1-mini',
22295
+ 'o1',
22296
+ 'o3-mini',
22297
+ 'gpt-4.1',
22298
+ 'gpt-4.1-mini',
22299
+ 'o4-mini',
22300
+ 'gpt-4.1-nano',
22301
+ 'o3',
22302
+ 'gpt-5.4-pro',
22303
+ ];
22304
+ for (const model of deprecatedModels) {
22305
+ if (isOpenAIModel(model)) {
22306
+ throw new Error(`Expected ${model} to be deprecated from direct OpenAI support`);
22307
+ }
22308
+ }
22309
+ if (OPENAI_MODELS.length !== supportedModels.length) {
22310
+ throw new Error(`Expected ${supportedModels.length} direct OpenAI models, received ${OPENAI_MODELS.length}`);
22311
+ }
22312
+ const expectedOpenRouterModel = 'openai/gpt-5-mini';
22313
+ if (!OPENROUTER_MODELS.includes(expectedOpenRouterModel)) {
22314
+ throw new Error(`Expected OPENROUTER_MODELS to include ${expectedOpenRouterModel}`);
22315
+ }
22316
+ if (!isOpenRouterModel(expectedOpenRouterModel)) {
22317
+ throw new Error(`Expected ${expectedOpenRouterModel} to be accepted as an OpenRouter model`);
22318
+ }
22319
+ if (isOpenRouterModel('openai/gpt-4o-mini')) {
22320
+ throw new Error('Expected openai/gpt-4o-mini to be excluded from OpenRouter runtime models');
22321
+ }
22322
+ console.log('\n[OpenAI] Model deprecation test');
22323
+ console.log(` Default model: ${DEFAULT_MODEL}`);
22324
+ console.log(` Supported direct OpenAI models: ${OPENAI_MODELS.join(', ')}`);
22325
+ console.log(` Supported OpenRouter models: ${OPENROUTER_MODELS.join(', ')}`);
22326
+ }
22426
22327
  async function testLLMStructuredOutputWithZod() {
22427
22328
  if (!process.env.OPENAI_API_KEY) {
22428
22329
  console.log('Skipping OpenAI structured output Zod test: OPENAI_API_KEY not set');
@@ -22461,6 +22362,7 @@ async function testLLMStructuredOutputWithZod() {
22461
22362
  console.log(' Usage:', result.usage);
22462
22363
  }
22463
22364
  async function runActiveTests() {
22365
+ testOpenAIModelDeprecation();
22464
22366
  await testLLM();
22465
22367
  await testLLMStructuredOutputWithZod();
22466
22368
  }