import {
  buildAppToolOpenAITools,
  createAppToolRuntimeExecutor,
  isAppToolName
} from "./chunk-MFRCM32T.js";

// src/runtime/model-catalog.ts
var PROVIDER_TIER = [
  "anthropic",
  "openai",
  "google",
  "xai",
  "deepseek",
  "moonshotai",
  "moonshot",
  "zai",
  "z-ai",
  "mistral",
  "groq",
  "nvidia",
  "cohere",
  "cerebras"
];
var EXCLUDED_ID = /(embedding|tts|transcribe|whisper|audio|realtime|image|lyria|sora|dall-e|moderation|content-safety|search-preview|search-api|deep-research)/;
var FEATURED_RULES = [
  { providers: ["anthropic"], match: /^claude-sonnet-[\d-]+$/ },
  { providers: ["anthropic"], match: /^claude-opus-[\d-]+$/ },
  { providers: ["anthropic"], match: /^claude-haiku-[\d-]+$/ },
  { providers: ["openai"], match: /^gpt-\d+(\.\d+)?$/ },
  { providers: ["openai"], match: /^gpt-\d+(\.\d+)?-mini$/ },
  { providers: ["google"], match: /^gemini-[\d.]+-pro(-preview)?$/ },
  { providers: ["google"], match: /^gemini-[\d.]+-flash(-preview)?$/ },
  { providers: ["xai"], match: /^grok-[\d.]+$/ },
  { providers: ["deepseek"], match: /^deepseek-(chat|v[\d.]+(-\w+)?)$/ },
  { providers: ["moonshotai", "moonshot"], match: /^kimi-k[\d.]+$/ },
  { providers: ["zai", "z-ai"], match: /^glm-[\d.]+$/ },
  { providers: ["mistral"], match: /^mistral-(large|medium)-?[\d.-]*$/ }
];
var TOOL_CAPABLE_FAMILY = /^(claude|gpt-[45]|gpt-oss|o[134]|gemini|grok|deepseek|glm|kimi|mistral|ministral|magistral|command|nemotron|llama)/;
function normalizeModelId(id) {
  let tail = id.split("/").pop() ?? id;
  tail = tail.replace(/:free$/, "");
  tail = tail.replace(/-\d{8}$/, "");
  tail = tail.replace(/-\d{4}-\d{2}-\d{2}$/, "");
  return tail;
}
function versionOf(normId) {
  return (normId.match(/\d+/g) ?? []).map(Number);
}
function compareVersions(a, b) {
  const len = Math.max(a.length, b.length);
  for (let i = 0; i < len; i++) {
    const d = (a[i] ?? -1) - (b[i] ?? -1);
    if (d !== 0) return d;
  }
  return 0;
}
function aliasPenalty(id) {
  let p = 0;
  if (id.includes("/")) p += 4;
  if (/-\d{8}$|-\d{4}-\d{2}-\d{2}$/.test(id.replace(/:free$/, ""))) p += 2;
  if (id.endsWith(":free")) p += 1;
  return p;
}
function providerRank(provider) {
  const i = PROVIDER_TIER.indexOf(provider);
  return i === -1 ? PROVIDER_TIER.length : i;
}
function isChatModel(m) {
  const arch = m.architecture;
  if (!arch?.input_modalities || !arch?.output_modalities) return true;
  return arch.input_modalities.includes("text") && arch.output_modalities.includes("text");
}
function isRouteable(m) {
  return m.routeability?.routeable !== false && m.routeability?.status !== "unavailable";
}
function familyOf(normId) {
  return normId.replace(/[\d.]+/g, "").replace(/-+/g, "-").replace(/-$/, "");
}
function buildCatalog(raw, opts) {
  const candidates = raw.filter(
    (m) => m.id && isRouteable(m) && isChatModel(m) && !EXCLUDED_ID.test(normalizeModelId(m.id))
  );
  const groups = /* @__PURE__ */ new Map();
  for (const m of candidates) {
    const key = `${m._provider ?? ""}::${normalizeModelId(m.id)}`;
    const g = groups.get(key);
    if (g) g.push(m);
    else groups.set(key, [m]);
  }
  const reps = [];
  for (const group of groups.values()) {
    group.sort((a, b) => aliasPenalty(a.id) - aliasPenalty(b.id) || a.id.length - b.id.length);
    const rep = group[0];
    const mergedParams = new Set(group.flatMap((m) => m.supported_parameters ?? []));
    reps.push({ model: rep, normId: normalizeModelId(rep.id), mergedParams });
  }
  const featuredIds = [];
  for (const rule of FEATURED_RULES) {
    const matches = reps.filter(
      (r) => rule.providers.includes(r.model._provider ?? "") && rule.match.test(r.normId) && !featuredIds.includes(r.model.id)
    );
    if (!matches.length) continue;
    matches.sort(
      (a, b) => compareVersions(versionOf(b.normId), versionOf(a.normId)) || Number(a.normId.includes("preview")) - Number(b.normId.includes("preview")) || a.model.id.length - b.model.id.length
    );
    featuredIds.push(matches[0].model.id);
  }
  const toCatalogModel = (r) => {
    const m = r.model;
    const provider = m._provider ?? "unknown";
    return {
      id: m.id,
      name: m.name ?? m.id,
      provider,
      description: m.description ? m.description.slice(0, 160) : void 0,
      contextLength: m.context_length,
      pricing: m.pricing?.prompt || m.pricing?.completion ? { prompt: m.pricing.prompt ?? void 0, completion: m.pricing.completion ?? void 0 } : void 0,
      supportsTools: r.mergedParams.has("tools") || TOOL_CAPABLE_FAMILY.test(r.normId),
      supportsReasoning: r.mergedParams.has("reasoning") || r.mergedParams.has("include_reasoning"),
      featured: featuredIds.includes(m.id)
    };
  };
  const featured = featuredIds.map((id) => reps.find((r) => r.model.id === id)).map(toCatalogModel);
  const rest = reps.filter((r) => !featuredIds.includes(r.model.id)).sort((a, b) => {
    const pa = providerRank(a.model._provider ?? "");
    const pb = providerRank(b.model._provider ?? "");
    if (pa !== pb) return pa - pb;
    const fa = familyOf(a.normId);
    const fb = familyOf(b.normId);
    if (fa !== fb) return fa.localeCompare(fb);
    return compareVersions(versionOf(b.normId), versionOf(a.normId)) || a.model.id.localeCompare(b.model.id);
  }).map(toCatalogModel);
  const models = [...featured, ...rest];
  const preferred = opts?.preferredDefault;
  const defaultModelId = preferred && models.find((m) => m.id === preferred || normalizeModelId(m.id) === normalizeModelId(preferred))?.id || featured.find((m) => m.supportsTools)?.id || models[0]?.id || null;
  return { defaultModelId, fetchedAt: (/* @__PURE__ */ new Date()).toISOString(), models };
}
var CATALOG_TTL_MS = 5 * 60 * 1e3;
var _cache = null;
async function fetchModelCatalog(cfg) {
  if (_cache && Date.now() - _cache.at < CATALOG_TTL_MS) {
    return _cache.catalog;
  }
  try {
    const res = await fetch(`${cfg.baseUrl}/models`, {
      headers: { Authorization: `Bearer ${cfg.apiKey}` }
    });
    if (!res.ok) throw new Error(`Router /models returned ${res.status}`);
    const data = await res.json();
    const catalog = buildCatalog(data.data ?? [], { preferredDefault: cfg.preferredDefault });
    _cache = { catalog, at: Date.now() };
    return catalog;
  } catch (err) {
    if (_cache) return _cache.catalog;
    throw err;
  }
}
function __resetCatalogCache() {
  _cache = null;
}

// src/runtime/openai-stream.ts
async function* toLoopEvents(chunks) {
  const calls = /* @__PURE__ */ new Map();
  for await (const chunk of chunks) {
    if (chunk.usage?.prompt_tokens != null || chunk.usage?.completion_tokens != null) {
      yield {
        type: "usage",
        usage: {
          promptTokens: chunk.usage.prompt_tokens ?? 0,
          completionTokens: chunk.usage.completion_tokens ?? 0
        }
      };
    }
    const choice = chunk.choices?.[0];
    if (!choice) continue;
    const content = choice.delta?.content;
    if (content) yield { type: "text", text: content };
    const reasoning = choice.delta?.reasoning_content ?? choice.delta?.thinking;
    if (reasoning) yield { type: "reasoning", text: reasoning };
    for (const tc of choice.delta?.tool_calls ?? []) {
      const cur = calls.get(tc.index) ?? { name: "", args: "" };
      if (tc.id) cur.id = tc.id;
      if (tc.function?.name) cur.name += tc.function.name;
      if (tc.function?.arguments) cur.args += tc.function.arguments;
      calls.set(tc.index, cur);
    }
  }
  for (const [, c] of [...calls.entries()].sort((a, b) => a[0] - b[0])) {
    if (!c.name) continue;
    yield { type: "tool_call", call: { toolCallId: c.id, toolName: c.name, args: safeParse(c.args) } };
  }
}
function safeParse(s) {
  if (!s.trim()) return {};
  try {
    const v = JSON.parse(s);
    return v && typeof v === "object" && !Array.isArray(v) ? v : {};
  } catch {
    return {};
  }
}
function createOpenAICompatStreamTurn(opts) {
  const base = opts.baseUrl.replace(/\/+$/, "");
  const doFetch = opts.fetchImpl ?? fetch;
  return (messages) => toLoopEvents(
    streamChatCompletions(doFetch, `${base}/chat/completions`, opts.apiKey, {
      model: opts.model,
      messages,
      stream: true,
      stream_options: { include_usage: true },
      ...opts.tools && opts.tools.length > 0 ? { tools: opts.tools } : {},
      ...opts.temperature != null ? { temperature: opts.temperature } : {},
      ...opts.extraBody
    })
  );
}
async function* streamChatCompletions(doFetch, url, apiKey, body) {
  const res = await doFetch(url, {
    method: "POST",
    headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json", Accept: "text/event-stream" },
    body: JSON.stringify(body)
  });
  if (!res.ok || !res.body) {
    const text = res.body ? await res.text().catch(() => "") : "";
    throw new Error(`OpenAI-compat stream failed (HTTP ${res.status})${text ? `: ${text.slice(0, 200)}` : ""}`);
  }
  const reader = res.body.getReader();
  const decoder = new TextDecoder();
  let buffer = "";
  for (; ; ) {
    const { done, value } = await reader.read();
    if (done) break;
    buffer += decoder.decode(value, { stream: true });
    const lines = buffer.split("\n");
    buffer = lines.pop() ?? "";
    for (const line of lines) {
      const trimmed = line.trim();
      if (!trimmed.startsWith("data:")) continue;
      const data = trimmed.slice(5).trim();
      if (data === "[DONE]") return;
      try {
        yield JSON.parse(data);
      } catch {
      }
    }
  }
}

// src/runtime/loop.ts
import {
  runToolLoop,
  streamToolLoop
} from "@tangle-network/agent-runtime";

// src/runtime/agent.ts
function createAgentRuntime(opts) {
  if (opts.executeOtherTool && !opts.isOtherExecutableTool) {
    throw new Error("createAgentRuntime: isOtherExecutableTool is required when executeOtherTool is set");
  }
  const m = opts.model;
  const buildStreamTurn = (extraTools) => createOpenAICompatStreamTurn({
    baseUrl: m.baseUrl,
    apiKey: m.apiKey,
    model: m.model,
    tools: [...buildAppToolOpenAITools(opts.taxonomy), ...extraTools],
    temperature: m.temperature,
    fetchImpl: m.fetchImpl,
    extraBody: m.extraBody
  });
  const baseExtraTools = opts.extraTools ?? [];
  let activeExtraTools = baseExtraTools;
  let activeStreamTurn = buildStreamTurn(baseExtraTools);
  const streamTurnFor = (extraTools) => {
    if (extraTools !== activeExtraTools) {
      activeExtraTools = extraTools;
      activeStreamTurn = buildStreamTurn(extraTools);
    }
    return activeStreamTurn;
  };
  const resolveProfile = async (turn) => {
    const base = {
      systemPrompt: turn.systemPrompt ?? opts.systemPrompt,
      extraTools: baseExtraTools
    };
    return opts.composeProfile ? opts.composeProfile(base) : base;
  };
  const isExecutableTool = (name) => isAppToolName(name) || (opts.isOtherExecutableTool?.(name) ?? false);
  const buildExecutor = (turn) => {
    const appExecutor = createAppToolRuntimeExecutor({
      handlers: opts.handlers,
      taxonomy: opts.taxonomy,
      ctx: turn.ctx,
      onProduced: turn.onProduced
    });
    return async (call) => {
      if (isAppToolName(call.toolName)) return appExecutor({ toolName: call.toolName, args: call.args });
      if (opts.executeOtherTool && opts.isOtherExecutableTool?.(call.toolName)) {
        return opts.executeOtherTool(call, turn.ctx);
      }
      return { ok: false, code: "unknown_tool", message: `No executor for tool: ${call.toolName}` };
    };
  };
  return {
    async run(userMessage, turn) {
      const profile = await resolveProfile(turn);
      return runToolLoop({
        systemPrompt: profile.systemPrompt,
        userMessage,
        priorMessages: turn.priorMessages,
        // The awaitable loop consumes only text + tool_call; the app's UI-only
        // reasoning/usage events ride the substrate's `other` channel.
        streamTurn: narrowToToolLoopEvents(streamTurnFor(profile.extraTools)),
        executeToolCall: buildExecutor(turn),
        isExecutableTool,
        maxToolTurns: opts.maxToolTurns
      });
    },
    async *stream(userMessage, turn) {
      const profile = await resolveProfile(turn);
      yield* streamToolLoop({
        systemPrompt: profile.systemPrompt,
        userMessage,
        priorMessages: turn.priorMessages,
        streamTurn: streamTurnFor(profile.extraTools),
        extractText: (ev) => ev.type === "text" ? ev.text : "",
        extractToolCall: (ev) => ev.type === "tool_call" ? ev.call : null,
        isExecutableTool,
        executeToolCall: buildExecutor(turn),
        maxToolTurns: opts.maxToolTurns
      });
    }
  };
}
function narrowToToolLoopEvents(streamTurn) {
  return (messages) => (async function* () {
    for await (const ev of streamTurn(messages)) {
      if (ev.type === "text") yield { type: "text", text: ev.text };
      else if (ev.type === "tool_call") yield { type: "tool_call", call: ev.call };
      else yield { type: "other", event: ev };
    }
  })();
}

// src/runtime/certified-delivery.ts
import {
  composeCertifiedPrompt,
  pullCertified
} from "@tangle-network/agent-runtime/intelligence";
var defaultRefreshMs = 3e5;
function createCertifiedDelivery(config) {
  const refreshMs = config.refreshMs ?? defaultRefreshMs;
  let certified = null;
  let lastPullAt = 0;
  let inflight = null;
  async function refresh(force = false) {
    if (!force && Date.now() - lastPullAt < refreshMs) return;
    if (inflight) return inflight;
    inflight = (async () => {
      const outcome = await pullCertified({
        target: config.target,
        apiKey: config.apiKey,
        baseUrl: config.baseUrl,
        fetchImpl: config.fetchImpl
      });
      lastPullAt = Date.now();
      if (outcome.succeeded) certified = outcome.value;
    })();
    try {
      await inflight;
    } finally {
      inflight = null;
    }
  }
  return {
    async composeProfile(base) {
      await refresh();
      return {
        // prompt-surface + skill fold into the system prompt.
        systemPrompt: composeCertifiedPrompt(base.systemPrompt, certified),
        // Certified `tool` artifacts deliver here once they carry a runnable
        // OpenAI def + the product wires the executor; until then pass through.
        extraTools: base.extraTools
      };
    },
    refresh: () => refresh(true),
    current: () => certified
  };
}

// src/runtime/surface-profile.ts
function defineSurfaceKind(opts) {
  if (typeof opts.kind !== "string" || opts.kind.length === 0 || /\s/.test(opts.kind)) {
    throw new Error(`surface kind must be a non-empty string without whitespace (got ${JSON.stringify(opts.kind)})`);
  }
  if (typeof opts.build !== "function") {
    throw new Error(`surface kind '${opts.kind}' requires a build function`);
  }
  return { kind: opts.kind, build: opts.build };
}
function createSurfaceRegistry(kinds) {
  const byKind = /* @__PURE__ */ new Map();
  for (const definition of kinds) {
    if (byKind.has(definition.kind)) {
      throw new Error(`duplicate surface kind '${definition.kind}' \u2014 each kind must be registered exactly once`);
    }
    byKind.set(definition.kind, definition);
  }
  return {
    async resolve(kind, ctx) {
      const definition = byKind.get(kind);
      if (!definition) {
        const known = [...byKind.keys()].join(", ") || "(none)";
        throw new Error(
          `unknown surface kind '${kind}' \u2014 registered kinds: ${known}. An unknown surface is a routing bug: register the kind via defineSurfaceKind before clients can reference it.`
        );
      }
      const overlay = await definition.build(ctx);
      assertSurfaceOverlay(overlay, `surface kind '${kind}'`);
      return overlay;
    }
  };
}
var PERMISSION_SEVERITY = { allow: 0, ask: 1, deny: 2 };
function mergeSurfaceOverlay(base, overlay) {
  assertSurfaceOverlay(overlay, "surface overlay");
  const merged = { ...base };
  if (overlay.mcp && Object.keys(overlay.mcp).length > 0) {
    const baseMcp = base.mcp ?? {};
    const collisions = Object.keys(overlay.mcp).filter((name) => name in baseMcp);
    if (collisions.length > 0) {
      throw new Error(
        `surface overlay MCP name collision: ${collisions.map((n) => `'${n}'`).join(", ")} already exist on the base profile. Two servers cannot claim one name \u2014 give the surface server a distinct name.`
      );
    }
    merged.mcp = { ...baseMcp, ...overlay.mcp };
  }
  if (overlay.promptAddendum !== void 0) {
    merged.systemPromptAddendum = base.systemPromptAddendum ? `${base.systemPromptAddendum}

${overlay.promptAddendum}` : overlay.promptAddendum;
  }
  if (overlay.permissions && Object.keys(overlay.permissions).length > 0) {
    const permissions = { ...base.permissions ?? {} };
    for (const [key, value] of Object.entries(overlay.permissions)) {
      const existing = permissions[key];
      permissions[key] = existing === void 0 || PERMISSION_SEVERITY[value] > PERMISSION_SEVERITY[existing] ? value : existing;
    }
    merged.permissions = permissions;
  }
  return merged;
}
function assertSurfaceOverlay(overlay, label) {
  if (overlay.promptAddendum !== void 0) {
    if (typeof overlay.promptAddendum !== "string" || overlay.promptAddendum.trim().length === 0) {
      throw new Error(`${label}: promptAddendum must be a non-blank string when provided`);
    }
  }
  if (overlay.mcp !== void 0) {
    for (const [name, server] of Object.entries(overlay.mcp)) {
      if (name.trim().length === 0) throw new Error(`${label}: MCP server names must be non-empty`);
      if (server.transport !== "http") {
        throw new Error(`${label}: MCP server '${name}' must use transport 'http' (got ${JSON.stringify(server.transport)})`);
      }
      let parsed;
      try {
        parsed = new URL(server.url);
      } catch {
        throw new Error(`${label}: MCP server '${name}' url must be an absolute URL (got ${JSON.stringify(server.url)})`);
      }
      if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
        throw new Error(`${label}: MCP server '${name}' url must be http(s) (got ${JSON.stringify(server.url)})`);
      }
    }
  }
  if (overlay.permissions !== void 0) {
    for (const [key, value] of Object.entries(overlay.permissions)) {
      if (!(value in PERMISSION_SEVERITY)) {
        throw new Error(`${label}: permission '${key}' must be 'allow' | 'ask' | 'deny' (got ${JSON.stringify(value)})`);
      }
    }
  }
}

export {
  normalizeModelId,
  buildCatalog,
  fetchModelCatalog,
  __resetCatalogCache,
  toLoopEvents,
  createOpenAICompatStreamTurn,
  runToolLoop,
  streamToolLoop,
  createAgentRuntime,
  createCertifiedDelivery,
  defineSurfaceKind,
  createSurfaceRegistry,
  mergeSurfaceOverlay
};
//# sourceMappingURL=chunk-2A7STBX7.js.map