@livekit/agents-plugin-cerebras 1.6.1 → 1.6.3

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.
package/dist/index.cjs CHANGED
@@ -27,7 +27,7 @@ class CerebrasPlugin extends import_agents.Plugin {
27
27
  constructor() {
28
28
  super({
29
29
  title: "cerebras",
30
- version: "1.6.1",
30
+ version: "1.6.3",
31
31
  package: "@livekit/agents-plugin-cerebras"
32
32
  });
33
33
  }
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ class CerebrasPlugin extends Plugin {
4
4
  constructor() {
5
5
  super({
6
6
  title: "cerebras",
7
- version: "1.6.1",
7
+ version: "1.6.3",
8
8
  package: "@livekit/agents-plugin-cerebras"
9
9
  });
10
10
  }
package/dist/llm.cjs CHANGED
@@ -36,7 +36,7 @@ var import_msgpack = require("@msgpack/msgpack");
36
36
  var import_node_zlib = require("node:zlib");
37
37
  var import_openai = __toESM(require("openai"), 1);
38
38
  const defaultLLMOptions = {
39
- model: "llama-4-scout-17b-16e-instruct",
39
+ model: "gpt-oss-120b",
40
40
  baseURL: "https://api.cerebras.ai/v1",
41
41
  gzipCompression: true,
42
42
  msgpackEncoding: true
package/dist/llm.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/llm.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2026 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { llm } from '@livekit/agents';\nimport { LLM as OpenAILLM } from '@livekit/agents-plugin-openai';\nimport { encode } from '@msgpack/msgpack';\nimport { gzipSync } from 'node:zlib';\nimport OpenAI from 'openai';\nimport type { CerebrasChatModels } from './models.js';\n\nexport interface LLMOptions {\n model: string | CerebrasChatModels;\n apiKey?: string;\n baseURL?: string;\n user?: string;\n temperature?: number;\n client?: OpenAI;\n toolChoice?: llm.ToolChoice;\n parallelToolCalls?: boolean;\n gzipCompression?: boolean;\n msgpackEncoding?: boolean;\n}\n\nconst defaultLLMOptions: LLMOptions = {\n model: 'llama-4-scout-17b-16e-instruct',\n baseURL: 'https://api.cerebras.ai/v1',\n gzipCompression: true,\n msgpackEncoding: true,\n};\n\n/**\n * Create a custom fetch that compresses request payloads via msgpack and/or gzip.\n *\n * @see https://inference-docs.cerebras.ai/payload-optimization\n */\nfunction createCompressedFetch(opts: {\n useMsgpack: boolean;\n useGzip: boolean;\n}): typeof globalThis.fetch {\n return 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 return globalThis.fetch(input, { ...init, body: Buffer.from(body), headers });\n }\n return globalThis.fetch(input, init);\n };\n}\n\nexport class LLM extends OpenAILLM {\n constructor(opts: Partial<LLMOptions> = {}) {\n const merged = { ...defaultLLMOptions, ...opts };\n\n merged.apiKey = merged.apiKey || process.env.CEREBRAS_API_KEY;\n if (merged.apiKey === undefined && !merged.client) {\n throw new Error(\n 'Cerebras API key is required, either as an argument or as $CEREBRAS_API_KEY',\n );\n }\n\n if (!merged.client && (merged.gzipCompression || merged.msgpackEncoding)) {\n merged.client = new OpenAI({\n apiKey: merged.apiKey,\n baseURL: merged.baseURL,\n maxRetries: 0,\n fetch: createCompressedFetch({\n useMsgpack: merged.msgpackEncoding ?? true,\n useGzip: merged.gzipCompression ?? true,\n }),\n });\n }\n\n super(merged);\n }\n\n override label(): string {\n return 'cerebras.LLM';\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA,kCAAiC;AACjC,qBAAuB;AACvB,uBAAyB;AACzB,oBAAmB;AAgBnB,MAAM,oBAAgC;AAAA,EACpC,OAAO;AAAA,EACP,SAAS;AAAA,EACT,iBAAiB;AAAA,EACjB,iBAAiB;AACnB;AAOA,SAAS,sBAAsB,MAGH;AAC1B,SAAO,OAAO,OAA0B,SAA0C;AAChF,SAAI,6BAAM,YAAW,UAAU,KAAK,QAAQ,OAAO,KAAK,SAAS,UAAU;AACzE,YAAM,UAAU,IAAI,QAAQ,KAAK,OAAO;AAExC,UAAI;AACJ,UAAI,KAAK,YAAY;AACnB,mBAAO,uBAAO,KAAK,MAAM,KAAK,IAAI,CAAC;AACnC,gBAAQ,IAAI,gBAAgB,yBAAyB;AAAA,MACvD,OAAO;AACL,eAAO,IAAI,YAAY,EAAE,OAAO,KAAK,IAAI;AAAA,MAC3C;AAEA,UAAI,KAAK,SAAS;AAChB,mBAAO,2BAAS,MAAM,EAAE,OAAO,EAAE,CAAC;AAClC,gBAAQ,IAAI,oBAAoB,MAAM;AAAA,MACxC;AAEA,aAAO,WAAW,MAAM,OAAO,EAAE,GAAG,MAAM,MAAM,OAAO,KAAK,IAAI,GAAG,QAAQ,CAAC;AAAA,IAC9E;AACA,WAAO,WAAW,MAAM,OAAO,IAAI;AAAA,EACrC;AACF;AAEO,MAAM,YAAY,4BAAAA,IAAU;AAAA,EACjC,YAAY,OAA4B,CAAC,GAAG;AAC1C,UAAM,SAAS,EAAE,GAAG,mBAAmB,GAAG,KAAK;AAE/C,WAAO,SAAS,OAAO,UAAU,QAAQ,IAAI;AAC7C,QAAI,OAAO,WAAW,UAAa,CAAC,OAAO,QAAQ;AACjD,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,QAAI,CAAC,OAAO,WAAW,OAAO,mBAAmB,OAAO,kBAAkB;AACxE,aAAO,SAAS,IAAI,cAAAC,QAAO;AAAA,QACzB,QAAQ,OAAO;AAAA,QACf,SAAS,OAAO;AAAA,QAChB,YAAY;AAAA,QACZ,OAAO,sBAAsB;AAAA,UAC3B,YAAY,OAAO,mBAAmB;AAAA,UACtC,SAAS,OAAO,mBAAmB;AAAA,QACrC,CAAC;AAAA,MACH,CAAC;AAAA,IACH;AAEA,UAAM,MAAM;AAAA,EACd;AAAA,EAES,QAAgB;AACvB,WAAO;AAAA,EACT;AACF;","names":["OpenAILLM","OpenAI"]}
1
+ {"version":3,"sources":["../src/llm.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2026 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { llm } from '@livekit/agents';\nimport { LLM as OpenAILLM } from '@livekit/agents-plugin-openai';\nimport { encode } from '@msgpack/msgpack';\nimport { gzipSync } from 'node:zlib';\nimport OpenAI from 'openai';\nimport type { CerebrasChatModels } from './models.js';\n\nexport interface LLMOptions {\n model: string | CerebrasChatModels;\n apiKey?: string;\n baseURL?: string;\n user?: string;\n temperature?: number;\n client?: OpenAI;\n toolChoice?: llm.ToolChoice;\n parallelToolCalls?: boolean;\n gzipCompression?: boolean;\n msgpackEncoding?: boolean;\n}\n\nconst defaultLLMOptions: LLMOptions = {\n model: 'gpt-oss-120b',\n baseURL: 'https://api.cerebras.ai/v1',\n gzipCompression: true,\n msgpackEncoding: true,\n};\n\n/**\n * Create a custom fetch that compresses request payloads via msgpack and/or gzip.\n *\n * @see https://inference-docs.cerebras.ai/payload-optimization\n */\nfunction createCompressedFetch(opts: {\n useMsgpack: boolean;\n useGzip: boolean;\n}): typeof globalThis.fetch {\n return 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 return globalThis.fetch(input, { ...init, body: Buffer.from(body), headers });\n }\n return globalThis.fetch(input, init);\n };\n}\n\nexport class LLM extends OpenAILLM {\n constructor(opts: Partial<LLMOptions> = {}) {\n const merged = { ...defaultLLMOptions, ...opts };\n\n merged.apiKey = merged.apiKey || process.env.CEREBRAS_API_KEY;\n if (merged.apiKey === undefined && !merged.client) {\n throw new Error(\n 'Cerebras API key is required, either as an argument or as $CEREBRAS_API_KEY',\n );\n }\n\n if (!merged.client && (merged.gzipCompression || merged.msgpackEncoding)) {\n merged.client = new OpenAI({\n apiKey: merged.apiKey,\n baseURL: merged.baseURL,\n maxRetries: 0,\n fetch: createCompressedFetch({\n useMsgpack: merged.msgpackEncoding ?? true,\n useGzip: merged.gzipCompression ?? true,\n }),\n });\n }\n\n super(merged);\n }\n\n override label(): string {\n return 'cerebras.LLM';\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA,kCAAiC;AACjC,qBAAuB;AACvB,uBAAyB;AACzB,oBAAmB;AAgBnB,MAAM,oBAAgC;AAAA,EACpC,OAAO;AAAA,EACP,SAAS;AAAA,EACT,iBAAiB;AAAA,EACjB,iBAAiB;AACnB;AAOA,SAAS,sBAAsB,MAGH;AAC1B,SAAO,OAAO,OAA0B,SAA0C;AAChF,SAAI,6BAAM,YAAW,UAAU,KAAK,QAAQ,OAAO,KAAK,SAAS,UAAU;AACzE,YAAM,UAAU,IAAI,QAAQ,KAAK,OAAO;AAExC,UAAI;AACJ,UAAI,KAAK,YAAY;AACnB,mBAAO,uBAAO,KAAK,MAAM,KAAK,IAAI,CAAC;AACnC,gBAAQ,IAAI,gBAAgB,yBAAyB;AAAA,MACvD,OAAO;AACL,eAAO,IAAI,YAAY,EAAE,OAAO,KAAK,IAAI;AAAA,MAC3C;AAEA,UAAI,KAAK,SAAS;AAChB,mBAAO,2BAAS,MAAM,EAAE,OAAO,EAAE,CAAC;AAClC,gBAAQ,IAAI,oBAAoB,MAAM;AAAA,MACxC;AAEA,aAAO,WAAW,MAAM,OAAO,EAAE,GAAG,MAAM,MAAM,OAAO,KAAK,IAAI,GAAG,QAAQ,CAAC;AAAA,IAC9E;AACA,WAAO,WAAW,MAAM,OAAO,IAAI;AAAA,EACrC;AACF;AAEO,MAAM,YAAY,4BAAAA,IAAU;AAAA,EACjC,YAAY,OAA4B,CAAC,GAAG;AAC1C,UAAM,SAAS,EAAE,GAAG,mBAAmB,GAAG,KAAK;AAE/C,WAAO,SAAS,OAAO,UAAU,QAAQ,IAAI;AAC7C,QAAI,OAAO,WAAW,UAAa,CAAC,OAAO,QAAQ;AACjD,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,QAAI,CAAC,OAAO,WAAW,OAAO,mBAAmB,OAAO,kBAAkB;AACxE,aAAO,SAAS,IAAI,cAAAC,QAAO;AAAA,QACzB,QAAQ,OAAO;AAAA,QACf,SAAS,OAAO;AAAA,QAChB,YAAY;AAAA,QACZ,OAAO,sBAAsB;AAAA,UAC3B,YAAY,OAAO,mBAAmB;AAAA,UACtC,SAAS,OAAO,mBAAmB;AAAA,QACrC,CAAC;AAAA,MACH,CAAC;AAAA,IACH;AAEA,UAAM,MAAM;AAAA,EACd;AAAA,EAES,QAAgB;AACvB,WAAO;AAAA,EACT;AACF;","names":["OpenAILLM","OpenAI"]}
package/dist/llm.js CHANGED
@@ -3,7 +3,7 @@ import { encode } from "@msgpack/msgpack";
3
3
  import { gzipSync } from "node:zlib";
4
4
  import OpenAI from "openai";
5
5
  const defaultLLMOptions = {
6
- model: "llama-4-scout-17b-16e-instruct",
6
+ model: "gpt-oss-120b",
7
7
  baseURL: "https://api.cerebras.ai/v1",
8
8
  gzipCompression: true,
9
9
  msgpackEncoding: true
package/dist/llm.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/llm.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2026 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { llm } from '@livekit/agents';\nimport { LLM as OpenAILLM } from '@livekit/agents-plugin-openai';\nimport { encode } from '@msgpack/msgpack';\nimport { gzipSync } from 'node:zlib';\nimport OpenAI from 'openai';\nimport type { CerebrasChatModels } from './models.js';\n\nexport interface LLMOptions {\n model: string | CerebrasChatModels;\n apiKey?: string;\n baseURL?: string;\n user?: string;\n temperature?: number;\n client?: OpenAI;\n toolChoice?: llm.ToolChoice;\n parallelToolCalls?: boolean;\n gzipCompression?: boolean;\n msgpackEncoding?: boolean;\n}\n\nconst defaultLLMOptions: LLMOptions = {\n model: 'llama-4-scout-17b-16e-instruct',\n baseURL: 'https://api.cerebras.ai/v1',\n gzipCompression: true,\n msgpackEncoding: true,\n};\n\n/**\n * Create a custom fetch that compresses request payloads via msgpack and/or gzip.\n *\n * @see https://inference-docs.cerebras.ai/payload-optimization\n */\nfunction createCompressedFetch(opts: {\n useMsgpack: boolean;\n useGzip: boolean;\n}): typeof globalThis.fetch {\n return 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 return globalThis.fetch(input, { ...init, body: Buffer.from(body), headers });\n }\n return globalThis.fetch(input, init);\n };\n}\n\nexport class LLM extends OpenAILLM {\n constructor(opts: Partial<LLMOptions> = {}) {\n const merged = { ...defaultLLMOptions, ...opts };\n\n merged.apiKey = merged.apiKey || process.env.CEREBRAS_API_KEY;\n if (merged.apiKey === undefined && !merged.client) {\n throw new Error(\n 'Cerebras API key is required, either as an argument or as $CEREBRAS_API_KEY',\n );\n }\n\n if (!merged.client && (merged.gzipCompression || merged.msgpackEncoding)) {\n merged.client = new OpenAI({\n apiKey: merged.apiKey,\n baseURL: merged.baseURL,\n maxRetries: 0,\n fetch: createCompressedFetch({\n useMsgpack: merged.msgpackEncoding ?? true,\n useGzip: merged.gzipCompression ?? true,\n }),\n });\n }\n\n super(merged);\n }\n\n override label(): string {\n return 'cerebras.LLM';\n }\n}\n"],"mappings":"AAIA,SAAS,OAAO,iBAAiB;AACjC,SAAS,cAAc;AACvB,SAAS,gBAAgB;AACzB,OAAO,YAAY;AAgBnB,MAAM,oBAAgC;AAAA,EACpC,OAAO;AAAA,EACP,SAAS;AAAA,EACT,iBAAiB;AAAA,EACjB,iBAAiB;AACnB;AAOA,SAAS,sBAAsB,MAGH;AAC1B,SAAO,OAAO,OAA0B,SAA0C;AAChF,SAAI,6BAAM,YAAW,UAAU,KAAK,QAAQ,OAAO,KAAK,SAAS,UAAU;AACzE,YAAM,UAAU,IAAI,QAAQ,KAAK,OAAO;AAExC,UAAI;AACJ,UAAI,KAAK,YAAY;AACnB,eAAO,OAAO,KAAK,MAAM,KAAK,IAAI,CAAC;AACnC,gBAAQ,IAAI,gBAAgB,yBAAyB;AAAA,MACvD,OAAO;AACL,eAAO,IAAI,YAAY,EAAE,OAAO,KAAK,IAAI;AAAA,MAC3C;AAEA,UAAI,KAAK,SAAS;AAChB,eAAO,SAAS,MAAM,EAAE,OAAO,EAAE,CAAC;AAClC,gBAAQ,IAAI,oBAAoB,MAAM;AAAA,MACxC;AAEA,aAAO,WAAW,MAAM,OAAO,EAAE,GAAG,MAAM,MAAM,OAAO,KAAK,IAAI,GAAG,QAAQ,CAAC;AAAA,IAC9E;AACA,WAAO,WAAW,MAAM,OAAO,IAAI;AAAA,EACrC;AACF;AAEO,MAAM,YAAY,UAAU;AAAA,EACjC,YAAY,OAA4B,CAAC,GAAG;AAC1C,UAAM,SAAS,EAAE,GAAG,mBAAmB,GAAG,KAAK;AAE/C,WAAO,SAAS,OAAO,UAAU,QAAQ,IAAI;AAC7C,QAAI,OAAO,WAAW,UAAa,CAAC,OAAO,QAAQ;AACjD,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,QAAI,CAAC,OAAO,WAAW,OAAO,mBAAmB,OAAO,kBAAkB;AACxE,aAAO,SAAS,IAAI,OAAO;AAAA,QACzB,QAAQ,OAAO;AAAA,QACf,SAAS,OAAO;AAAA,QAChB,YAAY;AAAA,QACZ,OAAO,sBAAsB;AAAA,UAC3B,YAAY,OAAO,mBAAmB;AAAA,UACtC,SAAS,OAAO,mBAAmB;AAAA,QACrC,CAAC;AAAA,MACH,CAAC;AAAA,IACH;AAEA,UAAM,MAAM;AAAA,EACd;AAAA,EAES,QAAgB;AACvB,WAAO;AAAA,EACT;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/llm.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2026 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { llm } from '@livekit/agents';\nimport { LLM as OpenAILLM } from '@livekit/agents-plugin-openai';\nimport { encode } from '@msgpack/msgpack';\nimport { gzipSync } from 'node:zlib';\nimport OpenAI from 'openai';\nimport type { CerebrasChatModels } from './models.js';\n\nexport interface LLMOptions {\n model: string | CerebrasChatModels;\n apiKey?: string;\n baseURL?: string;\n user?: string;\n temperature?: number;\n client?: OpenAI;\n toolChoice?: llm.ToolChoice;\n parallelToolCalls?: boolean;\n gzipCompression?: boolean;\n msgpackEncoding?: boolean;\n}\n\nconst defaultLLMOptions: LLMOptions = {\n model: 'gpt-oss-120b',\n baseURL: 'https://api.cerebras.ai/v1',\n gzipCompression: true,\n msgpackEncoding: true,\n};\n\n/**\n * Create a custom fetch that compresses request payloads via msgpack and/or gzip.\n *\n * @see https://inference-docs.cerebras.ai/payload-optimization\n */\nfunction createCompressedFetch(opts: {\n useMsgpack: boolean;\n useGzip: boolean;\n}): typeof globalThis.fetch {\n return 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 return globalThis.fetch(input, { ...init, body: Buffer.from(body), headers });\n }\n return globalThis.fetch(input, init);\n };\n}\n\nexport class LLM extends OpenAILLM {\n constructor(opts: Partial<LLMOptions> = {}) {\n const merged = { ...defaultLLMOptions, ...opts };\n\n merged.apiKey = merged.apiKey || process.env.CEREBRAS_API_KEY;\n if (merged.apiKey === undefined && !merged.client) {\n throw new Error(\n 'Cerebras API key is required, either as an argument or as $CEREBRAS_API_KEY',\n );\n }\n\n if (!merged.client && (merged.gzipCompression || merged.msgpackEncoding)) {\n merged.client = new OpenAI({\n apiKey: merged.apiKey,\n baseURL: merged.baseURL,\n maxRetries: 0,\n fetch: createCompressedFetch({\n useMsgpack: merged.msgpackEncoding ?? true,\n useGzip: merged.gzipCompression ?? true,\n }),\n });\n }\n\n super(merged);\n }\n\n override label(): string {\n return 'cerebras.LLM';\n }\n}\n"],"mappings":"AAIA,SAAS,OAAO,iBAAiB;AACjC,SAAS,cAAc;AACvB,SAAS,gBAAgB;AACzB,OAAO,YAAY;AAgBnB,MAAM,oBAAgC;AAAA,EACpC,OAAO;AAAA,EACP,SAAS;AAAA,EACT,iBAAiB;AAAA,EACjB,iBAAiB;AACnB;AAOA,SAAS,sBAAsB,MAGH;AAC1B,SAAO,OAAO,OAA0B,SAA0C;AAChF,SAAI,6BAAM,YAAW,UAAU,KAAK,QAAQ,OAAO,KAAK,SAAS,UAAU;AACzE,YAAM,UAAU,IAAI,QAAQ,KAAK,OAAO;AAExC,UAAI;AACJ,UAAI,KAAK,YAAY;AACnB,eAAO,OAAO,KAAK,MAAM,KAAK,IAAI,CAAC;AACnC,gBAAQ,IAAI,gBAAgB,yBAAyB;AAAA,MACvD,OAAO;AACL,eAAO,IAAI,YAAY,EAAE,OAAO,KAAK,IAAI;AAAA,MAC3C;AAEA,UAAI,KAAK,SAAS;AAChB,eAAO,SAAS,MAAM,EAAE,OAAO,EAAE,CAAC;AAClC,gBAAQ,IAAI,oBAAoB,MAAM;AAAA,MACxC;AAEA,aAAO,WAAW,MAAM,OAAO,EAAE,GAAG,MAAM,MAAM,OAAO,KAAK,IAAI,GAAG,QAAQ,CAAC;AAAA,IAC9E;AACA,WAAO,WAAW,MAAM,OAAO,IAAI;AAAA,EACrC;AACF;AAEO,MAAM,YAAY,UAAU;AAAA,EACjC,YAAY,OAA4B,CAAC,GAAG;AAC1C,UAAM,SAAS,EAAE,GAAG,mBAAmB,GAAG,KAAK;AAE/C,WAAO,SAAS,OAAO,UAAU,QAAQ,IAAI;AAC7C,QAAI,OAAO,WAAW,UAAa,CAAC,OAAO,QAAQ;AACjD,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,QAAI,CAAC,OAAO,WAAW,OAAO,mBAAmB,OAAO,kBAAkB;AACxE,aAAO,SAAS,IAAI,OAAO;AAAA,QACzB,QAAQ,OAAO;AAAA,QACf,SAAS,OAAO;AAAA,QAChB,YAAY;AAAA,QACZ,OAAO,sBAAsB;AAAA,UAC3B,YAAY,OAAO,mBAAmB;AAAA,UACtC,SAAS,OAAO,mBAAmB;AAAA,QACrC,CAAC;AAAA,MACH,CAAC;AAAA,IACH;AAEA,UAAM,MAAM;AAAA,EACd;AAAA,EAES,QAAgB;AACvB,WAAO;AAAA,EACT;AACF;","names":[]}
package/dist/llm.test.cjs CHANGED
@@ -29,8 +29,8 @@ var import_vitest = require("vitest");
29
29
  var import_zod = require("zod");
30
30
  var import_llm = require("./llm.cjs");
31
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";
32
+ const CHAT_MODEL = "gpt-oss-120b";
33
+ const TOOL_MODEL = "gpt-oss-120b";
34
34
  function createCapturingFetch(opts) {
35
35
  const capturedRequests = [];
36
36
  const fetch = async (input, init) => {
@@ -1 +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 llm.tool({\n name: 'get_weather',\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"]}
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// gpt-oss-120b supports both basic chat and function calling.\nconst CHAT_MODEL = 'gpt-oss-120b';\nconst TOOL_MODEL = 'gpt-oss-120b';\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 llm.tool({\n name: 'get_weather',\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"]}
package/dist/llm.test.js CHANGED
@@ -6,8 +6,8 @@ import { assert, describe, expect, it } from "vitest";
6
6
  import { z } from "zod";
7
7
  import { LLM } from "./llm.js";
8
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";
9
+ const CHAT_MODEL = "gpt-oss-120b";
10
+ const TOOL_MODEL = "gpt-oss-120b";
11
11
  function createCapturingFetch(opts) {
12
12
  const capturedRequests = [];
13
13
  const fetch = async (input, init) => {
@@ -1 +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 llm.tool({\n name: 'get_weather',\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":[]}
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// gpt-oss-120b supports both basic chat and function calling.\nconst CHAT_MODEL = 'gpt-oss-120b';\nconst TOOL_MODEL = 'gpt-oss-120b';\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 llm.tool({\n name: 'get_weather',\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":[]}
@@ -1 +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":[]}
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 = 'gpt-oss-120b' | 'zai-glm-4.7' | 'gemma-4-31b';\n"],"mappings":";;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
package/dist/models.d.cts CHANGED
@@ -1,2 +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';
1
+ export type CerebrasChatModels = 'gpt-oss-120b' | 'zai-glm-4.7' | 'gemma-4-31b';
2
2
  //# sourceMappingURL=models.d.ts.map
package/dist/models.d.ts CHANGED
@@ -1,2 +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';
1
+ export type CerebrasChatModels = 'gpt-oss-120b' | 'zai-glm-4.7' | 'gemma-4-31b';
2
2
  //# sourceMappingURL=models.d.ts.map
@@ -1 +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"}
1
+ {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,kBAAkB,GAAG,cAAc,GAAG,aAAa,GAAG,aAAa,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@livekit/agents-plugin-cerebras",
3
- "version": "1.6.1",
3
+ "version": "1.6.3",
4
4
  "description": "Cerebras plugin for LiveKit Node Agents",
5
5
  "main": "dist/index.js",
6
6
  "require": "dist/index.cjs",
@@ -33,9 +33,9 @@
33
33
  "tsup": "^8.3.5",
34
34
  "typescript": "^5.0.0",
35
35
  "zod": "^3.25.76 || ^4.1.8",
36
- "@livekit/agents": "1.6.1",
37
- "@livekit/agents-plugin-openai": "1.6.1",
38
- "@livekit/agents-plugins-test": "1.6.1"
36
+ "@livekit/agents": "1.6.3",
37
+ "@livekit/agents-plugin-openai": "1.6.3",
38
+ "@livekit/agents-plugins-test": "1.6.3"
39
39
  },
40
40
  "dependencies": {
41
41
  "@msgpack/msgpack": "^3.0.0",
@@ -43,8 +43,8 @@
43
43
  },
44
44
  "peerDependencies": {
45
45
  "@livekit/rtc-node": "^0.13.33",
46
- "@livekit/agents": "1.6.1",
47
- "@livekit/agents-plugin-openai": "1.6.1"
46
+ "@livekit/agents": "1.6.3",
47
+ "@livekit/agents-plugin-openai": "1.6.3"
48
48
  },
49
49
  "scripts": {
50
50
  "build": "tsup --onSuccess \"pnpm build:types\"",
package/src/llm.test.ts CHANGED
@@ -12,10 +12,9 @@ import { LLM } from './llm.js';
12
12
 
13
13
  assert(process.env.CEREBRAS_API_KEY, 'CEREBRAS_API_KEY must be set');
14
14
 
15
- // llama3.1-8b is fast and has generous rate limits but can't do tool calls reliably;
16
- // qwen-3-235b is needed for function calling but has tight per-minute token quotas.
17
- const CHAT_MODEL = 'llama3.1-8b';
18
- const TOOL_MODEL = 'qwen-3-235b-a22b-instruct-2507';
15
+ // gpt-oss-120b supports both basic chat and function calling.
16
+ const CHAT_MODEL = 'gpt-oss-120b';
17
+ const TOOL_MODEL = 'gpt-oss-120b';
19
18
 
20
19
  interface CapturedRequest {
21
20
  url: string;
package/src/llm.ts CHANGED
@@ -22,7 +22,7 @@ export interface LLMOptions {
22
22
  }
23
23
 
24
24
  const defaultLLMOptions: LLMOptions = {
25
- model: 'llama-4-scout-17b-16e-instruct',
25
+ model: 'gpt-oss-120b',
26
26
  baseURL: 'https://api.cerebras.ai/v1',
27
27
  gzipCompression: true,
28
28
  msgpackEncoding: true,
package/src/models.ts CHANGED
@@ -2,13 +2,4 @@
2
2
  //
3
3
  // SPDX-License-Identifier: Apache-2.0
4
4
 
5
- export type CerebrasChatModels =
6
- | 'llama3.1-8b'
7
- | 'llama-3.3-70b'
8
- | 'llama-4-scout-17b-16e-instruct'
9
- | 'llama-4-maverick-17b-128e-instruct'
10
- | 'qwen-3-32b'
11
- | 'qwen-3-235b-a22b-instruct-2507'
12
- | 'qwen-3-235b-a22b-thinking-2507'
13
- | 'qwen-3-coder-480b'
14
- | 'gpt-oss-120b';
5
+ export type CerebrasChatModels = 'gpt-oss-120b' | 'zai-glm-4.7' | 'gemma-4-31b';