Files
zeekay acaeda400a Eradicate OpenClaw — resolve merge conflicts and finish the rebrand
Three coordinated things:

1. Resolve the committed upstream/main merge conflicts. 94 files were
   sitting with raw <<<<<<< HEAD ... >>>>>>> upstream/main blocks. Every
   conflict had HanzoBot/Bot on HEAD and OpenClaw on upstream. Resolved
   by keeping HEAD everywhere — 540 conflict blocks.

2. Rewrite remaining OpenClaw text refs.
     OPENCLAW   → HANZO_BOT
     OpenClaw   → HanzoBot          (PascalCase type identifiers)
     openclaw   → bot               (codebase convention — botToken,
                                    botUsername etc.; avoids invalid
                                    hyphenated JS identifiers)
     openclaw[_]/openclaw[A-Z] → bot[_]/bot[A-Z]   (compound)
     ai.openclaw.x → ai.hanzo.bot.x  (JVM package path)

3. Delete or rename openclaw-named file paths (116 of them). Dead
   duplicates with a Bot-named canonical from the partial migration:
   deleted. Otherwise renamed.
     ai/openclaw/**           → deleted (ai/hanzo/bot/** canonical)
     Sources/OpenClaw*/       → deleted (Sources/Bot* canonical)
     Tests/OpenClawIPCTests/  → deleted (Tests/BotIPCTests canonical)
     OpenClawKit/             → deleted (BotKit canonical)
     openclaw-tools.*.ts      → deleted (bot-tools.*.ts canonical)
     openclaw-root.ts etc.    → deleted (bot-root.ts canonical)
     types.openclaw.ts        → deleted (types.bot.ts canonical)
     extensions/*/openclaw.plugin.json → renamed hanzo-bot.plugin.json
     docs/start/openclaw.md   → renamed hanzo-bot.md (+ zh-CN)
     docs/assets/openclaw-*.png, whatsapp-openclaw*.jpg → deleted
     scripts/.../openclaw-*   → deleted (bot/hanzo-bot parallels)
     openclaw.mjs             → deleted (hanzo-bot.mjs is package.bin)

Then patched 65 broken JS/TS import strings where hanzo-bot had ended
up inside an import path ('./types.hanzo-bot.js' → './types.bot.js'
etc., since the on-disk filename uses the brand-neutral bot- prefix).

Pre-existing lint debt cleaned up to get oxlint --type-aware to 0/0:
removed the dead i18n test that referenced a path no longer existing;
defined the missing DIDConfig and WalletConfig types in types.base.ts
(they were imported but never declared); dropped unused imports;
collapsed redundant type assertion and a tautological meta.bot lookup
that the openclaw→bot rename made redundant.

The a2ui.bundle.js generated artifact is kept at its pre-rebrand
contents — it gets regenerated by 'pnpm canvas:a2ui:bundle' from
sources I cannot rebuild in this commit; the source side is clean.

Verified: 0 occurrences of openclaw (case-insensitive) in tree source
content, 0 file or directory paths with openclaw in the name; oxlint
--type-aware src test reports 0/0.
2026-05-11 17:56:29 -07:00

9.0 KiB
Raw Permalink Blame History

summary, read_when, title
summary read_when title
Agent session tools for listing sessions, fetching history, and sending cross-session messages
Adding or modifying session tools
Session Tools

Session Tools

Goal: small, hard-to-misuse tool set so agents can list sessions, fetch history, and send to another session.

Tool Names

  • sessions_list
  • sessions_history
  • sessions_send
  • sessions_spawn

Key Model

  • Main direct chat bucket is always the literal key "main" (resolved to the current agent’s main key).
  • Group chats use agent:<agentId>:<channel>:group:<id> or agent:<agentId>:<channel>:channel:<id> (pass the full key).
  • Cron jobs use cron:<job.id>.
  • Hooks use hook:<uuid> unless explicitly set.
  • Node sessions use node-<nodeId> unless explicitly set.

global and unknown are reserved values and are never listed. If session.scope = "global", we alias it to main for all tools so callers never see global.

sessions_list

List sessions as an array of rows.

Parameters:

  • kinds?: string[] filter: any of "main" | "group" | "cron" | "hook" | "node" | "other"
  • limit?: number max rows (default: server default, clamp e.g. 200)
  • activeMinutes?: number only sessions updated within N minutes
  • messageLimit?: number 0 = no messages (default 0); >0 = include last N messages

Behavior:

  • messageLimit > 0 fetches chat.history per session and includes the last N messages.
  • Tool results are filtered out in list output; use sessions_history for tool messages.
  • When running in a sandboxed agent session, session tools default to spawned-only visibility (see below).

Row shape (JSON):

  • key: session key (string)
  • kind: main | group | cron | hook | node | other
  • channel: whatsapp | telegram | discord | signal | imessage | webchat | internal | unknown
  • displayName (group display label if available)
  • updatedAt (ms)
  • sessionId
  • model, contextTokens, totalTokens
  • thinkingLevel, verboseLevel, systemSent, abortedLastRun
  • sendPolicy (session override if set)
  • lastChannel, lastTo
  • deliveryContext (normalized { channel, to, accountId } when available)
  • transcriptPath (best-effort path derived from store dir + sessionId)
  • messages? (only when messageLimit > 0)

sessions_history

Fetch transcript for one session.

Parameters:

  • sessionKey (required; accepts session key or sessionId from sessions_list)
  • limit?: number max messages (server clamps)
  • includeTools?: boolean (default false)

Behavior:

  • includeTools=false filters role: "toolResult" messages.
  • Returns messages array in the raw transcript format.
  • When given a sessionId, HanzoBot resolves it to the corresponding session key (missing ids error).

sessions_send

Send a message into another session.

Parameters:

  • sessionKey (required; accepts session key or sessionId from sessions_list)
  • message (required)
  • timeoutSeconds?: number (default >0; 0 = fire-and-forget)

Behavior:

  • timeoutSeconds = 0: enqueue and return { runId, status: "accepted" }.
  • timeoutSeconds > 0: wait up to N seconds for completion, then return { runId, status: "ok", reply }.
  • If wait times out: { runId, status: "timeout", error }. Run continues; call sessions_history later.
  • If the run fails: { runId, status: "error", error }.
  • Announce delivery runs after the primary run completes and is best-effort; status: "ok" does not guarantee the announce was delivered.
  • Waits via gateway agent.wait (server-side) so reconnects don't drop the wait.
  • Agent-to-agent message context is injected for the primary run.
  • Inter-session messages are persisted with message.provenance.kind = "inter_session" so transcript readers can distinguish routed agent instructions from external user input.
  • After the primary run completes, HanzoBot runs a reply-back loop:
    • Round 2+ alternates between requester and target agents.
    • Reply exactly REPLY_SKIP to stop the ping‑pong.
    • Max turns is session.agentToAgent.maxPingPongTurns (0–5, default 5).
  • Once the loop ends, HanzoBot runs the agent‑to‑agent announce step (target agent only):
    • Reply exactly ANNOUNCE_SKIP to stay silent.
    • Any other reply is sent to the target channel.
    • Announce step includes the original request + round‑1 reply + latest ping‑pong reply.

Channel Field

  • For groups, channel is the channel recorded on the session entry.
  • For direct chats, channel maps from lastChannel.
  • For cron/hook/node, channel is internal.
  • If missing, channel is unknown.

Security / Send Policy

Policy-based blocking by channel/chat type (not per session id).

{
  "session": {
    "sendPolicy": {
      "rules": [
        {
          "match": { "channel": "discord", "chatType": "group" },
          "action": "deny"
        }
      ],
      "default": "allow"
    }
  }
}

Runtime override (per session entry):

  • sendPolicy: "allow" | "deny" (unset = inherit config)
  • Settable via sessions.patch or owner-only /send on|off|inherit (standalone message).

Enforcement points:

  • chat.send / agent (gateway)
  • auto-reply delivery logic

sessions_spawn

Spawn a sub-agent run in an isolated session and announce the result back to the requester chat channel.

Parameters:

  • task (required)
  • label? (optional; used for logs/UI)
  • agentId? (optional; spawn under another agent id if allowed)
  • model? (optional; overrides the sub-agent model; invalid values error)
  • thinking? (optional; overrides thinking level for the sub-agent run)
  • runTimeoutSeconds? (defaults to agents.defaults.subagents.runTimeoutSeconds when set, otherwise 0; when set, aborts the sub-agent run after N seconds)
  • thread? (default false; request thread-bound routing for this spawn when supported by the channel/plugin)
  • mode? (run|session; defaults to run, but defaults to session when thread=true; mode="session" requires thread=true)
  • cleanup? (delete|keep, default keep)
  • sandbox? (inherit|require, default inherit; require rejects spawn unless the target child runtime is sandboxed)
  • attachments? (optional array of inline files; subagent runtime only, ACP rejects). Each entry: { name, content, encoding?: "utf8" | "base64", mimeType? }. Files are materialized into the child workspace at .hanzo-bot/attachments/<uuid>/. Returns a receipt with sha256 per file.
  • attachAs? (optional; { mountPath? } hint reserved for future mount implementations)

Allowlist:

  • agents.list[].subagents.allowAgents: list of agent ids allowed via agentId (["*"] to allow any). Default: only the requester agent.
  • Sandbox inheritance guard: if the requester session is sandboxed, sessions_spawn rejects targets that would run unsandboxed.

Discovery:

  • Use agents_list to discover which agent ids are allowed for sessions_spawn.

Behavior:

  • Starts a new agent:<agentId>:subagent:<uuid> session with deliver: false.
  • Sub-agents default to the full tool set minus session tools (configurable via tools.subagents.tools).
  • Sub-agents are not allowed to call sessions_spawn (no sub-agent → sub-agent spawning).
  • Always non-blocking: returns { status: "accepted", runId, childSessionKey } immediately.
  • With thread=true, channel plugins can bind delivery/routing to a thread target (Discord support is controlled by session.threadBindings.* and channels.discord.threadBindings.*).
  • After completion, HanzoBot runs a sub-agent announce step and posts the result to the requester chat channel.
    • If the assistant final reply is empty, the latest toolResult from sub-agent history is included as Result.
  • Reply exactly ANNOUNCE_SKIP during the announce step to stay silent.
  • Announce replies are normalized to Status/Result/Notes; Status comes from runtime outcome (not model text).
  • Sub-agent sessions are auto-archived after agents.defaults.subagents.archiveAfterMinutes (default: 60).
  • Announce replies include a stats line (runtime, tokens, sessionKey/sessionId, transcript path, and optional cost).

Sandbox Session Visibility

Session tools can be scoped to reduce cross-session access.

Default behavior:

  • tools.sessions.visibility defaults to tree (current session + spawned subagent sessions).
  • For sandboxed sessions, agents.defaults.sandbox.sessionToolsVisibility can hard-clamp visibility.

Config:

{
  tools: {
    sessions: {
      // "self" | "tree" | "agent" | "all"
      // default: "tree"
      visibility: "tree",
    },
  },
  agents: {
    defaults: {
      sandbox: {
        // default: "spawned"
        sessionToolsVisibility: "spawned", // or "all"
      },
    },
  },
}

Notes:

  • self: only the current session key.
  • tree: current session + sessions spawned by the current session.
  • agent: any session belonging to the current agent id.
  • all: any session (cross-agent access still requires tools.agentToAgent).
  • When a session is sandboxed and sessionToolsVisibility="spawned", HanzoBot clamps visibility to tree even if you set tools.sessions.visibility="all".