@discomedia/utils 1.0.63 → 1.0.65

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 (32) hide show
  1. package/dist/index-frontend.cjs +41 -5
  2. package/dist/index-frontend.cjs.map +1 -1
  3. package/dist/index-frontend.mjs +41 -5
  4. package/dist/index-frontend.mjs.map +1 -1
  5. package/dist/index.cjs +320 -208
  6. package/dist/index.cjs.map +1 -1
  7. package/dist/index.mjs +320 -208
  8. package/dist/index.mjs.map +1 -1
  9. package/dist/package.json +2 -2
  10. package/dist/test.js +364 -210
  11. package/dist/test.js.map +1 -1
  12. package/dist/types/alpaca-market-data-api.d.ts.map +1 -1
  13. package/dist/types/alpaca-trading-api.d.ts +8 -1
  14. package/dist/types/alpaca-trading-api.d.ts.map +1 -1
  15. package/dist/types/llm-config.d.ts.map +1 -1
  16. package/dist/types/llm-images.d.ts.map +1 -1
  17. package/dist/types/llm-openai.d.ts.map +1 -1
  18. package/dist/types/types/alpaca-types.d.ts +29 -0
  19. package/dist/types/types/alpaca-types.d.ts.map +1 -1
  20. package/dist/types/types/llm-types.d.ts +2 -2
  21. package/dist/types/types/llm-types.d.ts.map +1 -1
  22. package/dist/types-frontend/alpaca-market-data-api.d.ts.map +1 -1
  23. package/dist/types-frontend/alpaca-trading-api.d.ts +8 -1
  24. package/dist/types-frontend/alpaca-trading-api.d.ts.map +1 -1
  25. package/dist/types-frontend/llm-config.d.ts.map +1 -1
  26. package/dist/types-frontend/llm-images.d.ts.map +1 -1
  27. package/dist/types-frontend/llm-openai.d.ts.map +1 -1
  28. package/dist/types-frontend/types/alpaca-types.d.ts +29 -0
  29. package/dist/types-frontend/types/alpaca-types.d.ts.map +1 -1
  30. package/dist/types-frontend/types/llm-types.d.ts +2 -2
  31. package/dist/types-frontend/types/llm-types.d.ts.map +1 -1
  32. package/package.json +2 -2
package/dist/test.js CHANGED
@@ -1146,6 +1146,7 @@ function isOpenRouterModel(model) {
1146
1146
  const openRouterModels = [
1147
1147
  'openai/gpt-5',
1148
1148
  'openai/gpt-5-mini',
1149
+ 'openai/gpt-5.4-mini',
1149
1150
  'openai/gpt-5-nano',
1150
1151
  'openai/gpt-5.1',
1151
1152
  'openai/gpt-5.4',
@@ -1614,7 +1615,7 @@ const safeJSON = (text) => {
1614
1615
  // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
1615
1616
  const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
1616
1617
 
1617
- const VERSION = '6.27.0'; // x-release-please-version
1618
+ const VERSION = '6.32.0'; // x-release-please-version
1618
1619
 
1619
1620
  // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
1620
1621
  const isRunningInBrowser = () => {
@@ -4858,7 +4859,7 @@ class Speech extends APIResource {
4858
4859
  * const speech = await client.audio.speech.create({
4859
4860
  * input: 'input',
4860
4861
  * model: 'string',
4861
- * voice: 'ash',
4862
+ * voice: 'string',
4862
4863
  * });
4863
4864
  *
4864
4865
  * const content = await speech.blob();
@@ -8139,7 +8140,7 @@ class Videos extends APIResource {
8139
8140
  * Create a new video generation job from a prompt and optional reference assets.
8140
8141
  */
8141
8142
  create(body, options) {
8142
- return this._client.post('/videos', maybeMultipartFormRequestOptions({ body, ...options }, this._client));
8143
+ return this._client.post('/videos', multipartFormRequestOptions({ body, ...options }, this._client));
8143
8144
  }
8144
8145
  /**
8145
8146
  * Fetch the latest metadata for a generated video.
@@ -8159,6 +8160,12 @@ class Videos extends APIResource {
8159
8160
  delete(videoID, options) {
8160
8161
  return this._client.delete(path `/videos/${videoID}`, options);
8161
8162
  }
8163
+ /**
8164
+ * Create a character from an uploaded video.
8165
+ */
8166
+ createCharacter(body, options) {
8167
+ return this._client.post('/videos/characters', multipartFormRequestOptions({ body, ...options }, this._client));
8168
+ }
8162
8169
  /**
8163
8170
  * Download the generated video bytes or a derived preview asset.
8164
8171
  *
@@ -8172,6 +8179,25 @@ class Videos extends APIResource {
8172
8179
  __binaryResponse: true,
8173
8180
  });
8174
8181
  }
8182
+ /**
8183
+ * Create a new video generation job by editing a source video or existing
8184
+ * generated video.
8185
+ */
8186
+ edit(body, options) {
8187
+ return this._client.post('/videos/edits', multipartFormRequestOptions({ body, ...options }, this._client));
8188
+ }
8189
+ /**
8190
+ * Create an extension of a completed video.
8191
+ */
8192
+ extend(body, options) {
8193
+ return this._client.post('/videos/extensions', multipartFormRequestOptions({ body, ...options }, this._client));
8194
+ }
8195
+ /**
8196
+ * Fetch a character.
8197
+ */
8198
+ getCharacter(characterID, options) {
8199
+ return this._client.get(path `/videos/characters/${characterID}`, options);
8200
+ }
8175
8201
  /**
8176
8202
  * Create a remix of a completed video using a refreshed prompt.
8177
8203
  */
@@ -8453,8 +8479,9 @@ class OpenAI {
8453
8479
  new URL(path)
8454
8480
  : new URL(baseURL + (baseURL.endsWith('/') && path.startsWith('/') ? path.slice(1) : path));
8455
8481
  const defaultQuery = this.defaultQuery();
8456
- if (!isEmptyObj$1(defaultQuery)) {
8457
- query = { ...defaultQuery, ...query };
8482
+ const pathQuery = Object.fromEntries(url.searchParams);
8483
+ if (!isEmptyObj$1(defaultQuery) || !isEmptyObj$1(pathQuery)) {
8484
+ query = { ...pathQuery, ...defaultQuery, ...query };
8458
8485
  }
8459
8486
  if (typeof query === 'object' && query && !Array.isArray(query)) {
8460
8487
  url.search = this.stringifyQuery(query);
@@ -14934,6 +14961,11 @@ const openAiModelCosts = {
14934
14961
  cacheHitCost: 0.025 / 1_000_000,
14935
14962
  outputCost: 2 / 1_000_000,
14936
14963
  },
14964
+ 'gpt-5.4-mini': {
14965
+ inputCost: 0.25 / 1_000_000,
14966
+ cacheHitCost: 0.025 / 1_000_000,
14967
+ outputCost: 2 / 1_000_000,
14968
+ },
14937
14969
  'gpt-5-nano': {
14938
14970
  inputCost: 0.05 / 1_000_000,
14939
14971
  cacheHitCost: 0.005 / 1_000_000,
@@ -15444,6 +15476,7 @@ const isSupportedModel = (model) => {
15444
15476
  'gpt-4.1-nano',
15445
15477
  'gpt-5',
15446
15478
  'gpt-5-mini',
15479
+ 'gpt-5.4-mini',
15447
15480
  'gpt-5-nano',
15448
15481
  'gpt-5.1',
15449
15482
  'gpt-5.4',
@@ -15472,6 +15505,7 @@ function supportsTemperature(model) {
15472
15505
  'o3',
15473
15506
  'gpt-5',
15474
15507
  'gpt-5-mini',
15508
+ 'gpt-5.4-mini',
15475
15509
  'gpt-5-nano',
15476
15510
  'gpt-5.1',
15477
15511
  'gpt-5.4',
@@ -15501,6 +15535,7 @@ function isGPT5Model(model) {
15501
15535
  const gpt5Models = [
15502
15536
  'gpt-5',
15503
15537
  'gpt-5-mini',
15538
+ 'gpt-5.4-mini',
15504
15539
  'gpt-5-nano',
15505
15540
  'gpt-5.1',
15506
15541
  'gpt-5.4',
@@ -15810,6 +15845,7 @@ const MULTIMODAL_VISION_MODELS = new Set([
15810
15845
  'gpt-4o',
15811
15846
  'gpt-5',
15812
15847
  'gpt-5-mini',
15848
+ 'gpt-5.4-mini',
15813
15849
  'gpt-5-nano',
15814
15850
  'gpt-5.1',
15815
15851
  'gpt-5.4',
@@ -22297,7 +22333,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
22297
22333
  */
22298
22334
  async getHistoricalBars(params) {
22299
22335
  const symbols = params.symbols;
22300
- symbols.join(',');
22336
+ const symbolsStr = symbols.join(',');
22301
22337
  let allBars = {};
22302
22338
  let pageToken = null;
22303
22339
  let hasMorePages = true;
@@ -22308,7 +22344,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
22308
22344
  symbols.forEach((symbol) => {
22309
22345
  allBars[symbol] = [];
22310
22346
  });
22311
- log(`Starting historical bars fetch for ${symbols.length} symbols (${params.timeframe}, ${params.start || 'no start'} to ${params.end || 'no end'})`);
22347
+ log(`Starting ${params.timeframe}bars fetch for ${symbols.length} symbols (${symbolsStr}), ${params.start || 'no start'} to ${params.end || 'no end'})`, { symbol: symbolsStr });
22312
22348
  while (hasMorePages) {
22313
22349
  pageCount++;
22314
22350
  const requestParams = {
@@ -22319,7 +22355,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
22319
22355
  };
22320
22356
  const response = await this.makeRequest('/stocks/bars', 'GET', requestParams);
22321
22357
  if (!response.bars) {
22322
- log(`No bars data found in response for ${symbols.length} symbols`, { type: 'warn' });
22358
+ log(`No bars data found in response for ${symbols.length} symbols`, { symbol: symbolsStr, type: 'warn' });
22323
22359
  break;
22324
22360
  }
22325
22361
  // Track currency from first response
@@ -22353,7 +22389,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
22353
22389
  const dateRangeStr = earliestTimestamp && latestTimestamp
22354
22390
  ? `${new Date(earliestTimestamp).toLocaleDateString('en-US', { timeZone: 'America/New_York' })} to ${new Date(latestTimestamp).toLocaleDateString('en-US', { timeZone: 'America/New_York' })}`
22355
22391
  : 'unknown range';
22356
- log(`Page ${pageCount}: Fetched ${pageBarsCount.toLocaleString()} bars (total: ${totalBarsCount.toLocaleString()}) for ${symbols.length} symbols, date range: ${dateRangeStr}${hasMorePages ? ', more pages available' : ', complete'}`, { type: 'debug' });
22392
+ log(`Page ${pageCount}: Fetched ${pageBarsCount.toLocaleString()} bars (total: ${totalBarsCount.toLocaleString()}) for ${symbols.length} symbols, date range: ${dateRangeStr}${hasMorePages ? ', more pages available' : ', complete'}`, { symbol: symbolsStr, type: 'debug' });
22357
22393
  // Prevent infinite loops
22358
22394
  if (pageCount > 1000) {
22359
22395
  log(`Stopping pagination after ${pageCount} pages to prevent infinite loop`, { type: 'warn' });
@@ -22364,7 +22400,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
22364
22400
  const symbolCounts = Object.entries(allBars)
22365
22401
  .map(([symbol, bars]) => `${symbol}: ${bars.length}`)
22366
22402
  .join(', ');
22367
- log(`Bars fetch complete: ${totalBarsCount.toLocaleString()} total bars across ${pageCount} pages for ${symbols.length} symbols (${symbolCounts})`);
22403
+ log(`${params.timeframe} bars fetch complete: ${totalBarsCount.toLocaleString()} total bars across ${pageCount} pages for ${symbols.length} symbols (${symbolCounts})`, { symbol: symbolsStr });
22368
22404
  return {
22369
22405
  bars: allBars,
22370
22406
  next_page_token: null, // Always null since we fetch all pages
@@ -23216,6 +23252,26 @@ class AlpacaMarketDataAPI extends EventEmitter {
23216
23252
  const marketDataAPI = AlpacaMarketDataAPI.getInstance();
23217
23253
 
23218
23254
  const limitPriceSlippagePercent100 = 0.1; // 0.1%
23255
+ class AlpacaRequestError extends Error {
23256
+ method;
23257
+ status;
23258
+ url;
23259
+ responseCode;
23260
+ responseDetails;
23261
+ rawResponse;
23262
+ symbol;
23263
+ constructor(params) {
23264
+ super(params.message);
23265
+ this.name = 'AlpacaRequestError';
23266
+ this.method = params.method;
23267
+ this.status = params.status ?? null;
23268
+ this.url = params.url;
23269
+ this.responseCode = params.responseCode ?? null;
23270
+ this.responseDetails = params.responseDetails ?? null;
23271
+ this.rawResponse = params.rawResponse ?? null;
23272
+ this.symbol = params.symbol;
23273
+ }
23274
+ }
23219
23275
  /**
23220
23276
  Websocket example
23221
23277
  const alpacaAPI = createAlpacaTradingAPI(credentials); // type AlpacaCredentials
@@ -23299,6 +23355,75 @@ class AlpacaTradingAPI {
23299
23355
  roundPriceForAlpaca = (price) => {
23300
23356
  return price >= 1 ? Math.round(price * 100) / 100 : Math.round(price * 10000) / 10000;
23301
23357
  };
23358
+ isJsonObject(value) {
23359
+ return value !== null && !Array.isArray(value) && typeof value === 'object';
23360
+ }
23361
+ parseAlpacaAPIErrorResponse(rawResponse) {
23362
+ if (rawResponse.trim() === '') {
23363
+ return null;
23364
+ }
23365
+ try {
23366
+ const parsedValue = JSON.parse(rawResponse);
23367
+ if (!this.isJsonObject(parsedValue)) {
23368
+ return null;
23369
+ }
23370
+ const code = parsedValue['code'];
23371
+ const message = parsedValue['message'];
23372
+ const symbol = parsedValue['symbol'];
23373
+ if (typeof code !== 'number' || typeof message !== 'string') {
23374
+ return null;
23375
+ }
23376
+ if (symbol !== undefined && typeof symbol !== 'string') {
23377
+ return null;
23378
+ }
23379
+ return parsedValue;
23380
+ }
23381
+ catch {
23382
+ return null;
23383
+ }
23384
+ }
23385
+ formatJsonValueForLog(value) {
23386
+ if (value === undefined) {
23387
+ return 'undefined';
23388
+ }
23389
+ if (Array.isArray(value)) {
23390
+ return value.map((entry) => this.formatJsonValueForLog(entry)).join(', ');
23391
+ }
23392
+ if (value === null) {
23393
+ return 'null';
23394
+ }
23395
+ if (typeof value === 'object') {
23396
+ return JSON.stringify(value);
23397
+ }
23398
+ return `${value}`;
23399
+ }
23400
+ formatAlpacaAPIErrorDetails(errorResponse) {
23401
+ return Object.entries(errorResponse)
23402
+ .filter(([key]) => key !== 'code' && key !== 'message' && key !== 'symbol')
23403
+ .map(([key, value]) => `${key}=${this.formatJsonValueForLog(value)}`)
23404
+ .join(', ');
23405
+ }
23406
+ formatRequestAction(requestContext) {
23407
+ return requestContext?.action ? `${requestContext.action} failed` : 'Alpaca request failed';
23408
+ }
23409
+ buildAlpacaAPIErrorMessage(params) {
23410
+ const { requestContext, status, url, errorResponse, rawResponse } = params;
23411
+ const action = this.formatRequestAction(requestContext);
23412
+ const message = errorResponse?.message ?? (rawResponse || 'No error body returned');
23413
+ const responseCode = errorResponse?.code ? ` (code ${errorResponse.code})` : '';
23414
+ const detailSummary = errorResponse ? this.formatAlpacaAPIErrorDetails(errorResponse) : '';
23415
+ const detailText = detailSummary !== ''
23416
+ ? ` Details: ${detailSummary}.`
23417
+ : rawResponse.trim() !== '' && errorResponse === null
23418
+ ? ` Response: ${rawResponse}.`
23419
+ : '';
23420
+ return `${action}: Alpaca API ${status}${responseCode}: ${message}.${detailText} Url: ${url}`;
23421
+ }
23422
+ buildRequestExecutionErrorMessage(params) {
23423
+ const { requestContext, url, errorMessage } = params;
23424
+ const action = this.formatRequestAction(requestContext);
23425
+ return `${action}: ${errorMessage}. Url: ${url}`;
23426
+ }
23302
23427
  handleAuthMessage(data) {
23303
23428
  if (data.status === 'authorized') {
23304
23429
  this.authenticated = true;
@@ -23526,7 +23651,7 @@ class AlpacaTradingAPI {
23526
23651
  this.ws?.on('message', handleListenResponse);
23527
23652
  });
23528
23653
  }
23529
- async makeRequest(endpoint, method = 'GET', body, queryString = '') {
23654
+ async makeRequest(endpoint, method = 'GET', body, queryString = '', requestContext) {
23530
23655
  const url = `${this.apiBaseUrl}${endpoint}${queryString}`;
23531
23656
  try {
23532
23657
  const response = await fetch(url, {
@@ -23535,9 +23660,27 @@ class AlpacaTradingAPI {
23535
23660
  body: body ? JSON.stringify(body) : undefined,
23536
23661
  });
23537
23662
  if (!response.ok) {
23538
- const errorText = await response.text();
23539
- this.log(`Alpaca API error (${response.status}): ${errorText}`, { type: 'error' });
23540
- throw new Error(`Alpaca API error (${response.status}): ${errorText}`);
23663
+ const rawResponse = await response.text();
23664
+ const errorResponse = this.parseAlpacaAPIErrorResponse(rawResponse);
23665
+ const symbol = requestContext?.symbol ?? errorResponse?.symbol;
23666
+ const error = new AlpacaRequestError({
23667
+ message: this.buildAlpacaAPIErrorMessage({
23668
+ requestContext,
23669
+ status: response.status,
23670
+ url,
23671
+ errorResponse,
23672
+ rawResponse,
23673
+ }),
23674
+ method,
23675
+ status: response.status,
23676
+ url,
23677
+ responseCode: errorResponse?.code ?? null,
23678
+ responseDetails: errorResponse,
23679
+ rawResponse,
23680
+ symbol,
23681
+ });
23682
+ this.log(error.message, { symbol, type: 'error' });
23683
+ throw error;
23541
23684
  }
23542
23685
  // Handle responses with no content (e.g., 204 No Content)
23543
23686
  if (response.status === 204 || response.headers.get('content-length') === '0') {
@@ -23545,23 +23688,37 @@ class AlpacaTradingAPI {
23545
23688
  }
23546
23689
  const contentType = response.headers.get('content-type');
23547
23690
  if (contentType && contentType.includes('application/json')) {
23548
- return await response.json();
23691
+ return (await response.json());
23549
23692
  }
23550
23693
  // For non-JSON responses, return the text content
23551
23694
  const textContent = await response.text();
23552
- return textContent || null;
23695
+ return (textContent || null);
23553
23696
  }
23554
- catch (err) {
23555
- const error = err;
23556
- this.log(`Error in makeRequest: ${error.message}. Url: ${url}`, {
23557
- source: 'AlpacaAPI',
23558
- type: 'error',
23697
+ catch (error) {
23698
+ if (error instanceof AlpacaRequestError) {
23699
+ throw error;
23700
+ }
23701
+ const normalizedError = error instanceof Error ? error : new Error(`${error}`);
23702
+ const symbol = requestContext?.symbol;
23703
+ const requestError = new AlpacaRequestError({
23704
+ message: this.buildRequestExecutionErrorMessage({
23705
+ requestContext,
23706
+ url,
23707
+ errorMessage: normalizedError.message,
23708
+ }),
23709
+ method,
23710
+ url,
23711
+ rawResponse: null,
23712
+ symbol,
23559
23713
  });
23560
- throw error;
23714
+ this.log(requestError.message, { symbol, type: 'error' });
23715
+ throw requestError;
23561
23716
  }
23562
23717
  }
23563
23718
  async getPositions(assetClass) {
23564
- const positions = (await this.makeRequest('/positions'));
23719
+ const positions = await this.makeRequest('/positions', 'GET', undefined, '', {
23720
+ action: 'Get positions',
23721
+ });
23565
23722
  if (assetClass) {
23566
23723
  return positions.filter((position) => position.asset_class === assetClass);
23567
23724
  }
@@ -23599,22 +23756,15 @@ class AlpacaTradingAPI {
23599
23756
  if (params.side)
23600
23757
  queryParams.append('side', params.side);
23601
23758
  const endpoint = `/orders${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;
23602
- try {
23603
- return await this.makeRequest(endpoint);
23604
- }
23605
- catch (error) {
23606
- this.log(`Error getting orders: ${error}`, { type: 'error' });
23607
- throw error;
23608
- }
23759
+ return this.makeRequest(endpoint, 'GET', undefined, '', {
23760
+ action: 'Get orders',
23761
+ symbol: params.symbols?.join(','),
23762
+ });
23609
23763
  }
23610
23764
  async getAccountDetails() {
23611
- try {
23612
- return await this.makeRequest('/account');
23613
- }
23614
- catch (error) {
23615
- this.log(`Error getting account details: ${error}`, { type: 'error' });
23616
- throw error;
23617
- }
23765
+ return this.makeRequest('/account', 'GET', undefined, '', {
23766
+ action: 'Get account details',
23767
+ });
23618
23768
  }
23619
23769
  /**
23620
23770
  * Create a trailing stop order
@@ -23632,27 +23782,21 @@ class AlpacaTradingAPI {
23632
23782
  });
23633
23783
  const body = {
23634
23784
  symbol,
23635
- qty: Math.abs(qty),
23785
+ qty: Math.abs(qty).toString(),
23636
23786
  side,
23637
23787
  position_intent,
23638
23788
  order_class: 'simple',
23639
23789
  type: 'trailing_stop',
23640
- trail_percent: trailPercent100, // Already in decimal form (e.g., 4 for 4%)
23790
+ trail_percent: trailPercent100.toString(),
23641
23791
  time_in_force: 'gtc',
23642
23792
  };
23643
23793
  if (client_order_id !== undefined) {
23644
23794
  body.client_order_id = client_order_id;
23645
23795
  }
23646
- try {
23647
- return await this.makeRequest(`/orders`, 'POST', body);
23648
- }
23649
- catch (error) {
23650
- this.log(`Error creating trailing stop: ${error}`, {
23651
- symbol,
23652
- type: 'error',
23653
- });
23654
- throw error;
23655
- }
23796
+ return this.makeRequest('/orders', 'POST', body, '', {
23797
+ action: 'Create trailing stop order',
23798
+ symbol,
23799
+ });
23656
23800
  }
23657
23801
  /**
23658
23802
  * Create a stop order (stop or stop-limit)
@@ -23678,25 +23822,19 @@ class AlpacaTradingAPI {
23678
23822
  position_intent,
23679
23823
  order_class: 'simple',
23680
23824
  type: isStopLimit ? 'stop_limit' : 'stop',
23681
- stop_price: this.roundPriceForAlpaca(stopPrice),
23825
+ stop_price: this.roundPriceForAlpaca(stopPrice).toString(),
23682
23826
  time_in_force: 'gtc',
23683
23827
  };
23684
- if (isStopLimit) {
23685
- body.limit_price = this.roundPriceForAlpaca(limitPrice);
23828
+ if (limitPrice !== undefined) {
23829
+ body.limit_price = this.roundPriceForAlpaca(limitPrice).toString();
23686
23830
  }
23687
23831
  if (client_order_id !== undefined) {
23688
23832
  body.client_order_id = client_order_id;
23689
23833
  }
23690
- try {
23691
- return await this.makeRequest(`/orders`, 'POST', body);
23692
- }
23693
- catch (error) {
23694
- this.log(`Error creating ${orderType} order: ${error}`, {
23695
- symbol,
23696
- type: 'error',
23697
- });
23698
- throw error;
23699
- }
23834
+ return this.makeRequest('/orders', 'POST', body, '', {
23835
+ action: `Create ${orderType} order`,
23836
+ symbol,
23837
+ });
23700
23838
  }
23701
23839
  /**
23702
23840
  * Create a market order
@@ -23722,13 +23860,10 @@ class AlpacaTradingAPI {
23722
23860
  if (client_order_id !== undefined) {
23723
23861
  body.client_order_id = client_order_id;
23724
23862
  }
23725
- try {
23726
- return await this.makeRequest('/orders', 'POST', body);
23727
- }
23728
- catch (error) {
23729
- this.log(`Error creating market order: ${error}`, { type: 'error' });
23730
- throw error;
23731
- }
23863
+ return this.makeRequest('/orders', 'POST', body, '', {
23864
+ action: 'Create market order',
23865
+ symbol,
23866
+ });
23732
23867
  }
23733
23868
  /**
23734
23869
  * Create a Market on Open (MOO) order - executes in the opening auction
@@ -23762,13 +23897,10 @@ class AlpacaTradingAPI {
23762
23897
  if (client_order_id !== undefined) {
23763
23898
  body.client_order_id = client_order_id;
23764
23899
  }
23765
- try {
23766
- return await this.makeRequest('/orders', 'POST', body);
23767
- }
23768
- catch (error) {
23769
- this.log(`Error creating MOO order: ${error}`, { type: 'error' });
23770
- throw error;
23771
- }
23900
+ return this.makeRequest('/orders', 'POST', body, '', {
23901
+ action: 'Create market on open order',
23902
+ symbol,
23903
+ });
23772
23904
  }
23773
23905
  /**
23774
23906
  * Create a Market on Close (MOC) order - executes in the closing auction
@@ -23802,13 +23934,10 @@ class AlpacaTradingAPI {
23802
23934
  if (client_order_id !== undefined) {
23803
23935
  body.client_order_id = client_order_id;
23804
23936
  }
23805
- try {
23806
- return await this.makeRequest('/orders', 'POST', body);
23807
- }
23808
- catch (error) {
23809
- this.log(`Error creating MOC order: ${error}`, { type: 'error' });
23810
- throw error;
23811
- }
23937
+ return this.makeRequest('/orders', 'POST', body, '', {
23938
+ action: 'Create market on close order',
23939
+ symbol,
23940
+ });
23812
23941
  }
23813
23942
  /**
23814
23943
  * Create an OCO (One-Cancels-Other) order with take profit and stop loss
@@ -23834,32 +23963,29 @@ class AlpacaTradingAPI {
23834
23963
  position_intent,
23835
23964
  order_class: 'oco',
23836
23965
  type: 'limit',
23837
- limit_price: this.roundPriceForAlpaca(limitPrice),
23966
+ limit_price: this.roundPriceForAlpaca(limitPrice).toString(),
23838
23967
  time_in_force: 'gtc',
23839
23968
  take_profit: {
23840
- limit_price: this.roundPriceForAlpaca(takeProfitPrice),
23969
+ limit_price: this.roundPriceForAlpaca(takeProfitPrice).toString(),
23841
23970
  },
23842
23971
  stop_loss: {
23843
- stop_price: this.roundPriceForAlpaca(stopLossPrice),
23972
+ stop_price: this.roundPriceForAlpaca(stopLossPrice).toString(),
23844
23973
  },
23845
23974
  };
23846
23975
  // If stop loss limit price is provided, create stop-limit order
23847
23976
  if (stopLossLimitPrice !== undefined) {
23848
- body.stop_loss.limit_price = this.roundPriceForAlpaca(stopLossLimitPrice);
23977
+ body.stop_loss = {
23978
+ stop_price: this.roundPriceForAlpaca(stopLossPrice).toString(),
23979
+ limit_price: this.roundPriceForAlpaca(stopLossLimitPrice).toString(),
23980
+ };
23849
23981
  }
23850
23982
  if (client_order_id !== undefined) {
23851
23983
  body.client_order_id = client_order_id;
23852
23984
  }
23853
- try {
23854
- return await this.makeRequest(`/orders`, 'POST', body);
23855
- }
23856
- catch (error) {
23857
- this.log(`Error creating OCO order: ${error}`, {
23858
- symbol,
23859
- type: 'error',
23860
- });
23861
- throw error;
23862
- }
23985
+ return this.makeRequest('/orders', 'POST', body, '', {
23986
+ action: 'Create OCO order',
23987
+ symbol,
23988
+ });
23863
23989
  }
23864
23990
  /**
23865
23991
  * Get the current trail percent for a symbol, assuming that it has an open position and a trailing stop order to close it. Because this relies on an orders request for one symbol, you can't do it too often.
@@ -23867,35 +23993,26 @@ class AlpacaTradingAPI {
23867
23993
  * @returns the current trail percent
23868
23994
  */
23869
23995
  async getCurrentTrailPercent(symbol) {
23870
- try {
23871
- const orders = await this.getOrders({
23872
- status: 'open',
23873
- symbols: [symbol],
23996
+ const orders = await this.getOrders({
23997
+ status: 'open',
23998
+ symbols: [symbol],
23999
+ });
24000
+ const trailingStopOrder = orders.find((order) => order.type === 'trailing_stop' &&
24001
+ (order.position_intent === 'sell_to_close' || order.position_intent === 'buy_to_close'));
24002
+ if (!trailingStopOrder) {
24003
+ this.log(`No closing trailing stop order found for ${symbol}`, {
24004
+ symbol,
23874
24005
  });
23875
- const trailingStopOrder = orders.find((order) => order.type === 'trailing_stop' &&
23876
- (order.position_intent === 'sell_to_close' || order.position_intent === 'buy_to_close'));
23877
- if (!trailingStopOrder) {
23878
- this.log(`No closing trailing stop order found for ${symbol}`, {
23879
- symbol,
23880
- });
23881
- return null;
23882
- }
23883
- if (!trailingStopOrder.trail_percent) {
23884
- this.log(`Trailing stop order found for ${symbol} but no trail_percent value`, {
23885
- symbol,
23886
- });
23887
- return null;
23888
- }
23889
- const trailPercent = parseFloat(trailingStopOrder.trail_percent);
23890
- return trailPercent;
24006
+ return null;
23891
24007
  }
23892
- catch (error) {
23893
- this.log(`Error getting current trail percent: ${error}`, {
24008
+ if (!trailingStopOrder.trail_percent) {
24009
+ this.log(`Trailing stop order found for ${symbol} but no trail_percent value`, {
23894
24010
  symbol,
23895
- type: 'error',
23896
24011
  });
23897
- throw error;
24012
+ return null;
23898
24013
  }
24014
+ const trailPercent = parseFloat(trailingStopOrder.trail_percent);
24015
+ return trailPercent;
23899
24016
  }
23900
24017
  /**
23901
24018
  * Update the trail percent for a trailing stop order
@@ -23927,18 +24044,10 @@ class AlpacaTradingAPI {
23927
24044
  this.log(`Updating trailing stop for ${symbol} from ${currentTrailPercent}% to ${trailPercent100}%`, {
23928
24045
  symbol,
23929
24046
  });
23930
- try {
23931
- await this.makeRequest(`/orders/${trailingStopOrder.id}`, 'PATCH', {
23932
- trail: trailPercent100.toString(), // Changed from trail_percent to trail
23933
- });
23934
- }
23935
- catch (error) {
23936
- this.log(`Error updating trailing stop: ${error}`, {
23937
- symbol,
23938
- type: 'error',
23939
- });
23940
- throw error;
23941
- }
24047
+ await this.makeRequest(`/orders/${trailingStopOrder.id}`, 'PATCH', { trail: trailPercent100.toString() }, '', {
24048
+ action: 'Update trailing stop order',
24049
+ symbol,
24050
+ });
23942
24051
  }
23943
24052
  /**
23944
24053
  * Cancel all open orders
@@ -23946,10 +24055,16 @@ class AlpacaTradingAPI {
23946
24055
  async cancelAllOrders() {
23947
24056
  this.log(`Canceling all open orders`);
23948
24057
  try {
23949
- await this.makeRequest('/orders', 'DELETE');
24058
+ await this.makeRequest('/orders', 'DELETE', undefined, '', {
24059
+ action: 'Cancel all open orders',
24060
+ });
23950
24061
  }
23951
24062
  catch (error) {
23952
- this.log(`Error canceling all orders: ${error}`, { type: 'error' });
24063
+ if (!(error instanceof AlpacaRequestError)) {
24064
+ this.log(`Error canceling all orders: ${error instanceof Error ? error.message : `${error}`}`, {
24065
+ type: 'error',
24066
+ });
24067
+ }
23953
24068
  }
23954
24069
  }
23955
24070
  /**
@@ -23961,15 +24076,14 @@ class AlpacaTradingAPI {
23961
24076
  async cancelOrder(orderId) {
23962
24077
  this.log(`Attempting to cancel order ${orderId}`);
23963
24078
  try {
23964
- await this.makeRequest(`/orders/${orderId}`, 'DELETE');
24079
+ await this.makeRequest(`/orders/${orderId}`, 'DELETE', undefined, '', {
24080
+ action: `Cancel order ${orderId}`,
24081
+ });
23965
24082
  this.log(`Successfully canceled order ${orderId}`);
23966
24083
  }
23967
24084
  catch (error) {
23968
24085
  // If the error is a 422, it means the order is not cancelable
23969
- if (error instanceof Error && error.message.includes('422')) {
23970
- this.log(`Order ${orderId} is not cancelable`, {
23971
- type: 'error',
23972
- });
24086
+ if (error instanceof AlpacaRequestError && error.status === 422) {
23973
24087
  throw new Error(`Order ${orderId} is not cancelable`);
23974
24088
  }
23975
24089
  // Re-throw other errors
@@ -24004,13 +24118,10 @@ class AlpacaTradingAPI {
24004
24118
  if (client_order_id !== undefined) {
24005
24119
  body.client_order_id = client_order_id;
24006
24120
  }
24007
- try {
24008
- return await this.makeRequest('/orders', 'POST', body);
24009
- }
24010
- catch (error) {
24011
- this.log(`Error creating limit order: ${error}`, { type: 'error' });
24012
- throw error;
24013
- }
24121
+ return this.makeRequest('/orders', 'POST', body, '', {
24122
+ action: 'Create limit order',
24123
+ symbol,
24124
+ });
24014
24125
  }
24015
24126
  /**
24016
24127
  * Close all equities positions
@@ -24076,7 +24187,9 @@ class AlpacaTradingAPI {
24076
24187
  }
24077
24188
  }
24078
24189
  else {
24079
- await this.makeRequest('/positions', 'DELETE', undefined, options.cancel_orders ? '?cancel_orders=true' : '');
24190
+ await this.makeRequest('/positions', 'DELETE', undefined, options.cancel_orders ? '?cancel_orders=true' : '', {
24191
+ action: 'Close all positions',
24192
+ });
24080
24193
  }
24081
24194
  }
24082
24195
  /**
@@ -24155,7 +24268,9 @@ class AlpacaTradingAPI {
24155
24268
  queryParams.append('end', params.end);
24156
24269
  if (params.date_end)
24157
24270
  queryParams.append('date_end', params.date_end);
24158
- const response = await this.makeRequest(`/account/portfolio/history?${queryParams.toString()}`);
24271
+ const response = await this.makeRequest(`/account/portfolio/history?${queryParams.toString()}`, 'GET', undefined, '', {
24272
+ action: 'Get portfolio history',
24273
+ });
24159
24274
  return response;
24160
24275
  }
24161
24276
  /**
@@ -24246,7 +24361,10 @@ class AlpacaTradingAPI {
24246
24361
  this.log(`Fetching option contracts for ${params.underlying_symbols.join(', ')}`, {
24247
24362
  symbol: params.underlying_symbols.join(', '),
24248
24363
  });
24249
- const response = (await this.makeRequest(`/options/contracts?${queryParams.toString()}`));
24364
+ const response = await this.makeRequest(`/options/contracts?${queryParams.toString()}`, 'GET', undefined, '', {
24365
+ action: 'Get option contracts',
24366
+ symbol: params.underlying_symbols.join(', '),
24367
+ });
24250
24368
  this.log(`Found ${response.option_contracts.length} option contracts`, {
24251
24369
  symbol: params.underlying_symbols.join(', '),
24252
24370
  });
@@ -24261,7 +24379,10 @@ class AlpacaTradingAPI {
24261
24379
  this.log(`Fetching option contract details for ${symbolOrId}`, {
24262
24380
  symbol: symbolOrId,
24263
24381
  });
24264
- const response = (await this.makeRequest(`/options/contracts/${symbolOrId}`));
24382
+ const response = await this.makeRequest(`/options/contracts/${symbolOrId}`, 'GET', undefined, '', {
24383
+ action: 'Get option contract details',
24384
+ symbol: symbolOrId,
24385
+ });
24265
24386
  this.log(`Found option contract details for ${symbolOrId}: ${response.name}`, {
24266
24387
  symbol: symbolOrId,
24267
24388
  });
@@ -24279,10 +24400,10 @@ class AlpacaTradingAPI {
24279
24400
  */
24280
24401
  async createOptionOrder(symbol, qty, side, position_intent, type, limitPrice) {
24281
24402
  if (!Number.isInteger(qty) || qty <= 0) {
24282
- this.log('Quantity must be a positive whole number for option orders', { type: 'error' });
24403
+ this.log('Quantity must be a positive whole number for option orders', { symbol, type: 'error' });
24283
24404
  }
24284
24405
  if (type === 'limit' && limitPrice === undefined) {
24285
- this.log('Limit price is required for limit orders', { type: 'error' });
24406
+ this.log('Limit price is required for limit orders', { symbol, type: 'error' });
24286
24407
  }
24287
24408
  this.log(`Creating ${type} option order for ${symbol}: ${side} ${qty} contracts (${position_intent})${type === 'limit' ? ` at $${limitPrice?.toFixed(2)}` : ''}`, {
24288
24409
  symbol,
@@ -24300,7 +24421,10 @@ class AlpacaTradingAPI {
24300
24421
  if (type === 'limit' && limitPrice !== undefined) {
24301
24422
  orderData.limit_price = this.roundPriceForAlpaca(limitPrice).toString();
24302
24423
  }
24303
- return this.makeRequest('/orders', 'POST', orderData);
24424
+ return this.makeRequest('/orders', 'POST', orderData, '', {
24425
+ action: 'Create option order',
24426
+ symbol,
24427
+ });
24304
24428
  }
24305
24429
  /**
24306
24430
  * Create a multi-leg option order
@@ -24311,16 +24435,19 @@ class AlpacaTradingAPI {
24311
24435
  * @returns The created multi-leg order
24312
24436
  */
24313
24437
  async createMultiLegOptionOrder(legs, qty, type, limitPrice) {
24438
+ const legSymbols = legs.map((leg) => leg.symbol).join(', ');
24314
24439
  if (!Number.isInteger(qty) || qty <= 0) {
24315
- this.log('Quantity must be a positive whole number for option orders', { type: 'error' });
24440
+ this.log('Quantity must be a positive whole number for option orders', {
24441
+ symbol: legSymbols,
24442
+ type: 'error',
24443
+ });
24316
24444
  }
24317
24445
  if (type === 'limit' && limitPrice === undefined) {
24318
- this.log('Limit price is required for limit orders', { type: 'error' });
24446
+ this.log('Limit price is required for limit orders', { symbol: legSymbols, type: 'error' });
24319
24447
  }
24320
24448
  if (legs.length < 2) {
24321
- this.log('Multi-leg orders require at least 2 legs', { type: 'error' });
24449
+ this.log('Multi-leg orders require at least 2 legs', { symbol: legSymbols, type: 'error' });
24322
24450
  }
24323
- const legSymbols = legs.map((leg) => leg.symbol).join(', ');
24324
24451
  this.log(`Creating multi-leg ${type} option order with ${legs.length} legs (${legSymbols})${type === 'limit' ? ` at $${limitPrice?.toFixed(2)}` : ''}`, {
24325
24452
  symbol: legSymbols,
24326
24453
  });
@@ -24334,7 +24461,10 @@ class AlpacaTradingAPI {
24334
24461
  if (type === 'limit' && limitPrice !== undefined) {
24335
24462
  orderData.limit_price = this.roundPriceForAlpaca(limitPrice).toString();
24336
24463
  }
24337
- return this.makeRequest('/orders', 'POST', orderData);
24464
+ return this.makeRequest('/orders', 'POST', orderData, '', {
24465
+ action: 'Create multi-leg option order',
24466
+ symbol: legSymbols,
24467
+ });
24338
24468
  }
24339
24469
  /**
24340
24470
  * Exercise an option contract
@@ -24345,7 +24475,10 @@ class AlpacaTradingAPI {
24345
24475
  this.log(`Exercising option contract ${symbolOrContractId}`, {
24346
24476
  symbol: symbolOrContractId,
24347
24477
  });
24348
- return this.makeRequest(`/positions/${symbolOrContractId}/exercise`, 'POST');
24478
+ return this.makeRequest(`/positions/${symbolOrContractId}/exercise`, 'POST', undefined, '', {
24479
+ action: 'Exercise option contract',
24480
+ symbol: symbolOrContractId,
24481
+ });
24349
24482
  }
24350
24483
  /**
24351
24484
  * Get option positions
@@ -24381,7 +24514,9 @@ class AlpacaTradingAPI {
24381
24514
  queryParams.append('date', date);
24382
24515
  }
24383
24516
  this.log(`Fetching option activities${activityType ? ` of type ${activityType}` : ''}${date ? ` for date ${date}` : ''}`);
24384
- return this.makeRequest(`/account/activities?${queryParams.toString()}`);
24517
+ return this.makeRequest(`/account/activities?${queryParams.toString()}`, 'GET', undefined, '', {
24518
+ action: 'Get option activities',
24519
+ });
24385
24520
  }
24386
24521
  /**
24387
24522
  * Create a long call spread (buy lower strike call, sell higher strike call)
@@ -24479,13 +24614,7 @@ class AlpacaTradingAPI {
24479
24614
  position_intent: 'buy_to_open',
24480
24615
  },
24481
24616
  ];
24482
- try {
24483
- return await this.createMultiLegOptionOrder(legs, qty, 'limit', limitPrice);
24484
- }
24485
- catch (error) {
24486
- this.log(`Error creating iron condor: ${error}`, { type: 'error' });
24487
- throw error;
24488
- }
24617
+ return this.createMultiLegOptionOrder(legs, qty, 'limit', limitPrice);
24489
24618
  }
24490
24619
  /**
24491
24620
  * Create a covered call (sell call option against owned stock)
@@ -24501,13 +24630,7 @@ class AlpacaTradingAPI {
24501
24630
  });
24502
24631
  // For covered calls, we don't need to include the stock leg if we already own the shares
24503
24632
  // We just create a simple sell order for the call option
24504
- try {
24505
- return await this.createOptionOrder(callOptionSymbol, qty, 'sell', 'sell_to_open', 'limit', limitPrice);
24506
- }
24507
- catch (error) {
24508
- this.log(`Error creating covered call: ${error}`, { type: 'error' });
24509
- throw error;
24510
- }
24633
+ return this.createOptionOrder(callOptionSymbol, qty, 'sell', 'sell_to_open', 'limit', limitPrice);
24511
24634
  }
24512
24635
  /**
24513
24636
  * Roll an option position to a new expiration or strike
@@ -24542,13 +24665,7 @@ class AlpacaTradingAPI {
24542
24665
  position_intent: openPositionIntent,
24543
24666
  },
24544
24667
  ];
24545
- try {
24546
- return await this.createMultiLegOptionOrder(legs, qty, 'limit', limitPrice);
24547
- }
24548
- catch (error) {
24549
- this.log(`Error rolling option position: ${error}`, { type: 'error' });
24550
- throw error;
24551
- }
24668
+ return this.createMultiLegOptionOrder(legs, qty, 'limit', limitPrice);
24552
24669
  }
24553
24670
  /**
24554
24671
  * Get option chain for a specific underlying symbol and expiration date
@@ -24572,10 +24689,12 @@ class AlpacaTradingAPI {
24572
24689
  return response.option_contracts || [];
24573
24690
  }
24574
24691
  catch (error) {
24575
- this.log(`Failed to fetch option chain for ${underlyingSymbol}: ${error instanceof Error ? error.message : 'Unknown error'}`, {
24576
- type: 'error',
24577
- symbol: underlyingSymbol,
24578
- });
24692
+ if (!(error instanceof AlpacaRequestError)) {
24693
+ this.log(`Failed to fetch option chain for ${underlyingSymbol}: ${error instanceof Error ? error.message : `${error}`}`, {
24694
+ type: 'error',
24695
+ symbol: underlyingSymbol,
24696
+ });
24697
+ }
24579
24698
  return [];
24580
24699
  }
24581
24700
  }
@@ -24606,10 +24725,12 @@ class AlpacaTradingAPI {
24606
24725
  return Array.from(expirationDates).sort();
24607
24726
  }
24608
24727
  catch (error) {
24609
- this.log(`Failed to fetch expiration dates for ${underlyingSymbol}: ${error instanceof Error ? error.message : 'Unknown error'}`, {
24610
- type: 'error',
24611
- symbol: underlyingSymbol,
24612
- });
24728
+ if (!(error instanceof AlpacaRequestError)) {
24729
+ this.log(`Failed to fetch expiration dates for ${underlyingSymbol}: ${error instanceof Error ? error.message : `${error}`}`, {
24730
+ type: 'error',
24731
+ symbol: underlyingSymbol,
24732
+ });
24733
+ }
24613
24734
  return [];
24614
24735
  }
24615
24736
  }
@@ -24668,7 +24789,10 @@ class AlpacaTradingAPI {
24668
24789
  this.log(`Canceling open order for ${order.symbol}`, {
24669
24790
  symbol: order.symbol,
24670
24791
  });
24671
- await this.makeRequest(`/orders/${order.id}`, 'DELETE');
24792
+ await this.makeRequest(`/orders/${order.id}`, 'DELETE', undefined, '', {
24793
+ action: `Cancel option order ${order.id}`,
24794
+ symbol: order.symbol,
24795
+ });
24672
24796
  }
24673
24797
  }
24674
24798
  }
@@ -24691,13 +24815,7 @@ class AlpacaTradingAPI {
24691
24815
  const quantityToClose = qty || parseInt(position.qty);
24692
24816
  const side = position.side === 'long' ? 'sell' : 'buy';
24693
24817
  const positionIntent = side === 'sell' ? 'sell_to_close' : 'buy_to_close';
24694
- try {
24695
- return await this.createOptionOrder(symbol, quantityToClose, side, positionIntent, 'market');
24696
- }
24697
- catch (error) {
24698
- this.log(`Error closing option position: ${error}`, { type: 'error' });
24699
- throw error;
24700
- }
24818
+ return this.createOptionOrder(symbol, quantityToClose, side, positionIntent, 'market');
24701
24819
  }
24702
24820
  /**
24703
24821
  * Create a complete equities trade with optional stop loss and take profit
@@ -24832,16 +24950,10 @@ class AlpacaTradingAPI {
24832
24950
  this.log(logMessage, {
24833
24951
  symbol,
24834
24952
  });
24835
- try {
24836
- return await this.makeRequest('/orders', 'POST', orderData);
24837
- }
24838
- catch (error) {
24839
- this.log(`Error creating equities trade: ${error}`, {
24840
- symbol,
24841
- type: 'error',
24842
- });
24843
- throw error;
24844
- }
24953
+ return this.makeRequest('/orders', 'POST', orderData, '', {
24954
+ action: 'Create equities trade',
24955
+ symbol,
24956
+ });
24845
24957
  }
24846
24958
  }
24847
24959
 
@@ -24892,6 +25004,48 @@ const disco = {
24892
25004
 
24893
25005
  // Test file for context functionality
24894
25006
  process.env['DEBUG'] === 'true' || false;
25007
+ async function testLLM() {
25008
+ //const models: LLMModel[] = ['gpt-5', 'gpt-5-mini', 'gpt-5.4-mini', 'gpt-5-nano'];
25009
+ const models = ['gpt-5.4-mini'];
25010
+ for (const model of models) {
25011
+ console.log(`\nTesting model: ${model}`);
25012
+ // 1. Basic call
25013
+ try {
25014
+ const basic = await disco.llm.call('What is the capital of France?', { model });
25015
+ if (!basic || !basic.response) {
25016
+ throw new Error('No response from LLM');
25017
+ }
25018
+ console.log(`Response: ${basic.response}`);
25019
+ }
25020
+ catch (e) {
25021
+ console.error(` Basic call error:`, e);
25022
+ }
25023
+ // 2. JSON call
25024
+ try {
25025
+ const jsonPrompt = 'Return a JSON object with keys country and capital for France.';
25026
+ const json = await disco.llm.call(jsonPrompt, { model, responseFormat: 'json' });
25027
+ if (!json || !json.response) {
25028
+ throw new Error('No response from LLM');
25029
+ }
25030
+ console.log(`Response: ${JSON.stringify(json.response)}`);
25031
+ }
25032
+ catch (e) {
25033
+ console.error(` JSON call error:`, e);
25034
+ }
25035
+ // 3. Web search
25036
+ try {
25037
+ const searchPrompt = 'What is the latest news about artificial intelligence? Respond with 3 sentences max.';
25038
+ const tool = await disco.llm.call(searchPrompt, { model, useWebSearch: true });
25039
+ if (!tool || !tool.response) {
25040
+ throw new Error('No response from LLM');
25041
+ }
25042
+ console.log(`Response: ${tool.response}`);
25043
+ }
25044
+ catch (e) {
25045
+ console.error(` Web search error:`, e);
25046
+ }
25047
+ }
25048
+ }
24895
25049
  async function testLLMStructuredOutputWithZod() {
24896
25050
  if (!process.env.OPENAI_API_KEY) {
24897
25051
  console.log('Skipping OpenAI structured output Zod test: OPENAI_API_KEY not set');
@@ -24906,7 +25060,7 @@ async function testLLMStructuredOutputWithZod() {
24906
25060
  try {
24907
25061
  const prompt = 'Return details for France using the exact schema.';
24908
25062
  const result = await disco.llm.call(prompt, {
24909
- model: 'gpt-5-mini',
25063
+ model: 'gpt-5.4-mini',
24910
25064
  schema: structuredSchema,
24911
25065
  schemaName: 'capital_response',
24912
25066
  schemaDescription: 'Country and capital metadata',
@@ -24937,7 +25091,6 @@ async function testLLMStructuredOutputWithZod() {
24937
25091
  // testGetPortfolioDailyHistory();
24938
25092
  // testWebSocketConnectAndDisconnect();
24939
25093
  // testGetAssetsShortableFilter();
24940
- // testLLM();
24941
25094
  // testImageModelDefaults();
24942
25095
  // testGetTradingDaysBack();
24943
25096
  // testMOOAndMOCOrders();
@@ -24947,5 +25100,6 @@ async function testLLMStructuredOutputWithZod() {
24947
25100
  // testMarketDataSubscription('SPY');
24948
25101
  // testMarketDataSubscription('FAKEPACA');
24949
25102
  // testGetTradingDate();
25103
+ testLLM();
24950
25104
  testLLMStructuredOutputWithZod();
24951
25105
  //# sourceMappingURL=test.js.map