Skip to content

[Bug]: Nested Base64 media remains embedded when compressed context is archived #3200

Description

@wuyak

Prerequisites

  • I have searched the existing issues and discussions, and this is not a duplicate.
  • This is a bug, not a usage question. (For questions, please use Discussions instead.)

Background / Description

When context compression replaces older messages with a summary, WorkspaceBase.offload_context() can preserve the removed messages in sessions/<session_id>/context.jsonl.

The existing implementation extracts Base64 media from top-level DataBlock objects into the workspace data/ directory and replaces the archived source with a workspace:// URL. However, the message model also allows DataBlock objects inside:

  • ToolResultBlock.output
  • HintBlock.hint

These nested blocks are not currently inspected, so their complete Base64 payloads remain embedded in context.jsonl.

For example, this is a valid message structure:

AssistantMsg(
    name="assistant",
    content=[
        ToolResultBlock(
            id="call-1",
            name="get_image",
            output=[
                DataBlock(
                    source=Base64Source(
                        data=image_base64,
                        media_type="image/png",
                    ),
                ),
            ],
            state=ToolResultState.SUCCESS,
        ),
    ],
)

After offload_context() processes this message, the nested source is still serialized as:

{
  "type": "base64",
  "media_type": "image/png",
  "data": "<complete Base64 payload>"
}

A top-level DataBlock containing the same media is instead stored in the workspace data directory and archived as:

{
  "type": "url",
  "url": "workspace:///data/<content-hash>.png",
  "media_type": "image/png"
}

Nested media should use the same existing offloading behavior. The archived copy should contain the workspace:// source, while the original message supplied by the caller remains unchanged.

#2146 changes only the message copies sent to context summarization and intentionally preserves the original messages used for workspace offloading. This issue covers that separate archival path.

Error Messages

No exception is raised. The complete Base64 payload remains embedded in context.jsonl.

Steps to Reproduce

  1. Create an AssistantMsg containing a Base64-backed DataBlock in ToolResultBlock.output.
  2. Pass the message to WorkspaceBase.offload_context().
  3. Read the resulting sessions/<session_id>/context.jsonl.
  4. Observe that the nested source still has "type": "base64" and contains the complete payload.
  5. Move the same DataBlock to the top level of the message and repeat the operation.
  6. Observe that the top-level source is replaced with a workspace:// URL.

The same omission occurs for a DataBlock inside HintBlock.hint.

Environment

  • AgentScope Version: 2.0.10dev
  • Python Version: 3.14.7
  • OS: macOS 26.6.1 (arm64)

Activity

  1. added
    triage/verifyingA bot is verifying whether this bug is real
    triage/confirmedVerified: the reported defect exists
    and removed
    triage/verifyingA bot is verifying whether this bug is real
    on Oct 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    triage/confirmedVerified: the reported defect exists

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions