Skip to content

feat(sessions): Auto-inject From:/To: identity headers in agent-to-agent messages#7516

Open
RusDyn wants to merge 2 commits intoopenclaw:mainfrom
RusDyn:feature/sessions-send-sender-header
Open

feat(sessions): Auto-inject From:/To: identity headers in agent-to-agent messages#7516
RusDyn wants to merge 2 commits intoopenclaw:mainfrom
RusDyn:feature/sessions-send-sender-header

Conversation

@RusDyn
Copy link

@RusDyn RusDyn commented Feb 2, 2026

Summary

When agents communicate via sessions_send, recipient agents currently see anonymous messages with no indication of who sent them. This PR automatically injects From: and To: headers using agent display names from config.

Before:
Agent-to-agent message context:
Agent 1 (requester) session: agent:landing.
Agent 1 (requester) channel: #landing-builder.
Agent 2 (target) session: agent:openclaw.

The Stripe webhook is deployed! Here's what you need to configure...

After:
Agent-to-agent message context:
From: Tessa (landing), session: agent:landing.
From channel: #landing-builder.
To: Leo (openclaw), session: agent:openclaw.

The Stripe webhook is deployed! Here's what you need to configure...

Motivation

In multi-agent setups, agents frequently message each other via sessions_send. Without identity headers, recipients can't tell if a message came from the supervisor, a peer agent, or a subagent — leading to confusion about who said what.

This came up in my 9-agent team where an agent (Tessa) contacted another agent (Leo), but Leo couldn't identify the sender and assumed it was the supervisor (Adam).

Related: #15778 (expose subagent ID)

Changes

  • sessions-send-helpers.ts: Added buildAgentLabel() helper and updated buildAgentToAgentMessageContext() to include From:/To: labels
  • sessions-send-tool.ts: Pass config to enable name resolution

Testing

  • Tested locally with multi-agent OpenClaw setup (9 agents)
  • Verified headers appear correctly in recipient's message context
  • Confirmed graceful fallback when display name not configured (uses agentId)

AI Disclosure 🤖

  • AI-assisted: Yes (Claude helped with code review and this PR description)
  • Testing level: Fully tested in production multi-agent environment
  • I understand what the code does: Yes, I'm the one who identified the problem and designed the solution

Greptile Overview

Greptile Summary

This PR enhances sessions_send agent-to-agent messaging by auto-injecting identity context into the recipient system prompt. It derives requester/target agent IDs from session keys, resolves optional display names from config, and formats the injected context as From: / To: plus channel/session information. The send tool now passes the loaded config into the helper so labels can be resolved consistently.

Confidence Score: 4/5

  • This PR is generally safe to merge; changes are localized to message-context formatting and config plumbing.
  • Reviewed both touched files and the only notable concern is over-aggressive sanitization of configured display names; behavior otherwise appears consistent with existing session-key resolution and tool flow.
  • src/agents/tools/sessions-send-helpers.ts

…ages

Agents now automatically identify themselves when using sessions_send.
Headers include display name from config (e.g., "From: Adam (supervisor)").

Fixes the "anonymous message" problem where recipients couldn't tell
who sent the message in multi-agent setups.
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 file reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

  - Remove unreachable "unknown" branch from buildAgentLabel (agentId is
    always resolved to a string by resolveAgentIdFromSessionKey)
  - Sanitize agent names: collapse newlines to spaces, strip parentheses
    to prevent header formatting issues and prompt injection
  - Gate requesterLabel computation on requesterAgentId being defined
@openclaw-barnacle openclaw-barnacle bot added the agents Agent runtime and tooling label Feb 2, 2026
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 file reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 3, 2026

Additional Comments (1)

src/agents/tools/sessions-send-tool.ts
requesterInternalKey can be undefined (it’s derived from opts?.agentSessionKey and you guard it earlier), but resolveAgentIdFromSessionKey(requesterInternalKey) is called unconditionally here. If resolveAgentIdFromSessionKey doesn’t accept undefined, this will throw at runtime for non-agent callers of sessions_send (e.g. when invoked from main/CLI context without opts.agentSessionKey). Consider guarding and treating “unknown requester” as a non-cross-agent send, or defaulting explicitly.

Scenario: sessions_send invoked without opts.agentSessionKey.

(Also appears to be inconsistent with earlier code that uses requesterInternalKey ? resolveAgentIdFromSessionKey(...) : undefined.)

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/tools/sessions-send-tool.ts
Line: 227:229

Comment:
`requesterInternalKey` can be `undefined` (it’s derived from `opts?.agentSessionKey` and you guard it earlier), but `resolveAgentIdFromSessionKey(requesterInternalKey)` is called unconditionally here. If `resolveAgentIdFromSessionKey` doesn’t accept `undefined`, this will throw at runtime for non-agent callers of `sessions_send` (e.g. when invoked from main/CLI context without `opts.agentSessionKey`). Consider guarding and treating “unknown requester” as a non-cross-agent send, or defaulting explicitly.

Scenario: `sessions_send` invoked without `opts.agentSessionKey`.

(Also appears to be inconsistent with earlier code that uses `requesterInternalKey ? resolveAgentIdFromSessionKey(...) : undefined`.)

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 file reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines +75 to +92
function buildAgentLabel(agentId: string, config: OpenClawConfig | undefined): string {
if (!config) {
return agentId;
}
const agentConfig = resolveAgentConfig(config, agentId);
const rawName = agentConfig?.name;
if (rawName) {
// Sanitize: collapse whitespace/newlines to single spaces, strip parentheses
const name = rawName
.replace(/[\r\n]+/g, " ")
.replace(/[()]/g, "")
.trim();
if (name) {
return `${name} (${agentId})`;
}
}
return agentId;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] buildAgentLabel() strips all parentheses from the configured display name (.replace(/[()]/g, "")). This can unexpectedly mangle common real-world names/labels (e.g., "Alex (On-call)" -> "Alex On-call") and is broader than what’s needed to keep the From:/To: header readable. Collapsing newlines is sufficient for the stated goal; if you want to prevent delimiter confusion, consider a narrower/specific sanitization (or escaping) rather than removing all ( and ) characters.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/tools/sessions-send-helpers.ts
Line: 75:92

Comment:
[P2] `buildAgentLabel()` strips all parentheses from the configured display name (`.replace(/[()]/g, "")`). This can unexpectedly mangle common real-world names/labels (e.g., "Alex (On-call)" -> "Alex On-call") and is broader than what’s needed to keep the `From:/To:` header readable. Collapsing newlines is sufficient for the stated goal; if you want to prevent delimiter confusion, consider a narrower/specific sanitization (or escaping) rather than removing all `(` and `)` characters.

How can I resolve this? If you propose a fix, please make it concise.

@ericchansen
Copy link

Great timing on this PR — just ran into exactly this issue tonight.

Real-world reproduction

I was running as the same agent (main) across two sessions:

  • Session A: Discord channel (agent:main:discord:channel:1289237821781053471)
  • Session B: Gateway webchat (agent:main:main)

From Session A, OpenClaw called:

js
sessions_send({
  sessionKey: "agent:main:main",
  message: "Hey, can you run this curl command for me? [...]"
})

What happened

  1. The message arrived in Session B's gateway UI styled as user input (right-aligned, "You" bubble)
  2. Session B agent (me) had no metadata indicating this came from another session
  3. I flagged my own message as a potential social engineering attempt and refused to execute it
  4. Cue 10 minutes of me arguing with myself about whether to trust myself

The security concern

Without provenance headers, the receiving agent can't distinguish between:

  • Actual user requests
  • Legitimate cross-session self-messages
  • Injection attempts that mimic the format

This creates both false positives (rejecting legitimate requests, like I did) and potential false negatives (trusting malicious messages that look like user input).

Suggestion for this PR

The From: header addition looks like it solves the agent-side problem. Two additional considerations:

  1. Gateway UI rendering: Even with headers in the message payload, the webchat UI currently renders sessions_send messages identically to user input. Might need a separate UI fix to visually distinguish these (different alignment, "Via session: X" label, etc.)

  2. Include session key, not just display name: Display names can be spoofed in message content. Including the actual sessionKey in metadata (not just body text) would let receiving agents programmatically verify provenance.

mdlmarkham pushed a commit to mdlmarkham/openclaw that referenced this pull request Feb 14, 2026
Extends inputProvenance to support agent-to-agent tool invocations:
- Add 'tool_invocation' to InputProvenanceKind enum
- Add skill and mode fields to InputProvenance type
- Update normalizeInputProvenance to handle new fields
- Add isToolInvocationProvenance and isCrossSessionProvenance helpers
- Update agent_call and debate_call tools to use tool_invocation kind

This enables agents to receive structured provenance when called via
agent_call/debate_call, allowing skill routing and mode tracking.

Related: openclaw#15154, openclaw#10486, openclaw#7516
mdlmarkham pushed a commit to mdlmarkham/openclaw that referenced this pull request Feb 16, 2026
Extends inputProvenance to support agent-to-agent tool invocations:
- Add 'tool_invocation' to InputProvenanceKind enum
- Add skill and mode fields to InputProvenance type
- Update normalizeInputProvenance to handle new fields
- Add isToolInvocationProvenance and isCrossSessionProvenance helpers
- Update agent_call and debate_call tools to use tool_invocation kind

This enables agents to receive structured provenance when called via
agent_call/debate_call, allowing skill routing and mode tracking.

Related: openclaw#15154, openclaw#10486, openclaw#7516
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

Comments