@livekit/agents-plugin-openai 0.6.1 → 0.7.1

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 (60) hide show
  1. package/README.md +18 -0
  2. package/dist/index.cjs +55 -0
  3. package/dist/index.cjs.map +1 -0
  4. package/dist/index.js +13 -8
  5. package/dist/index.js.map +1 -1
  6. package/dist/llm.cjs +506 -0
  7. package/dist/llm.cjs.map +1 -0
  8. package/dist/llm.d.ts.map +1 -1
  9. package/dist/llm.js +438 -423
  10. package/dist/llm.js.map +1 -1
  11. package/dist/llm.test.cjs +8 -0
  12. package/dist/llm.test.cjs.map +1 -0
  13. package/dist/llm.test.d.ts +2 -0
  14. package/dist/llm.test.d.ts.map +1 -0
  15. package/dist/llm.test.js +7 -0
  16. package/dist/llm.test.js.map +1 -0
  17. package/dist/models.cjs +17 -0
  18. package/dist/models.cjs.map +1 -0
  19. package/dist/models.js +0 -4
  20. package/dist/models.js.map +1 -1
  21. package/dist/realtime/api_proto.cjs +41 -0
  22. package/dist/realtime/api_proto.cjs.map +1 -0
  23. package/dist/realtime/api_proto.js +12 -8
  24. package/dist/realtime/api_proto.js.map +1 -1
  25. package/dist/realtime/index.cjs +25 -0
  26. package/dist/realtime/index.cjs.map +1 -0
  27. package/dist/realtime/index.js +2 -5
  28. package/dist/realtime/index.js.map +1 -1
  29. package/dist/realtime/realtime_model.cjs +878 -0
  30. package/dist/realtime/realtime_model.cjs.map +1 -0
  31. package/dist/realtime/realtime_model.js +828 -777
  32. package/dist/realtime/realtime_model.js.map +1 -1
  33. package/dist/stt.cjs +130 -0
  34. package/dist/stt.cjs.map +1 -0
  35. package/dist/stt.js +99 -102
  36. package/dist/stt.js.map +1 -1
  37. package/dist/stt.test.cjs +9 -0
  38. package/dist/stt.test.cjs.map +1 -0
  39. package/dist/stt.test.d.ts +2 -0
  40. package/dist/stt.test.d.ts.map +1 -0
  41. package/dist/stt.test.js +8 -0
  42. package/dist/stt.test.js.map +1 -0
  43. package/dist/tts.cjs +100 -0
  44. package/dist/tts.cjs.map +1 -0
  45. package/dist/tts.d.ts +1 -1
  46. package/dist/tts.d.ts.map +1 -1
  47. package/dist/tts.js +67 -65
  48. package/dist/tts.js.map +1 -1
  49. package/dist/tts.test.cjs +9 -0
  50. package/dist/tts.test.cjs.map +1 -0
  51. package/dist/tts.test.d.ts +2 -0
  52. package/dist/tts.test.d.ts.map +1 -0
  53. package/dist/tts.test.js +8 -0
  54. package/dist/tts.test.js.map +1 -0
  55. package/package.json +20 -8
  56. package/src/llm.test.ts +10 -0
  57. package/src/llm.ts +7 -2
  58. package/src/stt.test.ts +11 -0
  59. package/src/tts.test.ts +11 -0
  60. package/src/tts.ts +2 -1
package/README.md ADDED
@@ -0,0 +1,18 @@
1
+ <!--
2
+ SPDX-FileCopyrightText: 2024 LiveKit, Inc.
3
+
4
+ SPDX-License-Identifier: Apache-2.0
5
+ -->
6
+ # OpenAI plugin for LiveKit Agents
7
+
8
+ The Agents Framework is designed for building realtime, programmable
9
+ participants that run on servers. Use it to create conversational, multi-modal
10
+ voice agents that can see, hear, and understand.
11
+
12
+ This package contains the OpenAI plugin, which allows for TTS, STT, LLM, as well
13
+ as using the Realtime API. Refer to the
14
+ [documentation](https://docs.livekit.io/agents/overview/) for information on how
15
+ to use it, or browse the [API
16
+ reference](https://docs.livekit.io/agents-js/modules/plugins_agents_plugin_openai.html).
17
+ See the [repository](https://github.com/livekit/agents-js) for more information
18
+ about the framework as a whole.
package/dist/index.cjs ADDED
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
21
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
+ // If the importer is in node compatibility mode or this is not an ESM
23
+ // file that has been converted to a CommonJS file using a Babel-
24
+ // compatible transform (i.e. "__esModule" has not been set), then set
25
+ // "default" to the CommonJS "module.exports" for node compatibility.
26
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
+ mod
28
+ ));
29
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
+ var src_exports = {};
31
+ __export(src_exports, {
32
+ ChunkedStream: () => import_tts.ChunkedStream,
33
+ LLM: () => import_llm.LLM,
34
+ LLMStream: () => import_llm.LLMStream,
35
+ STT: () => import_stt.STT,
36
+ TTS: () => import_tts.TTS,
37
+ realtime: () => realtime
38
+ });
39
+ module.exports = __toCommonJS(src_exports);
40
+ var realtime = __toESM(require("./realtime/index.cjs"), 1);
41
+ __reExport(src_exports, require("./models.cjs"), module.exports);
42
+ var import_llm = require("./llm.cjs");
43
+ var import_stt = require("./stt.cjs");
44
+ var import_tts = require("./tts.cjs");
45
+ // Annotate the CommonJS export names for ESM import in node:
46
+ 0 && (module.exports = {
47
+ ChunkedStream,
48
+ LLM,
49
+ LLMStream,
50
+ STT,
51
+ TTS,
52
+ realtime,
53
+ ...require("./models.cjs")
54
+ });
55
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nexport * as realtime from './realtime/index.js';\nexport * from './models.js';\nexport { type LLMOptions, LLM, LLMStream } from './llm.js';\nexport { type STTOptions, STT } from './stt.js';\nexport { type TTSOptions, TTS, ChunkedStream } from './tts.js';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,eAA0B;AAC1B,wBAAc,wBAJd;AAKA,iBAAgD;AAChD,iBAAqC;AACrC,iBAAoD;","names":[]}
package/dist/index.js CHANGED
@@ -1,9 +1,14 @@
1
- // SPDX-FileCopyrightText: 2024 LiveKit, Inc.
2
- //
3
- // SPDX-License-Identifier: Apache-2.0
4
- export * as realtime from './realtime/index.js';
5
- export * from './models.js';
6
- export { LLM, LLMStream } from './llm.js';
7
- export { STT } from './stt.js';
8
- export { TTS, ChunkedStream } from './tts.js';
1
+ import * as realtime from "./realtime/index.js";
2
+ export * from "./models.js";
3
+ import { LLM, LLMStream } from "./llm.js";
4
+ import { STT } from "./stt.js";
5
+ import { TTS, ChunkedStream } from "./tts.js";
6
+ export {
7
+ ChunkedStream,
8
+ LLM,
9
+ LLMStream,
10
+ STT,
11
+ TTS,
12
+ realtime
13
+ };
9
14
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,EAAE;AACF,sCAAsC;AACtC,OAAO,KAAK,QAAQ,MAAM,qBAAqB,CAAC;AAChD,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAmB,GAAG,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAC3D,OAAO,EAAmB,GAAG,EAAE,MAAM,UAAU,CAAC;AAChD,OAAO,EAAmB,GAAG,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC"}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nexport * as realtime from './realtime/index.js';\nexport * from './models.js';\nexport { type LLMOptions, LLM, LLMStream } from './llm.js';\nexport { type STTOptions, STT } from './stt.js';\nexport { type TTSOptions, TTS, ChunkedStream } from './tts.js';\n"],"mappings":"AAGA,YAAY,cAAc;AAC1B,cAAc;AACd,SAA0B,KAAK,iBAAiB;AAChD,SAA0B,WAAW;AACrC,SAA0B,KAAK,qBAAqB;","names":[]}
package/dist/llm.cjs ADDED
@@ -0,0 +1,506 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var llm_exports = {};
30
+ __export(llm_exports, {
31
+ LLM: () => LLM,
32
+ LLMStream: () => LLMStream
33
+ });
34
+ module.exports = __toCommonJS(llm_exports);
35
+ var import_agents = require("@livekit/agents");
36
+ var import_node_crypto = require("node:crypto");
37
+ var import_openai = require("openai");
38
+ var import_sharp = __toESM(require("sharp"), 1);
39
+ const defaultLLMOptions = {
40
+ model: "gpt-4o",
41
+ apiKey: process.env.OPENAI_API_KEY
42
+ };
43
+ const defaultAzureLLMOptions = {
44
+ model: "gpt-4o",
45
+ apiKey: process.env.AZURE_API_KEY
46
+ };
47
+ class LLM extends import_agents.llm.LLM {
48
+ #opts;
49
+ #client;
50
+ /**
51
+ * Create a new instance of OpenAI LLM.
52
+ *
53
+ * @remarks
54
+ * `apiKey` must be set to your OpenAI API key, either using the argument or by setting the
55
+ * `OPENAI_API_KEY` environmental variable.
56
+ */
57
+ constructor(opts = defaultLLMOptions) {
58
+ super();
59
+ this.#opts = { ...defaultLLMOptions, ...opts };
60
+ if (this.#opts.apiKey === void 0) {
61
+ throw new Error("OpenAI API key is required, whether as an argument or as $OPENAI_API_KEY");
62
+ }
63
+ this.#client = this.#opts.client || new import_openai.OpenAI({
64
+ baseURL: opts.baseURL,
65
+ apiKey: opts.apiKey
66
+ });
67
+ }
68
+ /**
69
+ * Create a new instance of OpenAI LLM with Azure.
70
+ *
71
+ * @remarks
72
+ * This automatically infers the following arguments from their corresponding environment variables if they are not provided:
73
+ * - `apiKey` from `AZURE_OPENAI_API_KEY`
74
+ * - `organization` from `OPENAI_ORG_ID`
75
+ * - `project` from `OPENAI_PROJECT_ID`
76
+ * - `azureAdToken` from `AZURE_OPENAI_AD_TOKEN`
77
+ * - `apiVersion` from `OPENAI_API_VERSION`
78
+ * - `azureEndpoint` from `AZURE_OPENAI_ENDPOINT`
79
+ */
80
+ static withAzure(opts = defaultAzureLLMOptions) {
81
+ opts = { ...defaultLLMOptions, ...opts };
82
+ if (opts.apiKey === void 0) {
83
+ throw new Error("Azure API key is required, whether as an argument or as $AZURE_API_KEY");
84
+ }
85
+ return new LLM({
86
+ temperature: opts.temperature,
87
+ user: opts.user,
88
+ client: new import_openai.AzureOpenAI(opts)
89
+ });
90
+ }
91
+ /**
92
+ * Create a new instance of Cerebras LLM.
93
+ *
94
+ * @remarks
95
+ * `apiKey` must be set to your Cerebras API key, either using the argument or by setting the
96
+ * `CEREBRAS_API_KEY` environmental variable.
97
+ */
98
+ static withCerebras(opts = {}) {
99
+ opts.apiKey = opts.apiKey || process.env.CEREBRAS_API_KEY;
100
+ if (opts.apiKey === void 0) {
101
+ throw new Error(
102
+ "Cerebras API key is required, whether as an argument or as $CEREBRAS_API_KEY"
103
+ );
104
+ }
105
+ return new LLM({
106
+ model: "llama3.1-8b",
107
+ baseURL: "https://api.cerebras.ai/v1",
108
+ ...opts
109
+ });
110
+ }
111
+ /**
112
+ * Create a new instance of Fireworks LLM.
113
+ *
114
+ * @remarks
115
+ * `apiKey` must be set to your Fireworks API key, either using the argument or by setting the
116
+ * `FIREWORKS_API_KEY` environmental variable.
117
+ */
118
+ static withFireworks(opts = {}) {
119
+ opts.apiKey = opts.apiKey || process.env.FIREWORKS_API_KEY;
120
+ if (opts.apiKey === void 0) {
121
+ throw new Error(
122
+ "Fireworks API key is required, whether as an argument or as $FIREWORKS_API_KEY"
123
+ );
124
+ }
125
+ return new LLM({
126
+ model: "accounts/fireworks/models/llama-v3p1-70b-instruct",
127
+ baseURL: "https://api.fireworks.ai/inference/v1",
128
+ ...opts
129
+ });
130
+ }
131
+ /**
132
+ * Create a new instance of xAI LLM.
133
+ *
134
+ * @remarks
135
+ * `apiKey` must be set to your xAI API key, either using the argument or by setting the
136
+ * `XAI_API_KEY` environmental variable.
137
+ */
138
+ static withXAI(opts = {}) {
139
+ opts.apiKey = opts.apiKey || process.env.XAI_API_KEY;
140
+ if (opts.apiKey === void 0) {
141
+ throw new Error("xAI API key is required, whether as an argument or as $XAI_API_KEY");
142
+ }
143
+ return new LLM({
144
+ model: "grok-2-public",
145
+ baseURL: "https://api.x.ai/v1",
146
+ ...opts
147
+ });
148
+ }
149
+ /**
150
+ * Create a new instance of Groq LLM.
151
+ *
152
+ * @remarks
153
+ * `apiKey` must be set to your Groq API key, either using the argument or by setting the
154
+ * `GROQ_API_KEY` environmental variable.
155
+ */
156
+ static withGroq(opts = {}) {
157
+ opts.apiKey = opts.apiKey || process.env.GROQ_API_KEY;
158
+ if (opts.apiKey === void 0) {
159
+ throw new Error("Groq API key is required, whether as an argument or as $GROQ_API_KEY");
160
+ }
161
+ return new LLM({
162
+ model: "llama3-8b-8192",
163
+ baseURL: "https://api.groq.com/openai/v1",
164
+ ...opts
165
+ });
166
+ }
167
+ /**
168
+ * Create a new instance of DeepSeek LLM.
169
+ *
170
+ * @remarks
171
+ * `apiKey` must be set to your DeepSeek API key, either using the argument or by setting the
172
+ * `DEEPSEEK_API_KEY` environmental variable.
173
+ */
174
+ static withDeepSeek(opts = {}) {
175
+ opts.apiKey = opts.apiKey || process.env.DEEPSEEK_API_KEY;
176
+ if (opts.apiKey === void 0) {
177
+ throw new Error(
178
+ "DeepSeek API key is required, whether as an argument or as $DEEPSEEK_API_KEY"
179
+ );
180
+ }
181
+ return new LLM({
182
+ model: "deepseek-chat",
183
+ baseURL: "https://api.deepseek.com/v1",
184
+ ...opts
185
+ });
186
+ }
187
+ /**
188
+ * Create a new instance of OctoAI LLM.
189
+ *
190
+ * @remarks
191
+ * `apiKey` must be set to your OctoAI API key, either using the argument or by setting the
192
+ * `OCTOAI_TOKEN` environmental variable.
193
+ */
194
+ static withOcto(opts = {}) {
195
+ opts.apiKey = opts.apiKey || process.env.OCTOAI_TOKEN;
196
+ if (opts.apiKey === void 0) {
197
+ throw new Error("OctoAI API key is required, whether as an argument or as $OCTOAI_TOKEN");
198
+ }
199
+ return new LLM({
200
+ model: "llama-2-13b-chat",
201
+ baseURL: "https://text.octoai.run/v1",
202
+ ...opts
203
+ });
204
+ }
205
+ /** Create a new instance of Ollama LLM. */
206
+ static withOllama(opts = {}) {
207
+ return new LLM({
208
+ model: "llama-2-13b-chat",
209
+ baseURL: "https://text.octoai.run/v1",
210
+ apiKey: "ollama",
211
+ ...opts
212
+ });
213
+ }
214
+ /**
215
+ * Create a new instance of PerplexityAI LLM.
216
+ *
217
+ * @remarks
218
+ * `apiKey` must be set to your PerplexityAI API key, either using the argument or by setting the
219
+ * `PERPLEXITY_API_KEY` environmental variable.
220
+ */
221
+ static withPerplexity(opts = {}) {
222
+ opts.apiKey = opts.apiKey || process.env.PERPLEXITY_API_KEY;
223
+ if (opts.apiKey === void 0) {
224
+ throw new Error(
225
+ "PerplexityAI API key is required, whether as an argument or as $PERPLEXITY_API_KEY"
226
+ );
227
+ }
228
+ return new LLM({
229
+ model: "llama-3.1-sonar-small-128k-chat",
230
+ baseURL: "https://api.perplexity.ai",
231
+ ...opts
232
+ });
233
+ }
234
+ /**
235
+ * Create a new instance of TogetherAI LLM.
236
+ *
237
+ * @remarks
238
+ * `apiKey` must be set to your TogetherAI API key, either using the argument or by setting the
239
+ * `TOGETHER_API_KEY` environmental variable.
240
+ */
241
+ static withTogether(opts = {}) {
242
+ opts.apiKey = opts.apiKey || process.env.TOGETHER_API_KEY;
243
+ if (opts.apiKey === void 0) {
244
+ throw new Error(
245
+ "TogetherAI API key is required, whether as an argument or as $TOGETHER_API_KEY"
246
+ );
247
+ }
248
+ return new LLM({
249
+ model: "meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo",
250
+ baseURL: "https://api.together.xyz/v1",
251
+ ...opts
252
+ });
253
+ }
254
+ /**
255
+ * Create a new instance of Telnyx LLM.
256
+ *
257
+ * @remarks
258
+ * `apiKey` must be set to your Telnyx API key, either using the argument or by setting the
259
+ * `TELNYX_API_KEY` environmental variable.
260
+ */
261
+ static withTelnyx(opts = {}) {
262
+ opts.apiKey = opts.apiKey || process.env.TELNYX_API_KEY;
263
+ if (opts.apiKey === void 0) {
264
+ throw new Error("Telnyx API key is required, whether as an argument or as $TELNYX_API_KEY");
265
+ }
266
+ return new LLM({
267
+ model: "meta-llama/Meta-Llama-3.1-70B-Instruct",
268
+ baseURL: "https://api.telnyx.com/v2/ai",
269
+ ...opts
270
+ });
271
+ }
272
+ chat({
273
+ chatCtx,
274
+ fncCtx,
275
+ temperature,
276
+ n,
277
+ parallelToolCalls
278
+ }) {
279
+ temperature = temperature || this.#opts.temperature;
280
+ return new LLMStream(
281
+ this.#client,
282
+ chatCtx,
283
+ fncCtx,
284
+ this.#opts,
285
+ parallelToolCalls,
286
+ temperature,
287
+ n
288
+ );
289
+ }
290
+ }
291
+ class LLMStream extends import_agents.llm.LLMStream {
292
+ #toolCallId;
293
+ #fncName;
294
+ #fncRawArguments;
295
+ #client;
296
+ #logger = (0, import_agents.log)();
297
+ #id = (0, import_node_crypto.randomUUID)();
298
+ constructor(client, chatCtx, fncCtx, opts, parallelToolCalls, temperature, n) {
299
+ super(chatCtx, fncCtx);
300
+ this.#client = client;
301
+ this.#run(opts, n, parallelToolCalls, temperature);
302
+ }
303
+ async #run(opts, n, parallelToolCalls, temperature) {
304
+ const tools = this.fncCtx ? Object.entries(this.fncCtx).map(([name, func]) => ({
305
+ type: "function",
306
+ function: {
307
+ name,
308
+ description: func.description,
309
+ // don't format parameters if they are raw openai params
310
+ parameters: func.parameters.type == "object" ? func.parameters : import_agents.llm.oaiParams(func.parameters)
311
+ }
312
+ })) : void 0;
313
+ try {
314
+ const stream = await this.#client.chat.completions.create({
315
+ model: opts.model,
316
+ user: opts.user,
317
+ n,
318
+ messages: await Promise.all(
319
+ this.chatCtx.messages.map(async (m) => await buildMessage(m, this.#id))
320
+ ),
321
+ temperature: temperature || opts.temperature,
322
+ stream_options: { include_usage: true },
323
+ stream: true,
324
+ tools,
325
+ parallel_tool_calls: this.fncCtx && parallelToolCalls
326
+ });
327
+ for await (const chunk of stream) {
328
+ for (const choice of chunk.choices) {
329
+ const chatChunk = this.#parseChoice(chunk.id, choice);
330
+ if (chatChunk) {
331
+ this.queue.put(chatChunk);
332
+ }
333
+ if (chunk.usage) {
334
+ const usage = chunk.usage;
335
+ this.queue.put({
336
+ requestId: chunk.id,
337
+ choices: [],
338
+ usage: {
339
+ completionTokens: usage.completion_tokens,
340
+ promptTokens: usage.prompt_tokens,
341
+ totalTokens: usage.total_tokens
342
+ }
343
+ });
344
+ }
345
+ }
346
+ }
347
+ } finally {
348
+ this.queue.close();
349
+ }
350
+ }
351
+ #parseChoice(id, choice) {
352
+ const delta = choice.delta;
353
+ if (delta.tool_calls) {
354
+ for (const tool of delta.tool_calls) {
355
+ if (!tool.function) {
356
+ continue;
357
+ }
358
+ let callChunk;
359
+ if (this.#toolCallId && tool.id && tool.id !== this.#toolCallId) {
360
+ callChunk = this.#tryBuildFunction(id, choice);
361
+ }
362
+ if (tool.function.name) {
363
+ this.#toolCallId = tool.id;
364
+ this.#fncName = tool.function.name;
365
+ this.#fncRawArguments = tool.function.arguments || "";
366
+ } else if (tool.function.arguments) {
367
+ this.#fncRawArguments += tool.function.arguments;
368
+ }
369
+ if (callChunk) {
370
+ return callChunk;
371
+ }
372
+ }
373
+ }
374
+ if (choice.finish_reason && ["tool_calls", "stop"].includes(choice.finish_reason) && this.#toolCallId) {
375
+ return this.#tryBuildFunction(id, choice);
376
+ }
377
+ return {
378
+ requestId: id,
379
+ choices: [
380
+ {
381
+ delta: { content: delta.content || void 0, role: import_agents.llm.ChatRole.ASSISTANT },
382
+ index: choice.index
383
+ }
384
+ ]
385
+ };
386
+ }
387
+ #tryBuildFunction(id, choice) {
388
+ if (!this.fncCtx) {
389
+ this.#logger.warn("oai stream tried to run function without function context");
390
+ return void 0;
391
+ }
392
+ if (!this.#toolCallId) {
393
+ this.#logger.warn("oai stream tried to run function but toolCallId is not set");
394
+ return void 0;
395
+ }
396
+ if (!this.#fncRawArguments || !this.#fncName) {
397
+ this.#logger.warn("oai stream tried to run function but rawArguments or fncName are not set");
398
+ return void 0;
399
+ }
400
+ const functionInfo = import_agents.llm.oaiBuildFunctionInfo(
401
+ this.fncCtx,
402
+ this.#toolCallId,
403
+ this.#fncName,
404
+ this.#fncRawArguments
405
+ );
406
+ this.#toolCallId = this.#fncName = this.#fncRawArguments = void 0;
407
+ this._functionCalls.push(functionInfo);
408
+ return {
409
+ requestId: id,
410
+ choices: [
411
+ {
412
+ delta: {
413
+ content: choice.delta.content || void 0,
414
+ role: import_agents.llm.ChatRole.ASSISTANT,
415
+ toolCalls: this._functionCalls
416
+ },
417
+ index: choice.index
418
+ }
419
+ ]
420
+ };
421
+ }
422
+ }
423
+ const buildMessage = async (msg, cacheKey) => {
424
+ const oaiMsg = {};
425
+ switch (msg.role) {
426
+ case import_agents.llm.ChatRole.SYSTEM:
427
+ oaiMsg.role = "system";
428
+ break;
429
+ case import_agents.llm.ChatRole.USER:
430
+ oaiMsg.role = "user";
431
+ break;
432
+ case import_agents.llm.ChatRole.ASSISTANT:
433
+ oaiMsg.role = "assistant";
434
+ break;
435
+ case import_agents.llm.ChatRole.TOOL:
436
+ oaiMsg.role = "tool";
437
+ if (oaiMsg.role === "tool") {
438
+ oaiMsg.tool_call_id = msg.toolCallId;
439
+ }
440
+ break;
441
+ }
442
+ if (typeof msg.content === "string") {
443
+ oaiMsg.content = msg.content;
444
+ } else if (((c) => {
445
+ return c.length !== void 0;
446
+ })(msg.content)) {
447
+ oaiMsg.content = await Promise.all(
448
+ msg.content.map(async (c) => {
449
+ if (typeof c === "string") {
450
+ return { type: "text", text: c };
451
+ } else if (
452
+ // typescript type guard for determining ChatAudio vs ChatImage
453
+ ((c2) => {
454
+ return c2.image !== void 0;
455
+ })(c)
456
+ ) {
457
+ return await buildImageContent(c, cacheKey);
458
+ } else {
459
+ throw new Error("ChatAudio is not supported");
460
+ }
461
+ })
462
+ );
463
+ }
464
+ if (msg.toolCalls && oaiMsg.role === "assistant") {
465
+ oaiMsg.tool_calls = Object.entries(msg.toolCalls).map(([name, func]) => ({
466
+ id: func.toolCallId,
467
+ type: "function",
468
+ function: {
469
+ name,
470
+ arguments: func.rawParams
471
+ }
472
+ }));
473
+ }
474
+ return oaiMsg;
475
+ };
476
+ const buildImageContent = async (image, cacheKey) => {
477
+ if (typeof image.image === "string") {
478
+ return {
479
+ type: "image_url",
480
+ image_url: {
481
+ url: image.image,
482
+ detail: "auto"
483
+ }
484
+ };
485
+ } else {
486
+ if (!image.cache[cacheKey]) {
487
+ let encoded = (0, import_sharp.default)(image.image.data);
488
+ if (image.inferenceHeight && image.inferenceHeight) {
489
+ encoded = encoded.resize(image.inferenceWidth, image.inferenceHeight);
490
+ }
491
+ image.cache[cacheKey] = await encoded.jpeg().toBuffer().then((buffer) => buffer.toString("utf-8"));
492
+ }
493
+ return {
494
+ type: "image_url",
495
+ image_url: {
496
+ url: `data:image/jpeg;base64,${image.cache[cacheKey]}`
497
+ }
498
+ };
499
+ }
500
+ };
501
+ // Annotate the CommonJS export names for ESM import in node:
502
+ 0 && (module.exports = {
503
+ LLM,
504
+ LLMStream
505
+ });
506
+ //# sourceMappingURL=llm.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/llm.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { llm, log } from '@livekit/agents';\nimport { randomUUID } from 'node:crypto';\nimport { AzureOpenAI, OpenAI } from 'openai';\nimport sharp from 'sharp';\nimport type {\n CerebrasChatModels,\n ChatModels,\n DeepSeekChatModels,\n GroqChatModels,\n OctoChatModels,\n PerplexityChatModels,\n TelnyxChatModels,\n TogetherChatModels,\n XAIChatModels,\n} from './models.js';\n\nexport interface LLMOptions {\n model: string | ChatModels;\n apiKey?: string;\n baseURL?: string;\n user?: string;\n temperature?: number;\n client?: OpenAI;\n}\n\nconst defaultLLMOptions: LLMOptions = {\n model: 'gpt-4o',\n apiKey: process.env.OPENAI_API_KEY,\n};\n\nconst defaultAzureLLMOptions: LLMOptions = {\n model: 'gpt-4o',\n apiKey: process.env.AZURE_API_KEY,\n};\n\nexport class LLM extends llm.LLM {\n #opts: LLMOptions;\n #client: OpenAI;\n\n /**\n * Create a new instance of OpenAI 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` environmental 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: opts.baseURL,\n apiKey: opts.apiKey,\n });\n }\n\n /**\n * Create a new instance of OpenAI LLM with Azure.\n *\n * @remarks\n * This automatically infers the following arguments from their corresponding environment variables if they are not provided:\n * - `apiKey` from `AZURE_OPENAI_API_KEY`\n * - `organization` from `OPENAI_ORG_ID`\n * - `project` from `OPENAI_PROJECT_ID`\n * - `azureAdToken` from `AZURE_OPENAI_AD_TOKEN`\n * - `apiVersion` from `OPENAI_API_VERSION`\n * - `azureEndpoint` from `AZURE_OPENAI_ENDPOINT`\n */\n static withAzure(\n opts: {\n model: string | ChatModels;\n azureEndpoint?: string;\n azureDeployment?: string;\n apiVersion?: string;\n apiKey?: string;\n azureAdToken?: string;\n azureAdTokenProvider?: () => Promise<string>;\n organization?: string;\n project?: string;\n baseURL?: string;\n user?: string;\n temperature?: number;\n } = defaultAzureLLMOptions,\n ): LLM {\n opts = { ...defaultLLMOptions, ...opts };\n if (opts.apiKey === undefined) {\n throw new Error('Azure API key is required, whether as an argument or as $AZURE_API_KEY');\n }\n\n return new LLM({\n temperature: opts.temperature,\n user: opts.user,\n client: new AzureOpenAI(opts),\n });\n }\n\n /**\n * Create a new instance of Cerebras LLM.\n *\n * @remarks\n * `apiKey` must be set to your Cerebras API key, either using the argument or by setting the\n * `CEREBRAS_API_KEY` environmental variable.\n */\n static withCerebras(\n opts: Partial<{\n model: string | CerebrasChatModels;\n apiKey?: string;\n baseURL?: string;\n user?: string;\n temperature?: number;\n client: OpenAI;\n }> = {},\n ): LLM {\n opts.apiKey = opts.apiKey || process.env.CEREBRAS_API_KEY;\n if (opts.apiKey === undefined) {\n throw new Error(\n 'Cerebras API key is required, whether as an argument or as $CEREBRAS_API_KEY',\n );\n }\n\n return new LLM({\n model: 'llama3.1-8b',\n baseURL: 'https://api.cerebras.ai/v1',\n ...opts,\n });\n }\n\n /**\n * Create a new instance of Fireworks LLM.\n *\n * @remarks\n * `apiKey` must be set to your Fireworks API key, either using the argument or by setting the\n * `FIREWORKS_API_KEY` environmental variable.\n */\n static withFireworks(opts: Partial<LLMOptions> = {}): LLM {\n opts.apiKey = opts.apiKey || process.env.FIREWORKS_API_KEY;\n if (opts.apiKey === undefined) {\n throw new Error(\n 'Fireworks API key is required, whether as an argument or as $FIREWORKS_API_KEY',\n );\n }\n\n return new LLM({\n model: 'accounts/fireworks/models/llama-v3p1-70b-instruct',\n baseURL: 'https://api.fireworks.ai/inference/v1',\n ...opts,\n });\n }\n\n /**\n * Create a new instance of xAI LLM.\n *\n * @remarks\n * `apiKey` must be set to your xAI API key, either using the argument or by setting the\n * `XAI_API_KEY` environmental variable.\n */\n static withXAI(\n opts: Partial<{\n model: string | XAIChatModels;\n apiKey?: string;\n baseURL?: string;\n user?: string;\n temperature?: number;\n client: OpenAI;\n }> = {},\n ): LLM {\n opts.apiKey = opts.apiKey || process.env.XAI_API_KEY;\n if (opts.apiKey === undefined) {\n throw new Error('xAI API key is required, whether as an argument or as $XAI_API_KEY');\n }\n\n return new LLM({\n model: 'grok-2-public',\n baseURL: 'https://api.x.ai/v1',\n ...opts,\n });\n }\n\n /**\n * Create a new instance of Groq LLM.\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` environmental variable.\n */\n static withGroq(\n opts: Partial<{\n model: string | GroqChatModels;\n apiKey?: string;\n baseURL?: string;\n user?: string;\n temperature?: number;\n client: OpenAI;\n }> = {},\n ): LLM {\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 LLM({\n model: 'llama3-8b-8192',\n baseURL: 'https://api.groq.com/openai/v1',\n ...opts,\n });\n }\n\n /**\n * Create a new instance of DeepSeek LLM.\n *\n * @remarks\n * `apiKey` must be set to your DeepSeek API key, either using the argument or by setting the\n * `DEEPSEEK_API_KEY` environmental variable.\n */\n static withDeepSeek(\n opts: Partial<{\n model: string | DeepSeekChatModels;\n apiKey?: string;\n baseURL?: string;\n user?: string;\n temperature?: number;\n client: OpenAI;\n }> = {},\n ): LLM {\n opts.apiKey = opts.apiKey || process.env.DEEPSEEK_API_KEY;\n if (opts.apiKey === undefined) {\n throw new Error(\n 'DeepSeek API key is required, whether as an argument or as $DEEPSEEK_API_KEY',\n );\n }\n\n return new LLM({\n model: 'deepseek-chat',\n baseURL: 'https://api.deepseek.com/v1',\n ...opts,\n });\n }\n\n /**\n * Create a new instance of OctoAI LLM.\n *\n * @remarks\n * `apiKey` must be set to your OctoAI API key, either using the argument or by setting the\n * `OCTOAI_TOKEN` environmental variable.\n */\n static withOcto(\n opts: Partial<{\n model: string | OctoChatModels;\n apiKey?: string;\n baseURL?: string;\n user?: string;\n temperature?: number;\n client: OpenAI;\n }> = {},\n ): LLM {\n opts.apiKey = opts.apiKey || process.env.OCTOAI_TOKEN;\n if (opts.apiKey === undefined) {\n throw new Error('OctoAI API key is required, whether as an argument or as $OCTOAI_TOKEN');\n }\n\n return new LLM({\n model: 'llama-2-13b-chat',\n baseURL: 'https://text.octoai.run/v1',\n ...opts,\n });\n }\n\n /** Create a new instance of Ollama LLM. */\n static withOllama(\n opts: Partial<{\n model: string;\n baseURL?: string;\n temperature?: number;\n client: OpenAI;\n }> = {},\n ): LLM {\n return new LLM({\n model: 'llama-2-13b-chat',\n baseURL: 'https://text.octoai.run/v1',\n apiKey: 'ollama',\n ...opts,\n });\n }\n\n /**\n * Create a new instance of PerplexityAI LLM.\n *\n * @remarks\n * `apiKey` must be set to your PerplexityAI API key, either using the argument or by setting the\n * `PERPLEXITY_API_KEY` environmental variable.\n */\n static withPerplexity(\n opts: Partial<{\n model: string | PerplexityChatModels;\n apiKey?: string;\n baseURL?: string;\n user?: string;\n temperature?: number;\n client: OpenAI;\n }> = {},\n ): LLM {\n opts.apiKey = opts.apiKey || process.env.PERPLEXITY_API_KEY;\n if (opts.apiKey === undefined) {\n throw new Error(\n 'PerplexityAI API key is required, whether as an argument or as $PERPLEXITY_API_KEY',\n );\n }\n\n return new LLM({\n model: 'llama-3.1-sonar-small-128k-chat',\n baseURL: 'https://api.perplexity.ai',\n ...opts,\n });\n }\n\n /**\n * Create a new instance of TogetherAI LLM.\n *\n * @remarks\n * `apiKey` must be set to your TogetherAI API key, either using the argument or by setting the\n * `TOGETHER_API_KEY` environmental variable.\n */\n static withTogether(\n opts: Partial<{\n model: string | TogetherChatModels;\n apiKey?: string;\n baseURL?: string;\n user?: string;\n temperature?: number;\n client: OpenAI;\n }> = {},\n ): LLM {\n opts.apiKey = opts.apiKey || process.env.TOGETHER_API_KEY;\n if (opts.apiKey === undefined) {\n throw new Error(\n 'TogetherAI API key is required, whether as an argument or as $TOGETHER_API_KEY',\n );\n }\n\n return new LLM({\n model: 'meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo',\n baseURL: 'https://api.together.xyz/v1',\n ...opts,\n });\n }\n\n /**\n * Create a new instance of Telnyx LLM.\n *\n * @remarks\n * `apiKey` must be set to your Telnyx API key, either using the argument or by setting the\n * `TELNYX_API_KEY` environmental variable.\n */\n static withTelnyx(\n opts: Partial<{\n model: string | TelnyxChatModels;\n apiKey?: string;\n baseURL?: string;\n user?: string;\n temperature?: number;\n client: OpenAI;\n }> = {},\n ): LLM {\n opts.apiKey = opts.apiKey || process.env.TELNYX_API_KEY;\n if (opts.apiKey === undefined) {\n throw new Error('Telnyx API key is required, whether as an argument or as $TELNYX_API_KEY');\n }\n\n return new LLM({\n model: 'meta-llama/Meta-Llama-3.1-70B-Instruct',\n baseURL: 'https://api.telnyx.com/v2/ai',\n ...opts,\n });\n }\n\n chat({\n chatCtx,\n fncCtx,\n temperature,\n n,\n parallelToolCalls,\n }: {\n chatCtx: llm.ChatContext;\n fncCtx?: llm.FunctionContext | undefined;\n temperature?: number | undefined;\n n?: number | undefined;\n parallelToolCalls?: boolean | undefined;\n }): LLMStream {\n temperature = temperature || this.#opts.temperature;\n\n return new LLMStream(\n this.#client,\n chatCtx,\n fncCtx,\n this.#opts,\n parallelToolCalls,\n temperature,\n n,\n );\n }\n}\n\nexport class LLMStream extends llm.LLMStream {\n #toolCallId?: string;\n #fncName?: string;\n #fncRawArguments?: string;\n #client: OpenAI;\n #logger = log();\n #id = randomUUID();\n\n constructor(\n client: OpenAI,\n chatCtx: llm.ChatContext,\n fncCtx: llm.FunctionContext | undefined,\n opts: LLMOptions,\n parallelToolCalls?: boolean,\n temperature?: number,\n n?: number,\n ) {\n super(chatCtx, fncCtx);\n this.#client = client;\n this.#run(opts, n, parallelToolCalls, temperature);\n }\n\n async #run(opts: LLMOptions, n?: number, parallelToolCalls?: boolean, temperature?: number) {\n const tools = this.fncCtx\n ? Object.entries(this.fncCtx).map(([name, func]) => ({\n type: 'function' as const,\n function: {\n name,\n description: func.description,\n // don't format parameters if they are raw openai params\n parameters:\n func.parameters.type == ('object' as const)\n ? func.parameters\n : llm.oaiParams(func.parameters),\n },\n }))\n : undefined;\n\n try {\n const stream = await this.#client.chat.completions.create({\n model: opts.model,\n user: opts.user,\n n,\n messages: await Promise.all(\n this.chatCtx.messages.map(async (m) => await buildMessage(m, this.#id)),\n ),\n temperature: temperature || opts.temperature,\n stream_options: { include_usage: true },\n stream: true,\n tools,\n parallel_tool_calls: this.fncCtx && parallelToolCalls,\n });\n\n for await (const chunk of stream) {\n for (const choice of chunk.choices) {\n const chatChunk = this.#parseChoice(chunk.id, choice);\n if (chatChunk) {\n this.queue.put(chatChunk);\n }\n\n if (chunk.usage) {\n const usage = chunk.usage;\n this.queue.put({\n requestId: chunk.id,\n choices: [],\n usage: {\n completionTokens: usage.completion_tokens,\n promptTokens: usage.prompt_tokens,\n totalTokens: usage.total_tokens,\n },\n });\n }\n }\n }\n } finally {\n this.queue.close();\n }\n }\n\n #parseChoice(id: string, choice: OpenAI.ChatCompletionChunk.Choice): llm.ChatChunk | undefined {\n const delta = choice.delta;\n\n if (delta.tool_calls) {\n // check if we have functions to calls\n for (const tool of delta.tool_calls) {\n if (!tool.function) {\n continue; // oai may add other tools in the future\n }\n\n let callChunk: llm.ChatChunk | undefined;\n if (this.#toolCallId && tool.id && tool.id !== this.#toolCallId) {\n callChunk = this.#tryBuildFunction(id, choice);\n }\n\n if (tool.function.name) {\n this.#toolCallId = tool.id;\n this.#fncName = tool.function.name;\n this.#fncRawArguments = tool.function.arguments || '';\n } else if (tool.function.arguments) {\n this.#fncRawArguments += tool.function.arguments;\n }\n\n if (callChunk) {\n return callChunk;\n }\n }\n }\n\n if (\n choice.finish_reason &&\n ['tool_calls', 'stop'].includes(choice.finish_reason) &&\n this.#toolCallId\n ) {\n // we're done with the tool calls, run the last one\n return this.#tryBuildFunction(id, choice);\n }\n\n return {\n requestId: id,\n choices: [\n {\n delta: { content: delta.content || undefined, role: llm.ChatRole.ASSISTANT },\n index: choice.index,\n },\n ],\n };\n }\n\n #tryBuildFunction(\n id: string,\n choice: OpenAI.ChatCompletionChunk.Choice,\n ): llm.ChatChunk | undefined {\n if (!this.fncCtx) {\n this.#logger.warn('oai stream tried to run function without function context');\n return undefined;\n }\n\n if (!this.#toolCallId) {\n this.#logger.warn('oai stream tried to run function but toolCallId is not set');\n return undefined;\n }\n\n if (!this.#fncRawArguments || !this.#fncName) {\n this.#logger.warn('oai stream tried to run function but rawArguments or fncName are not set');\n return undefined;\n }\n\n const functionInfo = llm.oaiBuildFunctionInfo(\n this.fncCtx,\n this.#toolCallId,\n this.#fncName,\n this.#fncRawArguments,\n );\n this.#toolCallId = this.#fncName = this.#fncRawArguments = undefined;\n this._functionCalls.push(functionInfo);\n\n return {\n requestId: id,\n choices: [\n {\n delta: {\n content: choice.delta.content || undefined,\n role: llm.ChatRole.ASSISTANT,\n toolCalls: this._functionCalls,\n },\n index: choice.index,\n },\n ],\n };\n }\n}\n\nconst buildMessage = async (msg: llm.ChatMessage, cacheKey: any) => {\n const oaiMsg: Partial<OpenAI.ChatCompletionMessageParam> = {};\n\n switch (msg.role) {\n case llm.ChatRole.SYSTEM:\n oaiMsg.role = 'system';\n break;\n case llm.ChatRole.USER:\n oaiMsg.role = 'user';\n break;\n case llm.ChatRole.ASSISTANT:\n oaiMsg.role = 'assistant';\n break;\n case llm.ChatRole.TOOL:\n oaiMsg.role = 'tool';\n if (oaiMsg.role === 'tool') {\n oaiMsg.tool_call_id = msg.toolCallId;\n }\n break;\n }\n\n if (typeof msg.content === 'string') {\n oaiMsg.content = msg.content;\n } else if (\n ((c?: llm.ChatContent | llm.ChatContent[]): c is llm.ChatContent[] => {\n return (c as llm.ChatContent[]).length !== undefined;\n })(msg.content)\n ) {\n oaiMsg.content = (await Promise.all(\n msg.content.map(async (c) => {\n if (typeof c === 'string') {\n return { type: 'text', text: c };\n } else if (\n // typescript type guard for determining ChatAudio vs ChatImage\n ((c: llm.ChatAudio | llm.ChatImage): c is llm.ChatImage => {\n return (c as llm.ChatImage).image !== undefined;\n })(c)\n ) {\n return await buildImageContent(c, cacheKey);\n } else {\n throw new Error('ChatAudio is not supported');\n }\n }),\n )) as OpenAI.ChatCompletionContentPart[];\n }\n\n // make sure to provide when function has been called inside the context\n // (+ raw_arguments)\n if (msg.toolCalls && oaiMsg.role === 'assistant') {\n oaiMsg.tool_calls = Object.entries(msg.toolCalls).map(([name, func]) => ({\n id: func.toolCallId,\n type: 'function' as const,\n function: {\n name: name,\n arguments: func.rawParams,\n },\n }));\n }\n\n return oaiMsg as OpenAI.ChatCompletionMessageParam;\n};\n\nconst buildImageContent = async (image: llm.ChatImage, cacheKey: any) => {\n if (typeof image.image === 'string') {\n // image url\n return {\n type: 'image_url',\n image_url: {\n url: image.image,\n detail: 'auto',\n },\n };\n } else {\n if (!image.cache[cacheKey]) {\n // inside our internal implementation, we allow to put extra metadata to\n // each ChatImage (avoid to reencode each time we do a chatcompletion request)\n let encoded = sharp(image.image.data);\n\n if (image.inferenceHeight && image.inferenceHeight) {\n encoded = encoded.resize(image.inferenceWidth, image.inferenceHeight);\n }\n\n image.cache[cacheKey] = await encoded\n .jpeg()\n .toBuffer()\n .then((buffer) => buffer.toString('utf-8'));\n }\n\n return {\n type: 'image_url',\n image_url: {\n url: `data:image/jpeg;base64,${image.cache[cacheKey]}`,\n },\n };\n }\n};\n"],"mappings":"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","names":["c","sharp"]}