Skip to content

How it works

LeFlux is built on four ideas. Understanding them helps you debug, customize, and trust the agent.

1. Universal indexing

The widget can’t write CSS selectors — different sites have different markup, and selectors break the moment a host site re-renders. Instead, on every turn, the widget scans the page and assigns a fresh numeric id to every interactive element (links, buttons, inputs, selects, role-based widgets). Each id maps to a real DOM element via a data-leflux-id attribute.

The agent receives a list like:

[
{ "id": 5, "type": "a", "text": "Contact", "href": "/#contact", "parent": "nav" },
{ "id": 12, "type": "input", "text": null, "placeholder": "Your name", "required": true, "parent": "Drop a Message" },
{ "id": 13, "type": "input", "text": null, "placeholder": "Email", "required": true, "parent": "Drop a Message" },
{ "id": 19, "type": "button", "text": "Send", "parent": "Drop a Message" }
]

When the agent emits click 12 the widget looks up element 12, scrolls it into view, checks for blocking overlays, and executes the click. Same model for every site — no per-tenant configuration.

2. Iterative loop

A single visitor message doesn’t always map to a single action. “Hire Fahad” might mean: navigate to home → scroll to contact section → ask the visitor for their name and email → fill the form → click submit.

The loop runs server-side, up to 30 iterations:

[visitor message]
LLM call → { message, action } ────┐
↓ │
widget executes action ────────────┤
↓ │
new page context ──────────────────┘
(repeat until task_complete or guard fires)

Each iteration the LLM sees:

  • The latest page context (URL, indexedElements, visibleText, forms, previouslyFilledFields).
  • The site’s Sitemap + crawled knowledge.
  • The state trace of the previous action (“URL unchanged at /x — try a different strategy”).

Guards break the loop when progress stalls — same elementId clicked 3x, same URL navigated 2x in a row, scroll-only emissions 3x.

3. Knowledge-base injection

A Playwright crawler walks your site (BFS, configurable depth + cap) and stores for each page:

  • canonical URL + pathname
  • page title + meta description
  • headings (h1–h3)
  • the visible text body
  • structured signals (links, contact info via regex, prices, FAQ pairs)

On every LLM call, the server:

  1. Ranks crawled pages by relevance to the visitor’s latest message.
  2. Injects the top-K pages’ summaries, headings, notes, AND raw body text excerpts as a “Cross-page knowledge” block at the top of the prompt.
  3. Extracts emails + phone numbers from all top-K pages and injects them as a “Site contacts” block.

For info questions (“what’s your phone number”) the agent answers from the knowledge base inline — zero navigation. For navigational requests (“take me to pricing”) the agent navigates using a URL pulled verbatim from the Sitemap.

4. Action primitives

The agent emits actions, not code. Five primitives:

ActionArgs
clickelementId
typeelementId, inputData
selectelementId, inputData (must match an option)
scroll_toelementId
navigateurl (path or full URL — pulled from Sitemap)
waitwaitDuration (ms)

Compose them into a sequence (execute_generic_sequence) for atomic multi-step flows. Form submit, for example, lands as a single sequence:

{
"type": "execute_generic_sequence",
"steps": [
{ "action": "type", "elementId": 12, "inputData": "Ahmed Khan" },
{ "action": "type", "elementId": 13, "inputData": "ahmed@example.com" },
{ "action": "type", "elementId": 14, "inputData": "Hi, interested in pricing." },
{ "action": "click", "elementId": 19, "description": "submit" }
]
}

The widget validates each step, retries on transient failures (overlay, async dropdown), and reports the result back to the server which feeds the next iteration.

Where the magic happens

ConcernLives in
Element scanning + indexingwidget/src/dom-inspector.js
Action execution + retrywidget/src/action-executor.js
Iterative LLM loopserver/src/llm-integration.js
Loop guards + state tracesserver/src/websocket-handler.js
Knowledge-base rankingserver/src/page-context.js
Site crawl (BFS + extraction)crawler/src/crawl.js

Next → Install on any site.