Jump to content

Connect SuperML | Leeroopedia MCP: Equip your AI agents with best practices, code verification, and debugging knowledge. Powered by Leeroo — building Organizational Superintelligence. Contact us at founders@leeroo.com.

Implementation:Openclaw Openclaw BuildEmbeddedRunPayloads

From Leeroopedia


Knowledge Sources
Domains Agent_Runtime, Messaging
Last Updated 2026-02-06 12:00 GMT

Overview

Concrete functions for constructing reply payloads from LLM output and dispatching them to channels, provided by the OpenClaw agent runtime.

Description

This implementation covers two complementary functions that together handle the reply delivery pipeline:

buildEmbeddedRunPayloads (in src/agents/pi-embedded-runner/run/payloads.ts) -- Transforms the raw outputs of an LLM inference run into an ordered array of reply payloads. It processes error text from the last assistant message, inline tool result metadata, reasoning/thinking text, assistant text segments (with reply directive parsing), and tool error information. The function applies deduplication to avoid surfacing raw API errors that are already covered by formatted error messages, and filters out silent replies and empty payloads.

createReplyDispatcher (in src/auto-reply/reply/reply-dispatcher.ts) -- Creates a serialized dispatch queue that channel handlers use to deliver reply payloads in order. The dispatcher provides three enqueue methods (sendToolResult, sendBlockReply, sendFinalReply) and a waitForIdle method. Each payload is normalized (response prefix applied, heartbeat tokens stripped, empty payloads filtered) before entering the promise chain for sequential delivery. Human-like delays are injected between block replies when configured.

Together, these functions form the complete path from raw LLM output to channel-delivered messages.

Usage

buildEmbeddedRunPayloads is called at the end of runEmbeddedPiAgent to construct the final payloads from accumulated assistant texts and tool metadata. createReplyDispatcher is called by channel handlers to set up the delivery pipeline before starting inference, and the dispatcher's methods are passed as callbacks to the inference engine.

Code Reference

Source Location

  • Repository: openclaw
  • File: src/agents/pi-embedded-runner/run/payloads.ts (lines 23-255) and src/auto-reply/reply/reply-dispatcher.ts (lines 99-162)

Signature

// payloads.ts
export function buildEmbeddedRunPayloads(params: {
  assistantTexts: string[];
  toolMetas: ToolMetaEntry[];
  lastAssistant: AssistantMessage | undefined;
  lastToolError?: { toolName: string; meta?: string; error?: string };
  config?: OpenClawConfig;
  sessionKey: string;
  verboseLevel?: VerboseLevel;
  reasoningLevel?: ReasoningLevel;
  toolResultFormat?: ToolResultFormat;
  inlineToolResultsAllowed: boolean;
}): Array<{
  text?: string;
  mediaUrl?: string;
  mediaUrls?: string[];
  replyToId?: string;
  isError?: boolean;
  audioAsVoice?: boolean;
  replyToTag?: boolean;
  replyToCurrent?: boolean;
}>

// reply-dispatcher.ts
export function createReplyDispatcher(options: ReplyDispatcherOptions): ReplyDispatcher

Import

import { buildEmbeddedRunPayloads } from "../agents/pi-embedded-runner/run/payloads.js";
import { createReplyDispatcher } from "../auto-reply/reply/reply-dispatcher.js";

I/O Contract

Inputs (buildEmbeddedRunPayloads)

Name Type Required Description
assistantTexts string[] Yes Accumulated text segments from the assistant across all turns.
toolMetas ToolMetaEntry[] Yes Tool execution metadata entries ({ toolName, meta? }) for inline result formatting.
lastAssistant undefined Yes The final assistant message from the inference run, used for error text extraction and fallback text.
lastToolError { toolName: string; meta?: string; error?: string } No The last tool error encountered, surfaced when no user-facing reply exists.
config OpenClawConfig No Runtime configuration for error formatting.
sessionKey string Yes Session key for error context.
verboseLevel VerboseLevel No Controls whether inline tool results are included ("off" suppresses them).
reasoningLevel ReasoningLevel No When "on", includes reasoning/thinking text in the output.
toolResultFormat ToolResultFormat No "markdown" or "plain" for tool result formatting.
inlineToolResultsAllowed boolean Yes Whether inline tool results should be emitted (channel capability flag).

Inputs (createReplyDispatcher)

Name Type Required Description
deliver (payload: ReplyPayload, info: { kind: ReplyDispatchKind }) => Promise<void> Yes The actual delivery function that sends a payload to the channel.
responsePrefix string No Text to prepend to the first reply payload.
responsePrefixContext ResponsePrefixContext No Static context for response prefix template interpolation.
responsePrefixContextProvider () => ResponsePrefixContext No Dynamic context provider called at normalization time.
onHeartbeatStrip () => void No Callback when a heartbeat token is stripped from a payload.
onIdle () => void No Callback when all pending deliveries have completed.
onError (err, info) => void No Error handler for failed deliveries.
onSkip (payload, info) => void No Callback when a payload is filtered during normalization.
humanDelay HumanDelayConfig No Configuration for human-like delays between block replies.

Outputs (buildEmbeddedRunPayloads)

Name Type Description
(return) Array<{ text?, mediaUrl?, mediaUrls?, replyToId?, isError?, audioAsVoice?, replyToTag?, replyToCurrent? }> Ordered array of reply payloads ready for dispatch.

Outputs (createReplyDispatcher)

Name Type Description
sendToolResult (payload: ReplyPayload) => boolean Enqueues a tool result payload. Returns true if enqueued, false if filtered.
sendBlockReply (payload: ReplyPayload) => boolean Enqueues a block (streaming chunk) reply. Returns true if enqueued, false if filtered.
sendFinalReply (payload: ReplyPayload) => boolean Enqueues the final reply payload. Returns true if enqueued, false if filtered.
waitForIdle () => Promise<void> Resolves when all pending deliveries have completed.
getQueuedCounts () => Record<ReplyDispatchKind, number> Returns counts of enqueued payloads by kind (tool, block, final).

Usage Examples

Building Payloads

import { buildEmbeddedRunPayloads } from "../agents/pi-embedded-runner/run/payloads.js";

const payloads = buildEmbeddedRunPayloads({
  assistantTexts: ["Here is the file listing:\n- README.md\n- package.json"],
  toolMetas: [{ toolName: "exec", meta: "ls -la" }],
  lastAssistant: assistantMessage,
  sessionKey: "agent:default:telegram:dm:12345",
  verboseLevel: "on",
  toolResultFormat: "markdown",
  inlineToolResultsAllowed: true,
});

for (const payload of payloads) {
  console.log(payload.text);
}

Creating a Dispatcher

import { createReplyDispatcher } from "../auto-reply/reply/reply-dispatcher.js";

const dispatcher = createReplyDispatcher({
  deliver: async (payload, { kind }) => {
    await telegramBot.sendMessage(chatId, payload.text ?? "");
  },
  responsePrefix: "[Bot] ",
  onIdle: () => {
    console.log("All replies delivered");
  },
  onError: (err, { kind }) => {
    console.error(`Failed to deliver ${kind} reply:`, err);
  },
  humanDelay: { mode: "on" },
});

// During inference, enqueue replies as they arrive
dispatcher.sendToolResult({ text: "Ran `ls`: 5 files found" });
dispatcher.sendFinalReply({ text: "Here are the files in your directory." });

// Wait for all deliveries to complete
await dispatcher.waitForIdle();

Related Pages

Implements Principle

Uses Heuristic

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment