import { computed } from "vue";
import { JSONSchema, Schema } from "effect";
const ENDPOINT = "http://192.168.168.10/anthropic/v1/messages";
const MODEL = "MiniMax-M2.7";
const ANTHROPIC_VERSION = "2023-06-01";
const DEFAULT_MAX_TOKENS = 8192;
export class StructuredOutputDecodeError extends Error {
  rawOutput;
  constructor(rawOutput, cause) {
    super(cause instanceof Error ? cause.message : String(cause));
    this.name = "StructuredOutputDecodeError";
    this.rawOutput = rawOutput;
    if (cause !== void 0) this.cause = cause;
  }
}
async function readError(res) {
  try {
    const body = await res.json();
    if (typeof body.error === "string") return body.error;
    return body.error?.message ?? "";
  } catch {
    return await res.text().catch(() => "");
  }
}
async function* readSSE(res) {
  if (!res.body) return;
  const reader = res.body.getReader();
  const decoder = new TextDecoder();
  let buf = "";
  for (; ; ) {
    const { value, done } = await reader.read();
    if (done) break;
    buf += decoder.decode(value, { stream: true });
    buf = buf.replace(/\r\n/g, "\n");
    let idx;
    while ((idx = buf.indexOf("\n\n")) !== -1) {
      const block = buf.slice(0, idx);
      buf = buf.slice(idx + 2);
      let event;
      const dataLines = [];
      for (const line of block.split("\n")) {
        if (line.startsWith("event:")) event = line.slice(6).trim();
        else if (line.startsWith("data:")) dataLines.push(line.slice(5).replace(/^ /, ""));
      }
      if (dataLines.length === 0) continue;
      yield { event, data: dataLines.join("\n") };
    }
  }
}
function buildBody(messages, system, options) {
  return {
    model: MODEL,
    messages,
    max_tokens: options.maxTokens ?? DEFAULT_MAX_TOKENS,
    ...system !== void 0 ? { system } : {},
    ...options.tools !== void 0 ? { tools: options.tools } : {},
    ...options.toolChoice !== void 0 ? { tool_choice: options.toolChoice } : {}
  };
}
function buildInit(body, signal) {
  return {
    method: "POST",
    headers: {
      "content-type": "application/json",
      "anthropic-version": ANTHROPIC_VERSION,
      "anthropic-dangerous-direct-browser-access": "true"
    },
    body: JSON.stringify(body),
    ...signal ? { signal } : {}
  };
}
async function call(messages, system, options, signal) {
  const res = await fetch(ENDPOINT, buildInit(buildBody(messages, system, options), signal));
  if (!res.ok) {
    throw new Error(`Anthropic ${res.status}: ${await readError(res) || res.statusText}`);
  }
  return await res.json();
}
async function callStream(messages, system, options, signal, onProgress) {
  const body = { ...buildBody(messages, system, options), stream: true };
  const res = await fetch(ENDPOINT, buildInit(body, signal));
  if (!res.ok) {
    throw new Error(`Anthropic ${res.status}: ${await readError(res) || res.statusText}`);
  }
  const blocks = /* @__PURE__ */ new Map();
  let stopReason;
  for await (const ev of readSSE(res)) {
    if (!ev.event || !ev.data) continue;
    let payload;
    try {
      payload = JSON.parse(ev.data);
    } catch {
      continue;
    }
    const p = payload;
    if (p.type === "content_block_start" && typeof p.index === "number" && p.content_block) {
      const cb = p.content_block;
      blocks.set(p.index, {
        type: cb.type === "tool_use" ? "tool_use" : "text",
        text: "",
        toolId: cb.id,
        toolName: cb.name,
        inputJson: ""
      });
    } else if (p.type === "content_block_delta" && typeof p.index === "number" && p.delta) {
      const cur = blocks.get(p.index);
      if (!cur) continue;
      if (p.delta.type === "text_delta" && p.delta.text) {
        cur.text += p.delta.text;
        onProgress();
      } else if (p.delta.type === "input_json_delta" && p.delta.partial_json) {
        cur.inputJson += p.delta.partial_json;
        onProgress();
      }
    } else if (p.type === "message_delta" && p.delta?.stop_reason) {
      stopReason = p.delta.stop_reason;
    } else if (p.type === "message_stop") {
      break;
    }
  }
  const content = [...blocks.entries()].sort(([a], [b]) => a - b).map(([, v]) => {
    if (v.type === "tool_use") {
      let input = {};
      if (v.inputJson) {
        try {
          input = JSON.parse(v.inputJson);
        } catch {
          input = {};
        }
      }
      return {
        type: "tool_use",
        id: v.toolId ?? "",
        name: v.toolName ?? "",
        input
      };
    }
    return { type: "text", text: v.text };
  });
  return { content, stop_reason: stopReason };
}
const RETRY_TOOL_USE_ID = "retry_call_0";
function buildUserMessages(prompt) {
  return [{ role: "user", content: prompt }];
}
function appendRetry(messages, retry, toolName) {
  messages.push({
    role: "assistant",
    content: [{
      type: "tool_use",
      id: RETRY_TOOL_USE_ID,
      name: toolName,
      input: retry.previousOutput
    }]
  });
  messages.push({
    role: "user",
    content: [{
      type: "tool_result",
      tool_use_id: RETRY_TOOL_USE_ID,
      content: retry.feedback
    }]
  });
}
async function generateText(input) {
  const messages = buildUserMessages(input.prompt);
  const opts = input.maxTokens !== void 0 ? { maxTokens: input.maxTokens } : {};
  const response = input.onProgress ? await callStream(messages, input.system, opts, input.signal, input.onProgress) : await call(messages, input.system, opts, input.signal);
  return response.content.filter((b) => b.type === "text").map((b) => b.text).join("");
}
async function generateObject(input) {
  const toolName = input.objectName ?? "structured_output";
  const structuredParams = JSONSchema.make(input.schema);
  const helperTools = input.tools ?? [];
  const helperByName = new Map(helperTools.map((t) => [t.name, t]));
  const tools = [
    ...helperTools.map((t) => ({
      name: t.name,
      description: t.description,
      input_schema: t.inputJsonSchema
    })),
    {
      name: toolName,
      description: "Return the structured output as the tool input.",
      input_schema: structuredParams
    }
  ];
  const toolChoice = helperTools.length > 0 ? { type: "any" } : { type: "tool", name: toolName };
  const messages = buildUserMessages(input.prompt);
  if (input.retry) appendRetry(messages, input.retry, toolName);
  const opts = {
    tools,
    toolChoice,
    ...input.maxTokens !== void 0 ? { maxTokens: input.maxTokens } : {}
  };
  const decode = (raw) => {
    try {
      return Schema.decodeUnknownSync(input.schema)(raw);
    } catch (cause) {
      throw new StructuredOutputDecodeError(raw, cause);
    }
  };
  for (; ; ) {
    const response = input.onProgress ? await callStream(messages, input.system, opts, input.signal, input.onProgress) : await call(messages, input.system, opts, input.signal);
    const toolUses = response.content.filter(
      (b) => b.type === "tool_use"
    );
    const structured = toolUses.find((c) => c.name === toolName);
    if (structured) {
      return decode(structured.input);
    }
    if (toolUses.length === 0) {
      if (response.stop_reason === "max_tokens") {
        throw new Error("\u6A21\u578B\u5728\u4EA7\u51FA\u7ED3\u6784\u5316\u7ED3\u679C\u524D\u7528\u5C3D\u4E86 token \u9884\u7B97\uFF08stop_reason=max_tokens\uFF09\u3002\u8BF7\u63D0\u9AD8 maxTokens\uFF0C\u6216\u6362\u7528\u975E\u63A8\u7406\u6A21\u578B\u3002");
      }
      const text = response.content.filter((b) => b.type === "text").map((b) => b.text).join("");
      const reason = response.stop_reason ? `\uFF08stop_reason=${response.stop_reason}\uFF09` : "";
      throw new Error(`\u6A21\u578B\u672A\u8FD4\u56DE\u7ED3\u6784\u5316\u8F93\u51FA${reason}${text ? `: ${text.slice(0, 200)}` : ""}`);
    }
    messages.push({
      role: "assistant",
      content: toolUses
    });
    const results = [];
    for (const useBlock of toolUses) {
      const tool = helperByName.get(useBlock.name);
      if (!tool) {
        results.push({
          type: "tool_result",
          tool_use_id: useBlock.id,
          content: `Unknown tool: ${useBlock.name}`
        });
        continue;
      }
      try {
        const result = await tool.execute(useBlock.input ?? {});
        results.push({
          type: "tool_result",
          tool_use_id: useBlock.id,
          content: typeof result === "string" ? result : JSON.stringify(result)
        });
      } catch (err) {
        results.push({
          type: "tool_result",
          tool_use_id: useBlock.id,
          content: err instanceof Error ? err.message : String(err)
        });
      }
    }
    messages.push({ role: "user", content: results });
  }
}
export const ai = {
  available: computed(() => true),
  generateText,
  generateObject
};
