"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);

// src/agent/llm/index.ts
var index_exports = {};
__export(index_exports, {
  GoogleProvider: () => GoogleProvider,
  OpenAIProvider: () => OpenAIProvider,
  ProxyProvider: () => ProxyProvider,
  buildStream: () => buildStream,
  createProvider: () => createProvider,
  getAdapter: () => getAdapter,
  googleAdapter: () => googleAdapter,
  isLLMRouter: () => isLLMRouter,
  listAdapters: () => listAdapters,
  openaiAdapter: () => openaiAdapter,
  proxyAdapter: () => proxyAdapter,
  registerAdapter: () => registerAdapter,
  resolveLLM: () => resolveLLM,
  seedDefaultAdapters: () => seedDefaultAdapters,
  unregisterAdapter: () => unregisterAdapter
});
module.exports = __toCommonJS(index_exports);

// src/agent/llm/stream.ts
function buildStream(opts) {
  let text = "";
  const toolCalls = [];
  let finishReason;
  let usage;
  const buffered = [];
  let waiters = [];
  let done = false;
  let pendingError;
  const startedAt = Date.now();
  let firstDeltaAt;
  let endedAt = startedAt;
  let producerErrored = false;
  (async () => {
    try {
      for await (const evt of opts.produce()) {
        if (evt.toolCall) {
          const existing = toolCalls.find((t) => t.id === evt.toolCall.id);
          if (existing) {
            existing.arguments = { ...existing.arguments, ...evt.toolCall.arguments };
          } else {
            toolCalls.push(evt.toolCall);
          }
        }
        if (evt.delta !== void 0) {
          if (evt.delta.length > 0 && firstDeltaAt === void 0) {
            firstDeltaAt = Date.now();
          }
          text += evt.delta;
        }
        if (evt.usage) usage = evt.usage;
        if (evt.finishReason) finishReason = evt.finishReason;
        endedAt = Date.now();
        const chunk = {
          delta: evt.delta ?? "",
          text,
          toolCalls: toolCalls.length > 0 ? toolCalls : void 0,
          done: false
        };
        if (waiters.length > 0) {
          const w = waiters.shift();
          w(chunk);
        } else {
          buffered.push(chunk);
        }
      }
    } catch (err) {
      producerErrored = true;
      pendingError = err;
      const errChunk = {
        delta: "",
        text,
        toolCalls: toolCalls.length > 0 ? toolCalls : void 0,
        done: true,
        // No finishReason — caller can branch on `error` field instead.
        error: err
      };
      if (waiters.length > 0) {
        const w = waiters.shift();
        w(errChunk);
      } else {
        buffered.push(errChunk);
      }
      for (const w of waiters) w(null);
      waiters = [];
      done = true;
    } finally {
      if (!producerErrored) {
        const final = {
          delta: "",
          text,
          toolCalls: toolCalls.length > 0 ? toolCalls : void 0,
          done: true,
          finishReason: finishReason ?? "stop"
        };
        if (waiters.length > 0) {
          const w = waiters.shift();
          w(final);
        } else {
          buffered.push(final);
        }
        for (const w of waiters) w(null);
        waiters = [];
        done = true;
      }
    }
  })();
  const iterator = {
    next() {
      if (buffered.length > 0) {
        const c = buffered.shift();
        return Promise.resolve({ value: c, done: c.done && !buffered.length });
      }
      if (done) {
        return Promise.resolve({ value: void 0, done: true });
      }
      return new Promise((resolve) => {
        waiters.push((c) => {
          if (!c) resolve({ value: void 0, done: true });
          else resolve({ value: c, done: c.done && !buffered.length });
        });
      });
    }
  };
  const awaitable = (async () => {
    for await (const _ of {
      [Symbol.asyncIterator]() {
        return iterator;
      }
    }) {
    }
    if (pendingError) throw pendingError;
    return {
      content: text,
      toolCalls: toolCalls.length > 0 ? toolCalls : void 0,
      usage,
      finishReason: finishReason ?? "stop",
      streamMetrics: { startedAt, firstDeltaAt, endedAt }
    };
  })();
  const handle = awaitable;
  handle[Symbol.asyncIterator] = () => iterator;
  return handle;
}

// src/utils/redact.ts
function redactSecrets(s, secrets) {
  let out = s;
  for (const sec of secrets) {
    if (sec && sec.length > 0) {
      out = out.split(sec).join("[REDACTED]");
    }
  }
  return out;
}

// src/agent/llm/openai.ts
var OpenAIProvider = class {
  name = "openai";
  apiKey;
  model;
  baseURL;
  headers;
  extraBody;
  constructor(config) {
    this.apiKey = config.apiKey;
    this.model = config.model ?? "gpt-5.4-mini";
    this.baseURL = config.baseURL ?? "https://api.openai.com/v1";
    this.headers = {
      "Content-Type": "application/json",
      Authorization: `Bearer ${this.apiKey}`,
      ...config.organization ? { "OpenAI-Organization": config.organization } : {},
      ...config.headers ?? {}
    };
    this.extraBody = config.extraBody ?? {};
  }
  buildBody(opts, stream) {
    const model = opts.model ?? this.model;
    const body = {
      model,
      messages: opts.messages.map(toOpenAIMessage)
    };
    if (stream) body.stream = true;
    const newParamShape = usesMaxCompletionTokens(model);
    const reasoning = opts.thinking !== void 0 || isReasoningModel(model);
    if (newParamShape) {
      if (opts.maxTokens !== void 0) body.max_completion_tokens = opts.maxTokens;
    } else if (opts.maxTokens !== void 0) {
      body.max_tokens = opts.maxTokens;
    }
    if (reasoning) {
      const hasTools = (opts.tools?.length ?? 0) > 0;
      const wantsReasoning = opts.thinking && opts.thinking !== "off";
      if (wantsReasoning && !hasTools) {
        body.reasoning_effort = opts.thinking;
      }
    } else {
      body.temperature = opts.temperature ?? 0.7;
    }
    if (opts.jsonMode) {
      body.response_format = { type: "json_object" };
    }
    if (opts.tools && opts.tools.length > 0) {
      body.tools = opts.tools.map((t) => ({
        type: "function",
        function: {
          name: t.name,
          description: t.description,
          parameters: t.parameters
        }
      }));
      const choice = opts.toolChoice ?? "auto";
      if (choice === "auto" || choice === "required") {
        body.tool_choice = choice;
      } else if (typeof choice === "object" && typeof choice.name === "string") {
        body.tool_choice = { type: "function", function: { name: choice.name } };
      }
    }
    return { ...body, ...this.extraBody };
  }
  async complete(opts) {
    const body = this.buildBody(opts, false);
    const response = await fetch(`${this.baseURL}/chat/completions`, {
      method: "POST",
      headers: this.headers,
      body: JSON.stringify(body),
      signal: opts.signal
    });
    if (!response.ok) {
      const errText = await response.text().catch(() => response.statusText);
      throw new Error(
        `OpenAI HTTP ${response.status}: ${redactSecrets(errText, [this.apiKey])}`
      );
    }
    const data = await response.json();
    const choice = data.choices?.[0];
    if (!choice) throw new Error("OpenAI: no choices returned");
    const message = choice.message;
    const toolCalls = message.tool_calls?.map((tc) => ({
      id: tc.id,
      name: tc.function.name,
      arguments: safeParseJson(tc.function.arguments) ?? {}
    }));
    return {
      content: message.content ?? "",
      toolCalls,
      usage: data.usage ? {
        promptTokens: data.usage.prompt_tokens,
        completionTokens: data.usage.completion_tokens
      } : void 0,
      finishReason: choice.finish_reason ?? "stop"
    };
  }
  /**
   * Streaming via OpenAI's SSE `chat/completions?stream=true`. Each event is
   * `data: { ... }` carrying either a text delta or a tool_call fragment.
   * Tool calls stream piecewise — `index` slots; `id` / `function.name` arrive
   * on the first fragment, `function.arguments` accumulates JSON characters
   * across subsequent fragments.
   */
  streamComplete(opts) {
    const body = this.buildBody(opts, true);
    const baseURL = this.baseURL;
    const headers = this.headers;
    const apiKey = this.apiKey;
    return buildStream({
      produce: () => streamOpenAI({ url: `${baseURL}/chat/completions`, headers, body, signal: opts.signal, apiKey })
    });
  }
};
async function* streamOpenAI(args) {
  const response = await fetch(args.url, {
    method: "POST",
    headers: args.headers,
    body: JSON.stringify(args.body),
    signal: args.signal
  });
  if (!response.ok) {
    const errText = await response.text().catch(() => response.statusText);
    throw new Error(`OpenAI HTTP ${response.status}: ${redactSecrets(errText, [args.apiKey])}`);
  }
  if (!response.body) {
    throw new Error("OpenAI: no response body for stream");
  }
  const inflight = /* @__PURE__ */ new Map();
  const yielded = /* @__PURE__ */ new Set();
  const reader = response.body.getReader();
  const decoder = new TextDecoder();
  let buf = "";
  let finishReason;
  let usage;
  while (true) {
    let value;
    let done = false;
    try {
      const r = await reader.read();
      value = r.value;
      done = r.done;
    } catch (err) {
      if (err.name === "AbortError") return;
      throw err;
    }
    if (done) break;
    buf += decoder.decode(value, { stream: true });
    let sep;
    while ((sep = buf.indexOf("\n\n")) !== -1) {
      const event = buf.slice(0, sep);
      buf = buf.slice(sep + 2);
      if (!event.trim()) continue;
      for (const line of event.split("\n")) {
        if (!line.startsWith("data:")) continue;
        const payload = line.slice(5).trim();
        if (payload === "[DONE]") continue;
        let parsed;
        try {
          parsed = JSON.parse(payload);
        } catch {
          continue;
        }
        if (parsed.usage) {
          usage = {
            promptTokens: parsed.usage.prompt_tokens,
            completionTokens: parsed.usage.completion_tokens
          };
        }
        const choice = parsed.choices?.[0];
        if (!choice) continue;
        const delta = choice.delta ?? {};
        if (typeof delta.content === "string" && delta.content.length > 0) {
          yield { delta: delta.content };
        }
        if (Array.isArray(delta.tool_calls)) {
          for (const frag of delta.tool_calls) {
            const idx = frag.index ?? 0;
            let entry = inflight.get(idx);
            if (!entry) {
              entry = { id: frag.id ?? `call_${idx}_${Date.now()}`, name: frag.function?.name ?? "", argsBuf: "" };
              inflight.set(idx, entry);
            } else {
              if (frag.id) entry.id = frag.id;
              if (frag.function?.name) entry.name = frag.function.name;
            }
            if (frag.function?.arguments) entry.argsBuf += frag.function.arguments;
            if (entry.name && !yielded.has(idx)) {
              const parsedArgs = safeParseJson(entry.argsBuf);
              if (parsedArgs !== null) {
                yielded.add(idx);
                yield { toolCall: { id: entry.id, name: entry.name, arguments: parsedArgs } };
              }
            }
          }
        }
        if (choice.finish_reason) {
          finishReason = choice.finish_reason;
          for (const [idx, entry] of inflight) {
            if (yielded.has(idx) || !entry.name) continue;
            yielded.add(idx);
            yield { toolCall: { id: entry.id, name: entry.name, arguments: safeParseJson(entry.argsBuf) ?? {} } };
          }
        }
      }
    }
  }
  if (finishReason || usage) {
    yield { finishReason, usage };
  }
}
function toOpenAIMessage(m) {
  const out = { role: m.role };
  if (typeof m.content === "string") {
    out.content = m.content;
  } else {
    out.content = m.content.map(
      (part) => part.type === "image" ? { type: "image_url", image_url: { url: part.image } } : { type: "text", text: part.text }
    );
  }
  if (m.toolCallId) out.tool_call_id = m.toolCallId;
  if (m.toolCalls) {
    out.tool_calls = m.toolCalls.map((tc) => ({
      id: tc.id,
      type: "function",
      function: { name: tc.name, arguments: JSON.stringify(tc.arguments) }
    }));
  }
  if (m.name) out.name = m.name;
  return out;
}
function isReasoningModel(model) {
  return /^(o[1-9](?!.*-mini|.*-nano)|gpt-[5-9](?!.*-mini|.*-nano)|gpt-1\d(?!.*-mini|.*-nano))/i.test(
    model
  );
}
function usesMaxCompletionTokens(model) {
  return /^(o[1-9]|gpt-[5-9]|gpt-1\d)/i.test(model);
}
function safeParseJson(s) {
  try {
    return JSON.parse(s);
  } catch {
    return null;
  }
}

// src/agent/llm/google/transform.ts
function toGeminiMessages(messages) {
  const contents = [];
  let systemText = "";
  for (const m of messages) {
    if (m.role === "system") {
      systemText += (typeof m.content === "string" ? m.content : "") + "\n";
      continue;
    }
    const role = m.role === "assistant" ? "model" : "user";
    if (m.toolCalls && m.toolCalls.length > 0) {
      const parts2 = [];
      if (typeof m.content === "string" && m.content.length > 0) {
        parts2.push({ text: m.content });
      }
      for (const tc of m.toolCalls) {
        parts2.push({ functionCall: { name: tc.name, args: tc.arguments } });
      }
      contents.push({ role: "model", parts: parts2 });
      continue;
    }
    if (m.role === "tool") {
      contents.push({
        role: "user",
        parts: [
          {
            functionResponse: {
              name: m.toolCallId ?? m.name ?? "unknown",
              response: { content: typeof m.content === "string" ? m.content : "" }
            }
          }
        ]
      });
      continue;
    }
    const parts = typeof m.content === "string" ? [{ text: m.content }] : m.content.map(
      (p) => p.type === "text" ? { text: p.text } : { inlineData: { mimeType: "image/png", data: stripDataPrefix(p.image) } }
    );
    contents.push({ role, parts });
  }
  return {
    contents,
    systemInstruction: systemText.trim() ? { parts: [{ text: systemText.trim() }] } : void 0
  };
}
function stripDataPrefix(s) {
  const idx = s.indexOf("base64,");
  return idx >= 0 ? s.slice(idx + 7) : s;
}
function mapFinishReason(r) {
  switch (r) {
    case "STOP":
      return "stop";
    case "MAX_TOKENS":
      return "length";
    case "SAFETY":
      return "content_filter";
    default:
      return "stop";
  }
}

// src/agent/llm/google/stream.ts
var THINKING_BUDGET = {
  off: 0,
  minimal: 64,
  low: 512,
  medium: 1024,
  high: 4096
};
var GEMMA_THINKING_LEVEL = {
  off: "minimal",
  minimal: "minimal",
  low: "low",
  medium: "medium",
  high: "high"
};
function buildThinkingConfig(model, thinking) {
  if (!thinking) return null;
  const m = model.toLowerCase();
  if (m.startsWith("gemma-") || /^gemini-3(\.|-|$)/.test(m)) {
    return { thinkingLevel: GEMMA_THINKING_LEVEL[thinking] };
  }
  return { thinkingBudget: THINKING_BUDGET[thinking] };
}
async function* streamGemini(args) {
  const url = `${args.baseURL}/models/${args.model}:streamGenerateContent?alt=sse`;
  const { contents, systemInstruction } = toGeminiMessages(args.opts.messages);
  const generationConfig = {
    temperature: args.opts.temperature ?? 0.7,
    maxOutputTokens: args.opts.maxTokens
  };
  const thinkingPayload = buildThinkingConfig(args.model, args.opts.thinking);
  if (thinkingPayload) generationConfig.thinkingConfig = thinkingPayload;
  if (args.opts.jsonMode) {
    generationConfig.responseMimeType = "application/json";
  }
  const body = {
    contents,
    generationConfig
  };
  if (systemInstruction) body.systemInstruction = systemInstruction;
  if (args.opts.tools && args.opts.tools.length > 0) {
    body.tools = [
      {
        functionDeclarations: args.opts.tools.map((t) => ({
          name: t.name,
          description: t.description,
          parameters: t.parameters
        }))
      }
    ];
    const choice = args.opts.toolChoice;
    if (choice === "required") {
      body.tool_config = { function_calling_config: { mode: "ANY" } };
    } else if (typeof choice === "object" && typeof choice.name === "string") {
      body.tool_config = {
        function_calling_config: { mode: "ANY", allowed_function_names: [choice.name] }
      };
    }
  }
  const response = await fetch(url, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "x-goog-api-key": args.apiKey
    },
    body: JSON.stringify(body),
    signal: args.opts.signal
  });
  if (!response.ok || !response.body) {
    const txt = await response.text().catch(() => response.statusText);
    throw new Error(
      `Gemini stream HTTP ${response.status}: ${redactSecrets(txt, [args.apiKey])}`
    );
  }
  const reader = response.body.getReader();
  const decoder = new TextDecoder();
  let buf = "";
  while (true) {
    let done = false;
    let value;
    try {
      const r = await reader.read();
      done = r.done;
      value = r.value;
    } catch (err) {
      if (err.name === "AbortError") return;
      throw err;
    }
    if (done) break;
    buf += decoder.decode(value, { stream: true });
    const lines = buf.split("\n");
    buf = lines.pop() ?? "";
    for (const rawLine of lines) {
      const line = rawLine.trim();
      if (!line || !line.startsWith("data:")) continue;
      const data = line.slice(5).trim();
      if (!data) continue;
      let parsed;
      try {
        parsed = JSON.parse(data);
      } catch {
        continue;
      }
      const cand = parsed.candidates?.[0];
      if (!cand) continue;
      for (const part of cand.content?.parts ?? []) {
        if (part.thought === true) continue;
        if (part.text) {
          yield { delta: part.text };
        }
        if (part.functionCall) {
          yield {
            toolCall: {
              id: `gem_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`,
              name: part.functionCall.name,
              arguments: part.functionCall.args ?? {}
            }
          };
        }
      }
      if (cand.finishReason) {
        yield {
          finishReason: mapFinishReason(cand.finishReason),
          usage: parsed.usageMetadata ? {
            promptTokens: parsed.usageMetadata.promptTokenCount,
            completionTokens: parsed.usageMetadata.candidatesTokenCount
          } : void 0
        };
      }
    }
  }
}

// src/agent/llm/google/provider.ts
var GoogleProvider = class {
  name = "google";
  apiKey;
  model;
  baseURL;
  constructor(config) {
    this.apiKey = config.apiKey;
    this.model = config.model ?? "gemini-3.1-pro-preview";
    this.baseURL = config.baseURL ?? "https://generativelanguage.googleapis.com/v1beta";
  }
  async complete(opts) {
    const model = opts.model ?? this.model;
    const url = `${this.baseURL}/models/${model}:generateContent`;
    const { contents, systemInstruction } = toGeminiMessages(opts.messages);
    const generationConfig = {
      temperature: opts.temperature ?? 0.7,
      maxOutputTokens: opts.maxTokens
    };
    const thinkingPayload = buildThinkingConfig(model, opts.thinking);
    if (thinkingPayload) generationConfig.thinkingConfig = thinkingPayload;
    if (opts.jsonMode) {
      generationConfig.responseMimeType = "application/json";
    }
    const body = {
      contents,
      generationConfig
    };
    if (systemInstruction) body.systemInstruction = systemInstruction;
    if (opts.tools && opts.tools.length > 0) {
      body.tools = [
        {
          functionDeclarations: opts.tools.map((t) => ({
            name: t.name,
            description: t.description,
            parameters: t.parameters
          }))
        }
      ];
      const choice = opts.toolChoice;
      if (choice === "required") {
        body.tool_config = { function_calling_config: { mode: "ANY" } };
      } else if (typeof choice === "object" && typeof choice.name === "string") {
        body.tool_config = {
          function_calling_config: { mode: "ANY", allowed_function_names: [choice.name] }
        };
      }
    }
    const fetchOnce = () => fetch(url, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "x-goog-api-key": this.apiKey
      },
      body: JSON.stringify(body),
      signal: opts.signal
    });
    const backoffs = [700, 1500, 2800];
    let response = await fetchOnce();
    for (const base of backoffs) {
      if (response.ok) break;
      if (response.status < 500 || response.status >= 600) break;
      try {
        await response.text();
      } catch {
      }
      const jitter = Math.random() * 250;
      await new Promise((r) => setTimeout(r, base + jitter));
      response = await fetchOnce();
    }
    if (!response.ok) {
      const errText = await response.text().catch(() => response.statusText);
      throw new Error(
        `Gemini HTTP ${response.status}: ${redactSecrets(errText, [this.apiKey])}`
      );
    }
    const data = await response.json();
    const candidate = data.candidates?.[0];
    if (!candidate) throw new Error("Gemini: no candidates returned");
    let content = "";
    const toolCalls = [];
    for (const part of candidate.content?.parts ?? []) {
      if (part.thought === true) continue;
      if (part.text) content += part.text;
      if (part.functionCall) {
        toolCalls.push({
          id: `call_${toolCalls.length}_${Date.now()}`,
          name: part.functionCall.name,
          arguments: part.functionCall.args ?? {}
        });
      }
    }
    return {
      content,
      toolCalls: toolCalls.length > 0 ? toolCalls : void 0,
      usage: data.usageMetadata ? {
        promptTokens: data.usageMetadata.promptTokenCount,
        completionTokens: data.usageMetadata.candidatesTokenCount
      } : void 0,
      finishReason: mapFinishReason(candidate.finishReason)
    };
  }
  /**
   * Streaming via Gemini's :streamGenerateContent endpoint (alt=sse).
   */
  streamComplete(opts) {
    const apiKey = this.apiKey;
    const model = opts.model ?? this.model;
    const baseURL = this.baseURL;
    return buildStream({
      produce: () => streamGemini({ apiKey, model, baseURL, opts })
    });
  }
};

// src/agent/llm/proxy.ts
var DEFAULT_PROXY_TIMEOUT_MS = 3e4;
var ProxyProvider = class {
  name;
  config;
  constructor(config) {
    this.config = config;
    this.name = config.name ?? "proxy";
  }
  async complete(opts) {
    const body = this.config.buildBody ? this.config.buildBody(opts) : defaultBody(opts);
    const timeoutMs = this.config.timeoutMs ?? DEFAULT_PROXY_TIMEOUT_MS;
    const timeoutCtrl = new AbortController();
    let timeoutHandle = null;
    if (timeoutMs > 0) {
      timeoutHandle = setTimeout(() => timeoutCtrl.abort(new Error("proxy timeout")), timeoutMs);
    }
    const onCallerAbort = () => timeoutCtrl.abort(opts.signal.reason);
    if (opts.signal) {
      if (opts.signal.aborted) timeoutCtrl.abort(opts.signal.reason);
      else opts.signal.addEventListener("abort", onCallerAbort, { once: true });
    }
    try {
      const response = await fetch(this.config.endpoint, {
        method: this.config.method ?? "POST",
        headers: {
          "Content-Type": "application/json",
          ...this.config.headers ?? {}
        },
        credentials: this.config.credentials,
        body: JSON.stringify(body),
        signal: timeoutCtrl.signal
      });
      if (!response.ok) {
        const text = await response.text().catch(() => response.statusText);
        throw new Error(`Proxy HTTP ${response.status}: ${text}`);
      }
      const raw = await response.json();
      return this.config.parseResult ? this.config.parseResult(raw) : defaultParse(raw);
    } finally {
      if (timeoutHandle !== null) clearTimeout(timeoutHandle);
      if (opts.signal) opts.signal.removeEventListener("abort", onCallerAbort);
    }
  }
  /**
   * Streaming via the same endpoint. Default body shape (OpenAI-compatible)
   * is `{ messages, tools, ..., stream: true }`; the proxy is expected to
   * forward the SSE body verbatim. Hosts using a non-OpenAI wire shape
   * should override `buildBody` to inject their own streaming flag and
   * implement an OpenAI-style SSE on the backend (or use a separate
   * provider class).
   */
  streamComplete(opts) {
    const body = this.config.buildBody ? this.config.buildBody({ ...opts }) : { ...defaultBody(opts), stream: true };
    const endpoint = this.config.endpoint;
    const headers = {
      "Content-Type": "application/json",
      ...this.config.headers ?? {}
    };
    const method = this.config.method ?? "POST";
    const credentials = this.config.credentials;
    return buildStream({
      produce: () => streamProxy({ endpoint, method, headers, body, credentials, signal: opts.signal })
    });
  }
};
async function* streamProxy(args) {
  const response = await fetch(args.endpoint, {
    method: args.method,
    headers: args.headers,
    credentials: args.credentials,
    body: JSON.stringify(args.body),
    signal: args.signal
  });
  if (!response.ok) {
    const text = await response.text().catch(() => response.statusText);
    throw new Error(`Proxy HTTP ${response.status}: ${redactSecrets(text, [])}`);
  }
  if (!response.body) {
    throw new Error("Proxy: no response body for stream");
  }
  const inflight = /* @__PURE__ */ new Map();
  const yielded = /* @__PURE__ */ new Set();
  const reader = response.body.getReader();
  const decoder = new TextDecoder();
  let buf = "";
  let finishReason;
  while (true) {
    let value;
    let done = false;
    try {
      const r = await reader.read();
      value = r.value;
      done = r.done;
    } catch (err) {
      if (err.name === "AbortError") return;
      throw err;
    }
    if (done) break;
    buf += decoder.decode(value, { stream: true });
    let sep;
    while ((sep = buf.indexOf("\n\n")) !== -1) {
      const event = buf.slice(0, sep);
      buf = buf.slice(sep + 2);
      if (!event.trim()) continue;
      for (const line of event.split("\n")) {
        if (!line.startsWith("data:")) continue;
        const payload = line.slice(5).trim();
        if (payload === "[DONE]") continue;
        let parsed;
        try {
          parsed = JSON.parse(payload);
        } catch {
          continue;
        }
        const choice = parsed.choices?.[0];
        if (!choice) continue;
        const delta = choice.delta ?? {};
        if (typeof delta.content === "string" && delta.content.length > 0) {
          yield { delta: delta.content };
        }
        if (Array.isArray(delta.tool_calls)) {
          for (const frag of delta.tool_calls) {
            const idx = frag.index ?? 0;
            let entry = inflight.get(idx);
            if (!entry) {
              entry = { id: frag.id ?? `call_${idx}_${Date.now()}`, name: frag.function?.name ?? "", argsBuf: "" };
              inflight.set(idx, entry);
            } else {
              if (frag.id) entry.id = frag.id;
              if (frag.function?.name) entry.name = frag.function.name;
            }
            if (frag.function?.arguments) entry.argsBuf += frag.function.arguments;
            if (entry.name && !yielded.has(idx)) {
              const parsedArgs = safeParseJson2(entry.argsBuf);
              if (parsedArgs !== null) {
                yielded.add(idx);
                yield { toolCall: { id: entry.id, name: entry.name, arguments: parsedArgs } };
              }
            }
          }
        }
        if (choice.finish_reason) {
          finishReason = choice.finish_reason;
          for (const [idx, entry] of inflight) {
            if (yielded.has(idx) || !entry.name) continue;
            yielded.add(idx);
            yield { toolCall: { id: entry.id, name: entry.name, arguments: safeParseJson2(entry.argsBuf) ?? {} } };
          }
        }
      }
    }
  }
  if (finishReason) yield { finishReason };
}
function safeParseJson2(s) {
  if (!s) return {};
  try {
    return JSON.parse(s);
  } catch {
    return null;
  }
}
function defaultBody(opts) {
  return {
    messages: opts.messages,
    tools: opts.tools,
    toolChoice: opts.toolChoice,
    temperature: opts.temperature,
    maxTokens: opts.maxTokens,
    model: opts.model
  };
}
function defaultParse(raw) {
  if (raw && typeof raw === "object") {
    const r = raw;
    return {
      content: typeof r.content === "string" ? r.content : "",
      toolCalls: Array.isArray(r.toolCalls) ? r.toolCalls : void 0,
      usage: r.usage,
      finishReason: r.finishReason ?? "stop"
    };
  }
  return { content: "", finishReason: "stop" };
}

// src/agent/llm/router.ts
function isLLMRouter(v) {
  if (!v || typeof v !== "object") return false;
  if (!("webagent" in v)) return false;
  const inner = v.webagent;
  return !!inner && typeof inner.complete === "function";
}
function resolveLLM(source, role) {
  if (!isLLMRouter(source)) return source;
  switch (role) {
    case "webagent":
      return source.webagent;
    case "webagentWithSelection":
      return source.webagentWithSelection ?? source.webagent;
    case "inline":
      return source.inline ?? source.webagent;
    case "voiceCleanup":
      return source.voiceCleanup ?? source.webagent;
    case "plan":
      return source.plan ?? source.webagent;
  }
}

// src/agent/llm/adapters/registry.ts
var registry = /* @__PURE__ */ new Map();
function registerAdapter(adapter) {
  registry.set(adapter.id, adapter);
}
function getAdapter(id) {
  return registry.get(id);
}
function listAdapters() {
  return [...registry.values()];
}
function unregisterAdapter(id) {
  return registry.delete(id);
}
function createProvider(spec, extra) {
  if (typeof spec === "string") {
    const idx = spec.indexOf(":");
    if (idx < 0) throw new Error(`LLM spec must be "<adapter>:<model>", got "${spec}"`);
    const adapterId2 = spec.slice(0, idx).trim();
    const model = spec.slice(idx + 1).trim();
    return createProvider({ ...extra ?? {}, adapter: adapterId2, model });
  }
  const { adapter: adapterId, ...config } = spec;
  const adapter = registry.get(adapterId);
  if (!adapter) {
    throw new Error(
      `No LLM adapter registered for "${adapterId}". Did you call seedDefaultAdapters()?`
    );
  }
  return adapter.create(config);
}

// src/agent/llm/adapters/openai.ts
var openaiAdapter = {
  id: "openai",
  matchesModel(modelId) {
    return /^(gpt-|o[1-9]|text-)/i.test(modelId);
  },
  create(config) {
    const cfg = {
      apiKey: String(config.apiKey ?? ""),
      model: config.model,
      baseURL: config.baseURL,
      organization: config.organization,
      headers: config.headers,
      extraBody: config.extraBody
    };
    return new OpenAIProvider(cfg);
  }
};

// src/agent/llm/adapters/google.ts
var googleAdapter = {
  id: "google",
  matchesModel(modelId) {
    return /^(gemini-|gemma-)/i.test(modelId);
  },
  create(config) {
    const cfg = {
      apiKey: String(config.apiKey ?? ""),
      model: config.model,
      baseURL: config.baseURL
    };
    return new GoogleProvider(cfg);
  }
};

// src/agent/llm/adapters/proxy.ts
var proxyAdapter = {
  id: "proxy",
  create(config) {
    if (typeof config.endpoint !== "string" || !config.endpoint) {
      throw new Error("proxy adapter requires `endpoint` (string)");
    }
    const cfg = {
      endpoint: config.endpoint,
      method: config.method,
      headers: config.headers,
      credentials: config.credentials,
      buildBody: config.buildBody,
      parseResult: config.parseResult,
      name: config.name,
      timeoutMs: config.timeoutMs
    };
    return new ProxyProvider(cfg);
  }
};

// src/agent/llm/adapters/index.ts
function seedDefaultAdapters() {
  registerAdapter(openaiAdapter);
  registerAdapter(googleAdapter);
  registerAdapter(proxyAdapter);
  return [openaiAdapter.id, googleAdapter.id, proxyAdapter.id];
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  GoogleProvider,
  OpenAIProvider,
  ProxyProvider,
  buildStream,
  createProvider,
  getAdapter,
  googleAdapter,
  isLLMRouter,
  listAdapters,
  openaiAdapter,
  proxyAdapter,
  registerAdapter,
  resolveLLM,
  seedDefaultAdapters,
  unregisterAdapter
});
