91e75e620b
CI: cua-driver distro-compat matrix / debian:12 (glibc 2.36) (push) Has been cancelled
CI: SPDX Headers / Check SPDX headers (warn-only) (push) Has been cancelled
CD: Docs MCP Server / build (linux/amd64) (push) Has been cancelled
CD: Docs MCP Server / build (linux/arm64) (push) Has been cancelled
CD: Docs MCP Server / merge (push) Has been cancelled
CI: cua-driver distro-compat matrix / Resolve release version (push) Has been cancelled
CI: cua-driver distro-compat matrix / fedora:41 (glibc 2.40) (push) Has been cancelled
CI: cua-driver distro-compat matrix / rockylinux:9 (glibc 2.34) (push) Has been cancelled
CI: cua-driver distro-compat matrix / ubuntu:22.04 (glibc 2.35) (push) Has been cancelled
CI: cua-driver distro-compat matrix / ubuntu:24.04 (glibc 2.39) (push) Has been cancelled
CI: cua-driver distro-compat matrix / Distro compat summary (push) Has been cancelled
CI: Rust Linux unit / Rust Linux unit and compile (push) Has been cancelled
CI: Rust Windows unit / Rust Windows unit and compile (push) Has been cancelled
CI: Nix Linux Rust source / Nix / compositor build (push) Has been cancelled
CI: Nix Linux Rust source / Nix / driver package (push) Has been cancelled
CI: Nix Linux Rust source / Nix / Rust unit tests (push) Has been cancelled
96 lines
3.5 KiB
Python
96 lines
3.5 KiB
Python
"""
|
|
Image retention callback handler that limits the number of recent images in message history.
|
|
"""
|
|
|
|
from typing import Any, Dict, List, Optional
|
|
|
|
from .base import AsyncCallbackHandler
|
|
|
|
|
|
class ImageRetentionCallback(AsyncCallbackHandler):
|
|
"""
|
|
Callback handler that applies image retention policy to limit the number
|
|
of recent images in message history to prevent context window overflow.
|
|
"""
|
|
|
|
def __init__(self, only_n_most_recent_images: Optional[int] = None):
|
|
"""
|
|
Initialize the image retention callback.
|
|
|
|
Args:
|
|
only_n_most_recent_images: If set, only keep the N most recent images in message history
|
|
"""
|
|
self.only_n_most_recent_images = only_n_most_recent_images
|
|
|
|
async def on_llm_start(self, messages: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
|
|
"""
|
|
Apply image retention policy to messages before sending to agent loop.
|
|
|
|
Args:
|
|
messages: List of message dictionaries
|
|
|
|
Returns:
|
|
List of messages with image retention policy applied
|
|
"""
|
|
if self.only_n_most_recent_images is None:
|
|
return messages
|
|
|
|
return self._apply_image_retention(messages)
|
|
|
|
def _apply_image_retention(self, messages: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
|
|
"""Apply image retention policy to keep only the N most recent images.
|
|
|
|
Removes computer_call_output items with image_url and their corresponding computer_call items,
|
|
keeping only the most recent N image pairs based on only_n_most_recent_images setting.
|
|
|
|
Args:
|
|
messages: List of message dictionaries
|
|
|
|
Returns:
|
|
Filtered list of messages with image retention applied
|
|
"""
|
|
if self.only_n_most_recent_images is None:
|
|
return messages
|
|
|
|
# Gather indices of all computer_call_output messages that contain an image_url
|
|
output_indices: List[int] = []
|
|
for idx, msg in enumerate(messages):
|
|
if msg.get("type") == "computer_call_output":
|
|
out = msg.get("output")
|
|
if isinstance(out, dict) and ("image_url" in out):
|
|
output_indices.append(idx)
|
|
|
|
# Nothing to trim
|
|
if len(output_indices) <= self.only_n_most_recent_images:
|
|
return messages
|
|
|
|
# Determine which outputs to keep (most recent N)
|
|
keep_output_indices = set(output_indices[-self.only_n_most_recent_images :])
|
|
|
|
# Build set of indices to remove in one pass
|
|
to_remove: set[int] = set()
|
|
|
|
for idx in output_indices:
|
|
if idx in keep_output_indices:
|
|
continue # keep this screenshot and its context
|
|
|
|
to_remove.add(idx) # remove the computer_call_output itself
|
|
|
|
# Remove the immediately preceding computer_call with matching call_id (if present)
|
|
call_id = messages[idx].get("call_id")
|
|
prev_idx = idx - 1
|
|
if (
|
|
prev_idx >= 0
|
|
and messages[prev_idx].get("type") == "computer_call"
|
|
and messages[prev_idx].get("call_id") == call_id
|
|
):
|
|
to_remove.add(prev_idx)
|
|
# Check a single reasoning immediately before that computer_call
|
|
r_idx = prev_idx - 1
|
|
if r_idx >= 0 and messages[r_idx].get("type") == "reasoning":
|
|
to_remove.add(r_idx)
|
|
|
|
# Construct filtered list
|
|
filtered = [m for i, m in enumerate(messages) if i not in to_remove]
|
|
return filtered
|