@voicelayer/sdk 0.6.2 → 0.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.
@@ -1,4 +1,4 @@
1
- export { b1 as EmailResolver, b2 as FlowResolver, b3 as GraphResolvers, b4 as GraphTraceEvent, b5 as KnowledgeResolver, b6 as LiveTextConversation, b7 as LiveTurnResult, b8 as PlaybookLibraryEntry, b9 as PlaybookResolver, ba as RegistryToolsResolver, bb as RunLiveTextOptions, ag as RunTextSessionOptions, ah as RunTextTranscriptOptions, ay as TextSession, az as TextTranscriptResult, n as ToolExecutor, bc as dedupeConversationEmails, bd as denyPrivateNetwork, be as privateNetworkOptInHonoured, bf as runLiveTextConversation, aZ as runTextSession, a_ as runTextTranscript, bg as runWithOpenAIScope, bh as toPlaybookResolution } from '../text-session-B-T33y5P.js';
1
+ export { b1 as EmailResolver, b2 as FlowResolver, b3 as GraphResolvers, b4 as GraphTraceEvent, b5 as KnowledgeResolver, b6 as LiveTextConversation, b7 as LiveTurnResult, b8 as PlaybookLibraryEntry, b9 as PlaybookResolver, ba as RegistryToolsResolver, bb as RunLiveTextOptions, ag as RunTextSessionOptions, ah as RunTextTranscriptOptions, ay as TextSession, az as TextTranscriptResult, n as ToolExecutor, bc as dedupeConversationEmails, bd as denyPrivateNetwork, be as privateNetworkOptInHonoured, bf as runLiveTextConversation, aZ as runTextSession, a_ as runTextTranscript, bg as runWithOpenAIScope, bh as toPlaybookResolution } from '../text-session-B928dhkB.js';
2
2
  import '@livekit/agents';
3
3
  import 'zod';
4
4
  import '../types-KqrAfY85.js';
@@ -14,6 +14,7 @@ import '@opentelemetry/sdk-logs';
14
14
  import '@opentelemetry/sdk-metrics';
15
15
  import '@opentelemetry/sdk-node';
16
16
  import '@opentelemetry/semantic-conventions';
17
+ import { llm, DEFAULT_API_CONNECT_OPTIONS, intervalForRetry, APIStatusError, APITimeoutError, APIConnectionError } from '@livekit/agents';
17
18
  import http from 'http';
18
19
  import https from 'https';
19
20
  import { Readable } from 'stream';
@@ -4076,32 +4077,116 @@ function acceptsReasoningEffort(model2) {
4076
4077
  const id = baseModelId(model2);
4077
4078
  return isReasoningModel(model2) && !/^o1-(mini|preview)/.test(id) && !/-chat(-|$)/.test(id);
4078
4079
  }
4080
+ function acceptsNoReasoningEffort(model2) {
4081
+ if (!acceptsReasoningEffort(model2))
4082
+ return false;
4083
+ const id = baseModelId(model2);
4084
+ if (/-pro\b/.test(id))
4085
+ return false;
4086
+ const gpt = /^gpt-(\d+)(?:\.(\d+))?/.exec(id);
4087
+ if (!gpt)
4088
+ return false;
4089
+ const major = Number(gpt[1]);
4090
+ const minor = gpt[2] !== void 0 ? Number(gpt[2]) : 0;
4091
+ return major > 5 || major === 5 && minor >= 1;
4092
+ }
4093
+ function forgetLearnedReasoningEfforts() {
4094
+ learnedEfforts.clear();
4095
+ }
4096
+ function chatReasoningEffort(model2, opts) {
4097
+ const learned = learnedEfforts.get(learnedKey(model2, opts.tools === true));
4098
+ if (learned !== void 0)
4099
+ return learned === "omit" ? void 0 : learned;
4100
+ if (!acceptsReasoningEffort(model2))
4101
+ return void 0;
4102
+ if (opts.tools === true && acceptsNoReasoningEffort(model2))
4103
+ return "none";
4104
+ return opts.requested;
4105
+ }
4079
4106
  function chatCompletionParams(model2, input) {
4107
+ const effort = chatReasoningEffort(model2, {
4108
+ ...input.tools !== void 0 ? { tools: input.tools } : {},
4109
+ ...input.reasoningEffort !== void 0 ? { requested: input.reasoningEffort } : {}
4110
+ });
4080
4111
  if (isReasoningModel(model2)) {
4081
4112
  return {
4082
4113
  ...input.maxTokens !== void 0 ? { max_completion_tokens: Math.max(input.maxTokens, REASONING_MIN_COMPLETION_TOKENS) } : {},
4083
- ...input.reasoningEffort !== void 0 && acceptsReasoningEffort(model2) ? { reasoning_effort: input.reasoningEffort } : {}
4114
+ ...effort !== void 0 ? { reasoning_effort: effort } : {}
4084
4115
  };
4085
4116
  }
4086
4117
  return {
4118
+ // only when a provider taught the process that this model (one we don't know as a reasoning model) takes an effort
4119
+ ...effort !== void 0 ? { reasoning_effort: effort } : {},
4087
4120
  ...input.maxTokens !== void 0 ? { max_tokens: input.maxTokens } : {},
4088
4121
  ...input.temperature !== void 0 ? { temperature: input.temperature } : {},
4089
4122
  ...input.topP !== void 0 ? { top_p: input.topP } : {}
4090
4123
  };
4091
4124
  }
4092
- function modelRejectionOf(err) {
4125
+ function acceptsSamplingParams(model2) {
4126
+ return !isReasoningModel(model2);
4127
+ }
4128
+ function providerErrorOf(err) {
4129
+ if (err === null || typeof err !== "object")
4130
+ return null;
4093
4131
  const e = err;
4094
- const status = typeof e?.status === "number" ? e.status : null;
4095
- if (status !== 400 && status !== 403 && status !== 404)
4132
+ const body = e["body"] !== null && typeof e["body"] === "object" ? e["body"] : {};
4133
+ const pick = (k) => e[k] !== void 0 && e[k] !== null ? e[k] : body[k];
4134
+ const statusRaw = typeof e["status"] === "number" ? e["status"] : e["statusCode"];
4135
+ const status = typeof statusRaw === "number" && statusRaw > 0 ? statusRaw : null;
4136
+ const code = pick("code");
4137
+ const type = pick("type");
4138
+ const param = pick("param");
4139
+ const message = typeof body["message"] === "string" ? body["message"] : typeof e["message"] === "string" ? e["message"] : "";
4140
+ return {
4141
+ status,
4142
+ code: typeof code === "string" ? code : typeof type === "string" ? type : "",
4143
+ param: typeof param === "string" ? param : null,
4144
+ message
4145
+ };
4146
+ }
4147
+ function reasoningEffortRejectionOf(err) {
4148
+ const f = providerErrorOf(err);
4149
+ if (!f || f.status !== 400)
4096
4150
  return null;
4097
- const code = typeof e?.code === "string" ? e.code : typeof e?.type === "string" ? e.type : "";
4098
- const param = typeof e?.param === "string" ? e.param : null;
4099
- const rejected = REJECTION_CODES.has(code) || param !== null && MODEL_PARAMS.has(param);
4151
+ if (f.param !== "reasoning_effort" && !/reasoning[_ ]effort/i.test(f.message))
4152
+ return null;
4153
+ return { status: f.status, message: f.message, suggestsNone: /reasoning[_ ]effort[^.]*\bnone\b/i.test(f.message) };
4154
+ }
4155
+ function learnReasoningEffort(model2, shape, err) {
4156
+ const rejection = reasoningEffortRejectionOf(err);
4157
+ if (!rejection)
4158
+ return false;
4159
+ const next = shape.sent !== "none" && (rejection.suggestsNone || shape.sent === void 0) ? "none" : "omit";
4160
+ if ((next === "omit" ? void 0 : next) === shape.sent)
4161
+ return false;
4162
+ learnedEfforts.set(learnedKey(model2, shape.tools), next);
4163
+ return true;
4164
+ }
4165
+ async function withReasoningEffortRetry(shape, call) {
4166
+ const sent = chatReasoningEffort(shape.model, {
4167
+ tools: shape.tools,
4168
+ ...shape.requested !== void 0 ? { requested: shape.requested } : {}
4169
+ });
4170
+ try {
4171
+ return await call();
4172
+ } catch (err) {
4173
+ if (!learnReasoningEffort(shape.model, { tools: shape.tools, sent }, err))
4174
+ throw err;
4175
+ return call();
4176
+ }
4177
+ }
4178
+ function modelRejectionOf(err) {
4179
+ const f = providerErrorOf(err);
4180
+ const status = f?.status ?? null;
4181
+ if (!f || status === null || status !== 400 && status !== 403 && status !== 404)
4182
+ return null;
4183
+ const { code, param } = f;
4184
+ const rejected = REJECTION_CODES.has(code) || param !== null && MODEL_PARAMS.has(param) || reasoningEffortRejectionOf(err) !== null;
4100
4185
  if (!rejected)
4101
4186
  return null;
4102
4187
  if (status === 403 && code !== "model_not_found")
4103
4188
  return null;
4104
- return { status, code: code || "invalid_request_error", message: typeof e?.message === "string" ? e.message : "" };
4189
+ return { status, code: code || "invalid_request_error", message: f.message };
4105
4190
  }
4106
4191
  async function withModelFallback(opts) {
4107
4192
  const fallbackModel = opts.fallbackModel ?? PLATFORM_DEFAULT_CHAT_MODEL;
@@ -4122,11 +4207,13 @@ async function withModelFallback(opts) {
4122
4207
  return opts.call(fallbackModel);
4123
4208
  }
4124
4209
  }
4125
- var PLATFORM_DEFAULT_CHAT_MODEL, REASONING_MIN_COMPLETION_TOKENS, REJECTION_CODES, MODEL_PARAMS, MODEL_REJECTION_TTL_MS, ModelRejectionCache;
4210
+ var PLATFORM_DEFAULT_CHAT_MODEL, REASONING_MIN_COMPLETION_TOKENS, learnedEfforts, learnedKey, REJECTION_CODES, MODEL_PARAMS, MODEL_REJECTION_TTL_MS, ModelRejectionCache;
4126
4211
  var init_chat_params = __esm({
4127
4212
  "../llm-client/dist/chat-params.js"() {
4128
4213
  PLATFORM_DEFAULT_CHAT_MODEL = "gpt-4o-mini";
4129
4214
  REASONING_MIN_COMPLETION_TOKENS = 2048;
4215
+ learnedEfforts = /* @__PURE__ */ new Map();
4216
+ learnedKey = (model2, tools) => `${baseModelId(model2)}|${tools ? "tools" : "plain"}`;
4130
4217
  REJECTION_CODES = /* @__PURE__ */ new Set(["unsupported_parameter", "unsupported_value", "model_not_found"]);
4131
4218
  MODEL_PARAMS = /* @__PURE__ */ new Set(["model", "max_tokens", "max_completion_tokens", "temperature", "top_p", "reasoning_effort"]);
4132
4219
  MODEL_REJECTION_TTL_MS = 5 * 60 * 1e3;
@@ -4154,6 +4241,30 @@ var init_chat_params = __esm({
4154
4241
  };
4155
4242
  }
4156
4243
  });
4244
+
4245
+ // ../llm-client/dist/index.js
4246
+ var dist_exports = {};
4247
+ __export(dist_exports, {
4248
+ MODEL_REJECTION_TTL_MS: () => MODEL_REJECTION_TTL_MS,
4249
+ ModelRejectionCache: () => ModelRejectionCache,
4250
+ PLATFORM_DEFAULT_CHAT_MODEL: () => PLATFORM_DEFAULT_CHAT_MODEL,
4251
+ REASONING_MIN_COMPLETION_TOKENS: () => REASONING_MIN_COMPLETION_TOKENS,
4252
+ acceptsNoReasoningEffort: () => acceptsNoReasoningEffort,
4253
+ acceptsReasoningEffort: () => acceptsReasoningEffort,
4254
+ acceptsSamplingParams: () => acceptsSamplingParams,
4255
+ chatCompletionParams: () => chatCompletionParams,
4256
+ chatReasoningEffort: () => chatReasoningEffort,
4257
+ createChatClient: () => createChatClient,
4258
+ forgetLearnedReasoningEfforts: () => forgetLearnedReasoningEfforts,
4259
+ hasChatKey: () => hasChatKey,
4260
+ isReasoningModel: () => isReasoningModel,
4261
+ learnReasoningEffort: () => learnReasoningEffort,
4262
+ modelRejectionOf: () => modelRejectionOf,
4263
+ providerErrorOf: () => providerErrorOf,
4264
+ reasoningEffortRejectionOf: () => reasoningEffortRejectionOf,
4265
+ withModelFallback: () => withModelFallback,
4266
+ withReasoningEffortRetry: () => withReasoningEffortRetry
4267
+ });
4157
4268
  function createChatClient(config = {}) {
4158
4269
  return new OpenAI({
4159
4270
  ...config.apiKey ? { apiKey: config.apiKey } : {},
@@ -4161,6 +4272,9 @@ function createChatClient(config = {}) {
4161
4272
  ...config.timeoutMs ? { timeout: config.timeoutMs } : {}
4162
4273
  });
4163
4274
  }
4275
+ function hasChatKey(config = {}) {
4276
+ return Boolean(config.apiKey || process.env["OPENAI_API_KEY"]);
4277
+ }
4164
4278
  var init_dist = __esm({
4165
4279
  "../llm-client/dist/index.js"() {
4166
4280
  init_chat_params();
@@ -4300,6 +4414,340 @@ var init_wrap = __esm({
4300
4414
  "src/providers/wrap.ts"() {
4301
4415
  }
4302
4416
  });
4417
+ var init_start = __esm({
4418
+ "../observability/dist/start.js"() {
4419
+ }
4420
+ });
4421
+
4422
+ // ../observability/dist/attributes.js
4423
+ var ATTR;
4424
+ var init_attributes = __esm({
4425
+ "../observability/dist/attributes.js"() {
4426
+ ATTR = {
4427
+ projectId: "vl.project_id",
4428
+ callId: "vl.call_id",
4429
+ campaignId: "vl.campaign_id",
4430
+ room: "vl.room",
4431
+ agentId: "vl.agent_id",
4432
+ phoneNumberId: "vl.phone_number_id",
4433
+ bindingId: "vl.binding_id",
4434
+ source: "vl.source",
4435
+ kind: "vl.kind"
4436
+ };
4437
+ }
4438
+ });
4439
+ function getCurrentCallContext() {
4440
+ return callContextStore.getStore();
4441
+ }
4442
+ var callContextStore;
4443
+ var init_call_context = __esm({
4444
+ "../observability/dist/call-context.js"() {
4445
+ init_attributes();
4446
+ callContextStore = new AsyncLocalStorage();
4447
+ }
4448
+ });
4449
+ var init_trace_propagation = __esm({
4450
+ "../observability/dist/trace-propagation.js"() {
4451
+ }
4452
+ });
4453
+ function meter() {
4454
+ return metrics.getMeter(METER_NAME, METER_VERSION);
4455
+ }
4456
+ function modelFallbacks() {
4457
+ return _modelFallbacks ??= meter().createCounter("vl.llm.model_fallback", {
4458
+ description: "Model calls the provider rejected that fell back to the platform default model",
4459
+ unit: "{fallbacks}"
4460
+ });
4461
+ }
4462
+ function recordModelFallback(args) {
4463
+ const out = {
4464
+ "vl.model": args.model,
4465
+ "vl.fallback_model": args.fallbackModel,
4466
+ "vl.error_code": args.code
4467
+ };
4468
+ if (args.projectId)
4469
+ out[ATTR.projectId] = args.projectId;
4470
+ if (args.agentId)
4471
+ out[ATTR.agentId] = args.agentId;
4472
+ if (args.surface)
4473
+ out["vl.surface"] = args.surface;
4474
+ modelFallbacks().add(1, out);
4475
+ }
4476
+ var METER_NAME, METER_VERSION, _modelFallbacks;
4477
+ var init_metrics = __esm({
4478
+ "../observability/dist/metrics.js"() {
4479
+ init_attributes();
4480
+ METER_NAME = "voicelayer";
4481
+ METER_VERSION = "0.1.0";
4482
+ _modelFallbacks = null;
4483
+ }
4484
+ });
4485
+ var init_latency_span = __esm({
4486
+ "../observability/dist/latency-span.js"() {
4487
+ init_attributes();
4488
+ }
4489
+ });
4490
+
4491
+ // ../observability/dist/index.js
4492
+ var init_dist2 = __esm({
4493
+ "../observability/dist/index.js"() {
4494
+ init_start();
4495
+ init_call_context();
4496
+ init_trace_propagation();
4497
+ init_attributes();
4498
+ init_metrics();
4499
+ init_latency_span();
4500
+ }
4501
+ });
4502
+
4503
+ // src/providers/resilient-llm.ts
4504
+ var resilient_llm_exports = {};
4505
+ __export(resilient_llm_exports, {
4506
+ LLM_APOLOGY: () => LLM_APOLOGY,
4507
+ ResilientLLM: () => ResilientLLM,
4508
+ isResilientLLM: () => isResilientLLM
4509
+ });
4510
+ function isResilientLLM(value) {
4511
+ return typeof value === "object" && value !== null && value[RESILIENT] === true;
4512
+ }
4513
+ function transient(error) {
4514
+ if (error instanceof APIStatusError) {
4515
+ const s = error.statusCode;
4516
+ return s === 408 || s === 429 || s < 0 || s >= 500;
4517
+ }
4518
+ return error instanceof APITimeoutError || error instanceof APIConnectionError;
4519
+ }
4520
+ var LLM_APOLOGY, RESILIENT, ResilientLLM, sameModel, ServedLLM, ResilientLLMStream;
4521
+ var init_resilient_llm = __esm({
4522
+ "src/providers/resilient-llm.ts"() {
4523
+ init_dist();
4524
+ init_dist2();
4525
+ LLM_APOLOGY = "Sorry, I'm having trouble right now. Could you give me a moment and say that again?";
4526
+ RESILIENT = /* @__PURE__ */ Symbol.for("voicelayer.resilientLLM");
4527
+ ResilientLLM = class extends llm.LLM {
4528
+ [RESILIENT] = true;
4529
+ #opts;
4530
+ #fallback = null;
4531
+ #listeners = /* @__PURE__ */ new Set();
4532
+ /** Models the provider rejected on this call (a call's pipeline is built per call): later turns go straight to the fallback. */
4533
+ rejections = new ModelRejectionCache();
4534
+ constructor(opts) {
4535
+ super();
4536
+ this.#opts = opts;
4537
+ }
4538
+ label() {
4539
+ return this.#opts.primary.label();
4540
+ }
4541
+ get model() {
4542
+ return this.#opts.primary.model;
4543
+ }
4544
+ get provider() {
4545
+ return this.#opts.primary.provider;
4546
+ }
4547
+ get apology() {
4548
+ return this.#opts.apology ?? LLM_APOLOGY;
4549
+ }
4550
+ get reasoningParams() {
4551
+ return this.#opts.reasoningParams === true;
4552
+ }
4553
+ /** The fallback LLM, built on first need; null when there is none or it is the agent's own model. */
4554
+ fallbackLLM() {
4555
+ if (!this.#opts.fallback) return null;
4556
+ this.#fallback ??= this.#opts.fallback();
4557
+ return sameModel(this.#fallback.model, this.model) ? null : this.#fallback;
4558
+ }
4559
+ /** Hear about every recovery (and every apology). Returns the unsubscribe. */
4560
+ onIncident(listener) {
4561
+ this.#listeners.add(listener);
4562
+ return () => this.#listeners.delete(listener);
4563
+ }
4564
+ /** @internal */
4565
+ report(incident) {
4566
+ const log = incident.kind === "apology" ? console.error : console.warn;
4567
+ log(`[voicelayer] llm ${incident.kind.replace(/_/g, " ")}`, incident);
4568
+ if (incident.kind === "model_fallback") {
4569
+ const call = getCurrentCallContext();
4570
+ recordModelFallback({
4571
+ model: incident.model,
4572
+ fallbackModel: incident.fallbackModel,
4573
+ code: incident.code,
4574
+ surface: "voice",
4575
+ ...call?.projectId ? { projectId: call.projectId } : {},
4576
+ ...call?.agentId ? { agentId: call.agentId } : {}
4577
+ });
4578
+ }
4579
+ for (const listener of this.#listeners) {
4580
+ try {
4581
+ listener(incident);
4582
+ } catch {
4583
+ }
4584
+ }
4585
+ }
4586
+ chat(args) {
4587
+ return new ResilientLLMStream(this, args);
4588
+ }
4589
+ prewarm() {
4590
+ this.#opts.primary.prewarm();
4591
+ }
4592
+ async aclose() {
4593
+ await Promise.all([this.#opts.primary.aclose(), this.#fallback?.aclose()]);
4594
+ }
4595
+ /** @internal */
4596
+ get primary() {
4597
+ return this.#opts.primary;
4598
+ }
4599
+ };
4600
+ sameModel = (a, b) => a.trim().toLowerCase() === b.trim().toLowerCase();
4601
+ ServedLLM = class extends llm.LLM {
4602
+ constructor(owner, served) {
4603
+ super();
4604
+ this.owner = owner;
4605
+ this.served = served;
4606
+ }
4607
+ owner;
4608
+ served;
4609
+ label() {
4610
+ return this.owner.label();
4611
+ }
4612
+ get model() {
4613
+ return this.served();
4614
+ }
4615
+ get provider() {
4616
+ return this.owner.provider;
4617
+ }
4618
+ chat(args) {
4619
+ return this.owner.chat(args);
4620
+ }
4621
+ emit(event, ...args) {
4622
+ return this.owner.emit(event, ...args);
4623
+ }
4624
+ };
4625
+ ResilientLLMStream = class extends llm.LLMStream {
4626
+ #owner;
4627
+ #args;
4628
+ #conn;
4629
+ /** The model answering this stream — what its metrics report. */
4630
+ #served;
4631
+ #current = null;
4632
+ constructor(owner, args) {
4633
+ const conn = args.connOptions ?? DEFAULT_API_CONNECT_OPTIONS;
4634
+ const served = { model: owner.model };
4635
+ super(new ServedLLM(owner, () => served.model), {
4636
+ chatCtx: args.chatCtx,
4637
+ ...args.toolCtx ? { toolCtx: args.toolCtx } : {},
4638
+ connOptions: { ...conn, maxRetry: 0 }
4639
+ });
4640
+ this.#owner = owner;
4641
+ this.#args = args;
4642
+ this.#conn = conn;
4643
+ this.#served = served;
4644
+ this.abortController.signal.addEventListener("abort", () => this.#current?.close());
4645
+ }
4646
+ get #hasTools() {
4647
+ return this.#args.toolCtx !== void 0 && Object.keys(this.#args.toolCtx).length > 0;
4648
+ }
4649
+ #extraKwargs(model2) {
4650
+ const base = this.#args.extraKwargs;
4651
+ if (!this.#owner.reasoningParams) return base;
4652
+ const effort = chatReasoningEffort(model2, { tools: this.#hasTools });
4653
+ if (effort === void 0) {
4654
+ if (!base || !("reasoning_effort" in base)) return base;
4655
+ const { reasoning_effort: _dropped, ...rest } = base;
4656
+ return rest;
4657
+ }
4658
+ return { ...base, reasoning_effort: effort };
4659
+ }
4660
+ /** One request on `target`, forwarding its chunks. Its failure is the inner LLM's 'error' event. */
4661
+ async #attempt(target) {
4662
+ let failure = null;
4663
+ const onError = (ev) => {
4664
+ failure ??= ev.error;
4665
+ };
4666
+ target.on("error", onError);
4667
+ let started = false;
4668
+ try {
4669
+ const extraKwargs = this.#extraKwargs(target.model);
4670
+ const stream = target.chat({
4671
+ ...this.#args,
4672
+ connOptions: { ...this.#conn, maxRetry: 0 },
4673
+ ...extraKwargs !== void 0 ? { extraKwargs } : {}
4674
+ });
4675
+ this.#current = stream;
4676
+ for await (const chunk of stream) {
4677
+ if (this.abortController.signal.aborted) break;
4678
+ started = true;
4679
+ this.queue.put(chunk);
4680
+ }
4681
+ } catch (err) {
4682
+ failure ??= err instanceof Error ? err : new Error(String(err));
4683
+ } finally {
4684
+ target.off("error", onError);
4685
+ this.#current = null;
4686
+ }
4687
+ return failure ? { ok: false, error: failure, started } : { ok: true };
4688
+ }
4689
+ /** Run `target` until it answers, or a failure that retrying it won't fix. */
4690
+ async #run(target) {
4691
+ let effortRetried = false;
4692
+ for (let retries = 0; ; ) {
4693
+ const sent = this.#owner.reasoningParams ? chatReasoningEffort(target.model, { tools: this.#hasTools }) : void 0;
4694
+ const result = await this.#attempt(target);
4695
+ if (result.ok || result.started || this.abortController.signal.aborted) return result;
4696
+ if (this.#owner.reasoningParams && !effortRetried && learnReasoningEffort(target.model, { tools: this.#hasTools, sent }, result.error)) {
4697
+ effortRetried = true;
4698
+ this.#owner.report({
4699
+ kind: "reasoning_effort_adapted",
4700
+ model: target.model,
4701
+ message: providerErrorOf(result.error)?.message ?? result.error.message
4702
+ });
4703
+ continue;
4704
+ }
4705
+ if (!transient(result.error) || retries >= this.#conn.maxRetry) return result;
4706
+ const wait = intervalForRetry(this.#conn, retries);
4707
+ retries += 1;
4708
+ if (wait > 0) await new Promise((r) => setTimeout(r, wait));
4709
+ if (this.abortController.signal.aborted) return result;
4710
+ }
4711
+ }
4712
+ async run() {
4713
+ const owner = this.#owner;
4714
+ const model2 = owner.model;
4715
+ const fallback = owner.fallbackLLM();
4716
+ const known = fallback ? owner.rejections.get(model2) : null;
4717
+ let failure;
4718
+ if (known && fallback) {
4719
+ owner.report({ kind: "model_fallback", model: model2, fallbackModel: fallback.model, code: known.code, message: known.message, cached: true });
4720
+ failure = new Error(known.message);
4721
+ } else {
4722
+ const first = await this.#run(owner.primary);
4723
+ if (first.ok || first.started || this.abortController.signal.aborted) return;
4724
+ failure = first.error;
4725
+ const rejection = modelRejectionOf(first.error);
4726
+ if (rejection) owner.rejections.set(model2, rejection);
4727
+ if (fallback) {
4728
+ const f = providerErrorOf(first.error);
4729
+ owner.report({
4730
+ kind: "model_fallback",
4731
+ model: model2,
4732
+ fallbackModel: fallback.model,
4733
+ code: rejection?.code ?? (f?.status ? String(f.status) : "error"),
4734
+ message: f?.message || first.error.message,
4735
+ cached: false
4736
+ });
4737
+ }
4738
+ }
4739
+ if (fallback) {
4740
+ this.#served.model = fallback.model;
4741
+ const second = await this.#run(fallback);
4742
+ if (second.ok || second.started || this.abortController.signal.aborted) return;
4743
+ failure = second.error;
4744
+ }
4745
+ owner.report({ kind: "apology", model: this.#served.model, message: providerErrorOf(failure)?.message || failure.message });
4746
+ this.queue.put({ id: `vl-apology-${Date.now()}`, delta: { role: "assistant", content: owner.apology } });
4747
+ }
4748
+ };
4749
+ }
4750
+ });
4303
4751
 
4304
4752
  // src/providers/index.ts
4305
4753
  async function importOptional(spec, hint) {
@@ -4346,9 +4794,13 @@ var init_providers2 = __esm({
4346
4794
  llm(options = {}) {
4347
4795
  return async () => {
4348
4796
  const oa = await importOptional("@voicelayer/agents-plugin-openai", "openai.llm");
4349
- return new oa.LLM(
4350
- withCreds({ model: options.model ?? "gpt-4o-mini" }, options)
4351
- );
4797
+ const { ResilientLLM: ResilientLLM2 } = await Promise.resolve().then(() => (init_resilient_llm(), resilient_llm_exports));
4798
+ const { PLATFORM_DEFAULT_CHAT_MODEL: PLATFORM_DEFAULT_CHAT_MODEL2 } = await Promise.resolve().then(() => (init_dist(), dist_exports));
4799
+ return new ResilientLLM2({
4800
+ primary: new oa.LLM(withCreds({ model: options.model ?? "gpt-4o-mini" }, options)),
4801
+ fallback: () => new oa.LLM(withCreds({ model: PLATFORM_DEFAULT_CHAT_MODEL2 }, options)),
4802
+ reasoningParams: true
4803
+ });
4352
4804
  };
4353
4805
  },
4354
4806
  tts(options = {}) {
@@ -4424,9 +4876,10 @@ var init_providers2 = __esm({
4424
4876
  llm(options = {}) {
4425
4877
  return async () => {
4426
4878
  const g = await importOptional("@voicelayer/agents-plugin-google", "google.llm");
4427
- return new g.LLM(
4428
- withCreds({ model: options.model ?? "gemini-3.8-flash" }, options)
4429
- );
4879
+ const { ResilientLLM: ResilientLLM2 } = await Promise.resolve().then(() => (init_resilient_llm(), resilient_llm_exports));
4880
+ return new ResilientLLM2({
4881
+ primary: new g.LLM(withCreds({ model: options.model ?? "gemini-3.8-flash" }, options))
4882
+ });
4430
4883
  };
4431
4884
  },
4432
4885
  realtime(options = {}) {
@@ -4528,91 +4981,6 @@ var init_llm = __esm({
4528
4981
  init_registry();
4529
4982
  }
4530
4983
  });
4531
- var init_start = __esm({
4532
- "../observability/dist/start.js"() {
4533
- }
4534
- });
4535
-
4536
- // ../observability/dist/attributes.js
4537
- var ATTR;
4538
- var init_attributes = __esm({
4539
- "../observability/dist/attributes.js"() {
4540
- ATTR = {
4541
- projectId: "vl.project_id",
4542
- callId: "vl.call_id",
4543
- campaignId: "vl.campaign_id",
4544
- room: "vl.room",
4545
- agentId: "vl.agent_id",
4546
- phoneNumberId: "vl.phone_number_id",
4547
- bindingId: "vl.binding_id",
4548
- source: "vl.source",
4549
- kind: "vl.kind"
4550
- };
4551
- }
4552
- });
4553
- function getCurrentCallContext() {
4554
- return callContextStore.getStore();
4555
- }
4556
- var callContextStore;
4557
- var init_call_context = __esm({
4558
- "../observability/dist/call-context.js"() {
4559
- init_attributes();
4560
- callContextStore = new AsyncLocalStorage();
4561
- }
4562
- });
4563
- var init_trace_propagation = __esm({
4564
- "../observability/dist/trace-propagation.js"() {
4565
- }
4566
- });
4567
- function meter() {
4568
- return metrics.getMeter(METER_NAME, METER_VERSION);
4569
- }
4570
- function modelFallbacks() {
4571
- return _modelFallbacks ??= meter().createCounter("vl.llm.model_fallback", {
4572
- description: "Model calls the provider rejected that fell back to the platform default model",
4573
- unit: "{fallbacks}"
4574
- });
4575
- }
4576
- function recordModelFallback(args) {
4577
- const out = {
4578
- "vl.model": args.model,
4579
- "vl.fallback_model": args.fallbackModel,
4580
- "vl.error_code": args.code
4581
- };
4582
- if (args.projectId)
4583
- out[ATTR.projectId] = args.projectId;
4584
- if (args.agentId)
4585
- out[ATTR.agentId] = args.agentId;
4586
- if (args.surface)
4587
- out["vl.surface"] = args.surface;
4588
- modelFallbacks().add(1, out);
4589
- }
4590
- var METER_NAME, METER_VERSION, _modelFallbacks;
4591
- var init_metrics = __esm({
4592
- "../observability/dist/metrics.js"() {
4593
- init_attributes();
4594
- METER_NAME = "voicelayer";
4595
- METER_VERSION = "0.1.0";
4596
- _modelFallbacks = null;
4597
- }
4598
- });
4599
- var init_latency_span = __esm({
4600
- "../observability/dist/latency-span.js"() {
4601
- init_attributes();
4602
- }
4603
- });
4604
-
4605
- // ../observability/dist/index.js
4606
- var init_dist2 = __esm({
4607
- "../observability/dist/index.js"() {
4608
- init_start();
4609
- init_call_context();
4610
- init_trace_propagation();
4611
- init_attributes();
4612
- init_metrics();
4613
- init_latency_span();
4614
- }
4615
- });
4616
4984
 
4617
4985
  // src/runtime/helper-models.ts
4618
4986
  function rejectionsFor(client) {