var ye = Object.defineProperty;
var be = (t, e, o) => e in t ? ye(t, e, { enumerable: !0, configurable: !0, writable: !0, value: o }) : t[e] = o;
var D = (t, e, o) => be(t, typeof e != "symbol" ? e + "" : e, o);
import { jsonSchema as N, parsePartialJson as ie, asSchema as Y, tool as Se, streamText as ke, convertToModelMessages as we, isToolUIPart as ge } from "ai";
import X from "lodash.merge";
import { getErrorMessage as L } from "@ai-sdk/provider-utils";
import Te from "lodash.isequal";
import { getPmSchema as Pe, UnreachableCaseError as ve, getNodeById as Oe, updateBlockTr as Ee, insertBlocks as xe, trackPosition as Z, removeAndInsertBlocks as Be, getBlock as ce, defaultProps as le, isStyledTextInlineContent as Ce, isLinkInlineContent as Ie } from "@blocknote/core";
import { Slice as Ne } from "prosemirror-model";
import { TextSelection as Me } from "prosemirror-state";
import { Transform as E, Mapping as ue, ReplaceStep as P, ReplaceAroundStep as Ae } from "prosemirror-transform";
import { ChangeSet as G, simplifyChanges as _e } from "prosemirror-changeset";
import { applySuggestions as $e } from "@handlewithcare/prosemirror-suggest-changes";
function U(t) {
  return (t.type === "paragraph" || !t.type) && !t.content || Array.isArray(t.content) && t.content.length === 0;
}
function je(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 v(t, e) {
  return je(
    t,
    (r) => U(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 $t(t) {
  const {
    useSelection: e,
    deleteEmptyCursorBlock: o,
    streamToolsProvider: r,
    documentStateBuilder: n,
    onStart: a
  } = {
    useSelection: t.useSelection ?? !1,
    deleteEmptyCursorBlock: t.deleteEmptyCursorBlock ?? !0,
    streamToolsProvider: t.streamToolsProvider ?? ae.html.getStreamToolsProvider(),
    documentStateBuilder: t.documentStateBuilder ?? ae.html.defaultDocumentStateBuilder,
    onStart: t.onStart ?? (() => {
    })
  }, i = e ? void 0 : t.editor.getTextCursorPosition().block, s = i && o && U(i) && v(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 De(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 Le(t) {
  const e = t.map((r) => De(r)), o = {};
  for (const r of e)
    for (const n in r.$defs) {
      if (o[n] && !Te(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 Ue(t) {
  return {
    applyDocumentOperations: {
      inputSchema: N(Le(t)),
      outputSchema: N({ type: "object" })
    }
  };
}
class J extends Error {
  constructor(o, r, n) {
    super(o, n);
    D(this, "aborted");
    this.chunk = r, this.name = "ChunkExecutionError", this.aborted = (n == null ? void 0 : n.aborted) ?? !1;
  }
}
class Je {
  /**
   * @param streamTools - The StreamTools to use to apply the StreamToolCalls
   * @param abortSignal - Optional AbortSignal to cancel ongoing operations
   */
  constructor(e, o) {
    D(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 qe(
          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 J(
                `Tool execution failed: ${L(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 ie(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 qe(t, e, o) {
  const r = await ie(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 Re(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];
  });
}
async function ze(t) {
  const e = await Promise.all(
    Object.entries(t).map(async ([o, r]) => [
      o,
      {
        description: r.description,
        inputSchema: await Y(r.inputSchema).jsonSchema,
        outputSchema: await Y(r.outputSchema).jsonSchema
      }
    ])
  );
  return Object.fromEntries(e);
}
function He(t) {
  return Object.fromEntries(
    Object.entries(t).map(([e, o]) => [
      e,
      Se({
        ...o,
        inputSchema: N(o.inputSchema),
        outputSchema: N(o.outputSchema)
      })
    ])
  );
}
const Fe = {
  "mistral.chat": {
    mode: "auto"
  },
  "google.generative-ai": {
    mode: "auto"
  },
  "groq.chat": {
    providerOptions: {
      groq: {
        structuredOutputs: !1
      }
    }
  }
};
function jt(t) {
  return Fe[t.provider] || {};
}
class Dt {
  constructor(e) {
    this.opts = e;
  }
  /**
   * 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 ke({
      model: r,
      system: this.opts.systemPrompt,
      messages: await we(
        Re(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 = await He(n);
    if (r)
      return await this.streamText(e, a);
    throw new Error("Not implemented (generateText)");
  }
  reconnectToStream() {
    throw new Error("Not implemented");
  }
}
function We() {
  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 Ve(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 de(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 Ye(t) {
  return de(Ve(t));
}
async function* Xe(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* Ze(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* Ge(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* Ke(t, e) {
  const o = Ge(
    t,
    e
  );
  yield* Ze(
    o,
    (n) => {
      if (!n.isPossiblyPartial)
        throw new J(
          `Invalid operation. ${L(n.operation.error)}`,
          n,
          {
            cause: n.operation.error
          }
        );
    }
  );
}
function Qe(t, e, o) {
  return Ye(
    Ke(
      Xe(
        de(t),
        o
      ),
      e
    )
  );
}
async function et(t, e, o, r) {
  const n = new Je(t, r), a = We(), i = a.output.pipeTo(n.writable), s = /* @__PURE__ */ new Map();
  let c = !0;
  const d = e["~registerMessagesCallback"](() => {
    tt(e, (S) => {
      if (!s.has(S.toolCallId)) {
        const y = ot(
          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 J)
      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: L(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 tt(t, e) {
  var o;
  for (const r of ((o = t.lastMessage) == null ? void 0 : o.parts) ?? []) {
    if (!ge(r) || r.type.replace("tool-", "") !== "applyDocumentOperations")
      continue;
    const a = r.toolCallId, i = e({
      toolName: r.type.replace("tool-", ""),
      toolCallId: a
    });
    rt(r, i);
  }
}
function ot(t, e, o) {
  const r = new TransformStream(), n = Qe(
    r.readable,
    t,
    { toolCallId: o }
  );
  return {
    // stream,
    writer: r.writable.getWriter(),
    complete: !1,
    // executor,
    operationsStream: n,
    toolName: e,
    toolCallId: o
  };
}
function rt(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 Lt(t, e, o, r, n) {
  const a = o ?? t.lastMessage;
  if (!a)
    throw new Error("No message to send");
  a.metadata = X(a.metadata, {
    documentState: e.documentState
  });
  const i = et(
    e.streamTools,
    t,
    e.onStart,
    n
  );
  return r = X(r, {
    metadata: {
      source: "blocknote-ai"
    },
    body: {
      toolDefinitions: await ze(
        Ue(e.streamTools)
      )
    }
  }), await t.sendMessage(o, r), await i;
}
function pe(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 q(t) {
  return t.map((e) => typeof e == "object" && e && "id" in e ? {
    ...e,
    id: `${e.id}$`
  } : e);
}
function R(t) {
  return async (e) => e.selectedBlocks ? await st(
    e.editor,
    t,
    {
      selectedBlocks: e.selectedBlocks
    }
  ) : await nt(
    e.editor,
    t,
    {
      excludeBlockIds: e.emptyCursorBlockToDelete ? [e.emptyCursorBlockToDelete] : void 0
    }
  );
}
async function nt(t, e, o) {
  const r = v(t.document).length === 0, n = t.getTextCursorPosition().block.id, a = v(t.document, {
    cursorBlockId: n
  }), i = await M(
    O(a),
    async (u) => e(t, u)
  ), c = pe(t, i).filter(
    (u) => "cursor" in u || !(o.excludeBlockIds || []).includes(u.id)
  );
  return {
    selection: !1,
    blocks: q(c),
    isEmptyDocument: r
  };
}
async function st(t, e, o) {
  const r = v(t.document).length === 0, n = await M(
    O(o.selectedBlocks),
    async (i) => e(t, i)
  ), a = q(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 at(t) {
  let e, o = !1;
  return t.descendants((r, n) => o ? !1 : (r.isText && (o = !0, e = n), !0)), e;
}
function A(t) {
  var a;
  const e = Pe(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 ue(t.mapping.maps.slice(0, i)).invert();
    if (s.structure) {
      if (s instanceof P) {
        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 Ae) {
        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 P))
      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 = at(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 Ne(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 = Me.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 z(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 ve(t.type);
}
function H(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 it(t, e, o) {
  const r = new E(e);
  for (const i of t) {
    const s = new P(
      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 P(
        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 K = (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 j(t, e, o = !1, r, n) {
  const a = Oe(t.id, e), i = new E(e);
  Ee(
    i,
    a.posBeforeNode,
    t.block,
    r,
    n
  );
  let s = i.doc, c = G.create(
    e,
    void 0,
    K(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 P(l.toB, l.toB, b)
      ), s = i.doc, c = G.create(
        c.startDoc,
        void 0,
        K(c.startDoc, s)
      ), c = c.addSteps(s, i.mapping.maps, 0);
    }
  }
  const d = [], u = _e(
    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++;
    }
  }
  it(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 P(
        f.fromA,
        f.toA,
        p,
        f.type === "node-type-or-attr-update"
      )
    );
  }
  return d;
}
class fe extends Error {
  constructor(e, o) {
    super(e, o), this.name = "AbortError";
  }
}
function ct(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 F(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 = ct(
          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 && U(
              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 = j(
                  {
                    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 = A(p), b = b.filter(
                  (h) => h.type !== "select"
                );
              } else {
                const m = c.position === "after" ? a[c.referenceId] : void 0, S = xe(
                  p,
                  [f],
                  l > 0 ? n[l - 1] : m || c.referenceId,
                  l > 0 ? "after" : c.position
                );
                n.push(...S.map((y) => y.id)), b = A(p);
              }
              for (const m of b) {
                if (s != null && s.aborted)
                  throw new fe("Operation was aborted");
                o.withDelays && await z(m), e.transact((S) => {
                  H(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 W(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: Z(e, o.updateSelection.from),
          to: Z(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 = j(
              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 = A(S);
            for (const k of y) {
              if (c != null && c.aborted)
                throw new fe("Operation was aborted");
              o.withDelays && await z(k), e.transact((w) => {
                H(w, k);
              }), (h = o.onBlockUpdate) == null || h.call(o, d.id);
            }
            return !0;
          }
        };
      }
    };
  };
}
const V = (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;
      Be(n, [r.id], []);
      const a = A(n);
      for (const s of a)
        e.withDelays && await z(s), t.transact((c) => {
          H(c, s);
        }), (i = e.onBlockUpdate) == null || i.call(e, r.id);
      return !0;
    }
  })
});
function Q(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 _(t) {
  let e;
  if ($e(t.prosemirrorState, (o) => {
    e = o;
  }), !e)
    throw new Error("applySuggestionsTr is not set");
  return e;
}
function $(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 ee(t, e) {
  var d;
  const o = _(e), r = ce(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, j(
    {
      id: t,
      block: s
    },
    o.doc
  ).length)
    throw new Error("html diff", {
      cause: {
        html: n,
        htmlBlock: s
      }
    });
  return $(e, o);
}
function te(t) {
  return typeof t != "string" ? {
    ok: !1,
    error: "block must be a string"
  } : {
    ok: !0,
    value: t
  };
}
const B = {
  add: F({
    description: "Insert new blocks",
    schema: {
      block: {
        type: "string",
        description: "html of block (MUST be a single, VALID HTML element)"
      }
    },
    validateBlock: te,
    rebaseTool: ee,
    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 ? Q(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: W({
    description: "Update a block",
    schema: {
      block: {
        type: "string",
        description: "html of block (MUST be a single HTML element)"
      }
    },
    validateBlock: te,
    rebaseTool: ee,
    toJSONToolCall: async (t, e) => {
      const o = e.isPossiblyPartial ? Q(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: V
};
function lt(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 ut = `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\`
---
 `, dt = {
  /**
   * Function to get the stream tools that can apply HTML block updates to the editor
   */
  getStreamToolsProvider: (t = {}) => ({
    getStreamTools: (e, o, r) => lt(
      e,
      t.withDelays ?? !0,
      t.defaultStreamTools,
      o,
      r
    )
  }),
  systemPrompt: ut,
  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: R(
    async (t, e) => t.blocksToHTMLLossy([e])
  )
};
function pt(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 ft(t) {
  return {
    type: "object",
    properties: Object.fromEntries(
      Object.entries(t).map(([e, o]) => [
        e,
        {
          type: o.propSchema
        }
      ])
    ),
    additionalProperties: !1
  };
}
function mt() {
  return {
    type: "object",
    properties: {
      type: {
        type: "string",
        enum: ["text"]
      },
      text: {
        type: "string"
      },
      styles: {
        $ref: "#/$defs/styles"
      }
    },
    additionalProperties: !1,
    required: ["type", "text"]
  };
}
function me(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 ht(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: me(o.propSchema)
        },
        additionalProperties: !1,
        required: ["type", ...o.content === "styled" ? ["content"] : []]
      })
    }
  };
}
function yt(t) {
  return {
    anyOf: pt(
      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: me(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 bt(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 le[n[0]] > "u"
              )
            )
          }
        ])
      ), this;
    },
    get() {
      return e;
    }
  };
}
function oe(t) {
  return t = bt(t).removeFileBlocks().removeDefaultProps().get(), {
    $defs: {
      styles: ft(t.styleSchema),
      styledtext: mt(),
      inlinecontent: ht(
        t.inlineContentSchema
      ),
      block: yt(t.blockSchema)
    }
  };
}
function he(t, e) {
  return !e.schema.inlineContentSchema[t.type] || Ce(t) && !("text" in t) ? !1 : Ie(t) ? !("content" in t) || !("href" in t) ? !1 : he(t.content, e) : !0;
}
function re(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) => he(a, e)))
      return {
        ok: !1,
        error: "block content must be an array of inline content"
      };
  }
  return {
    ok: !0,
    value: t
  };
}
const C = {
  add: F({
    description: "Insert new blocks",
    schema: (t) => ({
      block: {
        $ref: "#/$defs/block"
      },
      ...oe(t.schema)
    }),
    validateBlock: re,
    rebaseTool: async (t, e) => $(e, _(e)),
    toJSONToolCall: async (t, e) => e.operation
  }),
  update: W({
    description: "Update a block, the new block will replace the existing block.",
    schema: (t) => ({
      block: {
        $ref: "#/$defs/block"
      },
      ...oe(t.schema)
    }),
    validateBlock: re,
    rebaseTool: async (t, e) => $(e, _(e)),
    toJSONToolCall: async (t, e) => {
      const o = Object.fromEntries(
        Object.entries(le).map(([r, n]) => [r, n.default])
      );
      return {
        ...e.operation,
        block: {
          ...e.operation.block,
          props: {
            ...o,
            ...e.operation.block.props
          }
        }
      };
    }
  }),
  delete: V
};
function St(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 kt = `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\`
---
 `, wt = {
  /**
   * Function to get the stream tools that can apply JSON block updates to the editor
   */
  getStreamToolsProvider: (t = {}) => ({
    getStreamTools: (e, o, r) => St(
      e,
      t.withDelays ?? !0,
      t.defaultStreamTools,
      o,
      r
    )
  }),
  tools: C,
  systemPrompt: kt,
  defaultDocumentStateBuilder: R(
    async (t, e) => ({
      ...e,
      id: void 0,
      // don't pass id, because LLM should use `jsonSelectedBlocks` for this
      children: void 0
    })
  )
};
async function ne(t, e) {
  const o = _(e), r = await e.blocksToMarkdownLossy([ce(o.doc, t)]), n = await e.tryParseMarkdownToBlocks(r), a = j(
    {
      id: t,
      block: n[0]
    },
    o.doc
  ), i = new ue();
  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 $(e, o);
}
function se(t) {
  return typeof t != "string" ? {
    ok: !1,
    error: "block must be a string"
  } : {
    ok: !0,
    value: t
  };
}
const I = {
  add: F({
    description: "Insert new blocks",
    schema: {
      block: {
        $ref: "#/$defs/block"
      },
      $defs: {
        block: { type: "string", description: "markdown of block" }
      }
    },
    validateBlock: se,
    rebaseTool: ne,
    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: W({
    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: se,
    rebaseTool: ne,
    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: V
};
function gt(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 Tt = `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\`
---
 `, Pt = {
  /**
   * Function to get the stream tools that can apply Markdown block updates to the editor
   */
  getStreamToolsProvider: (t = {}) => ({
    getStreamTools: (e, o, r) => gt(
      e,
      t.withDelays ?? !0,
      t.defaultStreamTools,
      o,
      r
    )
  }),
  systemPrompt: Tt,
  tools: I,
  defaultDocumentStateBuilder: R(
    async (t, e) => t.blocksToMarkdownLossy([e])
  )
}, ae = {
  _experimental_json: wt,
  _experimental_markdown: Pt,
  html: dt
}, Ut = {
  addCursorPosition: pe,
  flattenBlocks: O,
  suffixIDs: q,
  trimEmptyBlocks: v,
  convertBlocks: M
};
function Jt(t) {
  if (!t.dictionary.ai)
    throw new Error("AI dictionary not found");
  return t.dictionary.ai;
}
const qt = (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 {
  Dt as C,
  Fe as P,
  Je as S,
  ae as a,
  $t as b,
  Jt as c,
  Le as d,
  Ue as e,
  qt as f,
  _ as g,
  jt as h,
  et as i,
  Re as j,
  He as k,
  R as m,
  Qe as o,
  Ut as p,
  Lt as s,
  ze as t
};
//# sourceMappingURL=client-De9NkxJ-.js.map
