Skip to content

Call AI Models ​

Goal: call the PluginX AI gateway with LFModel — a button that streams an AI summary.

main.js

js
// ==UserScript==
// @name AI Page Summary
// @description Summarize the current page title with AI
// @match https://example.com/*
// @require dom
// @require model
// ==/UserScript==

LFDOM.ready(() => {
  const panel = LFDOM.createFloatingRoot({ id: "ai-summary" });
  panel.innerHTML =
    "<button id='lf-sum'>AI Summary</button><div id='lf-out' style='max-width:280px'></div>";

  panel.querySelector("#lf-sum").addEventListener("click", async () => {
    const out = panel.querySelector("#lf-out");
    out.textContent = "";
    try {
      const { models } = await LFModel.listModels();
      const chatModel = models.find((m) => m.kind === "chat");
      for await (const chunk of LFModel.chatStream({
        model: chatModel.id,
        messages: [{ role: "user", content: `Summarize this page title in one sentence: ${document.title}` }],
      })) {
        if (chunk.kind === "delta") out.textContent += chunk.data.choices?.[0]?.delta?.content ?? "";
      }
    } catch (error) {
      out.textContent = `Call failed: ${error.errorCode || error.message}`;
    }
  });
});

Key points ​

  • listModels() returns the models available to the current account; chat and image models share one list, so pick one with kind === "chat" — do not hard-code model IDs
  • chat() always returns the complete result in one go (stream: true is overridden to false); use chatStream() for incremental output
  • chatStream() returns an async iterable; for chunks with kind === "delta", chunk.data is an OpenAI stream chunk object and the incremental text is chunk.data.choices[0].delta.content
  • Errors are thrown from the loop as LFModelError; branch on errorCode (e.g. INSUFFICIENT_BALANCE, APP_BUDGET_EXHAUSTED)
  • Calls count against this app's budget; cost_points / charge_points are canonical (1 CNY = 200 points). Query it with getBudget() / getUsage()
  • Calls carry the PluginX login through the background; you cannot act as another app