@livekit/agents-plugin-cerebras 1.2.6

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.
@@ -0,0 +1,208 @@
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 __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") {
10
+ for (let key of __getOwnPropNames(from))
11
+ if (!__hasOwnProp.call(to, key) && key !== except)
12
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
13
+ }
14
+ return to;
15
+ };
16
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
17
+ // If the importer is in node compatibility mode or this is not an ESM
18
+ // file that has been converted to a CommonJS file using a Babel-
19
+ // compatible transform (i.e. "__esModule" has not been set), then set
20
+ // "default" to the CommonJS "module.exports" for node compatibility.
21
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
22
+ mod
23
+ ));
24
+ var import_agents = require("@livekit/agents");
25
+ var import_msgpack = require("@msgpack/msgpack");
26
+ var import_node_zlib = require("node:zlib");
27
+ var import_openai = __toESM(require("openai"), 1);
28
+ var import_vitest = require("vitest");
29
+ var import_zod = require("zod");
30
+ var import_llm = require("./llm.cjs");
31
+ (0, import_vitest.assert)(process.env.CEREBRAS_API_KEY, "CEREBRAS_API_KEY must be set");
32
+ const CHAT_MODEL = "llama3.1-8b";
33
+ const TOOL_MODEL = "qwen-3-235b-a22b-instruct-2507";
34
+ function createCapturingFetch(opts) {
35
+ const capturedRequests = [];
36
+ const fetch = async (input, init) => {
37
+ if ((init == null ? void 0 : init.method) === "POST" && init.body && typeof init.body === "string") {
38
+ const headers = new Headers(init.headers);
39
+ let body;
40
+ if (opts.useMsgpack) {
41
+ body = (0, import_msgpack.encode)(JSON.parse(init.body));
42
+ headers.set("Content-Type", "application/vnd.msgpack");
43
+ } else {
44
+ body = new TextEncoder().encode(init.body);
45
+ }
46
+ if (opts.useGzip) {
47
+ body = (0, import_node_zlib.gzipSync)(body, { level: 5 });
48
+ headers.set("Content-Encoding", "gzip");
49
+ }
50
+ capturedRequests.push({ url: extractUrl(input), headers });
51
+ return globalThis.fetch(input, { ...init, body: Buffer.from(body), headers });
52
+ }
53
+ capturedRequests.push({ url: extractUrl(input), headers: new Headers(init == null ? void 0 : init.headers) });
54
+ return globalThis.fetch(input, init);
55
+ };
56
+ return { fetch, capturedRequests };
57
+ }
58
+ function extractUrl(input) {
59
+ if (typeof input === "string") return input;
60
+ if (input instanceof URL) return input.toString();
61
+ return input.url;
62
+ }
63
+ function cerebrasLLM(opts = {}) {
64
+ return new import_llm.LLM({ model: CHAT_MODEL, ...opts });
65
+ }
66
+ function cerebrasLLMWithCapture(opts) {
67
+ const { fetch, capturedRequests } = createCapturingFetch(opts);
68
+ const client = new import_openai.default({
69
+ apiKey: process.env.CEREBRAS_API_KEY,
70
+ baseURL: "https://api.cerebras.ai/v1",
71
+ fetch
72
+ });
73
+ return { llm: new import_llm.LLM({ model: CHAT_MODEL, client }), capturedRequests };
74
+ }
75
+ class WeatherAgent extends import_agents.voice.Agent {
76
+ constructor() {
77
+ super({
78
+ instructions: "You are a helpful assistant.",
79
+ tools: {
80
+ get_weather: import_agents.llm.tool({
81
+ description: "Get the current weather for a location.",
82
+ parameters: import_zod.z.object({
83
+ location: import_zod.z.string().describe("The city name")
84
+ }),
85
+ execute: async ({ location }) => {
86
+ return `The weather in ${location} is sunny, 72\xB0F.`;
87
+ }
88
+ })
89
+ }
90
+ });
91
+ }
92
+ }
93
+ (0, import_vitest.describe)("Cerebras", { timeout: 3e4 }, () => {
94
+ (0, import_vitest.it)("basic chat completion returns a non-empty assistant message", async () => {
95
+ const session = new import_agents.voice.AgentSession({ llm: cerebrasLLM() });
96
+ await session.start({
97
+ agent: new import_agents.voice.Agent({ instructions: "You are a helpful assistant." })
98
+ });
99
+ const result = session.run({ userInput: "Say hello in exactly one word." });
100
+ await result.wait();
101
+ result.expect.nextEvent().isMessage({ role: "assistant" });
102
+ result.expect.noMoreEvents();
103
+ await session.close();
104
+ });
105
+ (0, import_vitest.it)("LLM can invoke a tool and the result is returned", async () => {
106
+ const session = new import_agents.voice.AgentSession({ llm: new import_llm.LLM({ model: TOOL_MODEL }) });
107
+ await session.start({ agent: new WeatherAgent() });
108
+ const result = session.run({ userInput: "What is the weather in Tokyo?" });
109
+ await result.wait();
110
+ result.expect.nextEvent().isFunctionCall({
111
+ name: "get_weather",
112
+ args: { location: "Tokyo" }
113
+ });
114
+ result.expect.nextEvent().isFunctionCallOutput({
115
+ output: JSON.stringify("The weather in Tokyo is sunny, 72\xB0F.")
116
+ });
117
+ result.expect.nextEvent().isMessage({ role: "assistant" });
118
+ result.expect.noMoreEvents();
119
+ await session.close();
120
+ });
121
+ (0, import_vitest.it)("gzip-only sends Content-Encoding: gzip with JSON content type", async () => {
122
+ const { llm: model, capturedRequests } = cerebrasLLMWithCapture({
123
+ useGzip: true,
124
+ useMsgpack: false
125
+ });
126
+ const session = new import_agents.voice.AgentSession({ llm: model });
127
+ await session.start({
128
+ agent: new import_agents.voice.Agent({ instructions: "You are a helpful assistant." })
129
+ });
130
+ const result = session.run({ userInput: "Say hello in exactly one word." });
131
+ await result.wait();
132
+ result.expect.nextEvent().isMessage({ role: "assistant" });
133
+ result.expect.noMoreEvents();
134
+ await session.close();
135
+ const chatReqs = capturedRequests.filter((r) => r.url.includes("/chat/completions"));
136
+ (0, import_vitest.expect)(chatReqs.length).toBeGreaterThan(0);
137
+ (0, import_vitest.expect)(chatReqs[0].headers.get("content-type")).toBe("application/json");
138
+ (0, import_vitest.expect)(chatReqs[0].headers.get("content-encoding")).toBe("gzip");
139
+ });
140
+ (0, import_vitest.it)("msgpack-only sends Content-Type: application/vnd.msgpack without gzip", async () => {
141
+ const { llm: model, capturedRequests } = cerebrasLLMWithCapture({
142
+ useGzip: false,
143
+ useMsgpack: true
144
+ });
145
+ const session = new import_agents.voice.AgentSession({ llm: model });
146
+ await session.start({
147
+ agent: new import_agents.voice.Agent({ instructions: "You are a helpful assistant." })
148
+ });
149
+ const result = session.run({ userInput: "Say hello in exactly one word." });
150
+ await result.wait();
151
+ result.expect.nextEvent().isMessage({ role: "assistant" });
152
+ result.expect.noMoreEvents();
153
+ await session.close();
154
+ const chatReqs = capturedRequests.filter((r) => r.url.includes("/chat/completions"));
155
+ (0, import_vitest.expect)(chatReqs.length).toBeGreaterThan(0);
156
+ (0, import_vitest.expect)(chatReqs[0].headers.get("content-type")).toBe("application/vnd.msgpack");
157
+ (0, import_vitest.expect)(chatReqs[0].headers.get("content-encoding")).toBeNull();
158
+ });
159
+ (0, import_vitest.it)("both flags send msgpack content type with gzip encoding", async () => {
160
+ const { llm: model, capturedRequests } = cerebrasLLMWithCapture({
161
+ useGzip: true,
162
+ useMsgpack: true
163
+ });
164
+ const session = new import_agents.voice.AgentSession({ llm: model });
165
+ await session.start({
166
+ agent: new import_agents.voice.Agent({ instructions: "You are a helpful assistant." })
167
+ });
168
+ const result = session.run({ userInput: "Say hello in exactly one word." });
169
+ await result.wait();
170
+ result.expect.nextEvent().isMessage({ role: "assistant" });
171
+ result.expect.noMoreEvents();
172
+ await session.close();
173
+ const chatReqs = capturedRequests.filter((r) => r.url.includes("/chat/completions"));
174
+ (0, import_vitest.expect)(chatReqs.length).toBeGreaterThan(0);
175
+ (0, import_vitest.expect)(chatReqs[0].headers.get("content-type")).toBe("application/vnd.msgpack");
176
+ (0, import_vitest.expect)(chatReqs[0].headers.get("content-encoding")).toBe("gzip");
177
+ });
178
+ (0, import_vitest.it)("with both flags off sends standard JSON without gzip", async () => {
179
+ const session = new import_agents.voice.AgentSession({
180
+ llm: cerebrasLLM({ gzipCompression: false, msgpackEncoding: false })
181
+ });
182
+ await session.start({
183
+ agent: new import_agents.voice.Agent({ instructions: "You are a helpful assistant." })
184
+ });
185
+ const result = session.run({ userInput: "Say hello in exactly one word." });
186
+ await result.wait();
187
+ result.expect.nextEvent().isMessage({ role: "assistant" });
188
+ result.expect.noMoreEvents();
189
+ await session.close();
190
+ });
191
+ (0, import_vitest.it)("streaming chat returns content via the LLM directly", async () => {
192
+ var _a;
193
+ const model = cerebrasLLM();
194
+ const chatCtx = new import_agents.llm.ChatContext();
195
+ chatCtx.addMessage({ role: "system", content: "You are a helpful assistant." });
196
+ chatCtx.addMessage({ role: "user", content: "Count from 1 to 5." });
197
+ const stream = model.chat({ chatCtx });
198
+ let text = "";
199
+ for await (const chunk of stream) {
200
+ if ((_a = chunk.delta) == null ? void 0 : _a.content) {
201
+ text += chunk.delta.content;
202
+ }
203
+ }
204
+ (0, import_vitest.expect)(text.length).toBeGreaterThan(0);
205
+ (0, import_vitest.expect)(text).toContain("3");
206
+ });
207
+ });
208
+ //# sourceMappingURL=llm.test.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/llm.test.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2026 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { llm, voice } from '@livekit/agents';\nimport { encode } from '@msgpack/msgpack';\nimport { gzipSync } from 'node:zlib';\nimport OpenAI from 'openai';\nimport { assert, describe, expect, it } from 'vitest';\nimport { z } from 'zod';\nimport type { LLMOptions } from './llm.js';\nimport { LLM } from './llm.js';\n\nassert(process.env.CEREBRAS_API_KEY, 'CEREBRAS_API_KEY must be set');\n\n// llama3.1-8b is fast and has generous rate limits but can't do tool calls reliably;\n// qwen-3-235b is needed for function calling but has tight per-minute token quotas.\nconst CHAT_MODEL = 'llama3.1-8b';\nconst TOOL_MODEL = 'qwen-3-235b-a22b-instruct-2507';\n\ninterface CapturedRequest {\n url: string;\n headers: Headers;\n}\n\n/**\n * Wraps a real fetch, applying msgpack/gzip compression and capturing outgoing\n * request metadata for assertion. TypeScript equivalent of Python's\n * `HeaderCapturingTransport` + `_CerebrasClient`.\n */\nfunction createCapturingFetch(opts: { useMsgpack: boolean; useGzip: boolean }): {\n fetch: typeof globalThis.fetch;\n capturedRequests: CapturedRequest[];\n} {\n const capturedRequests: CapturedRequest[] = [];\n\n const fetch = async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {\n if (init?.method === 'POST' && init.body && typeof init.body === 'string') {\n const headers = new Headers(init.headers);\n\n let body: Uint8Array;\n if (opts.useMsgpack) {\n body = encode(JSON.parse(init.body));\n headers.set('Content-Type', 'application/vnd.msgpack');\n } else {\n body = new TextEncoder().encode(init.body);\n }\n\n if (opts.useGzip) {\n body = gzipSync(body, { level: 5 });\n headers.set('Content-Encoding', 'gzip');\n }\n\n capturedRequests.push({ url: extractUrl(input), headers });\n return globalThis.fetch(input, { ...init, body: Buffer.from(body), headers });\n }\n\n capturedRequests.push({ url: extractUrl(input), headers: new Headers(init?.headers) });\n return globalThis.fetch(input, init);\n };\n\n return { fetch: fetch as typeof globalThis.fetch, capturedRequests };\n}\n\nfunction extractUrl(input: RequestInfo | URL): string {\n if (typeof input === 'string') return input;\n if (input instanceof URL) return input.toString();\n return input.url;\n}\n\nfunction cerebrasLLM(opts: Partial<LLMOptions> = {}): LLM {\n return new LLM({ model: CHAT_MODEL, ...opts });\n}\n\nfunction cerebrasLLMWithCapture(opts: { useGzip: boolean; useMsgpack: boolean }): {\n llm: LLM;\n capturedRequests: CapturedRequest[];\n} {\n const { fetch, capturedRequests } = createCapturingFetch(opts);\n const client = new OpenAI({\n apiKey: process.env.CEREBRAS_API_KEY,\n baseURL: 'https://api.cerebras.ai/v1',\n fetch,\n });\n return { llm: new LLM({ model: CHAT_MODEL, client }), capturedRequests };\n}\n\nclass WeatherAgent extends voice.Agent {\n constructor() {\n super({\n instructions: 'You are a helpful assistant.',\n tools: {\n get_weather: llm.tool({\n description: 'Get the current weather for a location.',\n parameters: z.object({\n location: z.string().describe('The city name'),\n }),\n execute: async ({ location }) => {\n return `The weather in ${location} is sunny, 72°F.`;\n },\n }),\n },\n });\n }\n}\n\ndescribe('Cerebras', { timeout: 30_000 }, () => {\n it('basic chat completion returns a non-empty assistant message', async () => {\n const session = new voice.AgentSession({ llm: cerebrasLLM() });\n await session.start({\n agent: new voice.Agent({ instructions: 'You are a helpful assistant.' }),\n });\n\n const result = session.run({ userInput: 'Say hello in exactly one word.' });\n await result.wait();\n\n result.expect.nextEvent().isMessage({ role: 'assistant' });\n result.expect.noMoreEvents();\n\n await session.close();\n });\n\n it('LLM can invoke a tool and the result is returned', async () => {\n const session = new voice.AgentSession({ llm: new LLM({ model: TOOL_MODEL }) });\n await session.start({ agent: new WeatherAgent() });\n\n const result = session.run({ userInput: 'What is the weather in Tokyo?' });\n await result.wait();\n\n result.expect.nextEvent().isFunctionCall({\n name: 'get_weather',\n args: { location: 'Tokyo' },\n });\n result.expect.nextEvent().isFunctionCallOutput({\n output: JSON.stringify('The weather in Tokyo is sunny, 72°F.'),\n });\n result.expect.nextEvent().isMessage({ role: 'assistant' });\n result.expect.noMoreEvents();\n\n await session.close();\n });\n\n it('gzip-only sends Content-Encoding: gzip with JSON content type', async () => {\n const { llm: model, capturedRequests } = cerebrasLLMWithCapture({\n useGzip: true,\n useMsgpack: false,\n });\n const session = new voice.AgentSession({ llm: model });\n await session.start({\n agent: new voice.Agent({ instructions: 'You are a helpful assistant.' }),\n });\n\n const result = session.run({ userInput: 'Say hello in exactly one word.' });\n await result.wait();\n\n result.expect.nextEvent().isMessage({ role: 'assistant' });\n result.expect.noMoreEvents();\n\n await session.close();\n\n const chatReqs = capturedRequests.filter((r) => r.url.includes('/chat/completions'));\n expect(chatReqs.length).toBeGreaterThan(0);\n expect(chatReqs[0]!.headers.get('content-type')).toBe('application/json');\n expect(chatReqs[0]!.headers.get('content-encoding')).toBe('gzip');\n });\n\n it('msgpack-only sends Content-Type: application/vnd.msgpack without gzip', async () => {\n const { llm: model, capturedRequests } = cerebrasLLMWithCapture({\n useGzip: false,\n useMsgpack: true,\n });\n const session = new voice.AgentSession({ llm: model });\n await session.start({\n agent: new voice.Agent({ instructions: 'You are a helpful assistant.' }),\n });\n\n const result = session.run({ userInput: 'Say hello in exactly one word.' });\n await result.wait();\n\n result.expect.nextEvent().isMessage({ role: 'assistant' });\n result.expect.noMoreEvents();\n\n await session.close();\n\n const chatReqs = capturedRequests.filter((r) => r.url.includes('/chat/completions'));\n expect(chatReqs.length).toBeGreaterThan(0);\n expect(chatReqs[0]!.headers.get('content-type')).toBe('application/vnd.msgpack');\n expect(chatReqs[0]!.headers.get('content-encoding')).toBeNull();\n });\n\n it('both flags send msgpack content type with gzip encoding', async () => {\n const { llm: model, capturedRequests } = cerebrasLLMWithCapture({\n useGzip: true,\n useMsgpack: true,\n });\n const session = new voice.AgentSession({ llm: model });\n await session.start({\n agent: new voice.Agent({ instructions: 'You are a helpful assistant.' }),\n });\n\n const result = session.run({ userInput: 'Say hello in exactly one word.' });\n await result.wait();\n\n result.expect.nextEvent().isMessage({ role: 'assistant' });\n result.expect.noMoreEvents();\n\n await session.close();\n\n const chatReqs = capturedRequests.filter((r) => r.url.includes('/chat/completions'));\n expect(chatReqs.length).toBeGreaterThan(0);\n expect(chatReqs[0]!.headers.get('content-type')).toBe('application/vnd.msgpack');\n expect(chatReqs[0]!.headers.get('content-encoding')).toBe('gzip');\n });\n\n it('with both flags off sends standard JSON without gzip', async () => {\n const session = new voice.AgentSession({\n llm: cerebrasLLM({ gzipCompression: false, msgpackEncoding: false }),\n });\n await session.start({\n agent: new voice.Agent({ instructions: 'You are a helpful assistant.' }),\n });\n\n const result = session.run({ userInput: 'Say hello in exactly one word.' });\n await result.wait();\n\n result.expect.nextEvent().isMessage({ role: 'assistant' });\n result.expect.noMoreEvents();\n\n await session.close();\n });\n\n it('streaming chat returns content via the LLM directly', async () => {\n const model = cerebrasLLM();\n const chatCtx = new llm.ChatContext();\n chatCtx.addMessage({ role: 'system', content: 'You are a helpful assistant.' });\n chatCtx.addMessage({ role: 'user', content: 'Count from 1 to 5.' });\n\n const stream = model.chat({ chatCtx });\n let text = '';\n for await (const chunk of stream) {\n if (chunk.delta?.content) {\n text += chunk.delta.content;\n }\n }\n\n expect(text.length).toBeGreaterThan(0);\n expect(text).toContain('3');\n });\n});\n"],"mappings":"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","names":["OpenAI"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=llm.test.d.ts.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=llm.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm.test.d.ts","sourceRoot":"","sources":["../src/llm.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,185 @@
1
+ import { llm, voice } from "@livekit/agents";
2
+ import { encode } from "@msgpack/msgpack";
3
+ import { gzipSync } from "node:zlib";
4
+ import OpenAI from "openai";
5
+ import { assert, describe, expect, it } from "vitest";
6
+ import { z } from "zod";
7
+ import { LLM } from "./llm.js";
8
+ assert(process.env.CEREBRAS_API_KEY, "CEREBRAS_API_KEY must be set");
9
+ const CHAT_MODEL = "llama3.1-8b";
10
+ const TOOL_MODEL = "qwen-3-235b-a22b-instruct-2507";
11
+ function createCapturingFetch(opts) {
12
+ const capturedRequests = [];
13
+ const fetch = async (input, init) => {
14
+ if ((init == null ? void 0 : init.method) === "POST" && init.body && typeof init.body === "string") {
15
+ const headers = new Headers(init.headers);
16
+ let body;
17
+ if (opts.useMsgpack) {
18
+ body = encode(JSON.parse(init.body));
19
+ headers.set("Content-Type", "application/vnd.msgpack");
20
+ } else {
21
+ body = new TextEncoder().encode(init.body);
22
+ }
23
+ if (opts.useGzip) {
24
+ body = gzipSync(body, { level: 5 });
25
+ headers.set("Content-Encoding", "gzip");
26
+ }
27
+ capturedRequests.push({ url: extractUrl(input), headers });
28
+ return globalThis.fetch(input, { ...init, body: Buffer.from(body), headers });
29
+ }
30
+ capturedRequests.push({ url: extractUrl(input), headers: new Headers(init == null ? void 0 : init.headers) });
31
+ return globalThis.fetch(input, init);
32
+ };
33
+ return { fetch, capturedRequests };
34
+ }
35
+ function extractUrl(input) {
36
+ if (typeof input === "string") return input;
37
+ if (input instanceof URL) return input.toString();
38
+ return input.url;
39
+ }
40
+ function cerebrasLLM(opts = {}) {
41
+ return new LLM({ model: CHAT_MODEL, ...opts });
42
+ }
43
+ function cerebrasLLMWithCapture(opts) {
44
+ const { fetch, capturedRequests } = createCapturingFetch(opts);
45
+ const client = new OpenAI({
46
+ apiKey: process.env.CEREBRAS_API_KEY,
47
+ baseURL: "https://api.cerebras.ai/v1",
48
+ fetch
49
+ });
50
+ return { llm: new LLM({ model: CHAT_MODEL, client }), capturedRequests };
51
+ }
52
+ class WeatherAgent extends voice.Agent {
53
+ constructor() {
54
+ super({
55
+ instructions: "You are a helpful assistant.",
56
+ tools: {
57
+ get_weather: llm.tool({
58
+ description: "Get the current weather for a location.",
59
+ parameters: z.object({
60
+ location: z.string().describe("The city name")
61
+ }),
62
+ execute: async ({ location }) => {
63
+ return `The weather in ${location} is sunny, 72\xB0F.`;
64
+ }
65
+ })
66
+ }
67
+ });
68
+ }
69
+ }
70
+ describe("Cerebras", { timeout: 3e4 }, () => {
71
+ it("basic chat completion returns a non-empty assistant message", async () => {
72
+ const session = new voice.AgentSession({ llm: cerebrasLLM() });
73
+ await session.start({
74
+ agent: new voice.Agent({ instructions: "You are a helpful assistant." })
75
+ });
76
+ const result = session.run({ userInput: "Say hello in exactly one word." });
77
+ await result.wait();
78
+ result.expect.nextEvent().isMessage({ role: "assistant" });
79
+ result.expect.noMoreEvents();
80
+ await session.close();
81
+ });
82
+ it("LLM can invoke a tool and the result is returned", async () => {
83
+ const session = new voice.AgentSession({ llm: new LLM({ model: TOOL_MODEL }) });
84
+ await session.start({ agent: new WeatherAgent() });
85
+ const result = session.run({ userInput: "What is the weather in Tokyo?" });
86
+ await result.wait();
87
+ result.expect.nextEvent().isFunctionCall({
88
+ name: "get_weather",
89
+ args: { location: "Tokyo" }
90
+ });
91
+ result.expect.nextEvent().isFunctionCallOutput({
92
+ output: JSON.stringify("The weather in Tokyo is sunny, 72\xB0F.")
93
+ });
94
+ result.expect.nextEvent().isMessage({ role: "assistant" });
95
+ result.expect.noMoreEvents();
96
+ await session.close();
97
+ });
98
+ it("gzip-only sends Content-Encoding: gzip with JSON content type", async () => {
99
+ const { llm: model, capturedRequests } = cerebrasLLMWithCapture({
100
+ useGzip: true,
101
+ useMsgpack: false
102
+ });
103
+ const session = new voice.AgentSession({ llm: model });
104
+ await session.start({
105
+ agent: new voice.Agent({ instructions: "You are a helpful assistant." })
106
+ });
107
+ const result = session.run({ userInput: "Say hello in exactly one word." });
108
+ await result.wait();
109
+ result.expect.nextEvent().isMessage({ role: "assistant" });
110
+ result.expect.noMoreEvents();
111
+ await session.close();
112
+ const chatReqs = capturedRequests.filter((r) => r.url.includes("/chat/completions"));
113
+ expect(chatReqs.length).toBeGreaterThan(0);
114
+ expect(chatReqs[0].headers.get("content-type")).toBe("application/json");
115
+ expect(chatReqs[0].headers.get("content-encoding")).toBe("gzip");
116
+ });
117
+ it("msgpack-only sends Content-Type: application/vnd.msgpack without gzip", async () => {
118
+ const { llm: model, capturedRequests } = cerebrasLLMWithCapture({
119
+ useGzip: false,
120
+ useMsgpack: true
121
+ });
122
+ const session = new voice.AgentSession({ llm: model });
123
+ await session.start({
124
+ agent: new voice.Agent({ instructions: "You are a helpful assistant." })
125
+ });
126
+ const result = session.run({ userInput: "Say hello in exactly one word." });
127
+ await result.wait();
128
+ result.expect.nextEvent().isMessage({ role: "assistant" });
129
+ result.expect.noMoreEvents();
130
+ await session.close();
131
+ const chatReqs = capturedRequests.filter((r) => r.url.includes("/chat/completions"));
132
+ expect(chatReqs.length).toBeGreaterThan(0);
133
+ expect(chatReqs[0].headers.get("content-type")).toBe("application/vnd.msgpack");
134
+ expect(chatReqs[0].headers.get("content-encoding")).toBeNull();
135
+ });
136
+ it("both flags send msgpack content type with gzip encoding", async () => {
137
+ const { llm: model, capturedRequests } = cerebrasLLMWithCapture({
138
+ useGzip: true,
139
+ useMsgpack: true
140
+ });
141
+ const session = new voice.AgentSession({ llm: model });
142
+ await session.start({
143
+ agent: new voice.Agent({ instructions: "You are a helpful assistant." })
144
+ });
145
+ const result = session.run({ userInput: "Say hello in exactly one word." });
146
+ await result.wait();
147
+ result.expect.nextEvent().isMessage({ role: "assistant" });
148
+ result.expect.noMoreEvents();
149
+ await session.close();
150
+ const chatReqs = capturedRequests.filter((r) => r.url.includes("/chat/completions"));
151
+ expect(chatReqs.length).toBeGreaterThan(0);
152
+ expect(chatReqs[0].headers.get("content-type")).toBe("application/vnd.msgpack");
153
+ expect(chatReqs[0].headers.get("content-encoding")).toBe("gzip");
154
+ });
155
+ it("with both flags off sends standard JSON without gzip", async () => {
156
+ const session = new voice.AgentSession({
157
+ llm: cerebrasLLM({ gzipCompression: false, msgpackEncoding: false })
158
+ });
159
+ await session.start({
160
+ agent: new voice.Agent({ instructions: "You are a helpful assistant." })
161
+ });
162
+ const result = session.run({ userInput: "Say hello in exactly one word." });
163
+ await result.wait();
164
+ result.expect.nextEvent().isMessage({ role: "assistant" });
165
+ result.expect.noMoreEvents();
166
+ await session.close();
167
+ });
168
+ it("streaming chat returns content via the LLM directly", async () => {
169
+ var _a;
170
+ const model = cerebrasLLM();
171
+ const chatCtx = new llm.ChatContext();
172
+ chatCtx.addMessage({ role: "system", content: "You are a helpful assistant." });
173
+ chatCtx.addMessage({ role: "user", content: "Count from 1 to 5." });
174
+ const stream = model.chat({ chatCtx });
175
+ let text = "";
176
+ for await (const chunk of stream) {
177
+ if ((_a = chunk.delta) == null ? void 0 : _a.content) {
178
+ text += chunk.delta.content;
179
+ }
180
+ }
181
+ expect(text.length).toBeGreaterThan(0);
182
+ expect(text).toContain("3");
183
+ });
184
+ });
185
+ //# sourceMappingURL=llm.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/llm.test.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2026 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { llm, voice } from '@livekit/agents';\nimport { encode } from '@msgpack/msgpack';\nimport { gzipSync } from 'node:zlib';\nimport OpenAI from 'openai';\nimport { assert, describe, expect, it } from 'vitest';\nimport { z } from 'zod';\nimport type { LLMOptions } from './llm.js';\nimport { LLM } from './llm.js';\n\nassert(process.env.CEREBRAS_API_KEY, 'CEREBRAS_API_KEY must be set');\n\n// llama3.1-8b is fast and has generous rate limits but can't do tool calls reliably;\n// qwen-3-235b is needed for function calling but has tight per-minute token quotas.\nconst CHAT_MODEL = 'llama3.1-8b';\nconst TOOL_MODEL = 'qwen-3-235b-a22b-instruct-2507';\n\ninterface CapturedRequest {\n url: string;\n headers: Headers;\n}\n\n/**\n * Wraps a real fetch, applying msgpack/gzip compression and capturing outgoing\n * request metadata for assertion. TypeScript equivalent of Python's\n * `HeaderCapturingTransport` + `_CerebrasClient`.\n */\nfunction createCapturingFetch(opts: { useMsgpack: boolean; useGzip: boolean }): {\n fetch: typeof globalThis.fetch;\n capturedRequests: CapturedRequest[];\n} {\n const capturedRequests: CapturedRequest[] = [];\n\n const fetch = async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {\n if (init?.method === 'POST' && init.body && typeof init.body === 'string') {\n const headers = new Headers(init.headers);\n\n let body: Uint8Array;\n if (opts.useMsgpack) {\n body = encode(JSON.parse(init.body));\n headers.set('Content-Type', 'application/vnd.msgpack');\n } else {\n body = new TextEncoder().encode(init.body);\n }\n\n if (opts.useGzip) {\n body = gzipSync(body, { level: 5 });\n headers.set('Content-Encoding', 'gzip');\n }\n\n capturedRequests.push({ url: extractUrl(input), headers });\n return globalThis.fetch(input, { ...init, body: Buffer.from(body), headers });\n }\n\n capturedRequests.push({ url: extractUrl(input), headers: new Headers(init?.headers) });\n return globalThis.fetch(input, init);\n };\n\n return { fetch: fetch as typeof globalThis.fetch, capturedRequests };\n}\n\nfunction extractUrl(input: RequestInfo | URL): string {\n if (typeof input === 'string') return input;\n if (input instanceof URL) return input.toString();\n return input.url;\n}\n\nfunction cerebrasLLM(opts: Partial<LLMOptions> = {}): LLM {\n return new LLM({ model: CHAT_MODEL, ...opts });\n}\n\nfunction cerebrasLLMWithCapture(opts: { useGzip: boolean; useMsgpack: boolean }): {\n llm: LLM;\n capturedRequests: CapturedRequest[];\n} {\n const { fetch, capturedRequests } = createCapturingFetch(opts);\n const client = new OpenAI({\n apiKey: process.env.CEREBRAS_API_KEY,\n baseURL: 'https://api.cerebras.ai/v1',\n fetch,\n });\n return { llm: new LLM({ model: CHAT_MODEL, client }), capturedRequests };\n}\n\nclass WeatherAgent extends voice.Agent {\n constructor() {\n super({\n instructions: 'You are a helpful assistant.',\n tools: {\n get_weather: llm.tool({\n description: 'Get the current weather for a location.',\n parameters: z.object({\n location: z.string().describe('The city name'),\n }),\n execute: async ({ location }) => {\n return `The weather in ${location} is sunny, 72°F.`;\n },\n }),\n },\n });\n }\n}\n\ndescribe('Cerebras', { timeout: 30_000 }, () => {\n it('basic chat completion returns a non-empty assistant message', async () => {\n const session = new voice.AgentSession({ llm: cerebrasLLM() });\n await session.start({\n agent: new voice.Agent({ instructions: 'You are a helpful assistant.' }),\n });\n\n const result = session.run({ userInput: 'Say hello in exactly one word.' });\n await result.wait();\n\n result.expect.nextEvent().isMessage({ role: 'assistant' });\n result.expect.noMoreEvents();\n\n await session.close();\n });\n\n it('LLM can invoke a tool and the result is returned', async () => {\n const session = new voice.AgentSession({ llm: new LLM({ model: TOOL_MODEL }) });\n await session.start({ agent: new WeatherAgent() });\n\n const result = session.run({ userInput: 'What is the weather in Tokyo?' });\n await result.wait();\n\n result.expect.nextEvent().isFunctionCall({\n name: 'get_weather',\n args: { location: 'Tokyo' },\n });\n result.expect.nextEvent().isFunctionCallOutput({\n output: JSON.stringify('The weather in Tokyo is sunny, 72°F.'),\n });\n result.expect.nextEvent().isMessage({ role: 'assistant' });\n result.expect.noMoreEvents();\n\n await session.close();\n });\n\n it('gzip-only sends Content-Encoding: gzip with JSON content type', async () => {\n const { llm: model, capturedRequests } = cerebrasLLMWithCapture({\n useGzip: true,\n useMsgpack: false,\n });\n const session = new voice.AgentSession({ llm: model });\n await session.start({\n agent: new voice.Agent({ instructions: 'You are a helpful assistant.' }),\n });\n\n const result = session.run({ userInput: 'Say hello in exactly one word.' });\n await result.wait();\n\n result.expect.nextEvent().isMessage({ role: 'assistant' });\n result.expect.noMoreEvents();\n\n await session.close();\n\n const chatReqs = capturedRequests.filter((r) => r.url.includes('/chat/completions'));\n expect(chatReqs.length).toBeGreaterThan(0);\n expect(chatReqs[0]!.headers.get('content-type')).toBe('application/json');\n expect(chatReqs[0]!.headers.get('content-encoding')).toBe('gzip');\n });\n\n it('msgpack-only sends Content-Type: application/vnd.msgpack without gzip', async () => {\n const { llm: model, capturedRequests } = cerebrasLLMWithCapture({\n useGzip: false,\n useMsgpack: true,\n });\n const session = new voice.AgentSession({ llm: model });\n await session.start({\n agent: new voice.Agent({ instructions: 'You are a helpful assistant.' }),\n });\n\n const result = session.run({ userInput: 'Say hello in exactly one word.' });\n await result.wait();\n\n result.expect.nextEvent().isMessage({ role: 'assistant' });\n result.expect.noMoreEvents();\n\n await session.close();\n\n const chatReqs = capturedRequests.filter((r) => r.url.includes('/chat/completions'));\n expect(chatReqs.length).toBeGreaterThan(0);\n expect(chatReqs[0]!.headers.get('content-type')).toBe('application/vnd.msgpack');\n expect(chatReqs[0]!.headers.get('content-encoding')).toBeNull();\n });\n\n it('both flags send msgpack content type with gzip encoding', async () => {\n const { llm: model, capturedRequests } = cerebrasLLMWithCapture({\n useGzip: true,\n useMsgpack: true,\n });\n const session = new voice.AgentSession({ llm: model });\n await session.start({\n agent: new voice.Agent({ instructions: 'You are a helpful assistant.' }),\n });\n\n const result = session.run({ userInput: 'Say hello in exactly one word.' });\n await result.wait();\n\n result.expect.nextEvent().isMessage({ role: 'assistant' });\n result.expect.noMoreEvents();\n\n await session.close();\n\n const chatReqs = capturedRequests.filter((r) => r.url.includes('/chat/completions'));\n expect(chatReqs.length).toBeGreaterThan(0);\n expect(chatReqs[0]!.headers.get('content-type')).toBe('application/vnd.msgpack');\n expect(chatReqs[0]!.headers.get('content-encoding')).toBe('gzip');\n });\n\n it('with both flags off sends standard JSON without gzip', async () => {\n const session = new voice.AgentSession({\n llm: cerebrasLLM({ gzipCompression: false, msgpackEncoding: false }),\n });\n await session.start({\n agent: new voice.Agent({ instructions: 'You are a helpful assistant.' }),\n });\n\n const result = session.run({ userInput: 'Say hello in exactly one word.' });\n await result.wait();\n\n result.expect.nextEvent().isMessage({ role: 'assistant' });\n result.expect.noMoreEvents();\n\n await session.close();\n });\n\n it('streaming chat returns content via the LLM directly', async () => {\n const model = cerebrasLLM();\n const chatCtx = new llm.ChatContext();\n chatCtx.addMessage({ role: 'system', content: 'You are a helpful assistant.' });\n chatCtx.addMessage({ role: 'user', content: 'Count from 1 to 5.' });\n\n const stream = model.chat({ chatCtx });\n let text = '';\n for await (const chunk of stream) {\n if (chunk.delta?.content) {\n text += chunk.delta.content;\n }\n }\n\n expect(text.length).toBeGreaterThan(0);\n expect(text).toContain('3');\n });\n});\n"],"mappings":"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","names":[]}
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __copyProps = (to, from, except, desc) => {
7
+ if (from && typeof from === "object" || typeof from === "function") {
8
+ for (let key of __getOwnPropNames(from))
9
+ if (!__hasOwnProp.call(to, key) && key !== except)
10
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
+ }
12
+ return to;
13
+ };
14
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
15
+ var models_exports = {};
16
+ module.exports = __toCommonJS(models_exports);
17
+ //# sourceMappingURL=models.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/models.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2026 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\n\nexport type CerebrasChatModels =\n | 'llama3.1-8b'\n | 'llama-3.3-70b'\n | 'llama-4-scout-17b-16e-instruct'\n | 'llama-4-maverick-17b-128e-instruct'\n | 'qwen-3-32b'\n | 'qwen-3-235b-a22b-instruct-2507'\n | 'qwen-3-235b-a22b-thinking-2507'\n | 'qwen-3-coder-480b'\n | 'gpt-oss-120b';\n"],"mappings":";;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
@@ -0,0 +1,2 @@
1
+ export type CerebrasChatModels = 'llama3.1-8b' | 'llama-3.3-70b' | 'llama-4-scout-17b-16e-instruct' | 'llama-4-maverick-17b-128e-instruct' | 'qwen-3-32b' | 'qwen-3-235b-a22b-instruct-2507' | 'qwen-3-235b-a22b-thinking-2507' | 'qwen-3-coder-480b' | 'gpt-oss-120b';
2
+ //# sourceMappingURL=models.d.ts.map
@@ -0,0 +1,2 @@
1
+ export type CerebrasChatModels = 'llama3.1-8b' | 'llama-3.3-70b' | 'llama-4-scout-17b-16e-instruct' | 'llama-4-maverick-17b-128e-instruct' | 'qwen-3-32b' | 'qwen-3-235b-a22b-instruct-2507' | 'qwen-3-235b-a22b-thinking-2507' | 'qwen-3-coder-480b' | 'gpt-oss-120b';
2
+ //# sourceMappingURL=models.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,kBAAkB,GAC1B,aAAa,GACb,eAAe,GACf,gCAAgC,GAChC,oCAAoC,GACpC,YAAY,GACZ,gCAAgC,GAChC,gCAAgC,GAChC,mBAAmB,GACnB,cAAc,CAAC"}
package/dist/models.js ADDED
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=models.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@livekit/agents-plugin-cerebras",
3
+ "version": "1.2.6",
4
+ "description": "Cerebras plugin for LiveKit Node Agents",
5
+ "main": "dist/index.js",
6
+ "require": "dist/index.cjs",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ "import": {
10
+ "types": "./dist/index.d.ts",
11
+ "default": "./dist/index.js"
12
+ },
13
+ "require": {
14
+ "types": "./dist/index.d.cts",
15
+ "default": "./dist/index.cjs"
16
+ }
17
+ },
18
+ "author": "LiveKit",
19
+ "type": "module",
20
+ "repository": "git@github.com:livekit/agents-js.git",
21
+ "license": "Apache-2.0",
22
+ "files": [
23
+ "dist",
24
+ "src",
25
+ "README.md"
26
+ ],
27
+ "devDependencies": {
28
+ "@livekit/rtc-node": "^0.13.25",
29
+ "@microsoft/api-extractor": "^7.35.0",
30
+ "tsup": "^8.3.5",
31
+ "typescript": "^5.0.0",
32
+ "zod": "^3.25.76 || ^4.1.8",
33
+ "@livekit/agents": "1.2.6",
34
+ "@livekit/agents-plugin-openai": "1.2.6",
35
+ "@livekit/agents-plugins-test": "1.2.6"
36
+ },
37
+ "dependencies": {
38
+ "@msgpack/msgpack": "^3.0.0",
39
+ "openai": "^6.8.1"
40
+ },
41
+ "peerDependencies": {
42
+ "@livekit/rtc-node": "^0.13.25",
43
+ "@livekit/agents": "1.2.6",
44
+ "@livekit/agents-plugin-openai": "1.2.6"
45
+ },
46
+ "scripts": {
47
+ "build": "tsup --onSuccess \"pnpm build:types\"",
48
+ "build:types": "tsc --declaration --emitDeclarationOnly && node ../../scripts/copyDeclarationOutput.js",
49
+ "clean": "rm -rf dist",
50
+ "clean:build": "pnpm clean && pnpm build",
51
+ "lint": "eslint -f unix \"src/**/*.{ts,js}\"",
52
+ "api:check": "api-extractor run --typescript-compiler-folder ../../node_modules/typescript",
53
+ "api:update": "api-extractor run --local --typescript-compiler-folder ../../node_modules/typescript --verbose"
54
+ }
55
+ }
package/src/index.ts ADDED
@@ -0,0 +1,20 @@
1
+ // SPDX-FileCopyrightText: 2026 LiveKit, Inc.
2
+ //
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ import { Plugin } from '@livekit/agents';
5
+
6
+ export { LLM } from './llm.js';
7
+ export type { LLMOptions } from './llm.js';
8
+ export type { CerebrasChatModels } from './models.js';
9
+
10
+ class CerebrasPlugin extends Plugin {
11
+ constructor() {
12
+ super({
13
+ title: 'cerebras',
14
+ version: __PACKAGE_VERSION__,
15
+ package: __PACKAGE_NAME__,
16
+ });
17
+ }
18
+ }
19
+
20
+ Plugin.registerPlugin(new CerebrasPlugin());