> ## Documentation Index
> Fetch the complete documentation index at: https://docs.voiceblox.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Framework Node

> The central orchestrator that connects all components and drives the conversation.

export const AgentNodePreview = () => {
  const PURPLE = "hsl(262,83%,58%)";
  const RED = "hsl(5,82%,55%)";
  const [agentName, setAgentName] = useState("");
  const [language, setLanguage] = useState("en");
  const [interruption, setInterruption] = useState(true);
  const LANGS = ["en", "es", "fr", "de", "pt", "ja", "zh", "ko", "it", "nl", "hi", "ar", "pl", "tr"];
  const slots = [{
    id: "transfer_in",
    label: "Transfer",
    color: RED,
    optional: true
  }, {
    id: "llm_in",
    label: "LLM",
    color: "hsl(142,71%,45%)",
    optional: false
  }, {
    id: "tts_in",
    label: "TTS",
    color: "hsl(38,92%,50%)",
    optional: false
  }, {
    id: "stt_in",
    label: "STT",
    color: "hsl(199,89%,48%)",
    optional: false
  }, {
    id: "avatar_in",
    label: "Avatar",
    color: "hsl(326,78%,60%)",
    optional: true
  }, {
    id: "tools_in",
    label: "Tools",
    color: PURPLE,
    optional: true
  }];
  const sel = {
    width: "100%",
    padding: "4px 24px 4px 8px",
    border: "1px solid rgba(128,128,128,0.2)",
    borderRadius: "6px",
    fontSize: "12px",
    background: "rgba(128,128,128,0.06)",
    cursor: "pointer",
    outline: "none",
    appearance: "none",
    WebkitAppearance: "none"
  };
  return <div style={{
    display: "flex",
    justifyContent: "center",
    padding: "28px 24px",
    background: "rgba(128,128,128,0.06)",
    borderRadius: "12px",
    margin: "16px 0"
  }}>
      <div style={{
    position: "relative",
    width: "240px",
    borderRadius: "12px",
    border: "1px solid hsla(262,83%,58%,0.3)",
    background: "hsla(262,83%,58%,0.1)",
    boxShadow: "0 4px 24px -4px rgba(0,0,0,0.08),0 1px 2px rgba(0,0,0,0.04)",
    fontFamily: "-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif"
  }}>
        <div style={{
    position: "absolute",
    right: "-6px",
    top: "18px",
    width: "12px",
    height: "12px",
    borderRadius: "50%",
    background: RED,
    border: "2px solid white",
    zIndex: 10,
    boxShadow: "0 1px 3px rgba(0,0,0,0.2)"
  }} />
        <div style={{
    display: "flex",
    alignItems: "center",
    gap: "8px",
    padding: "8px 12px",
    borderBottom: "1px solid rgba(128,128,128,0.12)"
  }}>
          <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke={PURPLE} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
            <path d="M12 8V4H8" /><rect width="16" height="12" x="4" y="8" rx="2" /><path d="M2 14h2" /><path d="M20 14h2" /><path d="M15 13v2" /><path d="M9 13v2" />
          </svg>
          <span style={{
    fontSize: "14px",
    fontWeight: 600,
    flex: 1
  }}>Agent</span>
          <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{
    opacity: 0.3
  }}>
            <path d="m21.64 3.64-1.28-1.28a1.21 1.21 0 0 0-1.72 0L2.36 18.64a1.21 1.21 0 0 0 0 1.72l1.28 1.28a1.21 1.21 0 0 0 1.72 0L21.64 5.36a1.21 1.21 0 0 0 0-1.72Z" />
            <path d="m14 7 3 3" /><path d="M5 6v4" /><path d="M19 14v4" /><path d="M10 2v2" /><path d="M7 8H3" /><path d="M21 16h-4" /><path d="M11 3H9" />
          </svg>
        </div>
        <div style={{
    padding: "10px 12px",
    display: "flex",
    flexDirection: "column",
    gap: "8px"
  }}>
          <p style={{
    fontSize: "10px",
    color: "#888",
    margin: 0,
    lineHeight: 1.4
  }}>The brain of your voice agent — define personality, connect components</p>
          <div>
            <p style={{
    fontSize: "10px",
    color: "#888",
    fontWeight: 500,
    margin: "0 0 4px 0"
  }}>Inputs</p>
            <div style={{
    display: "flex",
    flexDirection: "column",
    gap: "4px"
  }}>
              {slots.map(s => <div key={s.id} style={{
    position: "relative",
    display: "flex",
    alignItems: "center",
    gap: "8px",
    padding: "6px 8px",
    borderRadius: "4px",
    background: s.optional ? "transparent" : "rgba(128,128,128,0.1)",
    border: s.optional ? "1px dashed rgba(128,128,128,0.25)" : "none"
  }}>
                  <div style={{
    position: "absolute",
    left: "-18px",
    top: "50%",
    transform: "translateY(-50%)",
    width: "12px",
    height: "12px",
    borderRadius: "50%",
    background: s.color,
    border: "2px solid white",
    boxShadow: "0 1px 3px rgba(0,0,0,0.2)",
    zIndex: 10
  }} />
                  <span style={{
    fontSize: "12px",
    fontWeight: 500,
    color: s.color
  }}>{s.label}</span>
                  {s.optional && <span style={{
    marginLeft: "auto",
    fontSize: "9px",
    color: "#aaa"
  }}>optional</span>}
                </div>)}
            </div>
          </div>
          <div>
            <label style={{
    fontSize: "10px",
    color: "#888",
    display: "block",
    marginBottom: "3px"
  }}>Agent Name</label>
            <input type="text" placeholder="Luna" value={agentName} onChange={e => setAgentName(e.target.value)} style={{
    width: "100%",
    padding: "4px 8px",
    border: "1px solid rgba(128,128,128,0.2)",
    borderRadius: "6px",
    fontSize: "12px",
    background: "rgba(128,128,128,0.06)",
    outline: "none",
    boxSizing: "border-box"
  }} />
          </div>
          <div>
            <label style={{
    fontSize: "10px",
    color: "#888",
    display: "block",
    marginBottom: "3px"
  }}>Language</label>
            <div style={{
    position: "relative"
  }}>
              <select value={language} onChange={e => setLanguage(e.target.value)} style={sel}>
                {LANGS.map(l => <option key={l} value={l}>{l}</option>)}
              </select>
              <svg style={{
    position: "absolute",
    right: "7px",
    top: "50%",
    transform: "translateY(-50%)",
    pointerEvents: "none"
  }} width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="#aaa" strokeWidth="2"><polyline points="6 9 12 15 18 9" /></svg>
            </div>
          </div>
          <label style={{
    display: "flex",
    alignItems: "center",
    gap: "8px",
    padding: "6px 8px",
    borderRadius: "6px",
    border: `1px solid ${interruption ? "rgba(130,111,252,0.4)" : "rgba(128,128,128,0.2)"}`,
    background: interruption ? "rgba(130,111,252,0.1)" : "rgba(128,128,128,0.05)",
    cursor: "pointer"
  }}>
            <input type="checkbox" checked={interruption} onChange={e => setInterruption(e.target.checked)} style={{
    accentColor: PURPLE
  }} />
            <span style={{
    fontSize: "12px",
    fontWeight: 500,
    color: interruption ? PURPLE : "inherit"
  }}>Allow interruption</span>
          </label>
        </div>
      </div>
    </div>;
};

# Framework Node

The Framework node is the heart of every Voiceblox flow. It receives all component connections, acts as the entry point for the conversation step chain, and determines the runtime.

Every flow must have **exactly one** Framework node.

<AgentNodePreview />

## Providers

| Provider  | Status         |
| --------- | -------------- |
| `livekit` | ✅ Stable       |
| `pipecat` | 🔜 Coming soon |

## Parameters

| Parameter           | Type | Default   | Description                                                                                        |
| ------------------- | ---- | --------- | -------------------------------------------------------------------------------------------------- |
| `provider`          | enum | `livekit` | Runtime framework (`livekit`)                                                                      |
| `interruption_mode` | enum | `off`     | Interruption: `off` (disabled) or `on` (adaptive ML-based detection for cascade, VAD for realtime) |

## Input handles

| Handle        | Type      | Max connections | Description                            |
| ------------- | --------- | --------------- | -------------------------------------- |
| `persona_in`  | persona   | 1               | Agent identity and system prompt       |
| `llm_in`      | llm       | 1               | Language model                         |
| `tts_in`      | tts       | 1               | Text-to-speech engine                  |
| `stt_in`      | stt       | 1               | Speech-to-text engine                  |
| `avatar_in`   | avatar    | 1               | Visual avatar (optional)               |
| `transfer_in` | framework | unlimited       | Incoming transfers from Transfer nodes |
| `tools_in`    | context   | unlimited       | MCP servers and Exa search tools       |

## Output handle

| Handle   | Type    | Description                |
| -------- | ------- | -------------------------- |
| `output` | control | Connects to the Start node |

## Interruption behavior

The `interruption_mode` parameter controls how the agent handles user speech while it is speaking:

* **Off** — The agent cannot be interrupted. Useful for scripted announcements or compliance-sensitive flows.
* **On** — The agent can be interrupted by the user. For cascade agents, this uses adaptive ML-based interruption handling that distinguishes true interruptions from conversational backchanneling (e.g. "uh-huh", "okay"). For realtime agents, this uses VAD-based interruption detection.

<Warning>
  A flow without a Persona, LLM, TTS, and STT connected to the Framework node will fail to run.
</Warning>
