var ke = Object.defineProperty;
var we = (t, e, o) => e in t ? ke(t, e, { enumerable: !0, configurable: !0, writable: !0, value: o }) : t[e] = o;
var L = (t, e, o) => we(t, typeof e != "symbol" ? e + "" : e, o);
import { jsonSchema as N, parsePartialJson as ue, asSchema as Z, tool as ge, generateObject as Te, convertToModelMessages as q, streamObject as ve, streamText as Pe, isToolUIPart as Oe } from "ai";
import { getErrorMessage as $ } from "@ai-sdk/provider-utils";
import G from "lodash.merge";
import Ee from "lodash.isequal";
import { getPmSchema as xe, UnreachableCaseError as Be, getNodeById as Ce, updateBlockTr as Ie, insertBlocks as Ne, trackPosition as K, removeAndInsertBlocks as Me, getBlock as de, defaultProps as pe, isStyledTextInlineContent as _e, isLinkInlineContent as Ae } from "@blocknote/core";
import { Slice as je } from "prosemirror-model";
import { TextSelection as $e } from "prosemirror-state";
import { Transform as E, Mapping as fe, ReplaceStep as v, ReplaceAroundStep as De } from "prosemirror-transform";
import { ChangeSet as Q, simplifyChanges as Le } from "prosemirror-changeset";
import { applySuggestions as qe } from "@handlewithcare/prosemirror-suggest-changes";
function J(t) {
  return (t.type === "paragraph" || !t.type) && !t.content || Array.isArray(t.content) && t.content.length === 0;
}
function Ue(t, e, o = !0, r = !0) {
  let n = 0, a = t.length;
  if (o)
    for (; n < a && e(t[n]); )
      n++;
  if (r)
    for (; a > n && e(t[a - 1]); )
      a--;
  return t.slice(n, a);
}
function P(t, e) {
  return Ue(
    t,
    (r) => J(r) && (e == null ? void 0 : e.cursorBlockId) !== r.id,
    (e == null ? void 0 : e.trimStart) ?? !1,
    (e == null ? void 0 : e.trimEnd) ?? !0
  );
}
async function Ut(t) {
  const {
    useSelection: e,
    deleteEmptyCursorBlock: o,
    streamToolsProvider: r,
    documentStateBuilder: n,
    onStart: a
  } = {
    useSelection: t.useSelection ?? !1,
    deleteEmptyCursorBlock: t.deleteEmptyCursorBlock ?? !0,
    streamToolsProvider: t.streamToolsProvider ?? le.html.getStreamToolsProvider(),
    documentStateBuilder: t.documentStateBuilder ?? le.html.defaultDocumentStateBuilder,
    onStart: t.onStart ?? (() => {
    })
  }, i = e ? void 0 : t.editor.getTextCursorPosition().block, s = i && o && J(i) && P(t.editor.document).length > 0 ? i.id : void 0, c = e ? t.editor.getSelectionCutBlocks(!0) : void 0, d = r.getStreamTools(
    t.editor,
    c ? {
      from: c._meta.startPos,
      to: c._meta.endPos
    } : void 0,
    t.onBlockUpdated
  ), u = {
    editor: t.editor,
    selectedBlocks: c == null ? void 0 : c.blocks,
    streamTools: d,
    emptyCursorBlockToDelete: s,
    onStart: a
  };
  return {
    ...u,
    documentState: await n(u)
  };
}
function Je(t) {
  const { properties: e, required: o, $defs: r, ...n } = t.inputSchema;
  return {
    schema: {
      type: "object",
      description: t.description,
      properties: {
        type: {
          type: "string",
          enum: [t.name]
        },
        ...e
      },
      required: ["type", ...o ?? []],
      additionalProperties: !1,
      ...n
    },
    $defs: r
  };
}
function Re(t) {
  const e = t.map((r) => Je(r)), o = {};
  for (const r of e)
    for (const n in r.$defs) {
      if (o[n] && !Ee(o[n], r.$defs[n]))
        throw new Error(`Duplicate, but different definition for ${n}`);
      o[n] = r.$defs[n];
    }
  return {
    type: "object",
    properties: {
      operations: {
        //description:
        // "Operations to apply to the document. Put all operations in this array in ONE tool call / function call. DO NOT use multiple operation arrays with parallel tool calls.",
        type: "array",
        items: {
          anyOf: e.map((r) => r.schema)
        }
      }
    },
    additionalProperties: !1,
    required: ["operations"],
    $defs: Object.keys(o).length > 0 ? o : void 0
  };
}
function ze(t) {
  return {
    applyDocumentOperations: {
      inputSchema: N(Re(t)),
      outputSchema: N({ type: "object" })
    }
  };
}
class R extends Error {
  constructor(o, r, n) {
    super(o, n);
    L(this, "aborted");
    this.chunk = r, this.name = "ChunkExecutionError", this.aborted = (n == null ? void 0 : n.aborted) ?? !1;
  }
}
class He {
  /**
   * @param streamTools - The StreamTools to use to apply the StreamToolCalls
   * @param abortSignal - Optional AbortSignal to cancel ongoing operations
   */
  constructor(e, o) {
    L(this, "stream");
    this.streamTools = e, this.abortSignal = o, this.stream = this.createStream();
  }
  createStream() {
    let e;
    const o = new TransformStream({
      transform: async (s, c) => {
        const d = typeof s == "string" ? await Fe(
          s,
          (e == null ? void 0 : e.isPossiblyPartial) ?? !1,
          this.streamTools
        ) : s;
        d && (e = d, c.enqueue(d));
      },
      flush: (s) => {
        e != null && e.isPossiblyPartial && s.error(new Error("stream ended with a partial operation"));
      }
    }), r = o.readable.pipeThrough(this.createExecutor()), [n, a] = r.tee(), i = n.pipeTo(new WritableStream());
    return {
      writable: o.writable,
      // expose externalReadable to the consumer
      readable: a,
      finishPromise: i
    };
  }
  createExecutor() {
    const e = this.streamTools.map((o) => o.executor());
    return new TransformStream({
      transform: async (o, r) => {
        var a, i;
        let n = !1;
        for (const s of e)
          try {
            if (await s.execute(o, this.abortSignal)) {
              r.enqueue({ status: "ok", chunk: o }), n = !0;
              break;
            }
          } catch (c) {
            r.error(
              new R(
                `Tool execution failed: ${$(c)}`,
                o,
                {
                  cause: c,
                  aborted: ((a = this.abortSignal) == null ? void 0 : a.aborted) ?? !1
                }
              )
            );
            return;
          }
        if (!n) {
          const s = ((i = o.operation) == null ? void 0 : i.type) || "unknown";
          r.error(
            new Error(
              `No tool could handle operation of type: ${s}`
            )
          );
          return;
        }
      }
    });
  }
  /**
   * Returns a WritableStream that can be used to write StreamToolCalls to the executor.
   *
   * The WriteableStream accepts JSON strings or Operation objects.
   *
   * Make sure to call `close` on the StreamToolExecutor instead of on the writable returned here!
   */
  get writable() {
    return this.stream.writable;
  }
  /**
   * Returns a ReadableStream that can be used to read the results of the executor.
   */
  get readable() {
    return this.stream.readable;
  }
  async finish() {
    await this.stream.finishPromise;
  }
  async executeOperationsArray(e) {
    const o = this.writable.getWriter();
    for await (const r of e) {
      const n = await ue(r);
      if (n.state === "undefined-input" || n.state === "failed-parse" || !n)
        return;
      await o.write(r);
    }
    await o.close(), await this.finish();
  }
  /**
   * Accepts an async iterable and writes each chunk to the internal stream.
   *
   * (alternative to writing to the writable stream using {@link writable})
   */
  async execute(e) {
    const o = this.writable.getWriter();
    for await (const r of e)
      await o.write(r);
    await o.close(), await this.finish();
  }
  /**
   * Accepts a single chunk and processes it using the same logic.
   *
   * (alternative to writing to the writable stream using {@link writable})
   */
  async executeOne(e) {
    await this.execute(
      async function* () {
        yield {
          operation: e,
          isUpdateToPreviousOperation: !1,
          isPossiblyPartial: !1,
          metadata: {}
        };
      }()
    );
  }
}
async function Fe(t, e, o) {
  const r = await ue(t);
  if (r.state === "undefined-input" || r.state === "failed-parse" || !r)
    return;
  const n = o.find((i) => {
    var s;
    return i.name === ((s = r.value) == null ? void 0 : s.type);
  }), a = n && n.validate(r.value);
  if (a != null && a.ok)
    return {
      operation: a.value,
      isPossiblyPartial: r.state === "repaired-parse",
      isUpdateToPreviousOperation: e,
      metadata: void 0
    };
}
function U(t) {
  return t.flatMap((e) => {
    var o;
    if (e.role === "user" && ((o = e.metadata) != null && o.documentState)) {
      const r = e.metadata.documentState;
      return [
        {
          role: "assistant",
          id: "assistant-document-state-" + e.id,
          parts: [
            ...r.selection ? [
              {
                type: "text",
                text: "This is the latest state of the selection (ignore previous selections, you MUST issue operations against this latest version of the selection):"
              },
              {
                type: "text",
                text: JSON.stringify(r.selectedBlocks)
              },
              {
                type: "text",
                text: `This is the latest state of the entire document (INCLUDING the selected text), 
you can use this to find the selected text to understand the context (but you MUST NOT issue operations against this document, you MUST issue operations against the selection):`
              },
              {
                type: "text",
                text: JSON.stringify(r.blocks)
              }
            ] : [
              {
                type: "text",
                text: `There is no active selection. This is the latest state of the document (ignore previous documents, you MUST issue operations against this latest version of the document). 
The cursor is BETWEEN two blocks as indicated by cursor: true.
` + (r.isEmptyDocument ? "Because the document is empty, YOU MUST first update the empty block before adding new blocks." : "Prefer updating existing blocks over removing and adding (but this also depends on the user's question).")
              },
              {
                type: "text",
                text: JSON.stringify(r.blocks)
              }
            ]
            // Alternatively, we could explore using dynamic tools to fake document state retrieval:
            // {
            //   type: "dynamic-tool",
            //   toolName: "getDocument",
            //   input: {},
            //   output: documentState.htmlBlocks,
            //   state: "output-available",
            //   toolCallId: "getDocument-" + message.id,
            // },
            // {
            //   type: "dynamic-tool",
            //   toolName: "getDocumentSelection",
            //   input: {},
            //   output: documentState.selection
            //     ? documentState.htmlSelectedBlocks
            //     : "no selection active",
            //   state: "output-available",
            //   toolCallId: "getDocument-" + message.id,
            // },
          ]
        },
        e
      ];
    }
    return [e];
  });
}
function We(t, e) {
  let o = "";
  return t.pipeThrough(
    new TransformStream({
      start(r) {
        r.enqueue({ type: "start" }), r.enqueue({ type: "start-step" }), r.enqueue({
          type: "tool-input-start",
          toolCallId: "call_object_1",
          toolName: e
        });
      },
      transform(r, n) {
        switch (r.type) {
          case "text-delta":
            o += r.textDelta, n.enqueue({
              type: "tool-input-delta",
              toolCallId: "call_object_1",
              inputTextDelta: r.textDelta
            });
            break;
          case "object":
          case "finish":
            break;
          case "error":
            n.enqueue({
              type: "error",
              errorText: $(r.error)
            });
            break;
          default: {
            const a = r;
            throw new Error(`Unsupported chunk type: ${a}`);
          }
        }
      },
      async flush(r) {
        r.enqueue({
          type: "tool-input-available",
          toolCallId: "call_object_1",
          toolName: e,
          input: JSON.parse(o)
        }), r.enqueue({ type: "finish-step" }), r.enqueue({ type: "finish" });
      }
    })
  );
}
function Ve(t, e) {
  return new ReadableStream({
    start(r) {
      r.enqueue({ type: "start" }), r.enqueue({ type: "start-step" }), r.enqueue({
        type: "tool-input-start",
        toolCallId: "call_object_1",
        toolName: e
      }), r.enqueue({
        type: "tool-input-delta",
        toolCallId: "call_object_1",
        inputTextDelta: JSON.stringify(t)
      }), r.enqueue({
        type: "tool-input-available",
        toolCallId: "call_object_1",
        toolName: e,
        input: t
      }), r.enqueue({ type: "finish-step" }), r.enqueue({ type: "finish" }), r.close();
    }
  });
}
function Ye(t) {
  return Object.fromEntries(
    Object.entries(t).map(([e, o]) => [
      e,
      {
        description: o.description,
        inputSchema: Z(o.inputSchema).jsonSchema,
        outputSchema: Z(o.outputSchema).jsonSchema
      }
    ])
  );
}
function Xe(t) {
  return Object.fromEntries(
    Object.entries(t).map(([e, o]) => [
      e,
      ge({
        ...o,
        inputSchema: N(o.inputSchema),
        outputSchema: N(o.outputSchema)
      })
    ])
  );
}
const Ze = {
  "mistral.chat": {
    mode: "auto"
  },
  "google.generative-ai": {
    mode: "auto"
  },
  "groq.chat": {
    providerOptions: {
      groq: {
        structuredOutputs: !1
      }
    }
  }
};
function ee(t) {
  return Ze[t.provider] || {};
}
class Jt {
  constructor(e) {
    this.opts = e;
  }
  /**
   * Calls an LLM with StreamTools, using the `generateObject` of the AI SDK.
   *
   * This is the non-streaming version.
   */
  async generateObject(e, o) {
    const { model: r, _additionalOptions: n } = this.opts;
    if (typeof r == "string")
      throw new Error("model must be a LanguageModelV2");
    const a = Object.keys(o)[0], i = o[a].inputSchema, s = await Te({
      output: "object",
      schema: i,
      model: r,
      mode: "tool",
      system: this.opts.systemPrompt,
      messages: q(U(e)),
      ...ee(r),
      ...n ?? {}
    });
    return Ve(s.object, a);
  }
  /**
   * Calls an LLM with StreamTools, using the `streamObject` of the AI SDK.
   *
   * This is the streaming version.
   */
  async streamObject(e, o) {
    const { model: r, _additionalOptions: n } = this.opts;
    if (typeof r == "string")
      throw new Error("model must be a LanguageModelV2");
    const a = Object.keys(o)[0], i = o[a].inputSchema, s = ve({
      output: "object",
      schema: i,
      model: r,
      mode: "tool",
      system: this.opts.systemPrompt,
      messages: q(U(e)),
      ...ee(r),
      ...n ?? {}
    });
    return We(
      s.fullStream,
      a
    );
  }
  /**
   * Calls an LLM with StreamTools, using the `streamText` of the AI SDK.
   *
   * This is the streaming version.
   */
  async streamText(e, o) {
    const { model: r, _additionalOptions: n } = this.opts;
    return Pe({
      model: r,
      system: this.opts.systemPrompt,
      messages: q(U(e)),
      tools: o,
      toolChoice: "required",
      // extra options for streamObject
      ...n ?? {}
      // activeTools: ["applyDocumentOperations"],
    }).toUIMessageStream();
  }
  async sendMessages({
    messages: e,
    body: o
    // metadata,
  }) {
    const r = this.opts.stream ?? !0, n = o.toolDefinitions, a = Xe(n);
    if (this.opts.objectGeneration)
      return r ? this.streamObject(e, a) : this.generateObject(e, a);
    if (r)
      return await this.streamText(e, a);
    throw new Error("Not implemented (generateText)");
  }
  reconnectToStream() {
    throw new Error("Not implemented");
  }
}
function Ge() {
  let t, e = Promise.resolve(), o = !1, r;
  const n = new Promise((c, d) => {
    r = d;
  });
  n.catch(() => {
  });
  const a = new ReadableStream({
    start(c) {
      t = c;
    },
    cancel(c) {
      o = !0, t.error(c), r == null || r(c);
    }
  });
  async function i(c) {
    if (o)
      throw new Error("Appendable stream canceled, can't append");
    const d = c.getReader();
    return e = e.then(async () => {
      for (; ; )
        try {
          const { done: u, value: l } = await Promise.race([
            d.read(),
            n
          ]);
          if (u || o)
            break;
          t.enqueue(l);
        } catch (u) {
          o = !0, t.error(u);
          break;
        }
    }), e;
  }
  async function s() {
    await e, o || t.close();
  }
  return { output: a, append: i, finalize: s };
}
function Ke(t) {
  return new ReadableStream({
    async start(e) {
      try {
        for await (const o of t)
          e.enqueue(o);
        e.close();
      } catch (o) {
        e.error(o);
      }
    }
  });
}
function me(t) {
  if (t.locked)
    throw new Error(
      "Stream (source) is already locked and cannot be iterated."
    );
  const e = t.pipeThrough(new TransformStream());
  return e[Symbol.asyncIterator] = () => {
    if (e.locked)
      throw new Error("Stream is already locked and cannot be iterated again.");
    const o = e.getReader();
    return {
      async next() {
        const { done: r, value: n } = await o.read();
        return r ? { done: !0, value: void 0 } : { done: !1, value: n };
      }
    };
  }, e;
}
function Qe(t) {
  return me(Ke(t));
}
async function* et(t, e) {
  var a;
  let o = 0, r = !0, n;
  for await (const i of t)
    if ((a = i.operations) != null && a.length) {
      for (let s = o; s < i.operations.length; s++) {
        const c = i.operations[s];
        n = c, yield {
          partialOperation: c,
          isUpdateToPreviousOperation: s === o && !r,
          isPossiblyPartial: s === i.operations.length - 1,
          metadata: e
        }, r = !1;
      }
      o = i.operations.length - 1;
    }
  if (!n)
    throw new Error("No operations seen");
  yield {
    partialOperation: n,
    isUpdateToPreviousOperation: !0,
    isPossiblyPartial: !1,
    metadata: e
  };
}
async function* tt(t, e) {
  let o = !1;
  for await (const r of t) {
    const n = r.operation;
    n.ok ? (yield {
      operation: n.value,
      isUpdateToPreviousOperation: o ? !1 : r.isUpdateToPreviousOperation,
      isPossiblyPartial: r.isPossiblyPartial,
      metadata: r.metadata
    }, o = !1) : (o = o || !r.isUpdateToPreviousOperation, e == null || e({
      ...r,
      operation: n
    }));
  }
}
async function* ot(t, e) {
  for await (const o of t) {
    if (!o.partialOperation.type) {
      yield {
        operation: {
          ok: !1,
          error: "The `type` property of an operation is required."
        },
        isUpdateToPreviousOperation: o.isUpdateToPreviousOperation,
        isPossiblyPartial: o.isPossiblyPartial,
        metadata: o.metadata
      };
      continue;
    }
    const r = e.find(
      (a) => a.name === o.partialOperation.type
    );
    if (!r) {
      yield {
        operation: {
          ok: !1,
          error: `No matching function for ${o.partialOperation.type}`
        },
        isUpdateToPreviousOperation: o.isUpdateToPreviousOperation,
        isPossiblyPartial: o.isPossiblyPartial,
        metadata: o.metadata
      };
      continue;
    }
    yield {
      operation: r.validate(o.partialOperation),
      isUpdateToPreviousOperation: o.isUpdateToPreviousOperation,
      isPossiblyPartial: o.isPossiblyPartial,
      metadata: o.metadata
    };
  }
}
async function* rt(t, e) {
  const o = ot(
    t,
    e
  );
  yield* tt(
    o,
    (n) => {
      if (!n.isPossiblyPartial)
        throw new R(
          `Invalid operation. ${$(n.operation.error)}`,
          n,
          {
            cause: n.operation.error
          }
        );
    }
  );
}
function nt(t, e, o) {
  return Qe(
    rt(
      et(
        me(t),
        o
      ),
      e
    )
  );
}
async function st(t, e, o, r) {
  const n = new He(t, r), a = Ge(), i = a.output.pipeTo(n.writable), s = /* @__PURE__ */ new Map();
  let c = !0;
  const d = e["~registerMessagesCallback"](() => {
    at(e, (S) => {
      if (!s.has(S.toolCallId)) {
        const y = it(
          t,
          S.toolName,
          S.toolCallId
        );
        a.append(y.operationsStream), s.set(S.toolCallId, y), c && (c = !1, o == null || o());
      }
      return s.get(S.toolCallId);
    });
  });
  await new Promise((S) => {
    const y = e["~registerStatusCallback"](() => {
      (e.status === "ready" || e.status === "error") && (d(), y(), e.status !== "error" && h(), S());
    }), h = e["~registerErrorCallback"](() => {
      if (e.error) {
        h();
        for (const k of s.values())
          k.complete || k.writer.abort(e.error);
      }
    });
  }), await a.finalize();
  const l = await Promise.allSettled([n.finish(), i]), f = l[0];
  if (l[1].status === "rejected" && (l[0].status !== "rejected" || l[0].reason !== l[1].reason))
    throw new Error(
      "unexpected, pipeToPromise rejected but executor.finish() doesn't have same error!?"
    );
  let p;
  if (f.status === "rejected") {
    if (f.reason instanceof R)
      p = f.reason;
    else if (!e.error)
      throw new Error(
        "Unexpected: no ChunkExecutionError but also no chat.error (network error?)"
      );
  }
  let b = !1;
  const m = Array.from(
    s.values().filter((S) => S.complete)
  );
  return m.forEach((S, y) => {
    const h = S.toolCallId === (p == null ? void 0 : p.chunk.metadata.toolCallId);
    h && (b = !0), b ? e.addToolOutput({
      tool: m[y].toolName,
      toolCallId: m[y].toolCallId,
      state: "output-error",
      errorText: JSON.stringify(
        h ? { status: "error", error: $(p) } : { status: "not-executed-previous-tool-errored" }
      )
    }) : e.addToolOutput({
      state: "output-available",
      tool: m[y].toolName,
      toolCallId: m[y].toolCallId,
      output: { status: "ok" }
    });
  }), p ? {
    ok: !1,
    error: p
  } : { ok: !0, value: void 0 };
}
function at(t, e) {
  var o;
  for (const r of ((o = t.lastMessage) == null ? void 0 : o.parts) ?? []) {
    if (!Oe(r) || r.type.replace("tool-", "") !== "applyDocumentOperations")
      continue;
    const a = r.toolCallId, i = e({
      toolName: r.type.replace("tool-", ""),
      toolCallId: a
    });
    ct(r, i);
  }
}
function it(t, e, o) {
  const r = new TransformStream(), n = nt(
    r.readable,
    t,
    { toolCallId: o }
  );
  return {
    // stream,
    writer: r.writable.getWriter(),
    complete: !1,
    // executor,
    operationsStream: n,
    toolName: e,
    toolCallId: o
  };
}
function ct(t, e) {
  if (t.state === "input-streaming") {
    const o = t.input;
    o !== void 0 && e.writer.write(o);
  } else if (t.state === "input-available") {
    const o = t.input;
    if (o === void 0)
      throw new Error("input is undefined");
    e.complete || (e.complete = !0, e.writer.write(o), e.writer.close());
  }
}
async function Rt(t, e, o, r, n) {
  const a = o ?? t.lastMessage;
  if (!a)
    throw new Error("No message to send");
  a.metadata = G(a.metadata, {
    documentState: e.documentState
  });
  const i = st(
    e.streamTools,
    t,
    e.onStart,
    n
  );
  return r = G(r, {
    metadata: {
      source: "blocknote-ai"
    },
    body: {
      toolDefinitions: Ye(
        ze(e.streamTools)
      )
    }
  }), await t.sendMessage(o, r), await i;
}
function he(t, e) {
  const o = t.getTextCursorPosition(), r = [];
  for (const n of e) {
    const a = n.id === o.block.id;
    r.push({
      id: n.id,
      block: n.block
    }), a && r.push({
      cursor: !0
    });
  }
  return r;
}
async function M(t, e) {
  return await Promise.all(t.map(async (o) => ({
    id: o.id,
    block: await e(o)
  })));
}
function O(t) {
  return t.flatMap((e) => [
    {
      ...e,
      children: []
    },
    ...O(e.children)
  ]);
}
function z(t) {
  return t.map((e) => typeof e == "object" && e && "id" in e ? {
    ...e,
    id: `${e.id}$`
  } : e);
}
function H(t) {
  return async (e) => e.selectedBlocks ? await ut(
    e.editor,
    t,
    {
      selectedBlocks: e.selectedBlocks
    }
  ) : await lt(
    e.editor,
    t,
    {
      excludeBlockIds: e.emptyCursorBlockToDelete ? [e.emptyCursorBlockToDelete] : void 0
    }
  );
}
async function lt(t, e, o) {
  const r = P(t.document).length === 0, n = t.getTextCursorPosition().block.id, a = P(t.document, {
    cursorBlockId: n
  }), i = await M(
    O(a),
    async (u) => e(t, u)
  ), c = he(t, i).filter(
    (u) => "cursor" in u || !(o.excludeBlockIds || []).includes(u.id)
  );
  return {
    selection: !1,
    blocks: z(c),
    isEmptyDocument: r
  };
}
async function ut(t, e, o) {
  const r = P(t.document).length === 0, n = await M(
    O(o.selectedBlocks),
    async (i) => e(t, i)
  ), a = z(n);
  return {
    isEmptyDocument: r,
    selection: !0,
    selectedBlocks: a,
    blocks: (await M(O(t.document), async (i) => e(t, i))).map(({ block: i }) => ({ block: i }))
    // strip ids so LLM can't accidentally issue updates to ids not in selection
  };
}
function dt(t) {
  let e, o = !1;
  return t.descendants((r, n) => o ? !1 : (r.isText && (o = !0, e = n), !0)), e;
}
function _(t) {
  var a;
  const e = xe(t), { modification: o } = e.marks, r = [], n = new E(t.before);
  for (let i = 0; i < t.steps.length; i++) {
    const s = t.steps[i], c = new fe(t.mapping.maps.slice(0, i)).invert();
    if (s.structure) {
      if (s instanceof v) {
        if (s.to !== s.from + 1 || s.slice.openStart !== 0 || s.slice.openEnd !== 1 || s.slice.content.size !== 2)
          throw new Error(
            "Structure change is not in expected format (ReplaceStep)"
          );
      } else if (s instanceof De) {
        if (s.insert !== 1 || s.slice.size !== 2 || s.gapTo !== s.to - 1 || s.gapFrom !== s.from + 1)
          throw new Error(
            "Structure change is not in expected format (ReplaceAroundStep)"
          );
      } else
        throw new Error("Step is not a ReplaceStep or ReplaceAroundStep");
      const y = c.map(s.from), h = s.slice.content.firstChild, k = n.doc.resolve(n.mapping.map(y)).nodeAfter;
      let w = h.marks || [];
      h.type !== k.type && (w = o.create({
        type: "nodeType",
        previousValue: k.type.name,
        newValue: h.type.name
      }).addToSet(w));
      const x = /* @__PURE__ */ new Set([
        ...Object.keys(h.attrs),
        ...Object.keys(k.attrs)
      ]);
      for (const g of x)
        h.attrs[g] !== k.attrs[g] && (w = o.create({
          type: "attr",
          attrName: g,
          previousValue: k.attrs[g],
          newValue: h.attrs[g]
        }).addToSet(w));
      const T = n.steps.length;
      n.setNodeMarkup(
        n.mapping.map(y),
        h.type,
        h.attrs,
        w
      ), r.push({
        prosemirrorSteps: n.steps.slice(T),
        selection: void 0,
        type: "replace"
      });
      continue;
    }
    if (!(s instanceof v))
      throw new Error("Step is not a ReplaceStep");
    const d = c.map(s.from), u = c.map(s.to);
    if (s.slice.openStart > 0 || s.slice.openEnd > 0)
      throw new Error(
        "Slice has openStart or openEnd > 0, but structure=false"
      );
    r.push({
      prosemirrorSteps: [],
      selection: {
        anchor: n.mapping.map(d),
        head: n.mapping.map(u)
      },
      type: "select"
    });
    const l = s.slice.content.textBetween(0, s.slice.size), f = l === n.doc.textBetween(n.mapping.map(d), n.mapping.map(u));
    let p;
    if (f)
      p = s.slice.content.size;
    else if (l.length === 0)
      p = s.slice.content.size;
    else {
      const y = dt(s.slice.content);
      if (y === void 0)
        throw new Error("unexpected: no first character found");
      p = y + 1;
    }
    let b = n.mapping.map(u);
    const m = n.mapping.map(u);
    let S = !0;
    for (let y = p; y <= s.slice.content.size; y++) {
      const h = S && d !== u, k = n.steps.length;
      if (h) {
        const T = n.doc.resolve(n.mapping.map(d));
        (a = T.nodeAfter) != null && a.isBlock && n.addNodeMark(T.pos, e.mark("deletion", {})), n.addMark(T.pos, b, e.mark("deletion", {})), b = n.mapping.map(u);
      }
      const w = new je(s.slice.content.cut(0, y), 0, 0);
      n.replace(m, b, w).addMark(
        m,
        m + w.content.size,
        e.mark("insertion", {})
      ), n.doc.nodesBetween(
        m,
        m + w.content.size,
        (T, g) => g < m || g > m + w.content.size ? !0 : (T.isBlock && n.addNodeMark(g, e.mark("insertion", {})), !1)
      ), b = n.mapping.slice(k).map(b);
      const x = $e.near(
        n.doc.resolve(m + w.content.size),
        -1
      );
      r.push({
        prosemirrorSteps: n.steps.slice(k),
        selection: {
          anchor: x.from,
          head: x.from
        },
        type: h ? "replace" : "insert"
        // 3. Insert the replacement character by character
      }), S = !1;
    }
  }
  return r;
}
async function F(t) {
  const e = Math.random() * 0.3 + 0.85;
  if (t.type === "select")
    await new Promise((o) => setTimeout(o, 100 * e));
  else if (t.type === "insert")
    await new Promise((o) => setTimeout(o, 10 * e));
  else if (t.type === "replace")
    await new Promise((o) => setTimeout(o, 200 * e));
  else
    throw new Be(t.type);
}
function W(t, e) {
  t.setMeta("addToHistory", !1), e.selection && t.setMeta("aiAgent", {
    selection: {
      anchor: e.selection.anchor,
      head: e.selection.head
    }
  });
  for (const o of e.prosemirrorSteps)
    if (t.maybeStep(o).failed)
      throw new Error("failed to apply step");
  return t;
}
function pt(t, e, o) {
  const r = new E(e);
  for (const i of t) {
    const s = new v(
      r.mapping.map(i.fromA),
      r.mapping.map(i.toA),
      o.slice(i.fromB, i.toB)
    );
    r.step(s);
  }
  const n = r.mapping.invert();
  let a = r.doc.content.findDiffStart(o.content);
  for (; a !== null; ) {
    const i = o.resolve(a).nodeAfter, s = r.doc.resolve(a).nodeAfter;
    if (!i || !s)
      throw new Error("diffNode not found");
    const c = !i.isLeaf && i.content.eq(s.content), d = c ? 1 : Math.min(i.nodeSize, s.nodeSize), u = a + d, l = n.map(a), f = n.map(u);
    let p = t.length;
    for (let m = 0; m < t.length; m++)
      if (t[m].fromA >= f) {
        p = m;
        break;
      }
    t.splice(p, 0, {
      fromA: l,
      toA: f,
      fromB: a,
      toB: u,
      deleted: [],
      inserted: [],
      type: c ? "node-type-or-attr-update" : "mark-update"
    }), r.step(
      new v(
        a,
        u,
        o.slice(a, u),
        c
      )
    );
    const b = r.doc.content.findDiffStart(o.content);
    if (b === a)
      throw new Error("diffStart not moving");
    a = b;
  }
  return t;
}
const te = (t, e) => {
  const o = /* @__PURE__ */ new Set(), r = /* @__PURE__ */ new Set();
  t.descendants((i) => {
    i.type.name === "tableCell" && o.add(JSON.stringify(i.toJSON()));
  }), e.descendants((i) => {
    i.type.name === "tableCell" && r.add(JSON.stringify(i.toJSON()));
  });
  const n = new Set(
    [...o].filter((i) => r.has(i))
  );
  return {
    encodeCharacter: (i) => i,
    encodeNodeStart: (i) => {
      if (i.type.name === "tableCell") {
        const s = JSON.stringify(i.toJSON());
        return n.has(s) ? s : i.type.name;
      }
      return i.type.name;
    },
    encodeNodeEnd: (i) => {
      if (i.type.name === "tableCell") {
        const s = JSON.stringify(i.toJSON());
        return n.has(s) ? s : -1;
      }
      return -1;
    },
    compareTokens: (i, s) => i === s
  };
};
function D(t, e, o = !1, r, n) {
  const a = Ce(t.id, e), i = new E(e);
  Ie(
    i,
    a.posBeforeNode,
    t.block,
    r,
    n
  );
  let s = i.doc, c = Q.create(
    e,
    void 0,
    te(e, s)
  );
  if (c = c.addSteps(s, i.mapping.maps, 0), o && c.changes.length > 0) {
    const l = c.changes[c.changes.length - 1], f = l.toA - l.fromA, p = l.toB - l.fromB;
    if (f > p) {
      const b = e.slice(
        l.fromA + p,
        l.toA
      );
      i.step(
        new v(l.toB, l.toB, b)
      ), s = i.doc, c = Q.create(
        c.startDoc,
        void 0,
        te(c.startDoc, s)
      ), c = c.addSteps(s, i.mapping.maps, 0);
    }
  }
  const d = [], u = Le(
    c.changes,
    s
  );
  for (let l = 0; l < u.length; l++) {
    const f = u[l], p = s.slice(f.fromB, f.toB);
    if (p.openEnd === 1 && p.openStart === 0 && (f.type = "node-type-or-attr-update", p.size > 2)) {
      const b = {
        fromA: f.fromA,
        toA: f.fromA + 1,
        fromB: f.fromB,
        toB: f.fromB + 1,
        deleted: [],
        inserted: [],
        type: "node-type-or-attr-update"
      }, m = {
        fromA: f.fromA + 1,
        toA: f.toA,
        fromB: f.fromB + 1,
        toB: f.toB,
        deleted: [],
        inserted: []
      };
      u.splice(l, 1, b, m), l++;
    }
  }
  pt(u, e, s);
  for (let l = 0; l < u.length; l++) {
    const f = u[l], p = s.slice(f.fromB, f.toB);
    if (p.openEnd > 0 && p.size > 1)
      throw new Error(
        "unexpected, openEnd > 0 and size > 1, this should have been split into two steps"
      );
    l === u.length - 1 && o && f.type === "mark-update" || d.push(
      new v(
        f.fromA,
        f.toA,
        p,
        f.type === "node-type-or-attr-update"
      )
    );
  }
  return d;
}
class ye extends Error {
  constructor(e, o) {
    super(e, o), this.name = "AbortError";
  }
}
function ft(t, e) {
  if (!t || !Array.isArray(t) || t.length === 0)
    return {
      ok: !1,
      error: "blocks is required"
    };
  const o = [];
  for (const r of t) {
    const n = e(r);
    if (!n.ok)
      return {
        ok: !1,
        error: `Invalid block: ${n.error}`
      };
    o.push(n.value);
  }
  return {
    ok: !0,
    value: o
  };
}
function V(t) {
  return (e, o) => {
    const r = typeof t.schema == "function" ? t.schema(e) : t.schema;
    return {
      name: "add",
      description: t.description,
      inputSchema: {
        type: "object",
        properties: {
          referenceId: {
            type: "string",
            description: "MUST be an id of a block in the document"
          },
          position: {
            type: "string",
            enum: ["before", "after"],
            description: "`after` to add blocks AFTER (below) the block with `referenceId`, `before` to add the block BEFORE (above)"
          },
          blocks: {
            items: r.block,
            type: "array"
          }
        },
        required: ["referenceId", "position", "blocks"],
        $defs: r.$defs
      },
      validate: (n) => {
        if (n.type !== "add")
          return {
            ok: !1,
            error: "invalid operation type"
          };
        if (n.position !== "before" && n.position !== "after")
          return {
            ok: !1,
            error: "invalid position"
          };
        if (!n.referenceId || !n.blocks)
          return {
            ok: !1,
            error: "referenceId and blocks are required"
          };
        let a = n.referenceId;
        if (o.idsSuffixed) {
          if (!(a != null && a.endsWith("$")))
            return {
              ok: !1,
              error: "referenceId must end with $"
            };
          a = a.slice(0, -1);
        }
        if (!e.getBlock(a))
          return {
            ok: !1,
            error: "referenceId not found"
          };
        const s = ft(
          n.blocks,
          (c) => t.validateBlock(c, e)
        );
        return s.ok ? {
          ok: !0,
          value: {
            type: n.type,
            referenceId: a,
            position: n.position,
            blocks: s.value
          }
        } : s;
      },
      // Note: functionality mostly tested in jsontools.test.ts
      // would be nicer to add a direct unit test
      executor: () => {
        let n = [];
        const a = {};
        return {
          execute: async (i, s) => {
            var u;
            if (i.isUpdateToPreviousOperation || (n = []), i.operation.type !== "add")
              return !1;
            const c = i.operation, d = await t.toJSONToolCall(e, {
              ...i,
              operation: c
            });
            if (!d || i.isPossiblyPartial && J(
              d.blocks[d.blocks.length - 1]
            ))
              return !0;
            for (let l = 0; l < d.blocks.length; l++) {
              const f = d.blocks[l], p = e.prosemirrorState.tr;
              let b = [];
              if (l < n.length) {
                const m = await t.rebaseTool(n[l], e), y = D(
                  {
                    id: n[l],
                    block: f
                  },
                  m.doc,
                  !1
                ).map((h) => h.map(m.invertMap));
                for (const h of y)
                  p.step(h.map(p.mapping));
                b = _(p), b = b.filter(
                  (h) => h.type !== "select"
                );
              } else {
                const m = c.position === "after" ? a[c.referenceId] : void 0, S = Ne(
                  p,
                  [f],
                  l > 0 ? n[l - 1] : m || c.referenceId,
                  l > 0 ? "after" : c.position
                );
                n.push(...S.map((y) => y.id)), b = _(p);
              }
              for (const m of b) {
                if (s != null && s.aborted)
                  throw new ye("Operation was aborted");
                o.withDelays && await F(m), e.transact((S) => {
                  W(S, m);
                }), (u = o.onBlockUpdate) == null || u.call(o, n[l]);
              }
            }
            return i.isPossiblyPartial || c.position === "after" && (a[c.referenceId] = n[n.length - 1]), !0;
          }
        };
      }
    };
  };
}
function Y(t) {
  return (e, o) => {
    const r = typeof t.schema == "function" ? t.schema(e) : t.schema;
    return {
      name: "update",
      description: t.description,
      inputSchema: {
        type: "object",
        properties: {
          id: {
            type: "string",
            description: "id of block to update"
          },
          block: r.block
        },
        required: ["id", "block"],
        $defs: r.$defs
      },
      validate: (n) => {
        if (n.type !== "update")
          return {
            ok: !1,
            error: "invalid operation type"
          };
        if (!n.id)
          return {
            ok: !1,
            error: "id is required"
          };
        let a = n.id;
        if (o.idsSuffixed) {
          if (!(a != null && a.endsWith("$")))
            return {
              ok: !1,
              error: "id must end with $"
            };
          a = a.slice(0, -1);
        }
        if (!n.block)
          return {
            ok: !1,
            error: "block is required"
          };
        const i = e.getBlock(a);
        if (!i)
          return {
            ok: !1,
            error: new Error("Block not found (update)", {
              cause: {
                blockId: a
              }
            })
          };
        const s = t.validateBlock(n.block, e, i.type);
        return s.ok ? {
          ok: !0,
          value: {
            type: n.type,
            id: a,
            block: s.value
          }
        } : s;
      },
      // Note: functionality mostly tested in jsontools.test.ts
      // would be nicer to add a direct unit test
      executor: () => {
        let a = 50;
        const i = o.updateSelection ? {
          from: K(e, o.updateSelection.from),
          to: K(e, o.updateSelection.to)
        } : void 0;
        return {
          execute: async (s, c) => {
            var h;
            if (s.operation.type !== "update")
              return !1;
            const d = s.operation;
            if (s.isPossiblyPartial) {
              const k = JSON.stringify(d.block).length;
              if (k < a)
                return !0;
              a = k + 50;
            } else
              a = 50;
            const u = await t.rebaseTool(d.id, e), l = i ? u.invertMap.invert().map(i.from()) : void 0, f = i ? u.invertMap.invert().map(i.to()) : void 0, p = await t.toJSONToolCall(e, {
              ...s,
              operation: d
            });
            if (!p)
              return !0;
            const b = D(
              p,
              u.doc,
              s.isPossiblyPartial,
              l,
              f
            );
            if (b.length === 1 && s.isPossiblyPartial)
              return !0;
            const m = b.map((k) => k.map(u.invertMap)), S = new E(e.prosemirrorState.doc);
            for (const k of m)
              S.step(k.map(S.mapping));
            const y = _(S);
            for (const k of y) {
              if (c != null && c.aborted)
                throw new ye("Operation was aborted");
              o.withDelays && await F(k), e.transact((w) => {
                W(w, k);
              }), (h = o.onBlockUpdate) == null || h.call(o, d.id);
            }
            return !0;
          }
        };
      }
    };
  };
}
const X = (t, e) => ({
  name: "delete",
  description: "Delete a block",
  inputSchema: {
    type: "object",
    properties: {
      id: {
        type: "string",
        description: "id of block to delete"
      }
    },
    required: ["id"]
  },
  validate: (o) => {
    if (o.type !== "delete")
      return {
        ok: !1,
        error: "invalid operation type"
      };
    if (!o.id)
      return {
        ok: !1,
        error: "id is required"
      };
    let r = o.id;
    if (e.idsSuffixed) {
      if (!(r != null && r.endsWith("$")))
        return {
          ok: !1,
          error: "id must end with $"
        };
      r = r.slice(0, -1);
    }
    return t.getBlock(r) ? {
      ok: !0,
      value: {
        type: "delete",
        id: r
      }
    } : {
      ok: !1,
      error: new Error("Block not found (delete)", {
        cause: {
          blockId: r
        }
      })
    };
  },
  // Note: functionality mostly tested in jsontools.test.ts
  // would be nicer to add a direct unit test
  executor: () => ({
    execute: async (o) => {
      var i;
      if (o.operation.type !== "delete")
        return !1;
      const r = o.operation, n = t.prosemirrorState.tr;
      Me(n, [r.id], []);
      const a = _(n);
      for (const s of a)
        e.withDelays && await F(s), t.transact((c) => {
          W(c, s);
        }), (i = e.onBlockUpdate) == null || i.call(e, r.id);
      return !0;
    }
  })
});
function oe(t) {
  const e = t.lastIndexOf("<"), o = t.lastIndexOf(">");
  let r = t;
  if (e > o && (r = t.substring(0, e), !r.trim()))
    return;
  const n = r.match(/&[a-zA-Z0-9]*$/);
  n && (r = r.substring(
    0,
    r.length - n[0].length
  ));
  const s = new DOMParser().parseFromString(
    `<div>${r}</div>`,
    "text/html"
  ).body.firstChild;
  return s ? s.innerHTML : "";
}
function A(t) {
  let e;
  if (qe(t.prosemirrorState, (o) => {
    e = o;
  }), !e)
    throw new Error("applySuggestionsTr is not set");
  return e;
}
function j(t, e) {
  const o = e.mapping.invert();
  return {
    doc: e.doc,
    /**
     * Return a new transform that has the projection applied.
     * You can add new operations to this transform and later rebase those on the original document with `rebaseTr`
     */
    tr: () => new E(e.doc),
    /**
     * Invert map created by the projection.
     * You can use this to map positions on the "clean" document (the projection) to positions on the original document
     */
    invertMap: o,
    /**
     * Return a new transaction based on the editor state with all the steps you made to `tr`.
     * These steps are rebased on the original document.
     */
    rebaseTr: (r) => {
      if (r.steps.length === 0)
        throw new Error("No steps to apply");
      let n = t.prosemirrorState.tr;
      for (const a of r.steps) {
        const i = a.map(o);
        if (!i)
          throw new Error("Step is not mapped");
        n = n.step(i);
      }
      return n;
    }
  };
}
async function re(t, e) {
  var d;
  const o = A(e), r = de(o.doc, t);
  if (!r)
    throw new Error("block not found");
  const n = await e.blocksToHTMLLossy([
    {
      ...r,
      children: []
    }
  ]), a = (d = window.__TEST_OPTIONS) == null ? void 0 : d.mockID, i = await e.tryParseHTMLToBlocks(n);
  if (window.__TEST_OPTIONS && (window.__TEST_OPTIONS.mockID = a), i.length !== 1)
    throw new Error("html diff invalid block count");
  const s = i[0];
  if (s.id = t, D(
    {
      id: t,
      block: s
    },
    o.doc
  ).length)
    throw new Error("html diff", {
      cause: {
        html: n,
        htmlBlock: s
      }
    });
  return j(e, o);
}
function ne(t) {
  return typeof t != "string" ? {
    ok: !1,
    error: "block must be a string"
  } : {
    ok: !0,
    value: t
  };
}
const B = {
  add: V({
    description: "Insert new blocks",
    schema: {
      block: {
        type: "string",
        description: "html of block (MUST be a single, VALID HTML element)"
      }
    },
    validateBlock: ne,
    rebaseTool: re,
    toJSONToolCall: async (t, e) => {
      var n;
      const o = (n = window.__TEST_OPTIONS) == null ? void 0 : n.mockID, r = (await Promise.all(
        e.operation.blocks.map(async (a) => {
          const i = e.isPossiblyPartial ? oe(a) : a;
          return i ? (await t.tryParseHTMLToBlocks(i)).map(
            (s) => (delete s.id, s)
          ) : [];
        })
      )).flat();
      if (window.__TEST_OPTIONS && (window.__TEST_OPTIONS.mockID = o), r.length !== 0)
        return {
          ...e.operation,
          blocks: r
        };
    }
  }),
  update: Y({
    description: "Update a block",
    schema: {
      block: {
        type: "string",
        description: "html of block (MUST be a single HTML element)"
      }
    },
    validateBlock: ne,
    rebaseTool: re,
    toJSONToolCall: async (t, e) => {
      const o = e.isPossiblyPartial ? oe(e.operation.block) : e.operation.block;
      if (!o)
        return;
      const r = (await t.tryParseHTMLToBlocks(o))[0];
      return window.__TEST_OPTIONS && (window.__TEST_OPTIONS.mockID = void 0), delete r.id, {
        ...e.operation,
        block: r
      };
    }
  }),
  delete: X
};
function mt(t, e, o, r, n) {
  if (typeof r == "boolean") {
    const s = r ? t.getSelectionCutBlocks(!0) : void 0;
    r = s ? {
      from: s._meta.startPos,
      to: s._meta.endPos
    } : void 0;
  }
  const a = o ?? {
    add: !0,
    update: !0,
    delete: !0
  };
  return [
    ...a.update ? [
      B.update(t, {
        idsSuffixed: !0,
        withDelays: e,
        updateSelection: r,
        onBlockUpdate: n
      })
    ] : [],
    ...a.add ? [B.add(t, { idsSuffixed: !0, withDelays: e, onBlockUpdate: n })] : [],
    ...a.delete ? [B.delete(t, { idsSuffixed: !0, withDelays: e, onBlockUpdate: n })] : []
  ];
}
const ht = `You're manipulating a text document using HTML blocks. 
Make sure to follow the json schema provided. When referencing ids they MUST be EXACTLY the same (including the trailing $). 
List items are 1 block with 1 list item each, so block content \`<ul><li>item1</li></ul>\` is valid, but \`<ul><li>item1</li><li>item2</li></ul>\` is invalid. We'll merge them automatically.
For code blocks, you can use the \`data-language\` attribute on a <code> block (wrapped with <pre>) to specify the language.

If the user requests updates to the document, use the "applyDocumentOperations" tool to update the document.
---
IF there is no selection active in the latest state, first, determine what part of the document the user is talking about. You SHOULD probably take cursor info into account if needed.
  EXAMPLE: if user says "below" (without pointing to a specific part of the document) he / she probably indicates the block(s) after the cursor. 
  EXAMPLE: If you want to insert content AT the cursor position (UNLESS indicated otherwise by the user), then you need \`referenceId\` to point to the block before the cursor with position \`after\` (or block below and \`before\`
---
 `, yt = {
  /**
   * Function to get the stream tools that can apply HTML block updates to the editor
   */
  getStreamToolsProvider: (t = {}) => ({
    getStreamTools: (e, o, r) => mt(
      e,
      t.withDelays ?? !0,
      t.defaultStreamTools,
      o,
      r
    )
  }),
  systemPrompt: ht,
  tools: B,
  /**
   * The default DocumentStateBuilder that can take an editor and convert it to a document state that can be passed to the backend
   */
  defaultDocumentStateBuilder: H(
    async (t, e) => t.blocksToHTMLLossy([e])
  )
};
function bt(t) {
  const e = {}, o = {};
  return t.forEach((n) => {
    const { type: a, ...i } = n.properties, s = JSON.stringify(i);
    e[s] ? e[s].push(a.enum[0]) : (e[s] = [a.enum[0]], o[s] = n);
  }), Object.keys(
    e
  ).map((n) => {
    const a = o[n];
    return {
      ...a,
      properties: {
        ...a.properties,
        type: {
          type: "string",
          enum: e[n]
        }
      }
    };
  });
}
function St(t) {
  return {
    type: "object",
    properties: Object.fromEntries(
      Object.entries(t).map(([e, o]) => [
        e,
        {
          type: o.propSchema
        }
      ])
    ),
    additionalProperties: !1
  };
}
function kt() {
  return {
    type: "object",
    properties: {
      type: {
        type: "string",
        enum: ["text"]
      },
      text: {
        type: "string"
      },
      styles: {
        $ref: "#/$defs/styles"
      }
    },
    additionalProperties: !1,
    required: ["type", "text"]
  };
}
function be(t) {
  return {
    type: "object",
    properties: Object.fromEntries(
      Object.entries(t).filter(([e, o]) => o.default !== void 0).map(([e, o]) => [
        e,
        {
          type: typeof o.default,
          enum: o.values
        }
      ])
    ),
    additionalProperties: !1
  };
}
function wt(t) {
  return {
    type: "array",
    items: {
      anyOf: Object.entries(t).map(([e, o]) => o === "text" ? {
        $ref: "#/$defs/styledtext"
      } : o === "link" ? {
        type: "object",
        properties: {
          type: {
            type: "string",
            enum: ["link"]
          },
          content: {
            type: "array",
            items: {
              $ref: "#/$defs/styledtext"
            }
          },
          href: {
            type: "string"
          }
        },
        additionalProperties: !1,
        required: ["type", "href", "content"]
      } : {
        type: "object",
        properties: {
          type: {
            type: "string",
            enum: [o.type]
          },
          content: o.content === "styled" ? {
            type: "array",
            items: {
              $ref: "#/$defs/styledtext"
            }
          } : void 0,
          props: be(o.propSchema)
        },
        additionalProperties: !1,
        required: ["type", ...o.content === "styled" ? ["content"] : []]
      })
    }
  };
}
function gt(t) {
  return {
    anyOf: bt(
      Object.entries(t).map(([e, o]) => ({
        type: "object",
        properties: {
          type: {
            type: "string",
            enum: [o.type]
          },
          content: o.content === "inline" ? { $ref: "#/$defs/inlinecontent" } : o.content === "table" ? { type: "object", properties: {} } : void 0,
          // filter out default props (TODO: make option)
          props: be(o.propSchema)
          // Object.fromEntries(
          //   Object.entries(val.propSchema).filter(
          //     (key) => typeof (defaultProps as any)[key[0]] === "undefined"
          //   )
          // )
          // ),
        },
        additionalProperties: !1,
        required: ["type"]
        //, ...(val.content === "inline" ? ["content"] : [])],
      }))
    )
  };
}
function Tt(t) {
  const e = JSON.parse(
    JSON.stringify({
      blockSchema: t.blockSchema,
      inlineContentSchema: t.inlineContentSchema,
      styleSchema: t.styleSchema
    })
  );
  return {
    // TODO
    removeFileBlocks() {
      return e.blockSchema = Object.fromEntries(
        Object.entries(e.blockSchema).filter(
          ([o, r]) => {
            var n;
            return !((n = t.blockSpecs[r.type].implementation.meta) != null && n.fileBlockAccept);
          }
        )
      ), this;
    },
    removeDefaultProps() {
      return e.blockSchema = Object.fromEntries(
        Object.entries(e.blockSchema).map(([o, r]) => [
          o,
          {
            ...r,
            propSchema: Object.fromEntries(
              Object.entries(r.propSchema).filter(
                (n) => typeof pe[n[0]] > "u"
              )
            )
          }
        ])
      ), this;
    },
    get() {
      return e;
    }
  };
}
function se(t) {
  return t = Tt(t).removeFileBlocks().removeDefaultProps().get(), {
    $defs: {
      styles: St(t.styleSchema),
      styledtext: kt(),
      inlinecontent: wt(
        t.inlineContentSchema
      ),
      block: gt(t.blockSchema)
    }
  };
}
function Se(t, e) {
  return !e.schema.inlineContentSchema[t.type] || _e(t) && !("text" in t) ? !1 : Ae(t) ? !("content" in t) || !("href" in t) ? !1 : Se(t.content, e) : !0;
}
function ae(t, e, o) {
  const r = t.type || o, n = e.schema.blockSchema[r];
  if (!n)
    return {
      ok: !1,
      error: "block type not found in editor"
    };
  if (t.children, n.content === "none") {
    if (t.content)
      return {
        ok: !1,
        error: "block content not expected for this block type"
      };
  } else {
    if (!t.content)
      return {
        ok: !0,
        value: t
      };
    if (!Array.isArray(t.content))
      return {
        ok: !1,
        error: "block content must be an array"
      };
    if (n.content === "table")
      return {
        ok: !0,
        value: t
      };
    if (!t.content.every((a) => Se(a, e)))
      return {
        ok: !1,
        error: "block content must be an array of inline content"
      };
  }
  return {
    ok: !0,
    value: t
  };
}
const C = {
  add: V({
    description: "Insert new blocks",
    schema: (t) => ({
      block: {
        $ref: "#/$defs/block"
      },
      ...se(t.schema)
    }),
    validateBlock: ae,
    rebaseTool: async (t, e) => j(e, A(e)),
    toJSONToolCall: async (t, e) => e.operation
  }),
  update: Y({
    description: "Update a block, the new block will replace the existing block.",
    schema: (t) => ({
      block: {
        $ref: "#/$defs/block"
      },
      ...se(t.schema)
    }),
    validateBlock: ae,
    rebaseTool: async (t, e) => j(e, A(e)),
    toJSONToolCall: async (t, e) => {
      const o = Object.fromEntries(
        Object.entries(pe).map(([r, n]) => [r, n.default])
      );
      return {
        ...e.operation,
        block: {
          ...e.operation.block,
          props: {
            ...o,
            ...e.operation.block.props
          }
        }
      };
    }
  }),
  delete: X
};
function vt(t, e, o, r, n) {
  if (typeof r == "boolean") {
    const s = r ? t.getSelectionCutBlocks(!0) : void 0;
    r = s ? {
      from: s._meta.startPos,
      to: s._meta.endPos
    } : void 0;
  }
  const a = o ?? {
    add: !0,
    update: !0,
    delete: !0
  };
  return [
    ...a.update ? [
      C.update(t, {
        idsSuffixed: !0,
        withDelays: e,
        updateSelection: r,
        onBlockUpdate: n
      })
    ] : [],
    ...a.add ? [C.add(t, { idsSuffixed: !0, withDelays: e, onBlockUpdate: n })] : [],
    ...a.delete ? [C.delete(t, { idsSuffixed: !0, withDelays: e, onBlockUpdate: n })] : []
  ];
}
const Pt = `You're manipulating a text document using JSON blocks. 
Make sure to follow the json schema provided. When referencing ids they MUST be EXACTLY the same (including the trailing $). 

If the user requests updates to the document, use the "applyDocumentOperations" tool to update the document.
---
IF there is no selection active in the latest state, first, determine what part of the document the user is talking about. You SHOULD probably take cursor info into account if needed.
  EXAMPLE: if user says "below" (without pointing to a specific part of the document) he / she probably indicates the block(s) after the cursor. 
  EXAMPLE: If you want to insert content AT the cursor position (UNLESS indicated otherwise by the user), then you need \`referenceId\` to point to the block before the cursor with position \`after\` (or block below and \`before\`
---
 `, Ot = {
  /**
   * Function to get the stream tools that can apply JSON block updates to the editor
   */
  getStreamToolsProvider: (t = {}) => ({
    getStreamTools: (e, o, r) => vt(
      e,
      t.withDelays ?? !0,
      t.defaultStreamTools,
      o,
      r
    )
  }),
  tools: C,
  systemPrompt: Pt,
  defaultDocumentStateBuilder: H(
    async (t, e) => ({
      ...e,
      id: void 0,
      // don't pass id, because LLM should use `jsonSelectedBlocks` for this
      children: void 0
    })
  )
};
async function ie(t, e) {
  const o = A(e), r = await e.blocksToMarkdownLossy([de(o.doc, t)]), n = await e.tryParseMarkdownToBlocks(r), a = D(
    {
      id: t,
      block: n[0]
    },
    o.doc
  ), i = new fe();
  for (const s of a) {
    const c = s.map(i);
    if (!c)
      throw new Error("Failed to map step");
    o.step(c), i.appendMap(c.getMap());
  }
  return j(e, o);
}
function ce(t) {
  return typeof t != "string" ? {
    ok: !1,
    error: "block must be a string"
  } : {
    ok: !0,
    value: t
  };
}
const I = {
  add: V({
    description: "Insert new blocks",
    schema: {
      block: {
        $ref: "#/$defs/block"
      },
      $defs: {
        block: { type: "string", description: "markdown of block" }
      }
    },
    validateBlock: ce,
    rebaseTool: ie,
    toJSONToolCall: async (t, e) => {
      const o = await Promise.all(
        e.operation.blocks.map(async (r) => {
          const n = (await t.tryParseMarkdownToBlocks(r.trim()))[0];
          return delete n.id, n;
        })
      );
      return window.__TEST_OPTIONS && (window.__TEST_OPTIONS.mockID = void 0), {
        ...e.operation,
        blocks: o
      };
    }
  }),
  update: Y({
    description: "Update a block, the new block will replace the existing block.",
    schema: {
      block: {
        $ref: "#/$defs/block"
      },
      $defs: {
        block: { type: "string", description: "markdown of block" }
      }
    },
    validateBlock: ce,
    rebaseTool: ie,
    toJSONToolCall: async (t, e) => {
      const o = (await t.tryParseMarkdownToBlocks(e.operation.block.trim()))[0];
      return delete o.id, window.__TEST_OPTIONS && (window.__TEST_OPTIONS.mockID = void 0), {
        ...e.operation,
        block: o
      };
    }
  }),
  delete: X
};
function Et(t, e, o, r, n) {
  if (typeof r == "boolean") {
    const s = r ? t.getSelectionCutBlocks(!0) : void 0;
    r = s ? {
      from: s._meta.startPos,
      to: s._meta.endPos
    } : void 0;
  }
  const a = o ?? {
    add: !0,
    update: !0,
    delete: !0
  };
  return [
    ...a.update ? [
      I.update(t, {
        idsSuffixed: !0,
        withDelays: e,
        updateSelection: r,
        onBlockUpdate: n
      })
    ] : [],
    ...a.add ? [I.add(t, { idsSuffixed: !0, withDelays: e, onBlockUpdate: n })] : [],
    ...a.delete ? [I.delete(t, { idsSuffixed: !0, withDelays: e, onBlockUpdate: n })] : []
  ];
}
const xt = `You're manipulating a text document using Markdown blocks. 
Make sure to follow the json schema provided. When referencing ids they MUST be EXACTLY the same (including the trailing $). 
List items are 1 block with 1 list item each, so block content \`- item1\` is valid, but \`- item1
- item2\` is invalid. We'll merge them automatically.

If the user requests updates to the document, use the "applyDocumentOperations" tool to update the document.
---
IF there is no selection active in the latest state, first, determine what part of the document the user is talking about. You SHOULD probably take cursor info into account if needed.
  EXAMPLE: if user says "below" (without pointing to a specific part of the document) he / she probably indicates the block(s) after the cursor. 
  EXAMPLE: If you want to insert content AT the cursor position (UNLESS indicated otherwise by the user), then you need \`referenceId\` to point to the block before the cursor with position \`after\` (or block below and \`before\`
---
 `, Bt = {
  /**
   * Function to get the stream tools that can apply Markdown block updates to the editor
   */
  getStreamToolsProvider: (t = {}) => ({
    getStreamTools: (e, o, r) => Et(
      e,
      t.withDelays ?? !0,
      t.defaultStreamTools,
      o,
      r
    )
  }),
  systemPrompt: xt,
  tools: I,
  defaultDocumentStateBuilder: H(
    async (t, e) => t.blocksToMarkdownLossy([e])
  )
}, le = {
  _experimental_json: Ot,
  _experimental_markdown: Bt,
  html: yt
}, zt = {
  addCursorPosition: he,
  flattenBlocks: O,
  suffixIDs: z,
  trimEmptyBlocks: P,
  convertBlocks: M
};
function Ht(t) {
  if (!t.dictionary.ai)
    throw new Error("AI dictionary not found");
  return t.dictionary.ai;
}
const Ft = (t) => async (e, o) => {
  const r = new Request(e, o), n = t(r.url), a = new Request(n, {
    headers: r.headers,
    // if we just pass request.body, it's a readablestream which is not visible in chrome inspector,
    // so use init?.body instead if it's available to make debugging easier
    body: (o == null ? void 0 : o.body) || r.body,
    method: r.method,
    duplex: "half"
  });
  return await fetch(a);
};
export {
  Jt as C,
  Ze as P,
  He as S,
  le as a,
  Ut as b,
  Ht as c,
  Re as d,
  ze as e,
  Ft as f,
  A as g,
  ee as h,
  st as i,
  U as j,
  We as k,
  Xe as l,
  H as m,
  nt as n,
  Ve as o,
  zt as p,
  Rt as s,
  Ye as t
};
//# sourceMappingURL=client-B0lU3j7B.js.map
