@ai-sdk/openai 4.0.46 → 4.0.49

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.
@@ -1956,40 +1956,60 @@ The metadata includes the following fields:
1956
1956
  ### Text Batches
1957
1957
 
1958
1958
  <Note type="warning">
1959
- Text batch APIs are experimental and may change in future releases.
1959
+ Text batch support is experimental and the API may change in patch releases.
1960
1960
  </Note>
1961
1961
 
1962
- The OpenAI provider supports the [Batch API](https://developers.openai.com/api/docs/guides/batch) for text generation.
1962
+ The OpenAI provider supports asynchronous text generation through the
1963
+ [Batch API](https://developers.openai.com/api/docs/guides/batch). Use the
1964
+ experimental text batch APIs to start a batch, poll its status, and stream its
1965
+ results:
1963
1966
 
1964
1967
  ```ts
1965
1968
  import { openai } from '@ai-sdk/openai';
1966
1969
  import {
1967
- experimental_startTextBatch as startTextBatch,
1968
1970
  experimental_getBatchResults as getBatchResults,
1969
1971
  experimental_getBatchStatus as getBatchStatus,
1972
+ experimental_startTextBatch as startTextBatch,
1970
1973
  } from 'ai';
1974
+ import { setTimeout } from 'node:timers/promises';
1971
1975
 
1972
1976
  const model = openai('gpt-4.1-nano');
1973
1977
 
1974
1978
  const batch = await startTextBatch({
1975
1979
  model,
1976
1980
  requests: [
1977
- { id: 'france', prompt: 'What is the capital of France?' },
1978
- { id: 'germany', prompt: 'What is the capital of Germany?' },
1981
+ { id: 'capital-france', prompt: 'What is the capital of France?' },
1982
+ { id: 'capital-germany', prompt: 'What is the capital of Germany?' },
1979
1983
  ],
1980
1984
  });
1981
1985
 
1982
- // Persist `batch` and check its status later, or poll for status updates.
1983
- const { status } = await getBatchStatus({ model, batch });
1986
+ let status = batch.status;
1987
+ while (status === 'pending') {
1988
+ await setTimeout(60_000);
1989
+ ({ status } = await getBatchStatus({ model, batch }));
1990
+ }
1984
1991
 
1985
- if (status !== 'pending') {
1986
- for await (const result of getBatchResults({ model, batch })) {
1987
- console.log(result);
1992
+ for await (const item of getBatchResults({ model, batch })) {
1993
+ if (item.status === 'succeeded') {
1994
+ console.log(item.id, item.text);
1995
+ } else {
1996
+ console.error(item.id, item.error);
1988
1997
  }
1989
1998
  }
1990
1999
  ```
1991
2000
 
1992
- Starting a batch returns a serializable reference that can be persisted and used to retrieve the batch results later, or poll for status updates.
2001
+ `startTextBatch` returns a serializable batch reference. Persist this reference
2002
+ to check the batch status or retrieve its results from another process. Results
2003
+ can arrive in a different order from the input requests, so match each result by
2004
+ its `id`.
2005
+
2006
+ #### Webhooks
2007
+
2008
+ <Note>
2009
+ The OpenAI Batch API does not support per-batch webhooks. When you provide a
2010
+ `webhookUrl`, the provider returns an unsupported warning and starts the batch
2011
+ without a webhook.
2012
+ </Note>
1993
2013
 
1994
2014
  ### Chat Models
1995
2015
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/openai",
3
- "version": "4.0.46",
3
+ "version": "4.0.49",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "sideEffects": false,
@@ -35,16 +35,16 @@
35
35
  }
36
36
  },
37
37
  "dependencies": {
38
- "@ai-sdk/provider": "4.0.7",
39
- "@ai-sdk/provider-utils": "5.0.29"
38
+ "@ai-sdk/provider": "4.0.8",
39
+ "@ai-sdk/provider-utils": "5.0.32"
40
40
  },
41
41
  "devDependencies": {
42
+ "@ai-sdk/test-server": "2.0.1",
42
43
  "@types/node": "22.19.19",
44
+ "@vercel/ai-tsconfig": "0.0.0",
43
45
  "tsup": "^8.5.1",
44
46
  "typescript": "5.8.3",
45
- "zod": "3.25.76",
46
- "@ai-sdk/test-server": "2.0.1",
47
- "@vercel/ai-tsconfig": "0.0.0"
47
+ "zod": "3.25.76"
48
48
  },
49
49
  "peerDependencies": {
50
50
  "zod": "^3.25.76 || ^4.1.8"
@@ -40,7 +40,7 @@ export function convertOpenAIChatUsage(
40
40
  },
41
41
  outputTokens: {
42
42
  total: completionTokens,
43
- text: completionTokens - reasoningTokens,
43
+ text: Math.max(0, completionTokens - reasoningTokens),
44
44
  reasoning: reasoningTokens,
45
45
  },
46
46
  raw: usage,
@@ -13,7 +13,11 @@ import {
13
13
  } from '@ai-sdk/provider-utils';
14
14
 
15
15
  function serializeToolCallArguments(input: unknown): string {
16
- return JSON.stringify(input === undefined ? {} : input);
16
+ return JSON.stringify(
17
+ typeof input === 'object' && input !== null && !Array.isArray(input)
18
+ ? input
19
+ : {},
20
+ );
17
21
  }
18
22
 
19
23
  type OpenAIPromptCacheBreakpoint = { mode: 'explicit' };
@@ -26,7 +26,10 @@ import {
26
26
  } from '@ai-sdk/provider-utils';
27
27
  import { openaiFailedResponseHandler } from '../openai-error';
28
28
  import { getOpenAILanguageModelCapabilities } from '../openai-language-model-capabilities';
29
- import { throwIfOpenAIStreamErrorBeforeOutput } from '../openai-stream-error';
29
+ import {
30
+ createOpenAIProviderStreamError,
31
+ throwIfOpenAIStreamErrorBeforeOutput,
32
+ } from '../openai-stream-error';
30
33
  import {
31
34
  convertOpenAIChatUsage,
32
35
  type OpenAIChatUsage,
@@ -509,7 +512,11 @@ export class OpenAIChatLanguageModel implements LanguageModelV4 {
509
512
  // handle error chunks:
510
513
  if ('error' in value) {
511
514
  finishReason = { unified: 'error', raw: undefined };
512
- controller.enqueue({ type: 'error', error: value.error });
515
+ controller.enqueue({
516
+ type: 'error',
517
+ error:
518
+ createOpenAIProviderStreamError(value.error) ?? value.error,
519
+ });
513
520
  return;
514
521
  }
515
522
 
@@ -21,7 +21,10 @@ import {
21
21
  type ParseResult,
22
22
  } from '@ai-sdk/provider-utils';
23
23
  import { openaiFailedResponseHandler } from '../openai-error';
24
- import { throwIfOpenAIStreamErrorBeforeOutput } from '../openai-stream-error';
24
+ import {
25
+ createOpenAIProviderStreamError,
26
+ throwIfOpenAIStreamErrorBeforeOutput,
27
+ } from '../openai-stream-error';
25
28
  import {
26
29
  convertOpenAICompletionUsage,
27
30
  type OpenAICompletionUsage,
@@ -302,7 +305,11 @@ export class OpenAICompletionLanguageModel implements LanguageModelV4 {
302
305
  // handle error chunks:
303
306
  if ('error' in value) {
304
307
  finishReason = { unified: 'error', raw: undefined };
305
- controller.enqueue({ type: 'error', error: value.error });
308
+ controller.enqueue({
309
+ type: 'error',
310
+ error:
311
+ createOpenAIProviderStreamError(value.error) ?? value.error,
312
+ });
306
313
  return;
307
314
  }
308
315
 
@@ -5,6 +5,7 @@ import {
5
5
  import {
6
6
  combineHeaders,
7
7
  createJsonResponseHandler,
8
+ EXPERIMENTAL_EMBEDDING_MODEL_MAX_INPUT_BYTES_PER_CALL,
8
9
  parseProviderOptions,
9
10
  postJsonToApi,
10
11
  serializeModelOptions,
@@ -23,6 +24,7 @@ export class OpenAIEmbeddingModel implements EmbeddingModelV4 {
23
24
  readonly specificationVersion = 'v4';
24
25
  readonly modelId: OpenAIEmbeddingModelId;
25
26
  readonly maxEmbeddingsPerCall = 2048;
27
+ readonly [EXPERIMENTAL_EMBEDDING_MODEL_MAX_INPUT_BYTES_PER_CALL] = 300_000;
26
28
  readonly supportsParallelCalls = true;
27
29
 
28
30
  private readonly config: OpenAIConfig;
@@ -1,6 +1,6 @@
1
1
  import {
2
- EmptyResponseBodyError,
3
2
  InvalidArgumentError,
3
+ InvalidResponseDataError,
4
4
  type Experimental_BatchLanguageModelV4 as BatchLanguageModelV4,
5
5
  type Experimental_BatchV4StartOptions as BatchV4StartOptions,
6
6
  type Experimental_BatchV4StartResult as BatchV4StartResult,
@@ -15,19 +15,18 @@ import {
15
15
  import {
16
16
  combineHeaders,
17
17
  convertAsyncIteratorToReadableStream,
18
+ createJsonLinesResponseHandler,
18
19
  createJsonResponseHandler,
19
20
  getFromApi,
20
21
  lazySchema,
21
- parseJSON,
22
+ normalizeBatchRequestCounts,
22
23
  postJsonToApi,
23
24
  postToApi,
24
25
  safeValidateTypes,
25
- validateTypes,
26
26
  WORKFLOW_DESERIALIZE,
27
27
  WORKFLOW_SERIALIZE,
28
28
  zodSchema,
29
29
  type InferSchema,
30
- type ResponseHandler,
31
30
  } from '@ai-sdk/provider-utils';
32
31
  import { z } from 'zod/v4';
33
32
  import {
@@ -44,6 +43,7 @@ import {
44
43
  } from './responses/openai-responses-api';
45
44
  import { OpenAIResponsesLanguageModel } from './responses/openai-responses-language-model';
46
45
  import type { OpenAIResponsesModelId } from './responses/openai-responses-language-model-options';
46
+ import type { ResponsesReasoningProviderMetadata } from './responses/openai-responses-provider-metadata';
47
47
 
48
48
  const openaiBatchEndpoint = '/v1/responses';
49
49
  const openaiBatchInputFileExpiresAfterSeconds = 48 * 60 * 60;
@@ -133,7 +133,19 @@ class OpenAIResponsesBatch {
133
133
  options: BatchV4StartOptions<OpenAIBatchRequest>,
134
134
  ): Promise<BatchV4StartResult> {
135
135
  const fileParts: string[] = [];
136
- const warnings: BatchV4StartResult['warnings'] = [];
136
+ const warnings: BatchV4StartResult['warnings'] =
137
+ options.webhookUrl == null
138
+ ? []
139
+ : [
140
+ {
141
+ warning: {
142
+ type: 'unsupported',
143
+ feature: 'webhookUrl',
144
+ details:
145
+ 'The OpenAI Batch API does not support per-batch webhook URLs.',
146
+ },
147
+ },
148
+ ];
137
149
 
138
150
  for (const request of options.requests) {
139
151
  const preparedRequest = await this.options.prepareRequest(request);
@@ -229,7 +241,9 @@ class OpenAIResponsesBatch {
229
241
  ): Promise<ReadableStream<BatchV4ItemResult<LanguageModelV4GenerateResult>>> {
230
242
  const batch = await this.retrieveBatch(options);
231
243
 
232
- if (convertOpenAIBatchStatus(batch).status === 'pending') {
244
+ const batchStatus = convertOpenAIBatchStatus(batch);
245
+
246
+ if (batchStatus.status === 'pending') {
233
247
  throw new InvalidArgumentError({
234
248
  argument: 'batchId',
235
249
  message: `OpenAI batch "${options.batchId}" is not complete.`,
@@ -239,6 +253,14 @@ class OpenAIResponsesBatch {
239
253
  const fileIds = [batch.output_file_id, batch.error_file_id].filter(
240
254
  (fileId): fileId is string => fileId != null,
241
255
  );
256
+
257
+ if (batchStatus.status === 'completed' && fileIds.length === 0) {
258
+ throw new InvalidResponseDataError({
259
+ data: batch,
260
+ message: `OpenAI batch "${options.batchId}" completed without batch output.`,
261
+ });
262
+ }
263
+
242
264
  const iterator = this.iterateBatchResults({ fileIds, options });
243
265
 
244
266
  return convertAsyncIteratorToReadableStream(iterator);
@@ -270,20 +292,22 @@ class OpenAIResponsesBatch {
270
292
  options: BatchV4OperationOptions;
271
293
  }): AsyncGenerator<BatchV4ItemResult<LanguageModelV4GenerateResult>> {
272
294
  for (const fileId of fileIds) {
273
- const { value: stream } = await getFromApi({
295
+ const { value: lines } = await getFromApi({
274
296
  url: this.getUrl(`/files/${encodeURIComponent(fileId)}/content`),
275
297
  headers: combineHeaders(
276
298
  this.options.config.headers?.(),
277
299
  options.headers,
278
300
  ),
279
301
  failedResponseHandler: openaiFailedResponseHandler,
280
- successfulResponseHandler: rawStreamResponseHandler,
302
+ successfulResponseHandler: createJsonLinesResponseHandler(
303
+ openaiBatchResultLineSchema,
304
+ ),
281
305
  abortSignal: options.abortSignal,
282
306
  fetch: this.options.config.fetch,
283
307
  validateUrl: false,
284
308
  });
285
309
 
286
- for await (const line of parseJsonLines(stream)) {
310
+ for await (const line of lines) {
287
311
  yield await this.convertResultLine(line);
288
312
  }
289
313
  }
@@ -456,24 +480,15 @@ function convertOpenAIRequestCounts(
456
480
  const completed = counts?.completed;
457
481
  const failed = counts?.failed;
458
482
 
459
- if (
460
- total == null ||
461
- completed == null ||
462
- failed == null ||
463
- total < 0 ||
464
- completed < 0 ||
465
- failed < 0 ||
466
- completed + failed > total
467
- ) {
468
- return undefined;
469
- }
470
-
471
- return {
483
+ return normalizeBatchRequestCounts({
472
484
  total,
473
- pending: total - completed - failed,
485
+ pending:
486
+ total != null && completed != null && failed != null
487
+ ? total - completed - failed
488
+ : undefined,
474
489
  completed,
475
490
  failed,
476
- };
491
+ });
477
492
  }
478
493
 
479
494
  function convertUnixTimestamp(value: number | null | undefined) {
@@ -518,11 +533,23 @@ async function convertOpenAIErrorResponse({
518
533
  async function convertOpenAIResponsesBatchResponse(
519
534
  body: unknown,
520
535
  ): Promise<OpenAIBatchResponseConversion> {
521
- const response = await validateTypes({
536
+ const validation = await safeValidateTypes({
522
537
  value: body,
523
538
  schema: openaiResponsesResponseSchema,
524
539
  });
525
540
 
541
+ if (!validation.success) {
542
+ return {
543
+ success: false,
544
+ error: {
545
+ message: 'OpenAI returned an invalid Responses batch result.',
546
+ code: 'invalid_response',
547
+ },
548
+ };
549
+ }
550
+
551
+ const response = validation.value;
552
+
526
553
  if (response.error != null) {
527
554
  return {
528
555
  success: false,
@@ -552,25 +579,59 @@ async function convertOpenAIResponsesBatchResponse(
552
579
  const logprobs: Array<NonNullable<OpenAIResponsesLogprobs>> = [];
553
580
 
554
581
  for (const part of response.output) {
555
- if (part.type === 'message') {
556
- for (const contentPart of part.content) {
557
- content.push({ type: 'text', text: contentPart.text });
558
- if (contentPart.logprobs != null) {
559
- logprobs.push(contentPart.logprobs);
582
+ switch (part.type) {
583
+ case 'reasoning': {
584
+ const summaries =
585
+ part.summary.length > 0
586
+ ? part.summary
587
+ : [{ type: 'summary_text' as const, text: '' }];
588
+
589
+ for (const summary of summaries) {
590
+ content.push({
591
+ type: 'reasoning',
592
+ text: summary.text,
593
+ providerMetadata: {
594
+ openai: {
595
+ itemId: part.id,
596
+ reasoningEncryptedContent: part.encrypted_content ?? null,
597
+ } satisfies ResponsesReasoningProviderMetadata,
598
+ },
599
+ });
560
600
  }
601
+ break;
561
602
  }
562
- } else if (
563
- part.type === 'function_call' ||
564
- part.type === 'custom_tool_call'
565
- ) {
566
- return {
567
- success: false,
568
- error: {
569
- message:
570
- 'OpenAI returned a tool call, but tool calls are not supported in AI SDK text batches.',
571
- code: 'unsupported_tool_call',
572
- },
573
- };
603
+
604
+ case 'message': {
605
+ for (const contentPart of part.content) {
606
+ content.push({ type: 'text', text: contentPart.text });
607
+ if (contentPart.logprobs != null) {
608
+ logprobs.push(contentPart.logprobs);
609
+ }
610
+ }
611
+ break;
612
+ }
613
+
614
+ case 'function_call':
615
+ case 'custom_tool_call':
616
+ return {
617
+ success: false,
618
+ error: {
619
+ message:
620
+ 'OpenAI returned a tool call, but tool calls are not supported in AI SDK text batches.',
621
+ code: 'unsupported_content',
622
+ },
623
+ };
624
+
625
+ default:
626
+ return {
627
+ success: false,
628
+ error: {
629
+ message:
630
+ `OpenAI returned an unsupported "${part.type}" output item ` +
631
+ 'in an AI SDK text batch.',
632
+ code: 'unsupported_content',
633
+ },
634
+ };
574
635
  }
575
636
  }
576
637
 
@@ -612,64 +673,3 @@ async function convertOpenAIResponsesBatchResponse(
612
673
  },
613
674
  };
614
675
  }
615
-
616
- const rawStreamResponseHandler: ResponseHandler<
617
- ReadableStream<Uint8Array>
618
- > = async ({ response }) => {
619
- if (response.body == null) {
620
- throw new EmptyResponseBodyError();
621
- }
622
-
623
- return { value: response.body };
624
- };
625
-
626
- async function* parseJsonLines(
627
- stream: ReadableStream<Uint8Array>,
628
- ): AsyncGenerator<OpenAIBatchResultLine> {
629
- const reader = stream.getReader();
630
- const decoder = new TextDecoder();
631
- let buffer = '';
632
- let finished = false;
633
-
634
- try {
635
- while (true) {
636
- const { done, value } = await reader.read();
637
-
638
- if (done) {
639
- finished = true;
640
- buffer += decoder.decode();
641
- break;
642
- }
643
-
644
- buffer += decoder.decode(value, { stream: true });
645
-
646
- let lineEnd = buffer.indexOf('\n');
647
- while (lineEnd !== -1) {
648
- const line = buffer.slice(0, lineEnd).replace(/\r$/, '');
649
- buffer = buffer.slice(lineEnd + 1);
650
-
651
- if (line.trim().length > 0) {
652
- yield await parseJSON({
653
- text: line,
654
- schema: openaiBatchResultLineSchema,
655
- });
656
- }
657
-
658
- lineEnd = buffer.indexOf('\n');
659
- }
660
- }
661
-
662
- const finalLine = buffer.replace(/\r$/, '');
663
- if (finalLine.trim().length > 0) {
664
- yield await parseJSON({
665
- text: finalLine,
666
- schema: openaiBatchResultLineSchema,
667
- });
668
- }
669
- } finally {
670
- if (!finished) {
671
- await reader.cancel().catch(() => {});
672
- }
673
- reader.releaseLock();
674
- }
675
- }
@@ -1,13 +1,41 @@
1
1
  import { APICallError } from '@ai-sdk/provider';
2
- import type { ParseResult } from '@ai-sdk/provider-utils';
2
+ import {
3
+ createProviderStreamError,
4
+ type ParseResult,
5
+ type ProviderStreamError,
6
+ } from '@ai-sdk/provider-utils';
3
7
 
4
8
  type StreamError = {
5
9
  message: string;
6
10
  code?: string | number | null;
7
11
  type?: string | null;
8
- frame: unknown;
9
12
  };
10
13
 
14
+ /**
15
+ * Converts an OpenAI stream error frame into provider-owned metadata that AI
16
+ * SDK Core can normalize without duplicating OpenAI error-code semantics.
17
+ */
18
+ export function createOpenAIProviderStreamError(
19
+ frame: unknown,
20
+ ): ProviderStreamError | undefined {
21
+ const streamError = parseStreamError(frame);
22
+
23
+ if (streamError == null) {
24
+ return undefined;
25
+ }
26
+
27
+ const statusCode = getStatusCode(streamError);
28
+
29
+ return createProviderStreamError({
30
+ message: streamError.message,
31
+ type: streamError.type ?? undefined,
32
+ code: streamError.code ?? undefined,
33
+ statusCode,
34
+ isRetryable: isRetryableStreamError(streamError, statusCode),
35
+ data: frame,
36
+ });
37
+ }
38
+
11
39
  export async function throwIfOpenAIStreamErrorBeforeOutput<T>({
12
40
  stream,
13
41
  getError,
@@ -154,17 +182,18 @@ function createOpenAIStreamError({
154
182
  requestBodyValues: unknown;
155
183
  responseHeaders?: Record<string, string>;
156
184
  }): APICallError {
157
- const streamError = parseStreamError(frame);
185
+ const streamError = createOpenAIProviderStreamError(frame);
158
186
  return new APICallError({
159
187
  message:
160
188
  streamError?.message ??
161
189
  'OpenAI stream failed before any output was generated',
162
190
  url,
163
191
  requestBodyValues,
164
- statusCode: streamError == null ? 500 : getStatusCode(streamError),
192
+ statusCode: streamError?.statusCode ?? 500,
165
193
  responseHeaders,
166
194
  responseBody: JSON.stringify(frame),
167
195
  data: frame,
196
+ isRetryable: streamError?.isRetryable,
168
197
  });
169
198
  }
170
199
 
@@ -184,7 +213,6 @@ function parseStreamError(frame: unknown): StreamError | undefined {
184
213
  message: responseError.message,
185
214
  code: getStringOrNumber(responseError.code),
186
215
  type: 'response.failed',
187
- frame,
188
216
  }
189
217
  : undefined;
190
218
  }
@@ -200,21 +228,14 @@ function parseStreamError(frame: unknown): StreamError | undefined {
200
228
  message: error.message,
201
229
  code: getStringOrNumber(error.code),
202
230
  type: typeof error.type === 'string' ? error.type : undefined,
203
- frame,
204
231
  }
205
232
  : undefined;
206
233
  }
207
234
 
208
235
  function getStatusCode(error: StreamError): number {
209
- if (typeof error.code === 'number' && isHttpErrorStatusCode(error.code)) {
210
- return error.code;
211
- }
212
-
213
- if (typeof error.code === 'string' && /^\d{3}$/.test(error.code)) {
214
- const numericCode = Number(error.code);
215
- if (isHttpErrorStatusCode(numericCode)) {
216
- return numericCode;
217
- }
236
+ const explicitStatusCode = getHttpStatusCode(error.code);
237
+ if (explicitStatusCode != null) {
238
+ return explicitStatusCode;
218
239
  }
219
240
 
220
241
  const discriminator = [error.code, error.type]
@@ -260,3 +281,35 @@ function getStringOrNumber(value: unknown): string | number | undefined {
260
281
  function isHttpErrorStatusCode(value: number): boolean {
261
282
  return Number.isInteger(value) && value >= 400 && value <= 599;
262
283
  }
284
+
285
+ function getHttpStatusCode(value: string | number | null | undefined) {
286
+ const statusCode =
287
+ typeof value === 'string' && /^\d{3}$/.test(value) ? Number(value) : value;
288
+
289
+ return typeof statusCode === 'number' && isHttpErrorStatusCode(statusCode)
290
+ ? statusCode
291
+ : undefined;
292
+ }
293
+
294
+ function isRetryableStatusCode(statusCode: number): boolean {
295
+ return (
296
+ statusCode === 408 ||
297
+ statusCode === 409 ||
298
+ statusCode === 429 ||
299
+ statusCode >= 500
300
+ );
301
+ }
302
+
303
+ function isRetryableStreamError(
304
+ error: StreamError,
305
+ statusCode: number,
306
+ ): boolean {
307
+ if (
308
+ error.code === 'insufficient_quota' ||
309
+ error.type === 'insufficient_quota'
310
+ ) {
311
+ return false;
312
+ }
313
+
314
+ return isRetryableStatusCode(statusCode);
315
+ }