openclaw - ✅(Solved) Fix Feature Request: Per-Agent Bedrock requestMetadata Injection for Multi-Agent Cost Attribution [1 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#60602Fetched 2026-04-08 02:49:16
View on GitHub
Comments
0
Participants
1
Timeline
3
Reactions
0
Author
Participants
Timeline (top)
referenced ×2cross-referenced ×1

When running multiple agents via OpenClaw's multi-agent architecture, there's no way to attribute Bedrock API costs to individual agents. All calls appear as the same IAM role with no distinguishing metadata.

Root Cause

When running multiple agents via OpenClaw's multi-agent architecture, there's no way to attribute Bedrock API costs to individual agents. All calls appear as the same IAM role with no distinguishing metadata.

Fix Action

Solution

The Bedrock ConverseStream API supports a requestMetadata parameter — a Record<string, string> map that flows through to CloudTrail and invocation logs. The pi-ai library already passes options.requestMetadata through to the command input (confirmed in amazon-bedrock.js).

Requested: Automatically inject per-agent metadata into every Bedrock API call. The gateway knows which agent is active during each stream call — just needs to pass it through.

Minimal implementation:

// In the stream options builder, when provider is bedrock:
options.requestMetadata = {
  "openclaw:agentId": currentAgent.id,
  "openclaw:agentName": currentAgent.name
};

Or expose a config option:

{
  "bedrock": {
    "requestMetadata": {
      "openclaw:agentId": "${agentId}",
      "openclaw:agentName": "${agentName}"
    }
  }
}

PR fix notes

PR #60698: feat: inject per-agent requestMetadata into Bedrock calls (#60602)

Description (problem / solution / changelog)

Summary

Describe the problem and fix in 2–5 bullets:

  • Problem: When running multiple agents on Amazon Bedrock, all ConverseStream API calls go through the same IAM role with no distinguishing metadata. AWS Cost Explorer cannot attribute costs to individual agents.
  • Why it matters: Multi-agent setups (e.g., 6 agents sharing one EC2 instance) have no way to build per-agent cost dashboards, budgets, or alerts. Users must resort to fragile monkey-patching workarounds.
  • What changed: Automatically injects openclaw:agentId and openclaw:agentName into the requestMetadata field of every Bedrock stream call when the provider is amazon-bedrock. The @mariozechner/pi-ai library already supports passing requestMetadata through to ConverseStream.
  • What did NOT change (scope boundary): No changes to non-Bedrock providers. No changes to existing function signatures, config schema, or public API. No changes to test files. Single file change only (src/agents/pi-embedded-runner/extra-params.ts).

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #60602
  • Related: N/A
  • This PR fixes a bug or regression

Root Cause (if applicable)

N/A — This is a new feature, not a bug fix.

Regression Test Plan (if applicable)

N/A — New feature. No existing behavior is modified.

  • If no new test is added, why not: The createStreamFnWithExtraParams function is a private helper that wraps the stream function. The injected requestMetadata is a pass-through to the AWS SDK via pi-ai and cannot be easily asserted without mocking the full Bedrock stream pipeline. The feature is guarded by a provider check (provider === "amazon-bedrock") and an agentId check, so it cannot affect non-Bedrock providers. A future integration test with a Bedrock endpoint would be the appropriate coverage level.

User-visible / Behavior Changes

  • When using Amazon Bedrock as the model provider in a multi-agent setup, each ConverseStream API call now includes requestMetadata with openclaw:agentId and (when configured) openclaw:agentName.
  • This metadata appears in AWS CloudTrail invocation logs and can be used to group costs in AWS Cost Explorer.
  • No config changes required — injection is automatic.
  • No impact on non-Bedrock providers.

Diagram (if applicable)

Before:
[Agent A] -> [Gateway] -> [Bedrock ConverseStream] (no metadata)
[Agent B] -> [Gateway] -> [Bedrock ConverseStream] (no metadata)
AWS Cost Explorer: all calls appear as one bucket

After:
[Agent A] -> [Gateway] -> [Bedrock ConverseStream] (requestMetadata: {agentId: "a", agentName: "Agent A"})
[Agent B] -> [Gateway] -> [Bedrock ConverseStream] (requestMetadata: {agentId: "b", agentName: "Agent B"})
AWS Cost Explorer: costs can be grouped by openclaw:agentId or openclaw:agentName

Security Impact (required)

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No — same Bedrock API calls, just with additional non-sensitive metadata fields
  • Command/tool execution surface changed? No
  • Data access scope changed? No
  • If any Yes, explain risk + mitigation: N/A

Repro + Verification

Environment

  • OS: Ubuntu (Linux, Inspiron 14)
  • Runtime/container: Node.js v24.14.1, pnpm
  • Model/provider: Amazon Bedrock (claude-sonnet-4-5, claude-opus-4-6)
  • Integration/channel (if any): Multi-agent gateway setup
  • Relevant config (redacted):
{
  "agents": {
    "list": [
      { "id": "billing", "name": "Billing Bot" },
      { "id": "support", "name": "Support Agent" }
    ]
  }
}

Steps

  1. Configure OpenClaw with multiple agents and Amazon Bedrock as the model provider
  2. Send messages through different agents
  3. Check AWS CloudTrail for ConverseStream events

Expected

  • Each ConverseStream event in CloudTrail includes requestMetadata with openclaw:agentId and openclaw:agentName matching the agent that initiated the call

Actual

  • Before this change: no requestMetadata present on any Bedrock calls
  • After this change: metadata is injected automatically

Evidence

  • Trace/log snippets

Type-checked with npx tsc --noEmit — no errors in the changed file. With --verbose gateway logging, the debug line creating streamFn wrapper with params: {"requestMetadata":{"openclaw:agentId":"...","openclaw:agentName":"..."}} confirms injection.

Note: Pre-existing build errors in compact.ts and setup.ts (contextTokens property) are unrelated to this change and exist on the main branch.

Human Verification (required)

  • Verified scenarios:
    • Type-checked the changed file with tsc --noEmit — no type errors
    • Verified boundary tests pass (13 files, 77 tests)
    • Reviewed the pi-ai library source (amazon-bedrock.js:89) to confirm requestMetadata is passed through to ConverseStreamCommand input
    • Confirmed agentId and agentName are correctly resolved from cfg.agents.list in the applyExtraParamsToAgent call path
  • Edge cases checked:
    • agentId is undefined → no metadata injected (guarded by if check)
    • agentName is undefined → only agentId is injected (spread with conditional)
    • Non-Bedrock provider → metadata block is skipped entirely (guarded by provider check)
    • No extra params configured → createStreamFnWithExtraParams returns undefined early (existing guard)
  • What you did not verify:
    • End-to-end verification against a live Bedrock endpoint (no AWS credentials available locally)
    • Full pnpm test suite completion (ran for 22 minutes, boundary tests passed; full suite requires CI)

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? Yes
  • Config/env changes? No
  • Migration needed? No
  • If yes, exact upgrade steps: N/A

Risks and Mitigations

  • Risk: requestMetadata keys with the openclaw: prefix could conflict with user-defined metadata if a future config option allows custom requestMetadata.
    • Mitigation: The openclaw: prefix is namespaced to avoid collisions. If a config-driven requestMetadata option is added later (as suggested in #60602), it should merge with — not override — the auto-injected agent metadata.

🤖 AI-assisted (Claude) — code changes understood and verified by contributor.

Changed files

  • extensions/feishu/src/media.test.ts (modified, +63/-0)
  • extensions/feishu/src/media.ts (modified, +8/-1)
  • src/agents/pi-embedded-runner/extra-params.ts (modified, +33/-11)

Code Example

// In the stream options builder, when provider is bedrock:
options.requestMetadata = {
  "openclaw:agentId": currentAgent.id,
  "openclaw:agentName": currentAgent.name
};

---

{
  "bedrock": {
    "requestMetadata": {
      "openclaw:agentId": "${agentId}",
      "openclaw:agentName": "${agentName}"
    }
  }
}
RAW_BUFFERClick to expand / collapse

Summary

When running multiple agents via OpenClaw's multi-agent architecture, there's no way to attribute Bedrock API costs to individual agents. All calls appear as the same IAM role with no distinguishing metadata.

Problem

  • OpenClaw supports multiple agents (e.g., 6 agents sharing one EC2 instance)
  • All Bedrock ConverseStream calls go through the same IAM role and BedrockRuntimeClient
  • AWS Cost Explorer can only break down costs by model ID, not by agent
  • Agents sharing the same model (e.g., 4 agents on Claude Sonnet 4.6) show as one cost bucket
  • Resource tags (Owner/Project) aren't applied to Bedrock invocations

Solution

The Bedrock ConverseStream API supports a requestMetadata parameter — a Record<string, string> map that flows through to CloudTrail and invocation logs. The pi-ai library already passes options.requestMetadata through to the command input (confirmed in amazon-bedrock.js).

Requested: Automatically inject per-agent metadata into every Bedrock API call. The gateway knows which agent is active during each stream call — just needs to pass it through.

Minimal implementation:

// In the stream options builder, when provider is bedrock:
options.requestMetadata = {
  "openclaw:agentId": currentAgent.id,
  "openclaw:agentName": currentAgent.name
};

Or expose a config option:

{
  "bedrock": {
    "requestMetadata": {
      "openclaw:agentId": "${agentId}",
      "openclaw:agentName": "${agentName}"
    }
  }
}

Technical Context

  • @mariozechner/pi-ai streamBedrock() already accepts requestMetadata in options
  • The onPayload callback could also be used, but agent context isn't available at that layer
  • The gateway knows which agent is active during each stream call
  • AWS Cost Explorer can group by requestMetadata keys once they're present on invocations
  • This would enable per-agent cost dashboards, budgeting, and alerting

Current Workaround

Monkey-patching amazon-bedrock.js with AsyncLocalStorage to thread agent ID through — fragile and breaks on every OC update.

Environment

  • OpenClaw v4.2 (Bedrock provider via @mariozechner/pi-ai)
  • Multi-agent setup: 6 agents on one EC2 g5g.2xlarge
  • Models: Claude Opus 4.6 + Claude Sonnet 4.6 via Amazon Bedrock (us-east-1)
  • Built Mission Control dashboard with AWS Costs module — this feature would complete per-agent cost attribution

extent analysis

TL;DR

Automatically inject per-agent metadata into every Bedrock API call using the requestMetadata parameter to enable per-agent cost attribution.

Guidance

  • Modify the stream options builder to include requestMetadata with the current agent's ID and name when the provider is Bedrock.
  • Consider exposing a config option for requestMetadata to allow for more flexibility in setting the metadata.
  • Verify that the requestMetadata is being passed through to CloudTrail and invocation logs by checking the logs for the presence of the openclaw:agentId and openclaw:agentName keys.
  • Use AWS Cost Explorer to group costs by the requestMetadata keys and create per-agent cost dashboards, budgeting, and alerting.

Example

options.requestMetadata = {
  "openclaw:agentId": currentAgent.id,
  "openclaw:agentName": currentAgent.name
};

Notes

The current workaround using monkey-patching amazon-bedrock.js is fragile and breaks on every OpenClaw update, so a more robust solution is needed. The proposed solution relies on the @mariozechner/pi-ai library already passing options.requestMetadata through to the command input.

Recommendation

Apply the workaround by modifying the stream options builder to include requestMetadata with the current agent's ID and name, as this will enable per-agent cost attribution without requiring an upgrade to a fixed version.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING