@livekit/agents-plugin-openai 1.0.50 → 1.1.0

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 (118) hide show
  1. package/dist/index.cjs +5 -2
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +1 -0
  4. package/dist/index.d.ts +1 -0
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +4 -2
  7. package/dist/index.js.map +1 -1
  8. package/dist/llm.cjs +8 -0
  9. package/dist/llm.cjs.map +1 -1
  10. package/dist/llm.d.cts +1 -0
  11. package/dist/llm.d.ts +1 -0
  12. package/dist/llm.d.ts.map +1 -1
  13. package/dist/llm.js +8 -0
  14. package/dist/llm.js.map +1 -1
  15. package/dist/llm.test.cjs +31 -16
  16. package/dist/llm.test.cjs.map +1 -1
  17. package/dist/llm.test.js +32 -17
  18. package/dist/llm.test.js.map +1 -1
  19. package/dist/realtime/api_proto.cjs.map +1 -1
  20. package/dist/realtime/api_proto.d.cts +7 -3
  21. package/dist/realtime/api_proto.d.ts +7 -3
  22. package/dist/realtime/api_proto.d.ts.map +1 -1
  23. package/dist/realtime/api_proto.js.map +1 -1
  24. package/dist/realtime/realtime_model.cjs +46 -22
  25. package/dist/realtime/realtime_model.cjs.map +1 -1
  26. package/dist/realtime/realtime_model.d.cts +2 -1
  27. package/dist/realtime/realtime_model.d.ts +2 -1
  28. package/dist/realtime/realtime_model.d.ts.map +1 -1
  29. package/dist/realtime/realtime_model.js +46 -22
  30. package/dist/realtime/realtime_model.js.map +1 -1
  31. package/dist/realtime/realtime_model.test.cjs +104 -14
  32. package/dist/realtime/realtime_model.test.cjs.map +1 -1
  33. package/dist/realtime/realtime_model.test.js +104 -14
  34. package/dist/realtime/realtime_model.test.js.map +1 -1
  35. package/dist/realtime/realtime_model_beta.cjs +40 -22
  36. package/dist/realtime/realtime_model_beta.cjs.map +1 -1
  37. package/dist/realtime/realtime_model_beta.d.ts.map +1 -1
  38. package/dist/realtime/realtime_model_beta.js +40 -22
  39. package/dist/realtime/realtime_model_beta.js.map +1 -1
  40. package/dist/responses/llm.cjs +71 -16
  41. package/dist/responses/llm.cjs.map +1 -1
  42. package/dist/responses/llm.d.cts +10 -25
  43. package/dist/responses/llm.d.ts +10 -25
  44. package/dist/responses/llm.d.ts.map +1 -1
  45. package/dist/responses/llm.js +71 -14
  46. package/dist/responses/llm.js.map +1 -1
  47. package/dist/responses/llm.test.cjs +32 -17
  48. package/dist/responses/llm.test.cjs.map +1 -1
  49. package/dist/responses/llm.test.js +33 -18
  50. package/dist/responses/llm.test.js.map +1 -1
  51. package/dist/stt.cjs +18 -3
  52. package/dist/stt.cjs.map +1 -1
  53. package/dist/stt.d.cts +2 -0
  54. package/dist/stt.d.ts +2 -0
  55. package/dist/stt.d.ts.map +1 -1
  56. package/dist/stt.js +19 -4
  57. package/dist/stt.js.map +1 -1
  58. package/dist/stt.test.cjs +11 -3
  59. package/dist/stt.test.cjs.map +1 -1
  60. package/dist/stt.test.js +12 -4
  61. package/dist/stt.test.js.map +1 -1
  62. package/dist/tts.cjs +11 -0
  63. package/dist/tts.cjs.map +1 -1
  64. package/dist/tts.d.cts +2 -0
  65. package/dist/tts.d.ts +2 -0
  66. package/dist/tts.d.ts.map +1 -1
  67. package/dist/tts.js +11 -0
  68. package/dist/tts.js.map +1 -1
  69. package/dist/tts.test.cjs +11 -3
  70. package/dist/tts.test.cjs.map +1 -1
  71. package/dist/tts.test.js +12 -4
  72. package/dist/tts.test.js.map +1 -1
  73. package/dist/ws/index.cjs +29 -0
  74. package/dist/ws/index.cjs.map +1 -0
  75. package/dist/ws/index.d.cts +3 -0
  76. package/dist/ws/index.d.ts +3 -0
  77. package/dist/ws/index.d.ts.map +1 -0
  78. package/dist/ws/index.js +5 -0
  79. package/dist/ws/index.js.map +1 -0
  80. package/dist/ws/llm.cjs +502 -0
  81. package/dist/ws/llm.cjs.map +1 -0
  82. package/dist/ws/llm.d.cts +74 -0
  83. package/dist/ws/llm.d.ts +74 -0
  84. package/dist/ws/llm.d.ts.map +1 -0
  85. package/dist/ws/llm.js +485 -0
  86. package/dist/ws/llm.js.map +1 -0
  87. package/dist/ws/llm.test.cjs +26 -0
  88. package/dist/ws/llm.test.cjs.map +1 -0
  89. package/dist/ws/llm.test.d.cts +2 -0
  90. package/dist/ws/llm.test.d.ts +2 -0
  91. package/dist/ws/llm.test.d.ts.map +1 -0
  92. package/dist/ws/llm.test.js +25 -0
  93. package/dist/ws/llm.test.js.map +1 -0
  94. package/dist/ws/types.cjs +128 -0
  95. package/dist/ws/types.cjs.map +1 -0
  96. package/dist/ws/types.d.cts +167 -0
  97. package/dist/ws/types.d.ts +167 -0
  98. package/dist/ws/types.d.ts.map +1 -0
  99. package/dist/ws/types.js +95 -0
  100. package/dist/ws/types.js.map +1 -0
  101. package/package.json +6 -5
  102. package/src/index.ts +1 -0
  103. package/src/llm.test.ts +31 -17
  104. package/src/llm.ts +9 -0
  105. package/src/realtime/api_proto.ts +8 -2
  106. package/src/realtime/realtime_model.test.ts +129 -14
  107. package/src/realtime/realtime_model.ts +51 -26
  108. package/src/realtime/realtime_model_beta.ts +42 -25
  109. package/src/responses/llm.test.ts +32 -18
  110. package/src/responses/llm.ts +105 -19
  111. package/src/stt.test.ts +12 -4
  112. package/src/stt.ts +21 -4
  113. package/src/tts.test.ts +12 -4
  114. package/src/tts.ts +13 -0
  115. package/src/ws/index.ts +17 -0
  116. package/src/ws/llm.test.ts +30 -0
  117. package/src/ws/llm.ts +665 -0
  118. package/src/ws/types.ts +131 -0
@@ -2,7 +2,7 @@ import type { APIConnectOptions } from '@livekit/agents';
2
2
  import { llm } from '@livekit/agents';
3
3
  import OpenAI from 'openai';
4
4
  import type { ChatModels } from '../models.js';
5
- interface LLMOptions {
5
+ export interface LLMOptions {
6
6
  model: string | ChatModels;
7
7
  apiKey?: string;
8
8
  baseURL?: string;
@@ -13,6 +13,11 @@ interface LLMOptions {
13
13
  store?: boolean;
14
14
  metadata?: Record<string, string>;
15
15
  strictToolSchema?: boolean;
16
+ /**
17
+ * Whether to use the WebSocket API.
18
+ * @default true
19
+ */
20
+ useWebSocket?: boolean;
16
21
  }
17
22
  export declare class LLM extends llm.LLM {
18
23
  #private;
@@ -26,6 +31,9 @@ export declare class LLM extends llm.LLM {
26
31
  constructor(opts?: Partial<LLMOptions>);
27
32
  label(): string;
28
33
  get model(): string;
34
+ prewarm(): void;
35
+ aclose(): Promise<void>;
36
+ close(): Promise<void>;
29
37
  chat({ chatCtx, toolCtx, connOptions, parallelToolCalls, toolChoice, extraKwargs, }: {
30
38
  chatCtx: llm.ChatContext;
31
39
  toolCtx?: llm.ToolContext;
@@ -33,29 +41,6 @@ export declare class LLM extends llm.LLM {
33
41
  parallelToolCalls?: boolean;
34
42
  toolChoice?: llm.ToolChoice;
35
43
  extraKwargs?: Record<string, unknown>;
36
- }): LLMStream;
37
- }
38
- export declare class LLMStream extends llm.LLMStream {
39
- private model;
40
- private client;
41
- private modelOptions;
42
- private strictToolSchema;
43
- private responseId;
44
- constructor(llm: LLM, { model, client, chatCtx, toolCtx, connOptions, modelOptions, strictToolSchema, }: {
45
- model: string | ChatModels;
46
- client: OpenAI;
47
- chatCtx: llm.ChatContext;
48
- toolCtx?: llm.ToolContext;
49
- connOptions: APIConnectOptions;
50
- modelOptions: Record<string, unknown>;
51
- strictToolSchema: boolean;
52
- });
53
- protected run(): Promise<void>;
54
- private handleError;
55
- private handleResponseCreated;
56
- private handleResponseOutputItemDone;
57
- private handleResponseOutputTextDelta;
58
- private handleResponseCompleted;
44
+ }): llm.LLMStream;
59
45
  }
60
- export {};
61
46
  //# sourceMappingURL=llm.d.ts.map
@@ -2,7 +2,7 @@ import type { APIConnectOptions } from '@livekit/agents';
2
2
  import { llm } from '@livekit/agents';
3
3
  import OpenAI from 'openai';
4
4
  import type { ChatModels } from '../models.js';
5
- interface LLMOptions {
5
+ export interface LLMOptions {
6
6
  model: string | ChatModels;
7
7
  apiKey?: string;
8
8
  baseURL?: string;
@@ -13,6 +13,11 @@ interface LLMOptions {
13
13
  store?: boolean;
14
14
  metadata?: Record<string, string>;
15
15
  strictToolSchema?: boolean;
16
+ /**
17
+ * Whether to use the WebSocket API.
18
+ * @default true
19
+ */
20
+ useWebSocket?: boolean;
16
21
  }
17
22
  export declare class LLM extends llm.LLM {
18
23
  #private;
@@ -26,6 +31,9 @@ export declare class LLM extends llm.LLM {
26
31
  constructor(opts?: Partial<LLMOptions>);
27
32
  label(): string;
28
33
  get model(): string;
34
+ prewarm(): void;
35
+ aclose(): Promise<void>;
36
+ close(): Promise<void>;
29
37
  chat({ chatCtx, toolCtx, connOptions, parallelToolCalls, toolChoice, extraKwargs, }: {
30
38
  chatCtx: llm.ChatContext;
31
39
  toolCtx?: llm.ToolContext;
@@ -33,29 +41,6 @@ export declare class LLM extends llm.LLM {
33
41
  parallelToolCalls?: boolean;
34
42
  toolChoice?: llm.ToolChoice;
35
43
  extraKwargs?: Record<string, unknown>;
36
- }): LLMStream;
37
- }
38
- export declare class LLMStream extends llm.LLMStream {
39
- private model;
40
- private client;
41
- private modelOptions;
42
- private strictToolSchema;
43
- private responseId;
44
- constructor(llm: LLM, { model, client, chatCtx, toolCtx, connOptions, modelOptions, strictToolSchema, }: {
45
- model: string | ChatModels;
46
- client: OpenAI;
47
- chatCtx: llm.ChatContext;
48
- toolCtx?: llm.ToolContext;
49
- connOptions: APIConnectOptions;
50
- modelOptions: Record<string, unknown>;
51
- strictToolSchema: boolean;
52
- });
53
- protected run(): Promise<void>;
54
- private handleError;
55
- private handleResponseCreated;
56
- private handleResponseOutputItemDone;
57
- private handleResponseOutputTextDelta;
58
- private handleResponseCompleted;
44
+ }): llm.LLMStream;
59
45
  }
60
- export {};
61
46
  //# sourceMappingURL=llm.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"llm.d.ts","sourceRoot":"","sources":["../../src/responses/llm.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAKL,GAAG,EAEJ,MAAM,iBAAiB,CAAC;AACzB,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE/C,UAAU,UAAU;IAClB,KAAK,EAAE,MAAM,GAAG,UAAU,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,UAAU,CAAC,EAAE,GAAG,CAAC,UAAU,CAAC;IAC5B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAQD,qBAAa,GAAI,SAAQ,GAAG,CAAC,GAAG;;IAI9B;;;;;;OAMG;gBACS,IAAI,GAAE,OAAO,CAAC,UAAU,CAAqB;IAgBzD,KAAK,IAAI,MAAM;IAIf,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,IAAI,CAAC,EACH,OAAO,EACP,OAAO,EACP,WAAyC,EACzC,iBAAiB,EACjB,UAAU,EACV,WAAW,GACZ,EAAE;QACD,OAAO,EAAE,GAAG,CAAC,WAAW,CAAC;QACzB,OAAO,CAAC,EAAE,GAAG,CAAC,WAAW,CAAC;QAC1B,WAAW,CAAC,EAAE,iBAAiB,CAAC;QAChC,iBAAiB,CAAC,EAAE,OAAO,CAAC;QAC5B,UAAU,CAAC,EAAE,GAAG,CAAC,UAAU,CAAC;QAC5B,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACvC,GAAG,SAAS;CAuCd;AAED,qBAAa,SAAU,SAAQ,GAAG,CAAC,SAAS;IAC1C,OAAO,CAAC,KAAK,CAAsB;IACnC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,YAAY,CAA0B;IAC9C,OAAO,CAAC,gBAAgB,CAAU;IAClC,OAAO,CAAC,UAAU,CAAS;gBAGzB,GAAG,EAAE,GAAG,EACR,EACE,KAAK,EACL,MAAM,EACN,OAAO,EACP,OAAO,EACP,WAAW,EACX,YAAY,EACZ,gBAAgB,GACjB,EAAE;QACD,KAAK,EAAE,MAAM,GAAG,UAAU,CAAC;QAC3B,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,GAAG,CAAC,WAAW,CAAC;QACzB,OAAO,CAAC,EAAE,GAAG,CAAC,WAAW,CAAC;QAC1B,WAAW,EAAE,iBAAiB,CAAC;QAC/B,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACtC,gBAAgB,EAAE,OAAO,CAAC;KAC3B;cAUa,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;IAqGpC,OAAO,CAAC,WAAW;IAUnB,OAAO,CAAC,qBAAqB;IAI7B,OAAO,CAAC,4BAA4B;IAwBpC,OAAO,CAAC,6BAA6B;IAYrC,OAAO,CAAC,uBAAuB;CAgBhC"}
1
+ {"version":3,"file":"llm.d.ts","sourceRoot":"","sources":["../../src/responses/llm.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAKL,GAAG,EAGJ,MAAM,iBAAiB,CAAC;AACzB,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG/C,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,GAAG,UAAU,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,UAAU,CAAC,EAAE,GAAG,CAAC,UAAU,CAAC;IAC5B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAE3B;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AA0SD,qBAAa,GAAI,SAAQ,GAAG,CAAC,GAAG;;IAK9B;;;;;;OAMG;gBACS,IAAI,GAAE,OAAO,CAAC,UAAU,CAAqB;IAuBhD,KAAK,IAAI,MAAM;IAIxB,IAAa,KAAK,IAAI,MAAM,CAE3B;IAEQ,OAAO,IAAI,IAAI;IAKT,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAIhC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAInB,IAAI,CAAC,EACZ,OAAO,EACP,OAAO,EACP,WAAyC,EACzC,iBAAiB,EACjB,UAAU,EACV,WAAW,GACZ,EAAE;QACD,OAAO,EAAE,GAAG,CAAC,WAAW,CAAC;QACzB,OAAO,CAAC,EAAE,GAAG,CAAC,WAAW,CAAC;QAC1B,WAAW,CAAC,EAAE,iBAAiB,CAAC;QAChC,iBAAiB,CAAC,EAAE,OAAO,CAAC;QAC5B,UAAU,CAAC,EAAE,GAAG,CAAC,UAAU,CAAC;QAC5B,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACvC,GAAG,GAAG,CAAC,SAAS;CAUlB"}
@@ -4,28 +4,24 @@ import {
4
4
  APITimeoutError,
5
5
  DEFAULT_API_CONNECT_OPTIONS,
6
6
  llm,
7
+ log,
7
8
  toError
8
9
  } from "@livekit/agents";
9
10
  import OpenAI from "openai";
11
+ import { WSLLM } from "../ws/llm.js";
10
12
  const defaultLLMOptions = {
11
13
  model: "gpt-4.1",
12
14
  apiKey: process.env.OPENAI_API_KEY,
13
- strictToolSchema: true
15
+ strictToolSchema: true,
16
+ useWebSocket: true
14
17
  };
15
- class LLM extends llm.LLM {
18
+ class ResponsesHttpLLM extends llm.LLM {
16
19
  #client;
17
20
  #opts;
18
- /**
19
- * Create a new instance of OpenAI Responses LLM.
20
- *
21
- * @remarks
22
- * `apiKey` must be set to your OpenAI API key, either using the argument or by setting the
23
- * `OPENAI_API_KEY` environment variable.
24
- */
25
21
  constructor(opts = defaultLLMOptions) {
26
22
  super();
27
23
  this.#opts = { ...defaultLLMOptions, ...opts };
28
- if (this.#opts.apiKey === void 0) {
24
+ if (this.#opts.apiKey === void 0 && this.#opts.client === void 0) {
29
25
  throw new Error("OpenAI API key is required, whether as an argument or as $OPENAI_API_KEY");
30
26
  }
31
27
  this.#client = this.#opts.client || new OpenAI({
@@ -65,7 +61,7 @@ class LLM extends llm.LLM {
65
61
  if (this.#opts.metadata) {
66
62
  modelOptions.metadata = this.#opts.metadata;
67
63
  }
68
- return new LLMStream(this, {
64
+ return new ResponsesHttpLLMStream(this, {
69
65
  model: this.#opts.model,
70
66
  client: this.#client,
71
67
  chatCtx,
@@ -76,7 +72,7 @@ class LLM extends llm.LLM {
76
72
  });
77
73
  }
78
74
  }
79
- class LLMStream extends llm.LLMStream {
75
+ class ResponsesHttpLLMStream extends llm.LLMStream {
80
76
  model;
81
77
  client;
82
78
  modelOptions;
@@ -239,8 +235,69 @@ class LLMStream extends llm.LLMStream {
239
235
  return void 0;
240
236
  }
241
237
  }
238
+ class LLM extends llm.LLM {
239
+ #opts;
240
+ #llm;
241
+ #logger = log();
242
+ /**
243
+ * Create a new instance of OpenAI Responses LLM.
244
+ *
245
+ * @remarks
246
+ * `apiKey` must be set to your OpenAI API key, either using the argument or by setting the
247
+ * `OPENAI_API_KEY` environment variable.
248
+ */
249
+ constructor(opts = defaultLLMOptions) {
250
+ super();
251
+ this.#opts = { ...defaultLLMOptions, ...opts };
252
+ const { useWebSocket, client, ...baseOpts } = this.#opts;
253
+ if (useWebSocket) {
254
+ if (client !== void 0) {
255
+ this.#logger.warn(
256
+ "WebSocket mode does not support custom client; provided client will be ignored"
257
+ );
258
+ }
259
+ this.#llm = new WSLLM(baseOpts);
260
+ } else {
261
+ this.#llm = new ResponsesHttpLLM({ ...baseOpts, client });
262
+ }
263
+ this.#llm.on("metrics_collected", (metrics) => this.emit("metrics_collected", metrics));
264
+ this.#llm.on("error", (error) => this.emit("error", error));
265
+ }
266
+ label() {
267
+ return this.#llm.label();
268
+ }
269
+ get model() {
270
+ return this.#llm.model;
271
+ }
272
+ prewarm() {
273
+ this.#llm.prewarm();
274
+ }
275
+ // Ref: python livekit-plugins/livekit-plugins-openai/livekit/plugins/openai/responses/llm.py - 229-233 lines
276
+ async aclose() {
277
+ await this.#llm.aclose();
278
+ }
279
+ async close() {
280
+ await this.aclose();
281
+ }
282
+ chat({
283
+ chatCtx,
284
+ toolCtx,
285
+ connOptions = DEFAULT_API_CONNECT_OPTIONS,
286
+ parallelToolCalls,
287
+ toolChoice,
288
+ extraKwargs
289
+ }) {
290
+ return this.#llm.chat({
291
+ chatCtx,
292
+ toolCtx,
293
+ connOptions,
294
+ parallelToolCalls,
295
+ toolChoice,
296
+ extraKwargs
297
+ });
298
+ }
299
+ }
242
300
  export {
243
- LLM,
244
- LLMStream
301
+ LLM
245
302
  };
246
303
  //# sourceMappingURL=llm.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/responses/llm.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { APIConnectOptions } from '@livekit/agents';\nimport {\n APIConnectionError,\n APIStatusError,\n APITimeoutError,\n DEFAULT_API_CONNECT_OPTIONS,\n llm,\n toError,\n} from '@livekit/agents';\nimport OpenAI from 'openai';\nimport type { ChatModels } from '../models.js';\n\ninterface LLMOptions {\n model: string | ChatModels;\n apiKey?: string;\n baseURL?: string;\n client?: OpenAI;\n temperature?: number;\n parallelToolCalls?: boolean;\n toolChoice?: llm.ToolChoice;\n store?: boolean;\n metadata?: Record<string, string>;\n strictToolSchema?: boolean;\n}\n\nconst defaultLLMOptions: LLMOptions = {\n model: 'gpt-4.1',\n apiKey: process.env.OPENAI_API_KEY,\n strictToolSchema: true,\n};\n\nexport class LLM extends llm.LLM {\n #client: OpenAI;\n #opts: LLMOptions;\n\n /**\n * Create a new instance of OpenAI Responses LLM.\n *\n * @remarks\n * `apiKey` must be set to your OpenAI API key, either using the argument or by setting the\n * `OPENAI_API_KEY` environment variable.\n */\n constructor(opts: Partial<LLMOptions> = defaultLLMOptions) {\n super();\n\n this.#opts = { ...defaultLLMOptions, ...opts };\n if (this.#opts.apiKey === undefined) {\n throw new Error('OpenAI API key is required, whether as an argument or as $OPENAI_API_KEY');\n }\n\n this.#client =\n this.#opts.client ||\n new OpenAI({\n baseURL: this.#opts.baseURL,\n apiKey: this.#opts.apiKey,\n });\n }\n\n label(): string {\n return 'openai.responses.LLM';\n }\n\n get model(): string {\n return this.#opts.model;\n }\n\n chat({\n chatCtx,\n toolCtx,\n connOptions = DEFAULT_API_CONNECT_OPTIONS,\n parallelToolCalls,\n toolChoice,\n extraKwargs,\n }: {\n chatCtx: llm.ChatContext;\n toolCtx?: llm.ToolContext;\n connOptions?: APIConnectOptions;\n parallelToolCalls?: boolean;\n toolChoice?: llm.ToolChoice;\n extraKwargs?: Record<string, unknown>;\n }): LLMStream {\n const modelOptions: Record<string, unknown> = { ...(extraKwargs || {}) };\n\n parallelToolCalls =\n parallelToolCalls !== undefined ? parallelToolCalls : this.#opts.parallelToolCalls;\n\n if (toolCtx && Object.keys(toolCtx).length > 0 && parallelToolCalls !== undefined) {\n modelOptions.parallel_tool_calls = parallelToolCalls;\n }\n\n toolChoice =\n toolChoice !== undefined ? toolChoice : (this.#opts.toolChoice as llm.ToolChoice | undefined);\n\n if (toolChoice) {\n modelOptions.tool_choice = toolChoice;\n }\n\n if (this.#opts.temperature !== undefined) {\n modelOptions.temperature = this.#opts.temperature;\n }\n\n if (this.#opts.store !== undefined) {\n modelOptions.store = this.#opts.store;\n }\n\n if (this.#opts.metadata) {\n modelOptions.metadata = this.#opts.metadata;\n }\n\n return new LLMStream(this, {\n model: this.#opts.model,\n client: this.#client,\n chatCtx,\n toolCtx,\n connOptions,\n modelOptions,\n strictToolSchema: this.#opts.strictToolSchema ?? true,\n });\n }\n}\n\nexport class LLMStream extends llm.LLMStream {\n private model: string | ChatModels;\n private client: OpenAI;\n private modelOptions: Record<string, unknown>;\n private strictToolSchema: boolean;\n private responseId: string;\n\n constructor(\n llm: LLM,\n {\n model,\n client,\n chatCtx,\n toolCtx,\n connOptions,\n modelOptions,\n strictToolSchema,\n }: {\n model: string | ChatModels;\n client: OpenAI;\n chatCtx: llm.ChatContext;\n toolCtx?: llm.ToolContext;\n connOptions: APIConnectOptions;\n modelOptions: Record<string, unknown>;\n strictToolSchema: boolean;\n },\n ) {\n super(llm, { chatCtx, toolCtx, connOptions });\n this.model = model;\n this.client = client;\n this.modelOptions = modelOptions;\n this.strictToolSchema = strictToolSchema;\n this.responseId = '';\n }\n\n protected async run(): Promise<void> {\n let retryable = true;\n\n try {\n const messages = (await this.chatCtx.toProviderFormat(\n 'openai.responses',\n )) as OpenAI.Responses.ResponseInputItem[];\n\n const tools = this.toolCtx\n ? Object.entries(this.toolCtx).map(([name, func]) => {\n const oaiParams = {\n type: 'function' as const,\n name: name,\n description: func.description,\n parameters: llm.toJsonSchema(\n func.parameters,\n true,\n this.strictToolSchema,\n ) as unknown as OpenAI.Responses.FunctionTool['parameters'],\n } as OpenAI.Responses.FunctionTool;\n\n if (this.strictToolSchema) {\n oaiParams.strict = true;\n }\n\n return oaiParams;\n })\n : undefined;\n\n const requestOptions: Record<string, unknown> = { ...this.modelOptions };\n if (!tools) {\n delete requestOptions.tool_choice;\n }\n\n const stream = await this.client.responses.create(\n {\n model: this.model,\n input: messages,\n tools: tools,\n stream: true,\n ...requestOptions,\n },\n {\n timeout: this.connOptions.timeoutMs,\n },\n );\n\n for await (const event of stream) {\n retryable = false;\n let chunk: llm.ChatChunk | undefined;\n\n switch (event.type) {\n case 'error':\n this.handleError(event);\n break;\n case 'response.created':\n this.handleResponseCreated(event);\n break;\n case 'response.output_item.done':\n chunk = this.handleResponseOutputItemDone(event);\n break;\n case 'response.output_text.delta':\n chunk = this.handleResponseOutputTextDelta(event);\n break;\n case 'response.completed':\n chunk = this.handleResponseCompleted(event);\n break;\n }\n\n if (chunk) {\n this.queue.put(chunk);\n }\n }\n } catch (error) {\n if (\n error instanceof APIStatusError ||\n error instanceof APITimeoutError ||\n error instanceof APIConnectionError\n ) {\n throw error;\n } else if (error instanceof OpenAI.APIConnectionTimeoutError) {\n throw new APITimeoutError({ options: { retryable } });\n } else if (error instanceof OpenAI.APIError) {\n throw new APIStatusError({\n message: error.message,\n options: {\n statusCode: error.status,\n body: error.error,\n requestId: error.requestID,\n retryable,\n },\n });\n } else {\n throw new APIConnectionError({\n message: toError(error).message,\n options: { retryable },\n });\n }\n }\n }\n\n private handleError(event: OpenAI.Responses.ResponseErrorEvent): void {\n throw new APIStatusError({\n message: event.message,\n options: {\n statusCode: -1,\n retryable: false,\n },\n });\n }\n\n private handleResponseCreated(event: OpenAI.Responses.ResponseCreatedEvent): void {\n this.responseId = event.response.id;\n }\n\n private handleResponseOutputItemDone(\n event: OpenAI.Responses.ResponseOutputItemDoneEvent,\n ): llm.ChatChunk | undefined {\n let chunk: llm.ChatChunk | undefined;\n\n if (event.item.type === 'function_call') {\n chunk = {\n id: this.responseId,\n delta: {\n role: 'assistant',\n content: undefined,\n toolCalls: [\n llm.FunctionCall.create({\n callId: event.item.call_id || '',\n name: event.item.name,\n args: event.item.arguments,\n }),\n ],\n },\n };\n }\n return chunk;\n }\n\n private handleResponseOutputTextDelta(\n event: OpenAI.Responses.ResponseTextDeltaEvent,\n ): llm.ChatChunk {\n return {\n id: this.responseId,\n delta: {\n role: 'assistant',\n content: event.delta,\n },\n };\n }\n\n private handleResponseCompleted(\n event: OpenAI.Responses.ResponseCompletedEvent,\n ): llm.ChatChunk | undefined {\n if (event.response.usage) {\n return {\n id: this.responseId,\n usage: {\n completionTokens: event.response.usage.output_tokens,\n promptTokens: event.response.usage.input_tokens,\n promptCachedTokens: event.response.usage.input_tokens_details.cached_tokens,\n totalTokens: event.response.usage.total_tokens,\n },\n };\n }\n return undefined;\n }\n}\n"],"mappings":"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","names":["llm"]}
1
+ {"version":3,"sources":["../../src/responses/llm.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { APIConnectOptions } from '@livekit/agents';\nimport {\n APIConnectionError,\n APIStatusError,\n APITimeoutError,\n DEFAULT_API_CONNECT_OPTIONS,\n llm,\n log,\n toError,\n} from '@livekit/agents';\nimport OpenAI from 'openai';\nimport type { ChatModels } from '../models.js';\nimport { WSLLM } from '../ws/llm.js';\n\nexport interface LLMOptions {\n model: string | ChatModels;\n apiKey?: string;\n baseURL?: string;\n client?: OpenAI;\n temperature?: number;\n parallelToolCalls?: boolean;\n toolChoice?: llm.ToolChoice;\n store?: boolean;\n metadata?: Record<string, string>;\n strictToolSchema?: boolean;\n\n /**\n * Whether to use the WebSocket API.\n * @default true\n */\n useWebSocket?: boolean;\n}\n\ntype HttpLLMOptions = Omit<LLMOptions, 'useWebSocket'>;\n\nconst defaultLLMOptions: LLMOptions = {\n model: 'gpt-4.1',\n apiKey: process.env.OPENAI_API_KEY,\n strictToolSchema: true,\n useWebSocket: true,\n};\n\nclass ResponsesHttpLLM extends llm.LLM {\n #client: OpenAI;\n #opts: HttpLLMOptions;\n\n constructor(opts: Partial<HttpLLMOptions> = defaultLLMOptions) {\n super();\n\n this.#opts = { ...defaultLLMOptions, ...opts };\n if (this.#opts.apiKey === undefined && this.#opts.client === undefined) {\n throw new Error('OpenAI API key is required, whether as an argument or as $OPENAI_API_KEY');\n }\n\n this.#client =\n this.#opts.client ||\n new OpenAI({\n baseURL: this.#opts.baseURL,\n apiKey: this.#opts.apiKey,\n });\n }\n\n override label(): string {\n return 'openai.responses.LLM';\n }\n\n override get model(): string {\n return this.#opts.model;\n }\n\n override chat({\n chatCtx,\n toolCtx,\n connOptions = DEFAULT_API_CONNECT_OPTIONS,\n parallelToolCalls,\n toolChoice,\n extraKwargs,\n }: {\n chatCtx: llm.ChatContext;\n toolCtx?: llm.ToolContext;\n connOptions?: APIConnectOptions;\n parallelToolCalls?: boolean;\n toolChoice?: llm.ToolChoice;\n extraKwargs?: Record<string, unknown>;\n }): ResponsesHttpLLMStream {\n const modelOptions: Record<string, unknown> = { ...(extraKwargs || {}) };\n\n parallelToolCalls =\n parallelToolCalls !== undefined ? parallelToolCalls : this.#opts.parallelToolCalls;\n\n if (toolCtx && Object.keys(toolCtx).length > 0 && parallelToolCalls !== undefined) {\n modelOptions.parallel_tool_calls = parallelToolCalls;\n }\n\n toolChoice =\n toolChoice !== undefined ? toolChoice : (this.#opts.toolChoice as llm.ToolChoice | undefined);\n\n if (toolChoice) {\n modelOptions.tool_choice = toolChoice;\n }\n\n if (this.#opts.temperature !== undefined) {\n modelOptions.temperature = this.#opts.temperature;\n }\n\n if (this.#opts.store !== undefined) {\n modelOptions.store = this.#opts.store;\n }\n\n if (this.#opts.metadata) {\n modelOptions.metadata = this.#opts.metadata;\n }\n\n return new ResponsesHttpLLMStream(this, {\n model: this.#opts.model,\n client: this.#client,\n chatCtx,\n toolCtx,\n connOptions,\n modelOptions,\n strictToolSchema: this.#opts.strictToolSchema ?? true,\n });\n }\n}\n\nclass ResponsesHttpLLMStream extends llm.LLMStream {\n private model: string | ChatModels;\n private client: OpenAI;\n private modelOptions: Record<string, unknown>;\n private strictToolSchema: boolean;\n private responseId: string;\n\n constructor(\n llm: ResponsesHttpLLM,\n {\n model,\n client,\n chatCtx,\n toolCtx,\n connOptions,\n modelOptions,\n strictToolSchema,\n }: {\n model: string | ChatModels;\n client: OpenAI;\n chatCtx: llm.ChatContext;\n toolCtx?: llm.ToolContext;\n connOptions: APIConnectOptions;\n modelOptions: Record<string, unknown>;\n strictToolSchema: boolean;\n },\n ) {\n super(llm, { chatCtx, toolCtx, connOptions });\n this.model = model;\n this.client = client;\n this.modelOptions = modelOptions;\n this.strictToolSchema = strictToolSchema;\n this.responseId = '';\n }\n\n protected async run(): Promise<void> {\n let retryable = true;\n\n try {\n const messages = (await this.chatCtx.toProviderFormat(\n 'openai.responses',\n )) as OpenAI.Responses.ResponseInputItem[];\n\n const tools = this.toolCtx\n ? Object.entries(this.toolCtx).map(([name, func]) => {\n const oaiParams = {\n type: 'function' as const,\n name: name,\n description: func.description,\n parameters: llm.toJsonSchema(\n func.parameters,\n true,\n this.strictToolSchema,\n ) as unknown as OpenAI.Responses.FunctionTool['parameters'],\n } as OpenAI.Responses.FunctionTool;\n\n if (this.strictToolSchema) {\n oaiParams.strict = true;\n }\n\n return oaiParams;\n })\n : undefined;\n\n const requestOptions: Record<string, unknown> = { ...this.modelOptions };\n if (!tools) {\n delete requestOptions.tool_choice;\n }\n\n const stream = await this.client.responses.create(\n {\n model: this.model,\n input: messages,\n tools: tools,\n stream: true,\n ...requestOptions,\n },\n {\n timeout: this.connOptions.timeoutMs,\n },\n );\n\n for await (const event of stream) {\n retryable = false;\n let chunk: llm.ChatChunk | undefined;\n\n switch (event.type) {\n case 'error':\n this.handleError(event);\n break;\n case 'response.created':\n this.handleResponseCreated(event);\n break;\n case 'response.output_item.done':\n chunk = this.handleResponseOutputItemDone(event);\n break;\n case 'response.output_text.delta':\n chunk = this.handleResponseOutputTextDelta(event);\n break;\n case 'response.completed':\n chunk = this.handleResponseCompleted(event);\n break;\n }\n\n if (chunk) {\n this.queue.put(chunk);\n }\n }\n } catch (error) {\n if (\n error instanceof APIStatusError ||\n error instanceof APITimeoutError ||\n error instanceof APIConnectionError\n ) {\n throw error;\n } else if (error instanceof OpenAI.APIConnectionTimeoutError) {\n throw new APITimeoutError({ options: { retryable } });\n } else if (error instanceof OpenAI.APIError) {\n throw new APIStatusError({\n message: error.message,\n options: {\n statusCode: error.status,\n body: error.error,\n requestId: error.requestID,\n retryable,\n },\n });\n } else {\n throw new APIConnectionError({\n message: toError(error).message,\n options: { retryable },\n });\n }\n }\n }\n\n private handleError(event: OpenAI.Responses.ResponseErrorEvent): void {\n throw new APIStatusError({\n message: event.message,\n options: {\n statusCode: -1,\n retryable: false,\n },\n });\n }\n\n private handleResponseCreated(event: OpenAI.Responses.ResponseCreatedEvent): void {\n this.responseId = event.response.id;\n }\n\n private handleResponseOutputItemDone(\n event: OpenAI.Responses.ResponseOutputItemDoneEvent,\n ): llm.ChatChunk | undefined {\n let chunk: llm.ChatChunk | undefined;\n\n if (event.item.type === 'function_call') {\n chunk = {\n id: this.responseId,\n delta: {\n role: 'assistant',\n content: undefined,\n toolCalls: [\n llm.FunctionCall.create({\n callId: event.item.call_id || '',\n name: event.item.name,\n args: event.item.arguments,\n }),\n ],\n },\n };\n }\n return chunk;\n }\n\n private handleResponseOutputTextDelta(\n event: OpenAI.Responses.ResponseTextDeltaEvent,\n ): llm.ChatChunk {\n return {\n id: this.responseId,\n delta: {\n role: 'assistant',\n content: event.delta,\n },\n };\n }\n\n private handleResponseCompleted(\n event: OpenAI.Responses.ResponseCompletedEvent,\n ): llm.ChatChunk | undefined {\n if (event.response.usage) {\n return {\n id: this.responseId,\n usage: {\n completionTokens: event.response.usage.output_tokens,\n promptTokens: event.response.usage.input_tokens,\n promptCachedTokens: event.response.usage.input_tokens_details.cached_tokens,\n totalTokens: event.response.usage.total_tokens,\n },\n };\n }\n return undefined;\n }\n}\n\nexport class LLM extends llm.LLM {\n #opts: LLMOptions;\n #llm: llm.LLM;\n #logger = log();\n\n /**\n * Create a new instance of OpenAI Responses LLM.\n *\n * @remarks\n * `apiKey` must be set to your OpenAI API key, either using the argument or by setting the\n * `OPENAI_API_KEY` environment variable.\n */\n constructor(opts: Partial<LLMOptions> = defaultLLMOptions) {\n super();\n\n this.#opts = { ...defaultLLMOptions, ...opts };\n const { useWebSocket, client, ...baseOpts } = this.#opts;\n\n if (useWebSocket) {\n if (client !== undefined) {\n this.#logger.warn(\n 'WebSocket mode does not support custom client; provided client will be ignored',\n );\n }\n this.#llm = new WSLLM(baseOpts);\n } else {\n this.#llm = new ResponsesHttpLLM({ ...baseOpts, client });\n }\n\n // Forward events from the inner delegate so consumers listening on this\n // wrapper instance (e.g. AgentActivity) receive them.\n this.#llm.on('metrics_collected', (metrics) => this.emit('metrics_collected', metrics));\n this.#llm.on('error', (error) => this.emit('error', error));\n }\n\n override label(): string {\n return this.#llm.label();\n }\n\n override get model(): string {\n return this.#llm.model;\n }\n\n override prewarm(): void {\n this.#llm.prewarm();\n }\n\n // Ref: python livekit-plugins/livekit-plugins-openai/livekit/plugins/openai/responses/llm.py - 229-233 lines\n override async aclose(): Promise<void> {\n await this.#llm.aclose();\n }\n\n async close(): Promise<void> {\n await this.aclose();\n }\n\n override chat({\n chatCtx,\n toolCtx,\n connOptions = DEFAULT_API_CONNECT_OPTIONS,\n parallelToolCalls,\n toolChoice,\n extraKwargs,\n }: {\n chatCtx: llm.ChatContext;\n toolCtx?: llm.ToolContext;\n connOptions?: APIConnectOptions;\n parallelToolCalls?: boolean;\n toolChoice?: llm.ToolChoice;\n extraKwargs?: Record<string, unknown>;\n }): llm.LLMStream {\n return this.#llm.chat({\n chatCtx,\n toolCtx,\n connOptions,\n parallelToolCalls,\n toolChoice,\n extraKwargs,\n });\n }\n}\n"],"mappings":"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","names":["llm"]}
@@ -2,21 +2,36 @@
2
2
  var import_agents_plugins_test = require("@livekit/agents-plugins-test");
3
3
  var import_vitest = require("vitest");
4
4
  var import_llm = require("./llm.cjs");
5
- (0, import_vitest.describe)("OpenAI Responses", async () => {
6
- await (0, import_agents_plugins_test.llm)(
7
- new import_llm.LLM({
8
- temperature: 0,
9
- strictToolSchema: false
10
- }),
11
- true
12
- );
13
- });
14
- (0, import_vitest.describe)("OpenAI Responses strict tool schema", async () => {
15
- await (0, import_agents_plugins_test.llmStrict)(
16
- new import_llm.LLM({
17
- temperature: 0,
18
- strictToolSchema: true
19
- })
20
- );
21
- });
5
+ const hasOpenAIApiKey = Boolean(process.env.OPENAI_API_KEY);
6
+ if (hasOpenAIApiKey) {
7
+ (0, import_vitest.describe)("OpenAI Responses", async () => {
8
+ await (0, import_agents_plugins_test.llm)(
9
+ new import_llm.LLM({
10
+ temperature: 0,
11
+ strictToolSchema: false
12
+ }),
13
+ true
14
+ );
15
+ });
16
+ } else {
17
+ (0, import_vitest.describe)("OpenAI Responses", () => {
18
+ import_vitest.it.skip("requires OPENAI_API_KEY", () => {
19
+ });
20
+ });
21
+ }
22
+ if (hasOpenAIApiKey) {
23
+ (0, import_vitest.describe)("OpenAI Responses strict tool schema", async () => {
24
+ await (0, import_agents_plugins_test.llmStrict)(
25
+ new import_llm.LLM({
26
+ temperature: 0,
27
+ strictToolSchema: true
28
+ })
29
+ );
30
+ });
31
+ } else {
32
+ (0, import_vitest.describe)("OpenAI Responses strict tool schema", () => {
33
+ import_vitest.it.skip("requires OPENAI_API_KEY", () => {
34
+ });
35
+ });
36
+ }
22
37
  //# sourceMappingURL=llm.test.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/responses/llm.test.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { llm, llmStrict } from '@livekit/agents-plugins-test';\nimport { describe } from 'vitest';\nimport { LLM } from './llm.js';\n\ndescribe('OpenAI Responses', async () => {\n await llm(\n new LLM({\n temperature: 0,\n strictToolSchema: false,\n }),\n true,\n );\n});\n\ndescribe('OpenAI Responses strict tool schema', async () => {\n await llmStrict(\n new LLM({\n temperature: 0,\n strictToolSchema: true,\n }),\n );\n});\n"],"mappings":";AAGA,iCAA+B;AAC/B,oBAAyB;AACzB,iBAAoB;AAAA,IAEpB,wBAAS,oBAAoB,YAAY;AACvC,YAAM;AAAA,IACJ,IAAI,eAAI;AAAA,MACN,aAAa;AAAA,MACb,kBAAkB;AAAA,IACpB,CAAC;AAAA,IACD;AAAA,EACF;AACF,CAAC;AAAA,IAED,wBAAS,uCAAuC,YAAY;AAC1D,YAAM;AAAA,IACJ,IAAI,eAAI;AAAA,MACN,aAAa;AAAA,MACb,kBAAkB;AAAA,IACpB,CAAC;AAAA,EACH;AACF,CAAC;","names":[]}
1
+ {"version":3,"sources":["../../src/responses/llm.test.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { llm, llmStrict } from '@livekit/agents-plugins-test';\nimport { describe, it } from 'vitest';\nimport { LLM } from './llm.js';\n\nconst hasOpenAIApiKey = Boolean(process.env.OPENAI_API_KEY);\n\nif (hasOpenAIApiKey) {\n describe('OpenAI Responses', async () => {\n await llm(\n new LLM({\n temperature: 0,\n strictToolSchema: false,\n }),\n true,\n );\n });\n} else {\n describe('OpenAI Responses', () => {\n it.skip('requires OPENAI_API_KEY', () => {});\n });\n}\n\nif (hasOpenAIApiKey) {\n describe('OpenAI Responses strict tool schema', async () => {\n await llmStrict(\n new LLM({\n temperature: 0,\n strictToolSchema: true,\n }),\n );\n });\n} else {\n describe('OpenAI Responses strict tool schema', () => {\n it.skip('requires OPENAI_API_KEY', () => {});\n });\n}\n"],"mappings":";AAGA,iCAA+B;AAC/B,oBAA6B;AAC7B,iBAAoB;AAEpB,MAAM,kBAAkB,QAAQ,QAAQ,IAAI,cAAc;AAE1D,IAAI,iBAAiB;AACnB,8BAAS,oBAAoB,YAAY;AACvC,cAAM;AAAA,MACJ,IAAI,eAAI;AAAA,QACN,aAAa;AAAA,QACb,kBAAkB;AAAA,MACpB,CAAC;AAAA,MACD;AAAA,IACF;AAAA,EACF,CAAC;AACH,OAAO;AACL,8BAAS,oBAAoB,MAAM;AACjC,qBAAG,KAAK,2BAA2B,MAAM;AAAA,IAAC,CAAC;AAAA,EAC7C,CAAC;AACH;AAEA,IAAI,iBAAiB;AACnB,8BAAS,uCAAuC,YAAY;AAC1D,cAAM;AAAA,MACJ,IAAI,eAAI;AAAA,QACN,aAAa;AAAA,QACb,kBAAkB;AAAA,MACpB,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AACH,OAAO;AACL,8BAAS,uCAAuC,MAAM;AACpD,qBAAG,KAAK,2BAA2B,MAAM;AAAA,IAAC,CAAC;AAAA,EAC7C,CAAC;AACH;","names":[]}
@@ -1,21 +1,36 @@
1
1
  import { llm, llmStrict } from "@livekit/agents-plugins-test";
2
- import { describe } from "vitest";
2
+ import { describe, it } from "vitest";
3
3
  import { LLM } from "./llm.js";
4
- describe("OpenAI Responses", async () => {
5
- await llm(
6
- new LLM({
7
- temperature: 0,
8
- strictToolSchema: false
9
- }),
10
- true
11
- );
12
- });
13
- describe("OpenAI Responses strict tool schema", async () => {
14
- await llmStrict(
15
- new LLM({
16
- temperature: 0,
17
- strictToolSchema: true
18
- })
19
- );
20
- });
4
+ const hasOpenAIApiKey = Boolean(process.env.OPENAI_API_KEY);
5
+ if (hasOpenAIApiKey) {
6
+ describe("OpenAI Responses", async () => {
7
+ await llm(
8
+ new LLM({
9
+ temperature: 0,
10
+ strictToolSchema: false
11
+ }),
12
+ true
13
+ );
14
+ });
15
+ } else {
16
+ describe("OpenAI Responses", () => {
17
+ it.skip("requires OPENAI_API_KEY", () => {
18
+ });
19
+ });
20
+ }
21
+ if (hasOpenAIApiKey) {
22
+ describe("OpenAI Responses strict tool schema", async () => {
23
+ await llmStrict(
24
+ new LLM({
25
+ temperature: 0,
26
+ strictToolSchema: true
27
+ })
28
+ );
29
+ });
30
+ } else {
31
+ describe("OpenAI Responses strict tool schema", () => {
32
+ it.skip("requires OPENAI_API_KEY", () => {
33
+ });
34
+ });
35
+ }
21
36
  //# sourceMappingURL=llm.test.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/responses/llm.test.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { llm, llmStrict } from '@livekit/agents-plugins-test';\nimport { describe } from 'vitest';\nimport { LLM } from './llm.js';\n\ndescribe('OpenAI Responses', async () => {\n await llm(\n new LLM({\n temperature: 0,\n strictToolSchema: false,\n }),\n true,\n );\n});\n\ndescribe('OpenAI Responses strict tool schema', async () => {\n await llmStrict(\n new LLM({\n temperature: 0,\n strictToolSchema: true,\n }),\n );\n});\n"],"mappings":"AAGA,SAAS,KAAK,iBAAiB;AAC/B,SAAS,gBAAgB;AACzB,SAAS,WAAW;AAEpB,SAAS,oBAAoB,YAAY;AACvC,QAAM;AAAA,IACJ,IAAI,IAAI;AAAA,MACN,aAAa;AAAA,MACb,kBAAkB;AAAA,IACpB,CAAC;AAAA,IACD;AAAA,EACF;AACF,CAAC;AAED,SAAS,uCAAuC,YAAY;AAC1D,QAAM;AAAA,IACJ,IAAI,IAAI;AAAA,MACN,aAAa;AAAA,MACb,kBAAkB;AAAA,IACpB,CAAC;AAAA,EACH;AACF,CAAC;","names":[]}
1
+ {"version":3,"sources":["../../src/responses/llm.test.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { llm, llmStrict } from '@livekit/agents-plugins-test';\nimport { describe, it } from 'vitest';\nimport { LLM } from './llm.js';\n\nconst hasOpenAIApiKey = Boolean(process.env.OPENAI_API_KEY);\n\nif (hasOpenAIApiKey) {\n describe('OpenAI Responses', async () => {\n await llm(\n new LLM({\n temperature: 0,\n strictToolSchema: false,\n }),\n true,\n );\n });\n} else {\n describe('OpenAI Responses', () => {\n it.skip('requires OPENAI_API_KEY', () => {});\n });\n}\n\nif (hasOpenAIApiKey) {\n describe('OpenAI Responses strict tool schema', async () => {\n await llmStrict(\n new LLM({\n temperature: 0,\n strictToolSchema: true,\n }),\n );\n });\n} else {\n describe('OpenAI Responses strict tool schema', () => {\n it.skip('requires OPENAI_API_KEY', () => {});\n });\n}\n"],"mappings":"AAGA,SAAS,KAAK,iBAAiB;AAC/B,SAAS,UAAU,UAAU;AAC7B,SAAS,WAAW;AAEpB,MAAM,kBAAkB,QAAQ,QAAQ,IAAI,cAAc;AAE1D,IAAI,iBAAiB;AACnB,WAAS,oBAAoB,YAAY;AACvC,UAAM;AAAA,MACJ,IAAI,IAAI;AAAA,QACN,aAAa;AAAA,QACb,kBAAkB;AAAA,MACpB,CAAC;AAAA,MACD;AAAA,IACF;AAAA,EACF,CAAC;AACH,OAAO;AACL,WAAS,oBAAoB,MAAM;AACjC,OAAG,KAAK,2BAA2B,MAAM;AAAA,IAAC,CAAC;AAAA,EAC7C,CAAC;AACH;AAEA,IAAI,iBAAiB;AACnB,WAAS,uCAAuC,YAAY;AAC1D,UAAM;AAAA,MACJ,IAAI,IAAI;AAAA,QACN,aAAa;AAAA,QACb,kBAAkB;AAAA,MACpB,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AACH,OAAO;AACL,WAAS,uCAAuC,MAAM;AACpD,OAAG,KAAK,2BAA2B,MAAM;AAAA,IAAC,CAAC;AAAA,EAC7C,CAAC;AACH;","names":[]}
package/dist/stt.cjs CHANGED
@@ -33,6 +33,17 @@ class STT extends import_agents.stt.STT {
33
33
  #opts;
34
34
  #client;
35
35
  label = "openai.STT";
36
+ get model() {
37
+ return this.#opts.model;
38
+ }
39
+ get provider() {
40
+ try {
41
+ const url = new URL(this.#client.baseURL);
42
+ return url.host;
43
+ } catch {
44
+ return "api.openai.com";
45
+ }
46
+ }
36
47
  /**
37
48
  * Create a new instance of OpenAI STT.
38
49
  *
@@ -42,7 +53,11 @@ class STT extends import_agents.stt.STT {
42
53
  */
43
54
  constructor(opts = defaultSTTOptions) {
44
55
  super({ streaming: false, interimResults: false, alignedTranscript: false });
45
- this.#opts = { ...defaultSTTOptions, ...opts };
56
+ this.#opts = {
57
+ ...defaultSTTOptions,
58
+ ...opts,
59
+ language: (0, import_agents.normalizeLanguage)(opts.language ?? defaultSTTOptions.language)
60
+ };
46
61
  if (this.#opts.apiKey === void 0) {
47
62
  throw new Error("OpenAI API key is required, whether as an argument or as $OPENAI_API_KEY");
48
63
  }
@@ -91,7 +106,7 @@ class STT extends import_agents.stt.STT {
91
106
  }
92
107
  #sanitizeOptions(language) {
93
108
  if (language) {
94
- return { ...this.#opts, language };
109
+ return { ...this.#opts, language: (0, import_agents.normalizeLanguage)(language) };
95
110
  } else {
96
111
  return this.#opts;
97
112
  }
@@ -138,7 +153,7 @@ class STT extends import_agents.stt.STT {
138
153
  alternatives: [
139
154
  {
140
155
  text: resp.text || "",
141
- language: config.language || "",
156
+ language: (0, import_agents.normalizeLanguage)(config.language || ""),
142
157
  startTime: 0,
143
158
  endTime: 0,
144
159
  confidence: 0
package/dist/stt.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/stt.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { type AudioBuffer, mergeFrames, stt } from '@livekit/agents';\nimport type { AudioFrame } from '@livekit/rtc-node';\nimport { OpenAI } from 'openai';\nimport type { GroqAudioModels, WhisperModels } from './models.js';\n\nexport interface STTOptions {\n apiKey?: string;\n language: string;\n prompt?: string;\n detectLanguage: boolean;\n model: WhisperModels | string;\n baseURL?: string;\n client?: OpenAI;\n}\n\nconst defaultSTTOptions: STTOptions = {\n apiKey: process.env.OPENAI_API_KEY,\n language: 'en',\n detectLanguage: false,\n model: 'whisper-1',\n};\n\nexport class STT extends stt.STT {\n #opts: STTOptions;\n #client: OpenAI;\n label = 'openai.STT';\n\n /**\n * Create a new instance of OpenAI STT.\n *\n * @remarks\n * `apiKey` must be set to your OpenAI API key, either using the argument or by setting the\n * `OPENAI_API_KEY` environment variable.\n */\n constructor(opts: Partial<STTOptions> = defaultSTTOptions) {\n super({ streaming: false, interimResults: false, alignedTranscript: false });\n\n this.#opts = { ...defaultSTTOptions, ...opts };\n if (this.#opts.apiKey === undefined) {\n throw new Error('OpenAI API key is required, whether as an argument or as $OPENAI_API_KEY');\n }\n\n this.#client =\n this.#opts.client ||\n new OpenAI({\n baseURL: this.#opts.baseURL,\n apiKey: this.#opts.apiKey,\n });\n }\n\n /**\n * Create a new instance of Groq STT.\n *\n * @remarks\n * `apiKey` must be set to your Groq API key, either using the argument or by setting the\n * `GROQ_API_KEY` environment variable.\n */\n static withGroq(\n opts: Partial<{\n model: string | GroqAudioModels;\n apiKey?: string;\n baseURL?: string;\n client: OpenAI;\n language: string;\n detectLanguage: boolean;\n }> = {},\n ): STT {\n opts.apiKey = opts.apiKey || process.env.GROQ_API_KEY;\n if (opts.apiKey === undefined) {\n throw new Error('Groq API key is required, whether as an argument or as $GROQ_API_KEY');\n }\n\n return new STT({\n model: 'whisper-large-v3-turbo',\n baseURL: 'https://api.groq.com/openai/v1',\n ...opts,\n });\n }\n\n /**\n * Create a new instance of OVHcloud AI Endpoints STT.\n *\n * @remarks\n * `apiKey` must be set to your OVHcloud AI Endpoints API key, either using the argument or by setting the\n * `OVHCLOUD_API_KEY` environment variable.\n */\n static withOVHcloud(\n opts: Partial<{\n model: string;\n apiKey?: string;\n baseURL?: string;\n client: OpenAI;\n language: string;\n detectLanguage: boolean;\n }> = {},\n ): STT {\n opts.apiKey = opts.apiKey || process.env.OVHCLOUD_API_KEY;\n if (opts.apiKey === undefined) {\n throw new Error(\n 'OVHcloud AI Endpoints API key is required, whether as an argument or as $OVHCLOUD_API_KEY',\n );\n }\n\n return new STT({\n model: 'whisper-large-v3-turbo',\n baseURL: 'https://oai.endpoints.kepler.ai.cloud.ovh.net/v1',\n ...opts,\n });\n }\n\n #sanitizeOptions(language?: string): STTOptions {\n if (language) {\n return { ...this.#opts, language };\n } else {\n return this.#opts;\n }\n }\n\n #createWav(frame: AudioFrame): Buffer {\n const bitsPerSample = 16;\n const byteRate = (frame.sampleRate * frame.channels * bitsPerSample) / 8;\n const blockAlign = (frame.channels * bitsPerSample) / 8;\n\n const header = Buffer.alloc(44);\n header.write('RIFF', 0);\n header.writeUInt32LE(36 + frame.data.byteLength, 4);\n header.write('WAVE', 8);\n header.write('fmt ', 12);\n header.writeUInt32LE(16, 16);\n header.writeUInt16LE(1, 20);\n header.writeUInt16LE(frame.channels, 22);\n header.writeUInt32LE(frame.sampleRate, 24);\n header.writeUInt32LE(byteRate, 28);\n header.writeUInt16LE(blockAlign, 32);\n header.writeUInt16LE(16, 34);\n header.write('data', 36);\n header.writeUInt32LE(frame.data.byteLength, 40);\n return Buffer.concat([header, Buffer.from(frame.data.buffer)]);\n }\n\n async _recognize(buffer: AudioBuffer, abortSignal?: AbortSignal): Promise<stt.SpeechEvent> {\n const config = this.#sanitizeOptions();\n buffer = mergeFrames(buffer);\n const wavBuffer = this.#createWav(buffer);\n const file = new File([new Uint8Array(wavBuffer)], 'audio.wav', { type: 'audio/wav' });\n\n const resp = await this.#client.audio.transcriptions.create(\n {\n file,\n model: this.#opts.model,\n language: config.language,\n prompt: config.prompt,\n response_format: 'json',\n },\n {\n signal: abortSignal,\n },\n );\n\n return {\n type: stt.SpeechEventType.FINAL_TRANSCRIPT,\n alternatives: [\n {\n text: resp.text || '',\n language: config.language || '',\n startTime: 0,\n endTime: 0,\n confidence: 0,\n },\n ],\n };\n }\n\n /** This method throws an error; streaming is unsupported on OpenAI STT. */\n stream(): stt.SpeechStream {\n throw new Error('Streaming is not supported on OpenAI STT');\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,oBAAmD;AAEnD,oBAAuB;AAavB,MAAM,oBAAgC;AAAA,EACpC,QAAQ,QAAQ,IAAI;AAAA,EACpB,UAAU;AAAA,EACV,gBAAgB;AAAA,EAChB,OAAO;AACT;AAEO,MAAM,YAAY,kBAAI,IAAI;AAAA,EAC/B;AAAA,EACA;AAAA,EACA,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASR,YAAY,OAA4B,mBAAmB;AACzD,UAAM,EAAE,WAAW,OAAO,gBAAgB,OAAO,mBAAmB,MAAM,CAAC;AAE3E,SAAK,QAAQ,EAAE,GAAG,mBAAmB,GAAG,KAAK;AAC7C,QAAI,KAAK,MAAM,WAAW,QAAW;AACnC,YAAM,IAAI,MAAM,0EAA0E;AAAA,IAC5F;AAEA,SAAK,UACH,KAAK,MAAM,UACX,IAAI,qBAAO;AAAA,MACT,SAAS,KAAK,MAAM;AAAA,MACpB,QAAQ,KAAK,MAAM;AAAA,IACrB,CAAC;AAAA,EACL;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAO,SACL,OAOK,CAAC,GACD;AACL,SAAK,SAAS,KAAK,UAAU,QAAQ,IAAI;AACzC,QAAI,KAAK,WAAW,QAAW;AAC7B,YAAM,IAAI,MAAM,sEAAsE;AAAA,IACxF;AAEA,WAAO,IAAI,IAAI;AAAA,MACb,OAAO;AAAA,MACP,SAAS;AAAA,MACT,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAO,aACL,OAOK,CAAC,GACD;AACL,SAAK,SAAS,KAAK,UAAU,QAAQ,IAAI;AACzC,QAAI,KAAK,WAAW,QAAW;AAC7B,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,WAAO,IAAI,IAAI;AAAA,MACb,OAAO;AAAA,MACP,SAAS;AAAA,MACT,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AAAA,EAEA,iBAAiB,UAA+B;AAC9C,QAAI,UAAU;AACZ,aAAO,EAAE,GAAG,KAAK,OAAO,SAAS;AAAA,IACnC,OAAO;AACL,aAAO,KAAK;AAAA,IACd;AAAA,EACF;AAAA,EAEA,WAAW,OAA2B;AACpC,UAAM,gBAAgB;AACtB,UAAM,WAAY,MAAM,aAAa,MAAM,WAAW,gBAAiB;AACvE,UAAM,aAAc,MAAM,WAAW,gBAAiB;AAEtD,UAAM,SAAS,OAAO,MAAM,EAAE;AAC9B,WAAO,MAAM,QAAQ,CAAC;AACtB,WAAO,cAAc,KAAK,MAAM,KAAK,YAAY,CAAC;AAClD,WAAO,MAAM,QAAQ,CAAC;AACtB,WAAO,MAAM,QAAQ,EAAE;AACvB,WAAO,cAAc,IAAI,EAAE;AAC3B,WAAO,cAAc,GAAG,EAAE;AAC1B,WAAO,cAAc,MAAM,UAAU,EAAE;AACvC,WAAO,cAAc,MAAM,YAAY,EAAE;AACzC,WAAO,cAAc,UAAU,EAAE;AACjC,WAAO,cAAc,YAAY,EAAE;AACnC,WAAO,cAAc,IAAI,EAAE;AAC3B,WAAO,MAAM,QAAQ,EAAE;AACvB,WAAO,cAAc,MAAM,KAAK,YAAY,EAAE;AAC9C,WAAO,OAAO,OAAO,CAAC,QAAQ,OAAO,KAAK,MAAM,KAAK,MAAM,CAAC,CAAC;AAAA,EAC/D;AAAA,EAEA,MAAM,WAAW,QAAqB,aAAqD;AACzF,UAAM,SAAS,KAAK,iBAAiB;AACrC,iBAAS,2BAAY,MAAM;AAC3B,UAAM,YAAY,KAAK,WAAW,MAAM;AACxC,UAAM,OAAO,IAAI,KAAK,CAAC,IAAI,WAAW,SAAS,CAAC,GAAG,aAAa,EAAE,MAAM,YAAY,CAAC;AAErF,UAAM,OAAO,MAAM,KAAK,QAAQ,MAAM,eAAe;AAAA,MACnD;AAAA,QACE;AAAA,QACA,OAAO,KAAK,MAAM;AAAA,QAClB,UAAU,OAAO;AAAA,QACjB,QAAQ,OAAO;AAAA,QACf,iBAAiB;AAAA,MACnB;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,MACV;AAAA,IACF;AAEA,WAAO;AAAA,MACL,MAAM,kBAAI,gBAAgB;AAAA,MAC1B,cAAc;AAAA,QACZ;AAAA,UACE,MAAM,KAAK,QAAQ;AAAA,UACnB,UAAU,OAAO,YAAY;AAAA,UAC7B,WAAW;AAAA,UACX,SAAS;AAAA,UACT,YAAY;AAAA,QACd;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,SAA2B;AACzB,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/stt.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { type AudioBuffer, mergeFrames, normalizeLanguage, stt } from '@livekit/agents';\nimport type { AudioFrame } from '@livekit/rtc-node';\nimport { OpenAI } from 'openai';\nimport type { GroqAudioModels, WhisperModels } from './models.js';\n\nexport interface STTOptions {\n apiKey?: string;\n language: string;\n prompt?: string;\n detectLanguage: boolean;\n model: WhisperModels | string;\n baseURL?: string;\n client?: OpenAI;\n}\n\nconst defaultSTTOptions: STTOptions = {\n apiKey: process.env.OPENAI_API_KEY,\n language: 'en',\n detectLanguage: false,\n model: 'whisper-1',\n};\n\nexport class STT extends stt.STT {\n #opts: STTOptions;\n #client: OpenAI;\n label = 'openai.STT';\n\n get model(): string {\n return this.#opts.model;\n }\n\n get provider(): string {\n try {\n const url = new URL(this.#client.baseURL);\n return url.host;\n } catch {\n return 'api.openai.com';\n }\n }\n\n /**\n * Create a new instance of OpenAI STT.\n *\n * @remarks\n * `apiKey` must be set to your OpenAI API key, either using the argument or by setting the\n * `OPENAI_API_KEY` environment variable.\n */\n constructor(opts: Partial<STTOptions> = defaultSTTOptions) {\n super({ streaming: false, interimResults: false, alignedTranscript: false });\n\n this.#opts = {\n ...defaultSTTOptions,\n ...opts,\n language: normalizeLanguage(opts.language ?? defaultSTTOptions.language),\n };\n if (this.#opts.apiKey === undefined) {\n throw new Error('OpenAI API key is required, whether as an argument or as $OPENAI_API_KEY');\n }\n\n this.#client =\n this.#opts.client ||\n new OpenAI({\n baseURL: this.#opts.baseURL,\n apiKey: this.#opts.apiKey,\n });\n }\n\n /**\n * Create a new instance of Groq STT.\n *\n * @remarks\n * `apiKey` must be set to your Groq API key, either using the argument or by setting the\n * `GROQ_API_KEY` environment variable.\n */\n static withGroq(\n opts: Partial<{\n model: string | GroqAudioModels;\n apiKey?: string;\n baseURL?: string;\n client: OpenAI;\n language: string;\n detectLanguage: boolean;\n }> = {},\n ): STT {\n opts.apiKey = opts.apiKey || process.env.GROQ_API_KEY;\n if (opts.apiKey === undefined) {\n throw new Error('Groq API key is required, whether as an argument or as $GROQ_API_KEY');\n }\n\n return new STT({\n model: 'whisper-large-v3-turbo',\n baseURL: 'https://api.groq.com/openai/v1',\n ...opts,\n });\n }\n\n /**\n * Create a new instance of OVHcloud AI Endpoints STT.\n *\n * @remarks\n * `apiKey` must be set to your OVHcloud AI Endpoints API key, either using the argument or by setting the\n * `OVHCLOUD_API_KEY` environment variable.\n */\n static withOVHcloud(\n opts: Partial<{\n model: string;\n apiKey?: string;\n baseURL?: string;\n client: OpenAI;\n language: string;\n detectLanguage: boolean;\n }> = {},\n ): STT {\n opts.apiKey = opts.apiKey || process.env.OVHCLOUD_API_KEY;\n if (opts.apiKey === undefined) {\n throw new Error(\n 'OVHcloud AI Endpoints API key is required, whether as an argument or as $OVHCLOUD_API_KEY',\n );\n }\n\n return new STT({\n model: 'whisper-large-v3-turbo',\n baseURL: 'https://oai.endpoints.kepler.ai.cloud.ovh.net/v1',\n ...opts,\n });\n }\n\n #sanitizeOptions(language?: string): STTOptions {\n if (language) {\n return { ...this.#opts, language: normalizeLanguage(language) };\n } else {\n return this.#opts;\n }\n }\n\n #createWav(frame: AudioFrame): Buffer {\n const bitsPerSample = 16;\n const byteRate = (frame.sampleRate * frame.channels * bitsPerSample) / 8;\n const blockAlign = (frame.channels * bitsPerSample) / 8;\n\n const header = Buffer.alloc(44);\n header.write('RIFF', 0);\n header.writeUInt32LE(36 + frame.data.byteLength, 4);\n header.write('WAVE', 8);\n header.write('fmt ', 12);\n header.writeUInt32LE(16, 16);\n header.writeUInt16LE(1, 20);\n header.writeUInt16LE(frame.channels, 22);\n header.writeUInt32LE(frame.sampleRate, 24);\n header.writeUInt32LE(byteRate, 28);\n header.writeUInt16LE(blockAlign, 32);\n header.writeUInt16LE(16, 34);\n header.write('data', 36);\n header.writeUInt32LE(frame.data.byteLength, 40);\n return Buffer.concat([header, Buffer.from(frame.data.buffer)]);\n }\n\n async _recognize(buffer: AudioBuffer, abortSignal?: AbortSignal): Promise<stt.SpeechEvent> {\n const config = this.#sanitizeOptions();\n buffer = mergeFrames(buffer);\n const wavBuffer = this.#createWav(buffer);\n const file = new File([new Uint8Array(wavBuffer)], 'audio.wav', { type: 'audio/wav' });\n\n const resp = await this.#client.audio.transcriptions.create(\n {\n file,\n model: this.#opts.model,\n language: config.language,\n prompt: config.prompt,\n response_format: 'json',\n },\n {\n signal: abortSignal,\n },\n );\n\n return {\n type: stt.SpeechEventType.FINAL_TRANSCRIPT,\n alternatives: [\n {\n text: resp.text || '',\n language: normalizeLanguage(config.language || ''),\n startTime: 0,\n endTime: 0,\n confidence: 0,\n },\n ],\n };\n }\n\n /** This method throws an error; streaming is unsupported on OpenAI STT. */\n stream(): stt.SpeechStream {\n throw new Error('Streaming is not supported on OpenAI STT');\n }\n}\n"],"mappings":"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","names":[]}
package/dist/stt.d.cts CHANGED
@@ -13,6 +13,8 @@ export interface STTOptions {
13
13
  export declare class STT extends stt.STT {
14
14
  #private;
15
15
  label: string;
16
+ get model(): string;
17
+ get provider(): string;
16
18
  /**
17
19
  * Create a new instance of OpenAI STT.
18
20
  *
package/dist/stt.d.ts CHANGED
@@ -13,6 +13,8 @@ export interface STTOptions {
13
13
  export declare class STT extends stt.STT {
14
14
  #private;
15
15
  label: string;
16
+ get model(): string;
17
+ get provider(): string;
16
18
  /**
17
19
  * Create a new instance of OpenAI STT.
18
20
  *
package/dist/stt.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"stt.d.ts","sourceRoot":"","sources":["../src/stt.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,WAAW,EAAe,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAErE,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAElE,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,OAAO,CAAC;IACxB,KAAK,EAAE,aAAa,GAAG,MAAM,CAAC;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AASD,qBAAa,GAAI,SAAQ,GAAG,CAAC,GAAG;;IAG9B,KAAK,SAAgB;IAErB;;;;;;OAMG;gBACS,IAAI,GAAE,OAAO,CAAC,UAAU,CAAqB;IAgBzD;;;;;;OAMG;IACH,MAAM,CAAC,QAAQ,CACb,IAAI,GAAE,OAAO,CAAC;QACZ,KAAK,EAAE,MAAM,GAAG,eAAe,CAAC;QAChC,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,cAAc,EAAE,OAAO,CAAC;KACzB,CAAM,GACN,GAAG;IAaN;;;;;;OAMG;IACH,MAAM,CAAC,YAAY,CACjB,IAAI,GAAE,OAAO,CAAC;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,cAAc,EAAE,OAAO,CAAC;KACzB,CAAM,GACN,GAAG;IA6CA,UAAU,CAAC,MAAM,EAAE,WAAW,EAAE,WAAW,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;IAiC1F,2EAA2E;IAC3E,MAAM,IAAI,GAAG,CAAC,YAAY;CAG3B"}
1
+ {"version":3,"file":"stt.d.ts","sourceRoot":"","sources":["../src/stt.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,WAAW,EAAkC,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAExF,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAElE,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,OAAO,CAAC;IACxB,KAAK,EAAE,aAAa,GAAG,MAAM,CAAC;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AASD,qBAAa,GAAI,SAAQ,GAAG,CAAC,GAAG;;IAG9B,KAAK,SAAgB;IAErB,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,IAAI,QAAQ,IAAI,MAAM,CAOrB;IAED;;;;;;OAMG;gBACS,IAAI,GAAE,OAAO,CAAC,UAAU,CAAqB;IAoBzD;;;;;;OAMG;IACH,MAAM,CAAC,QAAQ,CACb,IAAI,GAAE,OAAO,CAAC;QACZ,KAAK,EAAE,MAAM,GAAG,eAAe,CAAC;QAChC,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,cAAc,EAAE,OAAO,CAAC;KACzB,CAAM,GACN,GAAG;IAaN;;;;;;OAMG;IACH,MAAM,CAAC,YAAY,CACjB,IAAI,GAAE,OAAO,CAAC;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,cAAc,EAAE,OAAO,CAAC;KACzB,CAAM,GACN,GAAG;IA6CA,UAAU,CAAC,MAAM,EAAE,WAAW,EAAE,WAAW,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;IAiC1F,2EAA2E;IAC3E,MAAM,IAAI,GAAG,CAAC,YAAY;CAG3B"}
package/dist/stt.js CHANGED
@@ -1,4 +1,4 @@
1
- import { mergeFrames, stt } from "@livekit/agents";
1
+ import { mergeFrames, normalizeLanguage, stt } from "@livekit/agents";
2
2
  import { OpenAI } from "openai";
3
3
  const defaultSTTOptions = {
4
4
  apiKey: process.env.OPENAI_API_KEY,
@@ -10,6 +10,17 @@ class STT extends stt.STT {
10
10
  #opts;
11
11
  #client;
12
12
  label = "openai.STT";
13
+ get model() {
14
+ return this.#opts.model;
15
+ }
16
+ get provider() {
17
+ try {
18
+ const url = new URL(this.#client.baseURL);
19
+ return url.host;
20
+ } catch {
21
+ return "api.openai.com";
22
+ }
23
+ }
13
24
  /**
14
25
  * Create a new instance of OpenAI STT.
15
26
  *
@@ -19,7 +30,11 @@ class STT extends stt.STT {
19
30
  */
20
31
  constructor(opts = defaultSTTOptions) {
21
32
  super({ streaming: false, interimResults: false, alignedTranscript: false });
22
- this.#opts = { ...defaultSTTOptions, ...opts };
33
+ this.#opts = {
34
+ ...defaultSTTOptions,
35
+ ...opts,
36
+ language: normalizeLanguage(opts.language ?? defaultSTTOptions.language)
37
+ };
23
38
  if (this.#opts.apiKey === void 0) {
24
39
  throw new Error("OpenAI API key is required, whether as an argument or as $OPENAI_API_KEY");
25
40
  }
@@ -68,7 +83,7 @@ class STT extends stt.STT {
68
83
  }
69
84
  #sanitizeOptions(language) {
70
85
  if (language) {
71
- return { ...this.#opts, language };
86
+ return { ...this.#opts, language: normalizeLanguage(language) };
72
87
  } else {
73
88
  return this.#opts;
74
89
  }
@@ -115,7 +130,7 @@ class STT extends stt.STT {
115
130
  alternatives: [
116
131
  {
117
132
  text: resp.text || "",
118
- language: config.language || "",
133
+ language: normalizeLanguage(config.language || ""),
119
134
  startTime: 0,
120
135
  endTime: 0,
121
136
  confidence: 0