getpatter 0.5.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2748,7 +2748,7 @@ async function queryDeepgramCost(metricsAcc, deepgramKey, deepgramRequestId) {
2748
2748
  const usd = reqData.response?.details?.usd;
2749
2749
  if (usd != null) {
2750
2750
  metricsAcc.setActualSttCost(usd);
2751
- getLogger().info(`Deepgram actual cost: $${usd}`);
2751
+ getLogger().debug(`Deepgram actual cost: $${usd}`);
2752
2752
  }
2753
2753
  }
2754
2754
  }
@@ -2816,7 +2816,7 @@ var init_stream_handler = __esm({
2816
2816
  ttsProvider: ttsProviderName,
2817
2817
  pricing: deps.pricing
2818
2818
  });
2819
- getLogger().info(`WebSocket connection opened (${deps.bridge.label})`);
2819
+ getLogger().debug(`WebSocket connection opened (${deps.bridge.label})`);
2820
2820
  }
2821
2821
  // ---------------------------------------------------------------------------
2822
2822
  // Public: called by the provider-specific parsers in server.ts
@@ -2832,9 +2832,12 @@ var init_stream_handler = __esm({
2832
2832
  this.metricsAcc.callId = callId;
2833
2833
  if (customParams.caller && !this.caller) this.caller = customParams.caller;
2834
2834
  if (customParams.callee && !this.callee) this.callee = customParams.callee;
2835
- getLogger().info(`Call started: ${callId}`);
2835
+ const mode = this.deps.agent.engine ? `engine=${this.deps.agent.engine.kind ?? "unknown"}` : "pipeline";
2836
+ getLogger().info(
2837
+ `Call started: ${callId} (${this.deps.bridge.label}, ${mode}, ${sanitizeLogValue(this.caller || "?")} \u2192 ${sanitizeLogValue(this.callee || "?")})`
2838
+ );
2836
2839
  if (Object.keys(customParams).length > 0) {
2837
- getLogger().info(`Custom params: ${sanitizeLogValue(JSON.stringify(customParams))}`);
2840
+ getLogger().debug(`Custom params: ${sanitizeLogValue(JSON.stringify(customParams))}`);
2838
2841
  }
2839
2842
  this.deps.metricsStore.recordCallStart({
2840
2843
  call_id: callId,
@@ -2882,7 +2885,7 @@ var init_stream_handler = __esm({
2882
2885
  }
2883
2886
  });
2884
2887
  if (recResp.ok) {
2885
- getLogger().info(`Recording started for ${callId}`);
2888
+ getLogger().debug(`Recording started for ${callId}`);
2886
2889
  } else {
2887
2890
  getLogger().warn(`could not start recording: ${await recResp.text()}`);
2888
2891
  }
@@ -2937,7 +2940,7 @@ var init_stream_handler = __esm({
2937
2940
  }
2938
2941
  /** Handle a DTMF keypress event (Twilio only). */
2939
2942
  async handleDtmf(digit) {
2940
- getLogger().info(`DTMF: ${digit}`);
2943
+ getLogger().debug(`DTMF: ${digit}`);
2941
2944
  if (this.adapter instanceof OpenAIRealtimeAdapter) {
2942
2945
  await this.adapter.sendText(`The user pressed key ${digit} on their phone keypad.`);
2943
2946
  }
@@ -2999,14 +3002,14 @@ var init_stream_handler = __esm({
2999
3002
  this.stt = await this.deps.bridge.createStt(this.deps.agent);
3000
3003
  this.tts = await createTTS(this.deps.agent);
3001
3004
  if (!this.stt) {
3002
- getLogger().info(`Pipeline mode (${label}): no STT configured`);
3005
+ getLogger().debug(`Pipeline mode (${label}): no STT configured`);
3003
3006
  }
3004
3007
  if (!this.tts) {
3005
- getLogger().info(`Pipeline mode (${label}): no TTS configured`);
3008
+ getLogger().debug(`Pipeline mode (${label}): no TTS configured`);
3006
3009
  }
3007
3010
  try {
3008
3011
  if (this.stt) await this.stt.connect();
3009
- getLogger().info(`Pipeline mode (${label}): STT + TTS connected`);
3012
+ getLogger().debug(`Pipeline mode (${label}): STT + TTS connected`);
3010
3013
  } catch (e) {
3011
3014
  getLogger().error(`Pipeline connect FAILED (${label}):`, e);
3012
3015
  try {
@@ -3039,7 +3042,24 @@ var init_stream_handler = __esm({
3039
3042
  this.history.push({ role: "assistant", text: this.deps.agent.firstMessage, timestamp: Date.now() });
3040
3043
  }
3041
3044
  }
3042
- if (!this.deps.onMessage && this.deps.config.openaiKey) {
3045
+ if (this.deps.agent.llm) {
3046
+ if (this.deps.onMessage) {
3047
+ throw new Error(
3048
+ "Cannot pass both agent({ llm }) and serve({ onMessage }). Pick one \u2014 `llm` for built-in LLMs, `onMessage` for custom logic."
3049
+ );
3050
+ }
3051
+ this.llmLoop = new LLMLoop(
3052
+ "",
3053
+ // apiKey unused when llmProvider is supplied
3054
+ "",
3055
+ // model unused when llmProvider is supplied
3056
+ resolvedPrompt,
3057
+ this.deps.agent.tools,
3058
+ this.deps.agent.llm
3059
+ );
3060
+ const llmLabel = this.deps.agent.llm.constructor?.name ?? "custom";
3061
+ getLogger().debug(`Built-in LLM loop active (pipeline, ${label}, llm=${llmLabel})`);
3062
+ } else if (!this.deps.onMessage && this.deps.config.openaiKey) {
3043
3063
  let llmModel = this.deps.agent.model || "gpt-4o-mini";
3044
3064
  if (llmModel.includes("realtime")) llmModel = "gpt-4o-mini";
3045
3065
  this.llmLoop = new LLMLoop(
@@ -3048,7 +3068,7 @@ var init_stream_handler = __esm({
3048
3068
  resolvedPrompt,
3049
3069
  this.deps.agent.tools
3050
3070
  );
3051
- getLogger().info(`Built-in LLM loop active (pipeline, ${label})`);
3071
+ getLogger().debug(`Built-in LLM loop active (pipeline, ${label})`);
3052
3072
  }
3053
3073
  if (this.stt) {
3054
3074
  this.stt.onTranscript(async (transcript) => {
@@ -3109,7 +3129,7 @@ var init_stream_handler = __esm({
3109
3129
  }
3110
3130
  async processTranscript(transcript) {
3111
3131
  if (transcript.text && this.isSpeaking) {
3112
- getLogger().info(
3132
+ getLogger().debug(
3113
3133
  `Barge-in: caller spoke over agent (${sanitizeLogValue(transcript.text.slice(0, 40))})`
3114
3134
  );
3115
3135
  this.isSpeaking = false;
@@ -3144,17 +3164,17 @@ var init_stream_handler = __esm({
3144
3164
  "cool"
3145
3165
  ]);
3146
3166
  if (HALLUCINATIONS.has(stripped) || stripped === "") {
3147
- getLogger().info(`Dropped likely STT hallucination: ${sanitizeLogValue(normalised.slice(0, 40))}`);
3167
+ getLogger().debug(`Dropped likely STT hallucination: ${sanitizeLogValue(normalised.slice(0, 40))}`);
3148
3168
  return;
3149
3169
  }
3150
3170
  if (sinceLastMs < 2e3 && normalised === this.lastCommitText) {
3151
- getLogger().info(
3171
+ getLogger().debug(
3152
3172
  `Dropped duplicate final transcript (${(sinceLastMs / 1e3).toFixed(1)}s since last): ${sanitizeLogValue(normalised.slice(0, 40))}`
3153
3173
  );
3154
3174
  return;
3155
3175
  }
3156
3176
  if (sinceLastMs < 500) {
3157
- getLogger().info(
3177
+ getLogger().debug(
3158
3178
  `Dropped back-to-back final transcript (${(sinceLastMs / 1e3).toFixed(2)}s since last): ${sanitizeLogValue(normalised.slice(0, 40))}`
3159
3179
  );
3160
3180
  return;
@@ -3162,7 +3182,7 @@ var init_stream_handler = __esm({
3162
3182
  this.lastCommitText = normalised;
3163
3183
  this.lastCommitAt = now;
3164
3184
  const label = this.deps.bridge.label;
3165
- getLogger().info(`User (${label} pipeline): ${sanitizeLogValue(transcript.text)}`);
3185
+ getLogger().debug(`User (${label} pipeline): ${sanitizeLogValue(transcript.text)}`);
3166
3186
  this.metricsAcc.startTurn();
3167
3187
  this.metricsAcc.recordSttComplete(transcript.text);
3168
3188
  if (this.deps.onTranscript) {
@@ -3177,7 +3197,7 @@ var init_stream_handler = __esm({
3177
3197
  const hookCtx = this.buildHookContext();
3178
3198
  const filteredTranscript = await hookExecutor.runAfterTranscribe(transcript.text, hookCtx);
3179
3199
  if (filteredTranscript === null) {
3180
- getLogger().info(`afterTranscribe hook vetoed turn (${label})`);
3200
+ getLogger().debug(`afterTranscribe hook vetoed turn (${label})`);
3181
3201
  this.metricsAcc.recordTurnInterrupted();
3182
3202
  return;
3183
3203
  }
@@ -3265,7 +3285,7 @@ var init_stream_handler = __esm({
3265
3285
  if (!this.llmLoop) {
3266
3286
  const guard = checkGuardrails(responseText, this.deps.agent.guardrails);
3267
3287
  if (guard) {
3268
- getLogger().info(`Guardrail '${guard.name}' triggered (pipeline)`);
3288
+ getLogger().debug(`Guardrail '${guard.name}' triggered (pipeline)`);
3269
3289
  responseText = guard.replacement ?? "I'm sorry, I can't respond to that.";
3270
3290
  }
3271
3291
  this.metricsAcc.recordLlmComplete();
@@ -3343,7 +3363,7 @@ var init_stream_handler = __esm({
3343
3363
  this.adapter = this.deps.buildAIAdapter(resolvedPrompt);
3344
3364
  try {
3345
3365
  await this.adapter.connect();
3346
- getLogger().info(`AI adapter connected (${label})`);
3366
+ getLogger().debug(`AI adapter connected (${label})`);
3347
3367
  } catch (e) {
3348
3368
  getLogger().error(`AI adapter connect FAILED (${label}):`, e);
3349
3369
  try {
@@ -3385,7 +3405,7 @@ var init_stream_handler = __esm({
3385
3405
  this.deps.bridge.sendMark(this.ws, `audio_${this.chunkCount}`, this.streamSid);
3386
3406
  } else if (type === "transcript_input") {
3387
3407
  const inputText = eventData;
3388
- getLogger().info(`User (${this.deps.bridge.label}): ${sanitizeLogValue(inputText)}`);
3408
+ getLogger().debug(`User (${this.deps.bridge.label}): ${sanitizeLogValue(inputText)}`);
3389
3409
  this.history.push({ role: "user", text: inputText, timestamp: Date.now() });
3390
3410
  this.metricsAcc.startTurn();
3391
3411
  this.currentAgentText = "";
@@ -3403,7 +3423,7 @@ var init_stream_handler = __esm({
3403
3423
  if (outputText) {
3404
3424
  const triggered = checkGuardrails(outputText, this.deps.agent.guardrails);
3405
3425
  if (triggered) {
3406
- getLogger().info(`Guardrail '${triggered.name}' triggered`);
3426
+ getLogger().debug(`Guardrail '${triggered.name}' triggered`);
3407
3427
  if (this.adapter instanceof OpenAIRealtimeAdapter) {
3408
3428
  this.adapter.cancelResponse();
3409
3429
  await this.adapter.sendText(triggered.replacement ?? "I'm sorry, I can't respond to that.");
@@ -3462,7 +3482,7 @@ var init_stream_handler = __esm({
3462
3482
  await adapter.sendFunctionResult(fc.call_id, JSON.stringify({ error: "Invalid phone number format", status: "rejected" }));
3463
3483
  return;
3464
3484
  }
3465
- getLogger().info(`Transferring call to ${transferTo}`);
3485
+ getLogger().debug(`Transferring call to ${transferTo}`);
3466
3486
  await adapter.sendFunctionResult(fc.call_id, JSON.stringify({ status: "transferring", to: transferTo }));
3467
3487
  await this.deps.bridge.transferCall(this.callId, transferTo);
3468
3488
  if (this.deps.onTranscript) {
@@ -3478,7 +3498,7 @@ var init_stream_handler = __esm({
3478
3498
  endArgs = {};
3479
3499
  }
3480
3500
  const reason = endArgs.reason ?? "conversation_complete";
3481
- getLogger().info(`Ending call (${this.deps.bridge.label}): ${reason}`);
3501
+ getLogger().debug(`Ending call (${this.deps.bridge.label}): ${reason}`);
3482
3502
  await adapter.sendFunctionResult(fc.call_id, JSON.stringify({ status: "ending", reason }));
3483
3503
  await this.deps.bridge.endCall(this.callId, this.ws);
3484
3504
  if (this.deps.onTranscript) {
@@ -3530,6 +3550,11 @@ var init_stream_handler = __esm({
3530
3550
  transcript: [...this.history.entries],
3531
3551
  metrics: finalMetrics
3532
3552
  };
3553
+ const cost = finalMetrics.cost?.total ?? 0;
3554
+ const latencyP95 = finalMetrics.latency_p95?.total_ms ?? 0;
3555
+ getLogger().info(
3556
+ `Call ended: ${this.callId} (${finalMetrics.duration_seconds.toFixed(1)}s, ${finalMetrics.turns.length} turns, cost=$${cost.toFixed(4)}, p95=${Math.round(latencyP95)}ms)`
3557
+ );
3533
3558
  this.deps.metricsStore.recordCallEnd(
3534
3559
  callEndData,
3535
3560
  finalMetrics
@@ -4438,832 +4463,6 @@ Connect AI agents to phone numbers in 4 lines of code
4438
4463
  }
4439
4464
  });
4440
4465
 
4441
- // node_modules/cloudflared/lib/constants.js
4442
- var require_constants = __commonJS({
4443
- "node_modules/cloudflared/lib/constants.js"(exports2, module2) {
4444
- "use strict";
4445
- var __create2 = Object.create;
4446
- var __defProp2 = Object.defineProperty;
4447
- var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
4448
- var __getOwnPropNames2 = Object.getOwnPropertyNames;
4449
- var __getProtoOf2 = Object.getPrototypeOf;
4450
- var __hasOwnProp2 = Object.prototype.hasOwnProperty;
4451
- var __export2 = (target, all) => {
4452
- for (var name in all)
4453
- __defProp2(target, name, { get: all[name], enumerable: true });
4454
- };
4455
- var __copyProps2 = (to, from, except, desc) => {
4456
- if (from && typeof from === "object" || typeof from === "function") {
4457
- for (let key of __getOwnPropNames2(from))
4458
- if (!__hasOwnProp2.call(to, key) && key !== except)
4459
- __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
4460
- }
4461
- return to;
4462
- };
4463
- var __toESM2 = (mod, isNodeMode, target) => (target = mod != null ? __create2(__getProtoOf2(mod)) : {}, __copyProps2(
4464
- // If the importer is in node compatibility mode or this is not an ESM
4465
- // file that has been converted to a CommonJS file using a Babel-
4466
- // compatible transform (i.e. "__esModule" has not been set), then set
4467
- // "default" to the CommonJS "module.exports" for node compatibility.
4468
- isNodeMode || !mod || !mod.__esModule ? __defProp2(target, "default", { value: mod, enumerable: true }) : target,
4469
- mod
4470
- ));
4471
- var __toCommonJS2 = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
4472
- var constants_exports = {};
4473
- __export2(constants_exports, {
4474
- CLOUDFLARED_VERSION: () => CLOUDFLARED_VERSION,
4475
- DEFAULT_CLOUDFLARED_BIN: () => DEFAULT_CLOUDFLARED_BIN,
4476
- RELEASE_BASE: () => RELEASE_BASE,
4477
- bin: () => bin,
4478
- use: () => use
4479
- });
4480
- module2.exports = __toCommonJS2(constants_exports);
4481
- var import_node_path = __toESM2(require("path"));
4482
- var DEFAULT_CLOUDFLARED_BIN = import_node_path.default.join(
4483
- __dirname,
4484
- "..",
4485
- "bin",
4486
- process.platform === "win32" ? "cloudflared.exe" : "cloudflared"
4487
- );
4488
- var bin = process.env.CLOUDFLARED_BIN || DEFAULT_CLOUDFLARED_BIN;
4489
- function use(executable) {
4490
- bin = executable;
4491
- }
4492
- var CLOUDFLARED_VERSION = process.env.CLOUDFLARED_VERSION || "latest";
4493
- var RELEASE_BASE = "https://github.com/cloudflare/cloudflared/releases/";
4494
- }
4495
- });
4496
-
4497
- // node_modules/cloudflared/lib/error.js
4498
- var require_error = __commonJS({
4499
- "node_modules/cloudflared/lib/error.js"(exports2, module2) {
4500
- "use strict";
4501
- var __defProp2 = Object.defineProperty;
4502
- var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
4503
- var __getOwnPropNames2 = Object.getOwnPropertyNames;
4504
- var __hasOwnProp2 = Object.prototype.hasOwnProperty;
4505
- var __export2 = (target, all) => {
4506
- for (var name in all)
4507
- __defProp2(target, name, { get: all[name], enumerable: true });
4508
- };
4509
- var __copyProps2 = (to, from, except, desc) => {
4510
- if (from && typeof from === "object" || typeof from === "function") {
4511
- for (let key of __getOwnPropNames2(from))
4512
- if (!__hasOwnProp2.call(to, key) && key !== except)
4513
- __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
4514
- }
4515
- return to;
4516
- };
4517
- var __toCommonJS2 = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
4518
- var error_exports = {};
4519
- __export2(error_exports, {
4520
- UnsupportedError: () => UnsupportedError
4521
- });
4522
- module2.exports = __toCommonJS2(error_exports);
4523
- var UnsupportedError = class extends Error {
4524
- constructor(message) {
4525
- super(message);
4526
- }
4527
- };
4528
- }
4529
- });
4530
-
4531
- // node_modules/cloudflared/lib/install.js
4532
- var require_install = __commonJS({
4533
- "node_modules/cloudflared/lib/install.js"(exports2, module2) {
4534
- "use strict";
4535
- var __create2 = Object.create;
4536
- var __defProp2 = Object.defineProperty;
4537
- var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
4538
- var __getOwnPropNames2 = Object.getOwnPropertyNames;
4539
- var __getProtoOf2 = Object.getPrototypeOf;
4540
- var __hasOwnProp2 = Object.prototype.hasOwnProperty;
4541
- var __export2 = (target, all) => {
4542
- for (var name in all)
4543
- __defProp2(target, name, { get: all[name], enumerable: true });
4544
- };
4545
- var __copyProps2 = (to, from, except, desc) => {
4546
- if (from && typeof from === "object" || typeof from === "function") {
4547
- for (let key of __getOwnPropNames2(from))
4548
- if (!__hasOwnProp2.call(to, key) && key !== except)
4549
- __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
4550
- }
4551
- return to;
4552
- };
4553
- var __toESM2 = (mod, isNodeMode, target) => (target = mod != null ? __create2(__getProtoOf2(mod)) : {}, __copyProps2(
4554
- // If the importer is in node compatibility mode or this is not an ESM
4555
- // file that has been converted to a CommonJS file using a Babel-
4556
- // compatible transform (i.e. "__esModule" has not been set), then set
4557
- // "default" to the CommonJS "module.exports" for node compatibility.
4558
- isNodeMode || !mod || !mod.__esModule ? __defProp2(target, "default", { value: mod, enumerable: true }) : target,
4559
- mod
4560
- ));
4561
- var __toCommonJS2 = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
4562
- var install_exports = {};
4563
- __export2(install_exports, {
4564
- install: () => install,
4565
- install_linux: () => install_linux,
4566
- install_macos: () => install_macos,
4567
- install_windows: () => install_windows
4568
- });
4569
- module2.exports = __toCommonJS2(install_exports);
4570
- var import_node_fs = __toESM2(require("fs"));
4571
- var import_node_path = __toESM2(require("path"));
4572
- var import_node_https = __toESM2(require("https"));
4573
- var import_node_child_process = require("child_process");
4574
- var import_constants = require_constants();
4575
- var import_error = require_error();
4576
- var LINUX_URL = {
4577
- arm64: "cloudflared-linux-arm64",
4578
- arm: "cloudflared-linux-arm",
4579
- x64: "cloudflared-linux-amd64",
4580
- ia32: "cloudflared-linux-386"
4581
- };
4582
- var MACOS_URL = {
4583
- arm64: "cloudflared-darwin-arm64.tgz",
4584
- x64: "cloudflared-darwin-amd64.tgz"
4585
- };
4586
- var WINDOWS_URL = {
4587
- x64: "cloudflared-windows-amd64.exe",
4588
- ia32: "cloudflared-windows-386.exe"
4589
- };
4590
- function resolve_base(version2) {
4591
- if (version2 === "latest") {
4592
- return `${import_constants.RELEASE_BASE}latest/download/`;
4593
- }
4594
- return `${import_constants.RELEASE_BASE}download/${version2}/`;
4595
- }
4596
- async function install(to, version2 = import_constants.CLOUDFLARED_VERSION) {
4597
- if (process.platform === "linux") {
4598
- return install_linux(to, version2);
4599
- } else if (process.platform === "darwin") {
4600
- return install_macos(to, version2);
4601
- } else if (process.platform === "win32") {
4602
- return install_windows(to, version2);
4603
- } else {
4604
- throw new import_error.UnsupportedError("Unsupported platform: " + process.platform);
4605
- }
4606
- }
4607
- async function install_linux(to, version2 = import_constants.CLOUDFLARED_VERSION) {
4608
- const file = LINUX_URL[process.arch];
4609
- if (file === void 0) {
4610
- throw new import_error.UnsupportedError("Unsupported architecture: " + process.arch);
4611
- }
4612
- await download(resolve_base(version2) + file, to);
4613
- import_node_fs.default.chmodSync(to, "755");
4614
- return to;
4615
- }
4616
- async function install_macos(to, version2 = import_constants.CLOUDFLARED_VERSION) {
4617
- let arch = process.arch;
4618
- if (version2 !== "latest" && version_number(version2) < 20240802) {
4619
- arch = "x64";
4620
- }
4621
- const file = MACOS_URL[arch];
4622
- if (file === void 0) {
4623
- throw new import_error.UnsupportedError("Unsupported architecture: " + arch);
4624
- }
4625
- await download(resolve_base(version2) + file, `${to}.tgz`);
4626
- process.env.VERBOSE && console.log(`Extracting to ${to}`);
4627
- (0, import_node_child_process.execSync)(`tar -xzf ${import_node_path.default.basename(`${to}.tgz`)}`, { cwd: import_node_path.default.dirname(to) });
4628
- import_node_fs.default.unlinkSync(`${to}.tgz`);
4629
- import_node_fs.default.renameSync(`${import_node_path.default.dirname(to)}/cloudflared`, to);
4630
- return to;
4631
- }
4632
- async function install_windows(to, version2 = import_constants.CLOUDFLARED_VERSION) {
4633
- const file = WINDOWS_URL[process.arch];
4634
- if (file === void 0) {
4635
- throw new import_error.UnsupportedError("Unsupported architecture: " + process.arch);
4636
- }
4637
- await download(resolve_base(version2) + file, to);
4638
- return to;
4639
- }
4640
- function download(url, to, redirect = 0) {
4641
- if (redirect === 0) {
4642
- process.env.VERBOSE && console.log(`Downloading ${url} to ${to}`);
4643
- } else {
4644
- process.env.VERBOSE && console.log(`Redirecting to ${url}`);
4645
- }
4646
- if (!import_node_fs.default.existsSync(import_node_path.default.dirname(to))) {
4647
- import_node_fs.default.mkdirSync(import_node_path.default.dirname(to), { recursive: true });
4648
- }
4649
- return new Promise((resolve, reject) => {
4650
- const request = import_node_https.default.get(url, (res) => {
4651
- const redirect_code = [301, 302, 303, 307, 308];
4652
- if (redirect_code.includes(res.statusCode) && res.headers.location !== void 0) {
4653
- request.destroy();
4654
- const redirection = res.headers.location;
4655
- resolve(download(redirection, to, redirect + 1));
4656
- return;
4657
- }
4658
- if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
4659
- const file = import_node_fs.default.createWriteStream(to);
4660
- file.on("finish", () => {
4661
- file.close(() => resolve(to));
4662
- });
4663
- file.on("error", (err) => {
4664
- import_node_fs.default.unlink(to, () => reject(err));
4665
- });
4666
- res.pipe(file);
4667
- } else {
4668
- request.destroy();
4669
- reject(new Error(`HTTP response with status code: ${res.statusCode}`));
4670
- }
4671
- });
4672
- request.on("error", (err) => {
4673
- reject(err);
4674
- });
4675
- request.end();
4676
- });
4677
- }
4678
- function version_number(semver) {
4679
- const [major, minor, patch] = semver.split(".").map(Number);
4680
- return major * 1e4 + minor * 100 + patch;
4681
- }
4682
- }
4683
- });
4684
-
4685
- // node_modules/cloudflared/lib/regex.js
4686
- var require_regex = __commonJS({
4687
- "node_modules/cloudflared/lib/regex.js"(exports2, module2) {
4688
- "use strict";
4689
- var __defProp2 = Object.defineProperty;
4690
- var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
4691
- var __getOwnPropNames2 = Object.getOwnPropertyNames;
4692
- var __hasOwnProp2 = Object.prototype.hasOwnProperty;
4693
- var __export2 = (target, all) => {
4694
- for (var name in all)
4695
- __defProp2(target, name, { get: all[name], enumerable: true });
4696
- };
4697
- var __copyProps2 = (to, from, except, desc) => {
4698
- if (from && typeof from === "object" || typeof from === "function") {
4699
- for (let key of __getOwnPropNames2(from))
4700
- if (!__hasOwnProp2.call(to, key) && key !== except)
4701
- __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
4702
- }
4703
- return to;
4704
- };
4705
- var __toCommonJS2 = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
4706
- var regex_exports = {};
4707
- __export2(regex_exports, {
4708
- config_regex: () => config_regex,
4709
- conn_regex: () => conn_regex,
4710
- connectorID_regex: () => connectorID_regex,
4711
- disconnect_regex: () => disconnect_regex,
4712
- index_regex: () => index_regex,
4713
- ip_regex: () => ip_regex,
4714
- location_regex: () => location_regex,
4715
- metrics_regex: () => metrics_regex,
4716
- tunnelID_regex: () => tunnelID_regex
4717
- });
4718
- module2.exports = __toCommonJS2(regex_exports);
4719
- var conn_regex = /connection[= ]([0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[0-9a-f]{4}-[0-9a-f]{12})/i;
4720
- var ip_regex = /ip=([0-9.]+)/;
4721
- var location_regex = /location=([A-Za-z0-9]+)/;
4722
- var index_regex = /connIndex=(\d)/;
4723
- var disconnect_regex = /Unregistered tunnel connection connIndex=(\d)/i;
4724
- var tunnelID_regex = /tunnelID=([0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[0-9a-f]{4}-[0-9a-f]{12})/i;
4725
- var connectorID_regex = /Connector ID: ([0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[0-9a-f]{4}-[0-9a-f]{12})/i;
4726
- var metrics_regex = /metrics server on ([0-9.:]+\/metrics)/;
4727
- var config_regex = /config="(.+[^\\])"/;
4728
- }
4729
- });
4730
-
4731
- // node_modules/cloudflared/lib/handler.js
4732
- var require_handler = __commonJS({
4733
- "node_modules/cloudflared/lib/handler.js"(exports2, module2) {
4734
- "use strict";
4735
- var __defProp2 = Object.defineProperty;
4736
- var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
4737
- var __getOwnPropNames2 = Object.getOwnPropertyNames;
4738
- var __hasOwnProp2 = Object.prototype.hasOwnProperty;
4739
- var __export2 = (target, all) => {
4740
- for (var name in all)
4741
- __defProp2(target, name, { get: all[name], enumerable: true });
4742
- };
4743
- var __copyProps2 = (to, from, except, desc) => {
4744
- if (from && typeof from === "object" || typeof from === "function") {
4745
- for (let key of __getOwnPropNames2(from))
4746
- if (!__hasOwnProp2.call(to, key) && key !== except)
4747
- __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
4748
- }
4749
- return to;
4750
- };
4751
- var __toCommonJS2 = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
4752
- var handler_exports = {};
4753
- __export2(handler_exports, {
4754
- ConfigHandler: () => ConfigHandler,
4755
- ConnectionHandler: () => ConnectionHandler,
4756
- TryCloudflareHandler: () => TryCloudflareHandler
4757
- });
4758
- module2.exports = __toCommonJS2(handler_exports);
4759
- var import_node_stream = require("stream");
4760
- var import_regex2 = require_regex();
4761
- var ConnectionHandler = class {
4762
- constructor(tunnel) {
4763
- this.connections = [];
4764
- this.connected_handler = (output, tunnel2) => {
4765
- const conn_match = output.match(import_regex2.conn_regex);
4766
- const ip_match = output.match(import_regex2.ip_regex);
4767
- const location_match = output.match(import_regex2.location_regex);
4768
- const index_match = output.match(import_regex2.index_regex);
4769
- if (conn_match && ip_match && location_match && index_match) {
4770
- const connection = {
4771
- id: conn_match[1],
4772
- ip: ip_match[1],
4773
- location: location_match[1]
4774
- };
4775
- this.connections[Number(index_match[1])] = connection;
4776
- tunnel2.emit("connected", connection);
4777
- }
4778
- };
4779
- this.disconnected_handler = (output, tunnel2) => {
4780
- const index_match = output.includes("terminated") ? output.match(import_regex2.index_regex) : null;
4781
- if (index_match) {
4782
- const index = Number(index_match[1]);
4783
- if (this.connections[index]) {
4784
- tunnel2.emit("disconnected", this.connections[index]);
4785
- this.connections[index] = void 0;
4786
- }
4787
- }
4788
- };
4789
- tunnel.addHandler(this.connected_handler.bind(this));
4790
- tunnel.addHandler(this.disconnected_handler.bind(this));
4791
- }
4792
- };
4793
- var TryCloudflareHandler = class {
4794
- constructor(tunnel) {
4795
- this.url_handler = (output, tunnel2) => {
4796
- const url_match = output.match(/https:\/\/([a-z0-9-]+)\.trycloudflare\.com/);
4797
- if (url_match) {
4798
- tunnel2.emit("url", url_match[0]);
4799
- }
4800
- };
4801
- tunnel.addHandler(this.url_handler.bind(this));
4802
- }
4803
- };
4804
- var ConfigHandler = class extends import_node_stream.EventEmitter {
4805
- constructor(tunnel) {
4806
- super();
4807
- this.config_handler = (output, tunnel2) => {
4808
- const config_match = output.match(/\bconfig="(.+?)" version=(\d+)/);
4809
- if (config_match) {
4810
- try {
4811
- const config_str = config_match[1].replace(/\\"/g, '"');
4812
- const config = JSON.parse(config_str);
4813
- const version2 = parseInt(config_match[2], 10);
4814
- this.emit("config", {
4815
- config,
4816
- version: version2
4817
- });
4818
- if (config && typeof config === "object" && "ingress" in config && Array.isArray(config.ingress)) {
4819
- for (const ingress of config.ingress) {
4820
- if ("hostname" in ingress) {
4821
- tunnel2.emit("url", ingress.hostname);
4822
- }
4823
- }
4824
- }
4825
- } catch (error) {
4826
- this.emit("error", new Error(`Failed to parse config: ${error}`));
4827
- }
4828
- }
4829
- };
4830
- tunnel.addHandler(this.config_handler.bind(this));
4831
- }
4832
- on(event, listener) {
4833
- return super.on(event, listener);
4834
- }
4835
- once(event, listener) {
4836
- return super.once(event, listener);
4837
- }
4838
- off(event, listener) {
4839
- return super.off(event, listener);
4840
- }
4841
- emit(event, ...args) {
4842
- return super.emit(event, ...args);
4843
- }
4844
- };
4845
- }
4846
- });
4847
-
4848
- // node_modules/cloudflared/lib/tunnel.js
4849
- var require_tunnel = __commonJS({
4850
- "node_modules/cloudflared/lib/tunnel.js"(exports2, module2) {
4851
- "use strict";
4852
- var __defProp2 = Object.defineProperty;
4853
- var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
4854
- var __getOwnPropNames2 = Object.getOwnPropertyNames;
4855
- var __hasOwnProp2 = Object.prototype.hasOwnProperty;
4856
- var __export2 = (target, all) => {
4857
- for (var name in all)
4858
- __defProp2(target, name, { get: all[name], enumerable: true });
4859
- };
4860
- var __copyProps2 = (to, from, except, desc) => {
4861
- if (from && typeof from === "object" || typeof from === "function") {
4862
- for (let key of __getOwnPropNames2(from))
4863
- if (!__hasOwnProp2.call(to, key) && key !== except)
4864
- __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
4865
- }
4866
- return to;
4867
- };
4868
- var __toCommonJS2 = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
4869
- var tunnel_exports2 = {};
4870
- __export2(tunnel_exports2, {
4871
- Tunnel: () => Tunnel,
4872
- build_args: () => build_args,
4873
- build_options: () => build_options,
4874
- tunnel: () => tunnel
4875
- });
4876
- module2.exports = __toCommonJS2(tunnel_exports2);
4877
- var import_node_child_process = require("child_process");
4878
- var import_node_events = require("events");
4879
- var import_constants = require_constants();
4880
- var import_handler = require_handler();
4881
- var Tunnel = class _Tunnel extends import_node_events.EventEmitter {
4882
- constructor(options = ["tunnel", "--hello-world"]) {
4883
- super();
4884
- this.outputHandlers = [];
4885
- this.stop = this._stop.bind(this);
4886
- this.setupDefaultHandlers();
4887
- const args = Array.isArray(options) ? options : build_args(options);
4888
- this._process = this.createProcess(args);
4889
- this.setupEventHandlers();
4890
- }
4891
- get process() {
4892
- return this._process;
4893
- }
4894
- setupDefaultHandlers() {
4895
- new import_handler.ConnectionHandler(this);
4896
- new import_handler.TryCloudflareHandler(this);
4897
- }
4898
- /**
4899
- * Add a custom output handler
4900
- * @param handler Function to handle cloudflared output
4901
- */
4902
- addHandler(handler) {
4903
- this.outputHandlers.push(handler);
4904
- }
4905
- /**
4906
- * Remove a previously added output handler
4907
- * @param handler The handler to remove
4908
- */
4909
- removeHandler(handler) {
4910
- const index = this.outputHandlers.indexOf(handler);
4911
- if (index !== -1) {
4912
- this.outputHandlers.splice(index, 1);
4913
- }
4914
- }
4915
- processOutput(output) {
4916
- for (const handler of this.outputHandlers) {
4917
- try {
4918
- handler(output, this);
4919
- } catch (error) {
4920
- this.emit("error", error instanceof Error ? error : new Error(String(error)));
4921
- }
4922
- }
4923
- }
4924
- setupEventHandlers() {
4925
- this.on("stdout", (output) => {
4926
- this.processOutput(output);
4927
- });
4928
- this.on("stderr", (output) => {
4929
- this.processOutput(output);
4930
- });
4931
- }
4932
- createProcess(args) {
4933
- var _a, _b;
4934
- const child = (0, import_node_child_process.spawn)(import_constants.bin, args, { stdio: ["ignore", "pipe", "pipe"] });
4935
- child.on("error", (error) => this.emit("error", error));
4936
- child.on("exit", (code, signal) => this.emit("exit", code, signal));
4937
- if (process.env.VERBOSE) {
4938
- child.stdout.pipe(process.stdout);
4939
- child.stderr.pipe(process.stderr);
4940
- }
4941
- (_a = child.stdout) == null ? void 0 : _a.on("data", (data) => this.emit("stdout", data.toString()));
4942
- (_b = child.stderr) == null ? void 0 : _b.on("data", (data) => this.emit("stderr", data.toString()));
4943
- return child;
4944
- }
4945
- _stop() {
4946
- return this.process.kill("SIGINT");
4947
- }
4948
- on(event, listener) {
4949
- return super.on(event, listener);
4950
- }
4951
- once(event, listener) {
4952
- return super.once(event, listener);
4953
- }
4954
- off(event, listener) {
4955
- return super.off(event, listener);
4956
- }
4957
- emit(event, ...args) {
4958
- return super.emit(event, ...args);
4959
- }
4960
- /**
4961
- * Create a quick tunnel without a Cloudflare account.
4962
- * @param url The local service URL to connect to. If not provided, the hello world mode will be used.
4963
- * @param options The options to pass to cloudflared.
4964
- */
4965
- static quick(url, options = {}) {
4966
- const args = ["tunnel"];
4967
- if (url) {
4968
- args.push("--url", url);
4969
- } else {
4970
- args.push("--hello-world");
4971
- }
4972
- args.push(...build_options(options));
4973
- return new _Tunnel(args);
4974
- }
4975
- /**
4976
- * Create a tunnel with a Cloudflare account.
4977
- * @param token The Cloudflare Tunnel token.
4978
- * @param options The options to pass to cloudflared.
4979
- */
4980
- static withToken(token, options = {}) {
4981
- options["--token"] = token;
4982
- return new _Tunnel(build_args(options));
4983
- }
4984
- };
4985
- function tunnel(options = {}) {
4986
- return new Tunnel(options);
4987
- }
4988
- function build_args(options) {
4989
- const args = "--hello-world" in options ? ["tunnel"] : ["tunnel", "run"];
4990
- args.push(...build_options(options));
4991
- return args;
4992
- }
4993
- function build_options(options) {
4994
- const opts = [];
4995
- for (const [key, value] of Object.entries(options)) {
4996
- if (typeof value === "string") {
4997
- opts.push(`${key}`, value);
4998
- } else if (typeof value === "number") {
4999
- opts.push(`${key}`, value.toString());
5000
- } else if (typeof value === "boolean") {
5001
- if (value === true) {
5002
- opts.push(`${key}`);
5003
- }
5004
- }
5005
- }
5006
- return opts;
5007
- }
5008
- }
5009
- });
5010
-
5011
- // node_modules/cloudflared/lib/service.js
5012
- var require_service = __commonJS({
5013
- "node_modules/cloudflared/lib/service.js"(exports2, module2) {
5014
- "use strict";
5015
- var __create2 = Object.create;
5016
- var __defProp2 = Object.defineProperty;
5017
- var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
5018
- var __getOwnPropNames2 = Object.getOwnPropertyNames;
5019
- var __getProtoOf2 = Object.getPrototypeOf;
5020
- var __hasOwnProp2 = Object.prototype.hasOwnProperty;
5021
- var __export2 = (target, all) => {
5022
- for (var name in all)
5023
- __defProp2(target, name, { get: all[name], enumerable: true });
5024
- };
5025
- var __copyProps2 = (to, from, except, desc) => {
5026
- if (from && typeof from === "object" || typeof from === "function") {
5027
- for (let key of __getOwnPropNames2(from))
5028
- if (!__hasOwnProp2.call(to, key) && key !== except)
5029
- __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
5030
- }
5031
- return to;
5032
- };
5033
- var __toESM2 = (mod, isNodeMode, target) => (target = mod != null ? __create2(__getProtoOf2(mod)) : {}, __copyProps2(
5034
- // If the importer is in node compatibility mode or this is not an ESM
5035
- // file that has been converted to a CommonJS file using a Babel-
5036
- // compatible transform (i.e. "__esModule" has not been set), then set
5037
- // "default" to the CommonJS "module.exports" for node compatibility.
5038
- isNodeMode || !mod || !mod.__esModule ? __defProp2(target, "default", { value: mod, enumerable: true }) : target,
5039
- mod
5040
- ));
5041
- var __toCommonJS2 = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
5042
- var service_exports = {};
5043
- __export2(service_exports, {
5044
- AlreadyInstalledError: () => AlreadyInstalledError2,
5045
- LINUX_SERVICE_PATH: () => LINUX_SERVICE_PATH,
5046
- MACOS_SERVICE_PATH: () => MACOS_SERVICE_PATH2,
5047
- NotInstalledError: () => NotInstalledError2,
5048
- clean: () => clean,
5049
- current: () => current,
5050
- err: () => err,
5051
- exists: () => exists,
5052
- identifier: () => identifier2,
5053
- install: () => install,
5054
- journal: () => journal,
5055
- log: () => log2,
5056
- service: () => service2,
5057
- service_name: () => service_name,
5058
- uninstall: () => uninstall
5059
- });
5060
- module2.exports = __toCommonJS2(service_exports);
5061
- var import_node_os = __toESM2(require("os"));
5062
- var import_node_fs = __toESM2(require("fs"));
5063
- var import_node_child_process = require("child_process");
5064
- var import_constants = require_constants();
5065
- var import_regex2 = require_regex();
5066
- var identifier2 = "com.cloudflare.cloudflared";
5067
- var service_name = "cloudflared.service";
5068
- var MACOS_SERVICE_PATH2 = {
5069
- PLIST: is_root() ? `/Library/LaunchDaemons/${identifier2}.plist` : `${import_node_os.default.homedir()}/Library/LaunchAgents/${identifier2}.plist`,
5070
- OUT: is_root() ? `/Library/Logs/${identifier2}.out.log` : `${import_node_os.default.homedir()}/Library/Logs/${identifier2}.out.log`,
5071
- ERR: is_root() ? `/Library/Logs/${identifier2}.err.log` : `${import_node_os.default.homedir()}/Library/Logs/${identifier2}.err.log`
5072
- };
5073
- var LINUX_SERVICE_PATH = {
5074
- SYSTEMD: `/etc/systemd/system/${service_name}`,
5075
- SERVICE: "/etc/init.d/cloudflared",
5076
- SERVICE_OUT: "/var/log/cloudflared.log",
5077
- SERVICE_ERR: "/var/log/cloudflared.err"
5078
- };
5079
- var service2 = { install, uninstall, exists, log: log2, err, current, clean, journal };
5080
- var AlreadyInstalledError2 = class extends Error {
5081
- constructor() {
5082
- super("service is already installed");
5083
- }
5084
- };
5085
- var NotInstalledError2 = class extends Error {
5086
- constructor() {
5087
- super("service is not installed");
5088
- }
5089
- };
5090
- function install(token) {
5091
- if (!["darwin", "linux"].includes(process.platform)) {
5092
- throw new Error(`Not Implemented on platform ${process.platform}`);
5093
- }
5094
- if (exists()) {
5095
- throw new AlreadyInstalledError2();
5096
- }
5097
- const args = ["service", "install"];
5098
- if (token) {
5099
- args.push(token);
5100
- }
5101
- const result = (0, import_node_child_process.spawnSync)(import_constants.bin, args);
5102
- if (result.status !== 0) {
5103
- throw new Error(`service install failed: ${result.stderr.toString()}`);
5104
- }
5105
- }
5106
- function uninstall() {
5107
- if (!["darwin", "linux"].includes(process.platform)) {
5108
- throw new Error(`Not Implemented on platform ${process.platform}`);
5109
- }
5110
- if (!exists()) {
5111
- throw new NotInstalledError2();
5112
- }
5113
- const result = (0, import_node_child_process.spawnSync)(import_constants.bin, ["service", "uninstall"]);
5114
- if (result.status !== 0) {
5115
- throw new Error(`service uninstall failed: ${result.stderr.toString()}`);
5116
- }
5117
- if (process.platform === "darwin") {
5118
- import_node_fs.default.rmSync(MACOS_SERVICE_PATH2.OUT);
5119
- import_node_fs.default.rmSync(MACOS_SERVICE_PATH2.ERR);
5120
- } else if (process.platform === "linux" && !is_systemd()) {
5121
- import_node_fs.default.rmSync(LINUX_SERVICE_PATH.SERVICE_OUT);
5122
- import_node_fs.default.rmSync(LINUX_SERVICE_PATH.SERVICE_ERR);
5123
- }
5124
- }
5125
- function log2() {
5126
- if (!exists()) {
5127
- throw new NotInstalledError2();
5128
- }
5129
- if (process.platform === "darwin") {
5130
- return import_node_fs.default.readFileSync(MACOS_SERVICE_PATH2.OUT, "utf8");
5131
- }
5132
- if (process.platform === "linux" && !is_systemd()) {
5133
- return import_node_fs.default.readFileSync(LINUX_SERVICE_PATH.SERVICE_OUT, "utf8");
5134
- }
5135
- throw new Error(`Not Implemented on platform ${process.platform}`);
5136
- }
5137
- function err() {
5138
- if (!exists()) {
5139
- throw new NotInstalledError2();
5140
- }
5141
- if (process.platform === "darwin") {
5142
- return import_node_fs.default.readFileSync(MACOS_SERVICE_PATH2.ERR, "utf8");
5143
- }
5144
- if (process.platform === "linux" && !is_systemd()) {
5145
- return import_node_fs.default.readFileSync(LINUX_SERVICE_PATH.SERVICE_ERR, "utf8");
5146
- }
5147
- throw new Error(`Not Implemented on platform ${process.platform}`);
5148
- }
5149
- function journal(n = 300) {
5150
- if (process.platform === "linux" && is_systemd()) {
5151
- const args = ["-u", service_name, "-o", "cat", "-n", n.toString()];
5152
- return (0, import_node_child_process.spawnSync)("journalctl", args).stdout.toString();
5153
- }
5154
- throw new Error(`Not Implemented on platform ${process.platform}`);
5155
- }
5156
- function current() {
5157
- var _a, _b, _c, _d;
5158
- if (!["darwin", "linux"].includes(process.platform)) {
5159
- throw new Error(`Not Implemented on platform ${process.platform}`);
5160
- }
5161
- if (!exists()) {
5162
- throw new NotInstalledError2();
5163
- }
5164
- const log22 = is_systemd() ? journal() : err();
5165
- let tunnelID = "";
5166
- let connectorID = "";
5167
- const connections = [];
5168
- let metrics = "";
5169
- let config = {};
5170
- for (const line of log22.split("\n")) {
5171
- try {
5172
- if (line.match(import_regex2.tunnelID_regex)) {
5173
- tunnelID = ((_a = line.match(import_regex2.tunnelID_regex)) == null ? void 0 : _a[1]) ?? "";
5174
- } else if (line.match(import_regex2.connectorID_regex)) {
5175
- connectorID = ((_b = line.match(import_regex2.connectorID_regex)) == null ? void 0 : _b[1]) ?? "";
5176
- } else if (line.match(import_regex2.conn_regex) && line.match(import_regex2.location_regex) && line.match(import_regex2.ip_regex) && line.match(import_regex2.index_regex)) {
5177
- const [, id] = line.match(import_regex2.conn_regex) ?? [];
5178
- const [, location] = line.match(import_regex2.location_regex) ?? [];
5179
- const [, ip] = line.match(import_regex2.ip_regex) ?? [];
5180
- const [, idx] = line.match(import_regex2.index_regex) ?? [];
5181
- connections[parseInt(idx)] = { id, ip, location };
5182
- } else if (line.match(import_regex2.disconnect_regex)) {
5183
- const [, idx] = line.match(import_regex2.disconnect_regex) ?? [];
5184
- if (parseInt(idx) in connections) {
5185
- connections[parseInt(idx)] = { id: "", ip: "", location: "" };
5186
- }
5187
- } else if (line.match(import_regex2.metrics_regex)) {
5188
- metrics = ((_c = line.match(import_regex2.metrics_regex)) == null ? void 0 : _c[1]) ?? "";
5189
- } else if (line.match(import_regex2.config_regex)) {
5190
- config = JSON.parse(((_d = line.match(import_regex2.config_regex)) == null ? void 0 : _d[1].replace(/\\/g, "")) ?? "{}");
5191
- }
5192
- } catch (err2) {
5193
- if (process.env.VERBOSE) {
5194
- console.error("log parsing failed", err2);
5195
- }
5196
- }
5197
- }
5198
- return { tunnelID, connectorID, connections, metrics, config };
5199
- }
5200
- function clean() {
5201
- if (process.platform !== "darwin") {
5202
- throw new Error(`Not Implemented on platform ${process.platform}`);
5203
- }
5204
- if (exists()) {
5205
- throw new AlreadyInstalledError2();
5206
- }
5207
- import_node_fs.default.rmSync(MACOS_SERVICE_PATH2.OUT, { force: true });
5208
- import_node_fs.default.rmSync(MACOS_SERVICE_PATH2.ERR, { force: true });
5209
- }
5210
- function exists() {
5211
- if (process.platform === "darwin") {
5212
- return import_node_fs.default.existsSync(MACOS_SERVICE_PATH2.PLIST);
5213
- } else if (process.platform === "linux") {
5214
- return is_systemd() ? import_node_fs.default.existsSync(LINUX_SERVICE_PATH.SYSTEMD) : import_node_fs.default.existsSync(LINUX_SERVICE_PATH.SERVICE);
5215
- }
5216
- throw new Error(`Not Implemented on platform ${process.platform}`);
5217
- }
5218
- function is_root() {
5219
- var _a;
5220
- return ((_a = process.getuid) == null ? void 0 : _a.call(process)) === 0;
5221
- }
5222
- function is_systemd() {
5223
- return process.platform === "linux" && import_node_fs.default.existsSync("/run/systemd/system");
5224
- }
5225
- }
5226
- });
5227
-
5228
- // node_modules/cloudflared/lib/lib.js
5229
- var require_lib = __commonJS({
5230
- "node_modules/cloudflared/lib/lib.js"(exports2, module2) {
5231
- "use strict";
5232
- var __defProp2 = Object.defineProperty;
5233
- var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
5234
- var __getOwnPropNames2 = Object.getOwnPropertyNames;
5235
- var __hasOwnProp2 = Object.prototype.hasOwnProperty;
5236
- var __export2 = (target, all) => {
5237
- for (var name in all)
5238
- __defProp2(target, name, { get: all[name], enumerable: true });
5239
- };
5240
- var __copyProps2 = (to, from, except, desc) => {
5241
- if (from && typeof from === "object" || typeof from === "function") {
5242
- for (let key of __getOwnPropNames2(from))
5243
- if (!__hasOwnProp2.call(to, key) && key !== except)
5244
- __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
5245
- }
5246
- return to;
5247
- };
5248
- var __reExport = (target, mod, secondTarget) => (__copyProps2(target, mod, "default"), secondTarget && __copyProps2(secondTarget, mod, "default"));
5249
- var __toCommonJS2 = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
5250
- var lib_exports = {};
5251
- __export2(lib_exports, {
5252
- AlreadyInstalledError: () => import_service.AlreadyInstalledError,
5253
- MACOS_SERVICE_PATH: () => import_service.MACOS_SERVICE_PATH,
5254
- NotInstalledError: () => import_service.NotInstalledError,
5255
- identifier: () => import_service.identifier,
5256
- service: () => import_service.service
5257
- });
5258
- module2.exports = __toCommonJS2(lib_exports);
5259
- __reExport(lib_exports, require_constants(), module2.exports);
5260
- __reExport(lib_exports, require_install(), module2.exports);
5261
- __reExport(lib_exports, require_tunnel(), module2.exports);
5262
- var import_service = require_service();
5263
- __reExport(lib_exports, require_handler(), module2.exports);
5264
- }
5265
- });
5266
-
5267
4466
  // src/tunnel.ts
5268
4467
  var tunnel_exports = {};
5269
4468
  __export(tunnel_exports, {
@@ -5272,7 +4471,7 @@ __export(tunnel_exports, {
5272
4471
  async function startTunnel(port, timeoutMs = 3e4) {
5273
4472
  let tunnelMod;
5274
4473
  try {
5275
- tunnelMod = await Promise.resolve().then(() => __toESM(require_lib()));
4474
+ tunnelMod = await import("cloudflared");
5276
4475
  } catch {
5277
4476
  throw new Error(
5278
4477
  'Built-in tunnel requires the "cloudflared" package. Install it with:\n\n npm install cloudflared\n\nOr provide your own webhookUrl instead of using tunnel: true.'
@@ -6535,6 +5734,7 @@ var require_node_cron = __commonJS({
6535
5734
  var index_exports = {};
6536
5735
  __export(index_exports, {
6537
5736
  AllProvidersFailedError: () => AllProvidersFailedError,
5737
+ AnthropicLLM: () => LLM2,
6538
5738
  AssemblyAISTT: () => STT5,
6539
5739
  AuthenticationError: () => AuthenticationError,
6540
5740
  BackgroundAudioPlayer: () => BackgroundAudioPlayer,
@@ -6542,6 +5742,7 @@ __export(index_exports, {
6542
5742
  CallMetricsAccumulator: () => CallMetricsAccumulator,
6543
5743
  CartesiaSTT: () => STT3,
6544
5744
  CartesiaTTS: () => TTS3,
5745
+ CerebrasLLM: () => LLM4,
6545
5746
  ChatContext: () => ChatContext,
6546
5747
  CloudflareTunnel: () => CloudflareTunnel,
6547
5748
  DEFAULT_MIN_SENTENCE_LEN: () => DEFAULT_MIN_SENTENCE_LEN,
@@ -6555,11 +5756,14 @@ __export(index_exports, {
6555
5756
  GEMINI_DEFAULT_INPUT_SR: () => GEMINI_DEFAULT_INPUT_SR,
6556
5757
  GEMINI_DEFAULT_OUTPUT_SR: () => GEMINI_DEFAULT_OUTPUT_SR,
6557
5758
  GeminiLiveAdapter: () => GeminiLiveAdapter,
5759
+ GoogleLLM: () => LLM5,
5760
+ GroqLLM: () => LLM3,
6558
5761
  Guardrail: () => Guardrail,
6559
5762
  IVRActivity: () => IVRActivity,
6560
5763
  LLMLoop: () => LLMLoop,
6561
5764
  LMNTTTS: () => TTS5,
6562
5765
  MetricsStore: () => MetricsStore,
5766
+ OpenAILLM: () => LLM,
6563
5767
  OpenAILLMProvider: () => OpenAILLMProvider,
6564
5768
  OpenAIRealtime: () => Realtime,
6565
5769
  OpenAIRealtimeAdapter: () => OpenAIRealtimeAdapter,
@@ -6830,6 +6034,7 @@ var Static = class {
6830
6034
  };
6831
6035
 
6832
6036
  // src/client.ts
6037
+ init_logger();
6833
6038
  var DEFAULT_BACKEND_URL2 = "wss://api.getpatter.com";
6834
6039
  var DEFAULT_REST_URL = "https://api.getpatter.com";
6835
6040
  function sttConfigToDict(cfg) {
@@ -6938,6 +6143,8 @@ var Patter = class {
6938
6143
  "Unknown engine. Expected OpenAIRealtime or ElevenLabsConvAI instance."
6939
6144
  );
6940
6145
  }
6146
+ } else if (!working.provider && (working.stt !== void 0 || working.tts !== void 0 || working.llm !== void 0)) {
6147
+ working = { ...working, provider: "pipeline" };
6941
6148
  }
6942
6149
  if (working.provider) {
6943
6150
  const valid = ["openai_realtime", "elevenlabs_convai", "pipeline"];
@@ -6945,6 +6152,19 @@ var Patter = class {
6945
6152
  throw new Error(`provider must be one of: ${valid.join(", ")}. Got: '${working.provider}'`);
6946
6153
  }
6947
6154
  }
6155
+ if (working.llm !== void 0) {
6156
+ const llm = working.llm;
6157
+ if (!llm || typeof llm.stream !== "function") {
6158
+ throw new Error(
6159
+ "`llm` must be an LLMProvider instance (e.g. new AnthropicLLM()). Got a value without a `.stream` method."
6160
+ );
6161
+ }
6162
+ if (working.engine) {
6163
+ getLogger().warn(
6164
+ "agent({ engine, llm }): `llm` is ignored when `engine` is set \u2014 realtime/ConvAI engines run their own model. Remove `llm` or switch to pipeline mode (stt + tts + llm) to silence this warning."
6165
+ );
6166
+ }
6167
+ }
6948
6168
  if (working.tools) {
6949
6169
  if (!Array.isArray(working.tools)) {
6950
6170
  throw new TypeError("tools must be an array");
@@ -9464,6 +8684,621 @@ var TTS5 = class extends LMNTTTS {
9464
8684
  }
9465
8685
  };
9466
8686
 
8687
+ // src/llm/openai.ts
8688
+ init_llm_loop();
8689
+ var LLM = class extends OpenAILLMProvider {
8690
+ constructor(opts = {}) {
8691
+ const key = opts.apiKey ?? process.env.OPENAI_API_KEY;
8692
+ if (!key) {
8693
+ throw new Error(
8694
+ "OpenAI LLM requires an apiKey. Pass { apiKey: 'sk-...' } or set OPENAI_API_KEY."
8695
+ );
8696
+ }
8697
+ super(key, opts.model ?? "gpt-4o-mini");
8698
+ }
8699
+ };
8700
+
8701
+ // src/providers/anthropic-llm.ts
8702
+ init_logger();
8703
+ var DEFAULT_ANTHROPIC_URL = "https://api.anthropic.com/v1/messages";
8704
+ var DEFAULT_ANTHROPIC_VERSION = "2023-06-01";
8705
+ var DEFAULT_MODEL = "claude-3-5-sonnet-20241022";
8706
+ var DEFAULT_MAX_TOKENS = 1024;
8707
+ var AnthropicLLMProvider = class {
8708
+ apiKey;
8709
+ model;
8710
+ maxTokens;
8711
+ temperature;
8712
+ url;
8713
+ anthropicVersion;
8714
+ constructor(options) {
8715
+ if (!options.apiKey) {
8716
+ throw new Error(
8717
+ "Anthropic API key is required. Pass it via { apiKey } or set the ANTHROPIC_API_KEY environment variable before constructing the provider."
8718
+ );
8719
+ }
8720
+ this.apiKey = options.apiKey;
8721
+ this.model = options.model ?? DEFAULT_MODEL;
8722
+ this.maxTokens = options.maxTokens ?? DEFAULT_MAX_TOKENS;
8723
+ this.temperature = options.temperature;
8724
+ this.url = options.baseUrl ?? DEFAULT_ANTHROPIC_URL;
8725
+ this.anthropicVersion = options.anthropicVersion ?? DEFAULT_ANTHROPIC_VERSION;
8726
+ }
8727
+ async *stream(messages, tools) {
8728
+ const { system, messages: anthropicMessages } = toAnthropicMessages(messages);
8729
+ const anthropicTools = tools ? toAnthropicTools(tools) : null;
8730
+ const body = {
8731
+ model: this.model,
8732
+ messages: anthropicMessages,
8733
+ max_tokens: this.maxTokens,
8734
+ stream: true
8735
+ };
8736
+ if (system) body.system = system;
8737
+ if (anthropicTools && anthropicTools.length > 0) body.tools = anthropicTools;
8738
+ if (this.temperature !== void 0) body.temperature = this.temperature;
8739
+ const response = await fetch(this.url, {
8740
+ method: "POST",
8741
+ headers: {
8742
+ "Content-Type": "application/json",
8743
+ "x-api-key": this.apiKey,
8744
+ "anthropic-version": this.anthropicVersion
8745
+ },
8746
+ body: JSON.stringify(body),
8747
+ signal: AbortSignal.timeout(3e4)
8748
+ });
8749
+ if (!response.ok) {
8750
+ const errText = await response.text();
8751
+ getLogger().error(`Anthropic API error: ${response.status} ${errText}`);
8752
+ return;
8753
+ }
8754
+ const reader = response.body?.getReader();
8755
+ if (!reader) return;
8756
+ const decoder = new TextDecoder();
8757
+ let buffer = "";
8758
+ const toolIndexByBlock = /* @__PURE__ */ new Map();
8759
+ const toolIdByBlock = /* @__PURE__ */ new Map();
8760
+ let nextIndex = 0;
8761
+ while (true) {
8762
+ const { done, value } = await reader.read();
8763
+ if (done) break;
8764
+ buffer += decoder.decode(value, { stream: true });
8765
+ const lines = buffer.split("\n");
8766
+ buffer = lines.pop() || "";
8767
+ for (const line of lines) {
8768
+ const trimmed = line.trim();
8769
+ if (!trimmed.startsWith("data: ")) continue;
8770
+ const data = trimmed.slice(6);
8771
+ if (!data || data === "[DONE]") continue;
8772
+ let event;
8773
+ try {
8774
+ event = JSON.parse(data);
8775
+ } catch {
8776
+ continue;
8777
+ }
8778
+ if (event.type === "content_block_start" && event.content_block?.type === "tool_use") {
8779
+ const blockIdx = event.index ?? 0;
8780
+ const toolId = event.content_block.id ?? "";
8781
+ const toolName = event.content_block.name ?? "";
8782
+ const patterIndex = nextIndex++;
8783
+ toolIndexByBlock.set(blockIdx, patterIndex);
8784
+ toolIdByBlock.set(blockIdx, toolId);
8785
+ yield {
8786
+ type: "tool_call",
8787
+ index: patterIndex,
8788
+ id: toolId,
8789
+ name: toolName,
8790
+ arguments: ""
8791
+ };
8792
+ continue;
8793
+ }
8794
+ if (event.type === "content_block_delta") {
8795
+ if (event.delta?.type === "text_delta" && event.delta.text) {
8796
+ yield { type: "text", content: event.delta.text };
8797
+ continue;
8798
+ }
8799
+ if (event.delta?.type === "input_json_delta" && event.delta.partial_json) {
8800
+ const blockIdx = event.index ?? 0;
8801
+ const patterIndex = toolIndexByBlock.get(blockIdx);
8802
+ if (patterIndex !== void 0) {
8803
+ yield {
8804
+ type: "tool_call",
8805
+ index: patterIndex,
8806
+ id: toolIdByBlock.get(blockIdx),
8807
+ arguments: event.delta.partial_json
8808
+ };
8809
+ }
8810
+ }
8811
+ }
8812
+ }
8813
+ }
8814
+ yield { type: "done" };
8815
+ }
8816
+ };
8817
+ function toAnthropicTools(tools) {
8818
+ return tools.map((t) => {
8819
+ const fn = t.function ?? t;
8820
+ return {
8821
+ name: String(fn.name ?? ""),
8822
+ description: String(fn.description ?? ""),
8823
+ input_schema: fn.parameters ?? { type: "object", properties: {} }
8824
+ };
8825
+ });
8826
+ }
8827
+ function toAnthropicMessages(messages) {
8828
+ const systemParts = [];
8829
+ const out = [];
8830
+ for (const rawMsg of messages) {
8831
+ const role = rawMsg.role;
8832
+ if (role === "system") {
8833
+ if (typeof rawMsg.content === "string" && rawMsg.content) {
8834
+ systemParts.push(rawMsg.content);
8835
+ }
8836
+ continue;
8837
+ }
8838
+ if (role === "user") {
8839
+ if (typeof rawMsg.content === "string") {
8840
+ out.push({ role: "user", content: rawMsg.content });
8841
+ } else if (rawMsg.content) {
8842
+ out.push({ role: "user", content: rawMsg.content });
8843
+ }
8844
+ continue;
8845
+ }
8846
+ if (role === "assistant") {
8847
+ const blocks = [];
8848
+ if (typeof rawMsg.content === "string" && rawMsg.content) {
8849
+ blocks.push({ type: "text", text: rawMsg.content });
8850
+ }
8851
+ for (const tc of rawMsg.tool_calls ?? []) {
8852
+ let args = {};
8853
+ try {
8854
+ args = JSON.parse(tc.function?.arguments ?? "{}");
8855
+ } catch {
8856
+ args = {};
8857
+ }
8858
+ blocks.push({
8859
+ type: "tool_use",
8860
+ id: tc.id ?? "",
8861
+ name: tc.function?.name ?? "",
8862
+ input: args
8863
+ });
8864
+ }
8865
+ if (blocks.length > 0) {
8866
+ out.push({ role: "assistant", content: blocks });
8867
+ }
8868
+ continue;
8869
+ }
8870
+ if (role === "tool") {
8871
+ const contentStr = typeof rawMsg.content === "string" ? rawMsg.content : JSON.stringify(rawMsg.content);
8872
+ out.push({
8873
+ role: "user",
8874
+ content: [
8875
+ {
8876
+ type: "tool_result",
8877
+ tool_use_id: rawMsg.tool_call_id ?? "",
8878
+ content: contentStr
8879
+ }
8880
+ ]
8881
+ });
8882
+ continue;
8883
+ }
8884
+ }
8885
+ return { system: systemParts.join("\n\n"), messages: out };
8886
+ }
8887
+
8888
+ // src/llm/anthropic.ts
8889
+ var LLM2 = class extends AnthropicLLMProvider {
8890
+ constructor(opts = {}) {
8891
+ const key = opts.apiKey ?? process.env.ANTHROPIC_API_KEY;
8892
+ if (!key) {
8893
+ throw new Error(
8894
+ "Anthropic LLM requires an apiKey. Pass { apiKey: 'sk-ant-...' } or set ANTHROPIC_API_KEY."
8895
+ );
8896
+ }
8897
+ super({
8898
+ apiKey: key,
8899
+ model: opts.model,
8900
+ maxTokens: opts.maxTokens,
8901
+ temperature: opts.temperature,
8902
+ baseUrl: opts.baseUrl,
8903
+ anthropicVersion: opts.anthropicVersion
8904
+ });
8905
+ }
8906
+ };
8907
+
8908
+ // src/providers/groq-llm.ts
8909
+ init_logger();
8910
+ var GROQ_BASE_URL = "https://api.groq.com/openai/v1";
8911
+ var DEFAULT_MODEL2 = "llama-3.3-70b-versatile";
8912
+ var GroqLLMProvider = class {
8913
+ apiKey;
8914
+ model;
8915
+ baseUrl;
8916
+ constructor(options) {
8917
+ if (!options.apiKey) {
8918
+ throw new Error(
8919
+ "Groq API key is required. Pass it via { apiKey } or read GROQ_API_KEY from the environment."
8920
+ );
8921
+ }
8922
+ this.apiKey = options.apiKey;
8923
+ this.model = options.model ?? DEFAULT_MODEL2;
8924
+ this.baseUrl = options.baseUrl ?? GROQ_BASE_URL;
8925
+ }
8926
+ async *stream(messages, tools) {
8927
+ const body = {
8928
+ model: this.model,
8929
+ messages,
8930
+ stream: true
8931
+ };
8932
+ if (tools) body.tools = tools;
8933
+ const response = await fetch(`${this.baseUrl}/chat/completions`, {
8934
+ method: "POST",
8935
+ headers: {
8936
+ "Content-Type": "application/json",
8937
+ Authorization: `Bearer ${this.apiKey}`
8938
+ },
8939
+ body: JSON.stringify(body),
8940
+ signal: AbortSignal.timeout(3e4)
8941
+ });
8942
+ if (!response.ok) {
8943
+ const errText = await response.text();
8944
+ getLogger().error(`Groq API error: ${response.status} ${errText}`);
8945
+ return;
8946
+ }
8947
+ yield* parseOpenAISseStream(response);
8948
+ }
8949
+ };
8950
+ async function* parseOpenAISseStream(response) {
8951
+ const reader = response.body?.getReader();
8952
+ if (!reader) return;
8953
+ const decoder = new TextDecoder();
8954
+ let buffer = "";
8955
+ while (true) {
8956
+ const { done, value } = await reader.read();
8957
+ if (done) break;
8958
+ buffer += decoder.decode(value, { stream: true });
8959
+ const lines = buffer.split("\n");
8960
+ buffer = lines.pop() || "";
8961
+ for (const line of lines) {
8962
+ const trimmed = line.trim();
8963
+ if (!trimmed || !trimmed.startsWith("data: ")) continue;
8964
+ const data = trimmed.slice(6);
8965
+ if (data === "[DONE]") continue;
8966
+ let chunk;
8967
+ try {
8968
+ chunk = JSON.parse(data);
8969
+ } catch {
8970
+ continue;
8971
+ }
8972
+ const delta = chunk.choices?.[0]?.delta;
8973
+ if (!delta) continue;
8974
+ if (delta.content) {
8975
+ yield { type: "text", content: delta.content };
8976
+ }
8977
+ if (delta.tool_calls) {
8978
+ for (const tc of delta.tool_calls) {
8979
+ yield {
8980
+ type: "tool_call",
8981
+ index: tc.index,
8982
+ id: tc.id,
8983
+ name: tc.function?.name,
8984
+ arguments: tc.function?.arguments
8985
+ };
8986
+ }
8987
+ }
8988
+ }
8989
+ }
8990
+ }
8991
+
8992
+ // src/llm/groq.ts
8993
+ var LLM3 = class extends GroqLLMProvider {
8994
+ constructor(opts = {}) {
8995
+ const key = opts.apiKey ?? process.env.GROQ_API_KEY;
8996
+ if (!key) {
8997
+ throw new Error(
8998
+ "Groq LLM requires an apiKey. Pass { apiKey: 'gsk_...' } or set GROQ_API_KEY."
8999
+ );
9000
+ }
9001
+ super({
9002
+ apiKey: key,
9003
+ model: opts.model,
9004
+ baseUrl: opts.baseUrl
9005
+ });
9006
+ }
9007
+ };
9008
+
9009
+ // src/providers/cerebras-llm.ts
9010
+ init_logger();
9011
+ var CEREBRAS_BASE_URL = "https://api.cerebras.ai/v1";
9012
+ var DEFAULT_MODEL3 = "llama3.1-8b";
9013
+ var CerebrasLLMProvider = class {
9014
+ apiKey;
9015
+ model;
9016
+ baseUrl;
9017
+ gzipCompression;
9018
+ constructor(options) {
9019
+ if (!options.apiKey) {
9020
+ throw new Error(
9021
+ "Cerebras API key is required. Pass it via { apiKey } or read CEREBRAS_API_KEY from the environment."
9022
+ );
9023
+ }
9024
+ this.apiKey = options.apiKey;
9025
+ this.model = options.model ?? DEFAULT_MODEL3;
9026
+ this.baseUrl = options.baseUrl ?? CEREBRAS_BASE_URL;
9027
+ this.gzipCompression = options.gzipCompression ?? false;
9028
+ }
9029
+ async *stream(messages, tools) {
9030
+ const body = {
9031
+ model: this.model,
9032
+ messages,
9033
+ stream: true
9034
+ };
9035
+ if (tools) body.tools = tools;
9036
+ const headers = {
9037
+ "Content-Type": "application/json",
9038
+ Authorization: `Bearer ${this.apiKey}`
9039
+ };
9040
+ let payload = JSON.stringify(body);
9041
+ if (this.gzipCompression) {
9042
+ const compressed = await gzipEncode(payload);
9043
+ if (compressed) {
9044
+ payload = compressed;
9045
+ headers["Content-Encoding"] = "gzip";
9046
+ }
9047
+ }
9048
+ const response = await fetch(`${this.baseUrl}/chat/completions`, {
9049
+ method: "POST",
9050
+ headers,
9051
+ body: payload,
9052
+ signal: AbortSignal.timeout(3e4)
9053
+ });
9054
+ if (!response.ok) {
9055
+ const errText = await response.text();
9056
+ getLogger().error(`Cerebras API error: ${response.status} ${errText}`);
9057
+ return;
9058
+ }
9059
+ yield* parseOpenAISseStream(response);
9060
+ }
9061
+ };
9062
+ async function gzipEncode(data) {
9063
+ const CompressionCtor = globalThis.CompressionStream;
9064
+ if (!CompressionCtor) return null;
9065
+ const stream = new CompressionCtor("gzip");
9066
+ const writer = stream.writable.getWriter();
9067
+ const encoder = new TextEncoder();
9068
+ await writer.write(encoder.encode(data));
9069
+ await writer.close();
9070
+ const chunks = [];
9071
+ const reader = stream.readable.getReader();
9072
+ while (true) {
9073
+ const { done, value } = await reader.read();
9074
+ if (done) break;
9075
+ if (value) chunks.push(value);
9076
+ }
9077
+ const total = chunks.reduce((n, c) => n + c.length, 0);
9078
+ const out = new Uint8Array(total);
9079
+ let offset = 0;
9080
+ for (const c of chunks) {
9081
+ out.set(c, offset);
9082
+ offset += c.length;
9083
+ }
9084
+ return out;
9085
+ }
9086
+
9087
+ // src/llm/cerebras.ts
9088
+ var LLM4 = class extends CerebrasLLMProvider {
9089
+ constructor(opts = {}) {
9090
+ const key = opts.apiKey ?? process.env.CEREBRAS_API_KEY;
9091
+ if (!key) {
9092
+ throw new Error(
9093
+ "Cerebras LLM requires an apiKey. Pass { apiKey: 'csk-...' } or set CEREBRAS_API_KEY."
9094
+ );
9095
+ }
9096
+ super({
9097
+ apiKey: key,
9098
+ model: opts.model,
9099
+ baseUrl: opts.baseUrl,
9100
+ gzipCompression: opts.gzipCompression
9101
+ });
9102
+ }
9103
+ };
9104
+
9105
+ // src/providers/google-llm.ts
9106
+ init_logger();
9107
+ var DEFAULT_MODEL4 = "gemini-2.5-flash";
9108
+ var DEFAULT_BASE_URL3 = "https://generativelanguage.googleapis.com/v1beta";
9109
+ var GoogleLLMProvider = class {
9110
+ apiKey;
9111
+ model;
9112
+ baseUrl;
9113
+ temperature;
9114
+ maxOutputTokens;
9115
+ constructor(options) {
9116
+ if (!options.apiKey) {
9117
+ throw new Error(
9118
+ "Google API key is required. Pass it via { apiKey } or read GOOGLE_API_KEY from the environment."
9119
+ );
9120
+ }
9121
+ this.apiKey = options.apiKey;
9122
+ this.model = options.model ?? DEFAULT_MODEL4;
9123
+ this.baseUrl = options.baseUrl ?? DEFAULT_BASE_URL3;
9124
+ this.temperature = options.temperature;
9125
+ this.maxOutputTokens = options.maxOutputTokens;
9126
+ }
9127
+ async *stream(messages, tools) {
9128
+ const { systemInstruction, contents } = toGeminiContents(messages);
9129
+ const geminiTools = tools ? toGeminiTools(tools) : null;
9130
+ const body = { contents };
9131
+ if (systemInstruction) {
9132
+ body.systemInstruction = { role: "system", parts: [{ text: systemInstruction }] };
9133
+ }
9134
+ if (geminiTools) body.tools = geminiTools;
9135
+ const generationConfig = {};
9136
+ if (this.temperature !== void 0) generationConfig.temperature = this.temperature;
9137
+ if (this.maxOutputTokens !== void 0)
9138
+ generationConfig.maxOutputTokens = this.maxOutputTokens;
9139
+ if (Object.keys(generationConfig).length > 0) body.generationConfig = generationConfig;
9140
+ const url = `${this.baseUrl}/models/${encodeURIComponent(this.model)}:streamGenerateContent?alt=sse&key=${encodeURIComponent(this.apiKey)}`;
9141
+ const response = await fetch(url, {
9142
+ method: "POST",
9143
+ headers: { "Content-Type": "application/json" },
9144
+ body: JSON.stringify(body),
9145
+ signal: AbortSignal.timeout(3e4)
9146
+ });
9147
+ if (!response.ok) {
9148
+ const errText = await response.text();
9149
+ getLogger().error(`Gemini API error: ${response.status} ${errText}`);
9150
+ return;
9151
+ }
9152
+ const reader = response.body?.getReader();
9153
+ if (!reader) return;
9154
+ const decoder = new TextDecoder();
9155
+ let buffer = "";
9156
+ let nextIndex = 0;
9157
+ while (true) {
9158
+ const { done, value } = await reader.read();
9159
+ if (done) break;
9160
+ buffer += decoder.decode(value, { stream: true });
9161
+ const lines = buffer.split("\n");
9162
+ buffer = lines.pop() || "";
9163
+ for (const line of lines) {
9164
+ const trimmed = line.trim();
9165
+ if (!trimmed.startsWith("data: ")) continue;
9166
+ const data = trimmed.slice(6);
9167
+ if (!data) continue;
9168
+ let payload;
9169
+ try {
9170
+ payload = JSON.parse(data);
9171
+ } catch {
9172
+ continue;
9173
+ }
9174
+ const candidate = payload.candidates?.[0];
9175
+ const parts = candidate?.content?.parts ?? [];
9176
+ for (const part of parts) {
9177
+ if (part.functionCall) {
9178
+ const args = part.functionCall.args ?? {};
9179
+ const callId = part.functionCall.id ?? `gemini_call_${nextIndex}`;
9180
+ yield {
9181
+ type: "tool_call",
9182
+ index: nextIndex,
9183
+ id: callId,
9184
+ name: part.functionCall.name ?? "",
9185
+ arguments: JSON.stringify(args)
9186
+ };
9187
+ nextIndex++;
9188
+ continue;
9189
+ }
9190
+ if (part.text) {
9191
+ yield { type: "text", content: part.text };
9192
+ }
9193
+ }
9194
+ }
9195
+ }
9196
+ yield { type: "done" };
9197
+ }
9198
+ };
9199
+ function toGeminiTools(tools) {
9200
+ const functionDeclarations = tools.map((t) => {
9201
+ const fn = t.function ?? t;
9202
+ return {
9203
+ name: String(fn.name ?? ""),
9204
+ description: String(fn.description ?? ""),
9205
+ parameters: fn.parameters ?? { type: "object", properties: {} }
9206
+ };
9207
+ });
9208
+ if (functionDeclarations.length === 0) return [];
9209
+ return [{ functionDeclarations }];
9210
+ }
9211
+ function toGeminiContents(messages) {
9212
+ const systemParts = [];
9213
+ const contents = [];
9214
+ for (const rawMsg of messages) {
9215
+ const role = rawMsg.role;
9216
+ if (role === "system") {
9217
+ if (typeof rawMsg.content === "string" && rawMsg.content) {
9218
+ systemParts.push(rawMsg.content);
9219
+ }
9220
+ continue;
9221
+ }
9222
+ if (role === "user") {
9223
+ if (typeof rawMsg.content === "string" && rawMsg.content) {
9224
+ contents.push({ role: "user", parts: [{ text: rawMsg.content }] });
9225
+ }
9226
+ continue;
9227
+ }
9228
+ if (role === "assistant") {
9229
+ const parts = [];
9230
+ if (typeof rawMsg.content === "string" && rawMsg.content) {
9231
+ parts.push({ text: rawMsg.content });
9232
+ }
9233
+ for (const tc of rawMsg.tool_calls ?? []) {
9234
+ let args = {};
9235
+ try {
9236
+ const parsed = JSON.parse(tc.function?.arguments ?? "{}");
9237
+ if (parsed && typeof parsed === "object") args = parsed;
9238
+ } catch {
9239
+ args = {};
9240
+ }
9241
+ parts.push({
9242
+ functionCall: {
9243
+ name: tc.function?.name ?? "",
9244
+ args,
9245
+ id: tc.id
9246
+ }
9247
+ });
9248
+ }
9249
+ if (parts.length > 0) contents.push({ role: "model", parts });
9250
+ continue;
9251
+ }
9252
+ if (role === "tool") {
9253
+ const raw = rawMsg.content;
9254
+ let response;
9255
+ if (typeof raw === "string") {
9256
+ try {
9257
+ const parsed = JSON.parse(raw);
9258
+ response = parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : { result: parsed };
9259
+ } catch {
9260
+ response = { result: raw };
9261
+ }
9262
+ } else {
9263
+ response = raw ?? {};
9264
+ }
9265
+ contents.push({
9266
+ role: "user",
9267
+ parts: [
9268
+ {
9269
+ functionResponse: {
9270
+ name: rawMsg.name ?? rawMsg.tool_call_id ?? "",
9271
+ response,
9272
+ id: rawMsg.tool_call_id
9273
+ }
9274
+ }
9275
+ ]
9276
+ });
9277
+ continue;
9278
+ }
9279
+ }
9280
+ return { systemInstruction: systemParts.join("\n\n"), contents };
9281
+ }
9282
+
9283
+ // src/llm/google.ts
9284
+ var LLM5 = class extends GoogleLLMProvider {
9285
+ constructor(opts = {}) {
9286
+ const key = opts.apiKey ?? process.env.GEMINI_API_KEY ?? process.env.GOOGLE_API_KEY;
9287
+ if (!key) {
9288
+ throw new Error(
9289
+ "Google LLM requires an apiKey. Pass { apiKey: 'AIza...' } or set GEMINI_API_KEY (or GOOGLE_API_KEY)."
9290
+ );
9291
+ }
9292
+ super({
9293
+ apiKey: key,
9294
+ model: opts.model,
9295
+ baseUrl: opts.baseUrl,
9296
+ temperature: opts.temperature,
9297
+ maxOutputTokens: opts.maxOutputTokens
9298
+ });
9299
+ }
9300
+ };
9301
+
9467
9302
  // src/carriers/twilio.ts
9468
9303
  var Carrier = class {
9469
9304
  kind = "twilio";
@@ -10178,6 +10013,7 @@ function isAudioConfig(value) {
10178
10013
  // Annotate the CommonJS export names for ESM import in node:
10179
10014
  0 && (module.exports = {
10180
10015
  AllProvidersFailedError,
10016
+ AnthropicLLM,
10181
10017
  AssemblyAISTT,
10182
10018
  AuthenticationError,
10183
10019
  BackgroundAudioPlayer,
@@ -10185,6 +10021,7 @@ function isAudioConfig(value) {
10185
10021
  CallMetricsAccumulator,
10186
10022
  CartesiaSTT,
10187
10023
  CartesiaTTS,
10024
+ CerebrasLLM,
10188
10025
  ChatContext,
10189
10026
  CloudflareTunnel,
10190
10027
  DEFAULT_MIN_SENTENCE_LEN,
@@ -10198,11 +10035,14 @@ function isAudioConfig(value) {
10198
10035
  GEMINI_DEFAULT_INPUT_SR,
10199
10036
  GEMINI_DEFAULT_OUTPUT_SR,
10200
10037
  GeminiLiveAdapter,
10038
+ GoogleLLM,
10039
+ GroqLLM,
10201
10040
  Guardrail,
10202
10041
  IVRActivity,
10203
10042
  LLMLoop,
10204
10043
  LMNTTTS,
10205
10044
  MetricsStore,
10045
+ OpenAILLM,
10206
10046
  OpenAILLMProvider,
10207
10047
  OpenAIRealtime,
10208
10048
  OpenAIRealtimeAdapter,