mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-09-27 18:42:20 +02:00
188 lines
6.4 KiB
Python
188 lines
6.4 KiB
Python
import base64
|
|
import hashlib
|
|
import io
|
|
import shutil
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
from PIL import Image
|
|
|
|
from src.llm_core import _sanitize_llm_messages
|
|
from src.media_ingress import (
|
|
LocalMediaAttachment,
|
|
MediaIngressLimits,
|
|
_uniform_timestamps,
|
|
build_multimodal_user_content,
|
|
)
|
|
|
|
|
|
def _write_image(path: Path, *, size: tuple[int, int] = (320, 180)) -> None:
|
|
Image.new("RGB", size, (30, 160, 90)).save(path)
|
|
|
|
|
|
def test_image_ingress_hashes_normalizes_and_emits_openai_blocks(tmp_path):
|
|
source = tmp_path / "evidence.png"
|
|
_write_image(source, size=(2200, 1100))
|
|
|
|
result = build_multimodal_user_content(
|
|
"Inspect evidence.png",
|
|
[LocalMediaAttachment(source, "/workspace/evidence.png")],
|
|
limits=MediaIngressLimits(max_dimension=800),
|
|
)
|
|
|
|
assert [block["type"] for block in result.content] == ["text", "text", "image_url"]
|
|
assert result.content[0]["text"] == "Inspect evidence.png"
|
|
assert "/workspace/evidence.png" in result.content[1]["text"]
|
|
assert hashlib.sha256(source.read_bytes()).hexdigest() in result.content[1]["text"]
|
|
url = result.content[2]["image_url"]["url"]
|
|
assert url.startswith("data:image/jpeg;base64,")
|
|
decoded = Image.open(io.BytesIO(base64.b64decode(url.split(",", 1)[1])))
|
|
assert decoded.size == (800, 400)
|
|
artifact = result.artifacts[0]
|
|
assert (artifact.width, artifact.height) == (800, 400)
|
|
assert artifact.encoded_bytes == len(url.split(",", 1)[1])
|
|
assert result.estimated_visual_tokens > 0
|
|
assert "base64" not in str(result.metadata())
|
|
|
|
|
|
def test_ingress_rejects_symlink_without_leaking_target(tmp_path):
|
|
target = tmp_path / "target.png"
|
|
link = tmp_path / "link.png"
|
|
_write_image(target)
|
|
link.symlink_to(target)
|
|
|
|
result = build_multimodal_user_content(
|
|
"Inspect link.png",
|
|
[LocalMediaAttachment(link, "/workspace/link.png")],
|
|
)
|
|
|
|
assert result.content == [{"type": "text", "text": "Inspect link.png"}]
|
|
assert not result.artifacts
|
|
assert "symbolic links" in result.warnings[0]
|
|
|
|
|
|
def test_ingress_enforces_count_and_source_byte_limits(tmp_path):
|
|
first = tmp_path / "first.png"
|
|
second = tmp_path / "second.png"
|
|
_write_image(first)
|
|
_write_image(second)
|
|
|
|
result = build_multimodal_user_content(
|
|
"Inspect files",
|
|
[
|
|
LocalMediaAttachment(first, "/workspace/first.png"),
|
|
LocalMediaAttachment(second, "/workspace/second.png"),
|
|
],
|
|
limits=MediaIngressLimits(max_media_files=1, max_image_source_bytes=10),
|
|
)
|
|
|
|
assert not result.artifacts
|
|
assert any("source is" in warning for warning in result.warnings)
|
|
assert any("file count capped" in warning for warning in result.warnings)
|
|
|
|
|
|
def test_uniform_video_timestamps_cover_the_full_duration():
|
|
timestamps = _uniform_timestamps(40.0, 8)
|
|
assert timestamps == [2.5, 7.5, 12.5, 17.5, 22.5, 27.5, 32.5, 37.5]
|
|
|
|
|
|
@pytest.mark.skipif(not shutil.which("ffmpeg") or not shutil.which("ffprobe"), reason="ffmpeg unavailable")
|
|
def test_video_ingress_extracts_timestamped_frames(tmp_path):
|
|
video = tmp_path / "evidence.mp4"
|
|
subprocess.run(
|
|
[
|
|
"ffmpeg",
|
|
"-hide_banner",
|
|
"-loglevel",
|
|
"error",
|
|
"-f",
|
|
"lavfi",
|
|
"-i",
|
|
"color=c=blue:s=160x90:d=2",
|
|
"-pix_fmt",
|
|
"yuv420p",
|
|
"-y",
|
|
str(video),
|
|
],
|
|
check=True,
|
|
timeout=20,
|
|
)
|
|
|
|
result = build_multimodal_user_content(
|
|
"Inspect evidence.mp4",
|
|
[LocalMediaAttachment(video, "/workspace/evidence.mp4")],
|
|
limits=MediaIngressLimits(max_video_frames=2),
|
|
)
|
|
|
|
assert len(result.artifacts) == 1
|
|
artifact = result.artifacts[0]
|
|
assert artifact.modality == "video"
|
|
assert artifact.frame_timestamps_s == [1.0]
|
|
assert any("timestamp=00:01.000" in block.get("text", "") for block in result.content)
|
|
assert sum(block["type"] == "image_url" for block in result.content) == 1
|
|
|
|
|
|
def test_provider_sanitizer_preserves_ingested_image_blocks(tmp_path):
|
|
source = tmp_path / "evidence.png"
|
|
_write_image(source)
|
|
ingress = build_multimodal_user_content(
|
|
"Inspect evidence.png",
|
|
[LocalMediaAttachment(source, "/workspace/evidence.png")],
|
|
)
|
|
|
|
sanitized = _sanitize_llm_messages([{"role": "user", "content": ingress.content}])
|
|
|
|
assert sanitized[0]["content"] == ingress.content
|
|
|
|
|
|
def test_document_ingress_extracts_text_with_shared_budget_and_metadata(tmp_path):
|
|
source = tmp_path / "brief.txt"
|
|
source.write_text("alpha beta gamma\n" * 20, encoding="utf-8")
|
|
|
|
result = build_multimodal_user_content(
|
|
"Read brief.txt",
|
|
[LocalMediaAttachment(source, "/workspace/brief.txt")],
|
|
limits=MediaIngressLimits(max_inline_document_chars=100),
|
|
)
|
|
|
|
assert [block["type"] for block in result.content] == ["text", "text"]
|
|
assert "Document source=/workspace/brief.txt" in result.content[1]["text"]
|
|
assert "alpha beta gamma" in result.content[1]["text"]
|
|
assert "truncated by shared inline budget" in result.content[1]["text"]
|
|
artifact = result.artifacts[0]
|
|
assert artifact.modality == "document"
|
|
assert artifact.extracted_chars == 100
|
|
assert artifact.truncated is True
|
|
assert "alpha beta gamma" not in str(result.metadata())
|
|
|
|
|
|
def test_audio_ingress_falls_back_to_verified_workspace_path(tmp_path):
|
|
source = tmp_path / "sample.wav"
|
|
source.write_bytes(b"RIFF" + b"\x00" * 32)
|
|
|
|
result = build_multimodal_user_content(
|
|
"Inspect sample.wav",
|
|
[LocalMediaAttachment(source, "/workspace/sample.wav")],
|
|
)
|
|
|
|
assert [block["type"] for block in result.content] == ["text", "text"]
|
|
assert "inspect with workspace tools" in result.content[1]["text"]
|
|
assert result.artifacts[0].modality == "audio"
|
|
assert result.artifacts[0].encoded_bytes == 0
|
|
|
|
|
|
def test_audio_ingress_emits_native_block_only_when_enabled(tmp_path):
|
|
source = tmp_path / "sample.wav"
|
|
source.write_bytes(b"RIFF" + b"\x00" * 32)
|
|
|
|
result = build_multimodal_user_content(
|
|
"Listen to sample.wav",
|
|
[LocalMediaAttachment(source, "/workspace/sample.wav")],
|
|
input_modalities=["text", "audio"],
|
|
)
|
|
|
|
assert [block["type"] for block in result.content] == ["text", "text", "audio"]
|
|
assert result.content[2]["audio"]["url"].startswith("data:audio/")
|
|
assert result.artifacts[0].encoded_bytes > 0
|