feat: add multipart memory uploads

This commit is contained in:
2026-06-22 15:53:29 +08:00
parent 12c767cd68
commit f77454b4cc
6 changed files with 1076 additions and 1255 deletions

View File

@ -897,6 +897,117 @@ async def test_add_memory_materializes_base64_attachment(
assert backend.add_calls[0]["messages"][0]["content"][0]["base64"] == encoded
@pytest.mark.asyncio
async def test_add_memory_multipart_uploads_files_to_chat_session(
config: GatewayConfig,
repo: MemoryRepository,
) -> None:
backend = FakeBackendClient()
messages = [
{
"sender_id": "u_123",
"role": "user",
"timestamp": 1234567890123,
"content": [
{"type": "text", "text": "remember these attachments"},
{
"type": "image",
"upload_id": "image_1",
"name": "picture.png",
"ext": "png",
},
{
"type": "audio",
"upload_id": "audio_1",
"name": "tone.wav",
"ext": "wav",
},
],
}
]
async with app_client(config, backend) as client:
user_key = await create_user(client)
response = await client.post(
"/memories/add/multipart",
data={
"user_id": "u_123",
"user_key": user_key,
"session_id": "chat:c_uploads",
"app_id": "default",
"project_id": "default",
"messages": json.dumps(messages),
},
files=[
("image_1", ("picture.png", b"png bytes", "image/png")),
("audio_1", ("tone.wav", b"wav bytes", "audio/wav")),
],
)
assert response.status_code == 200, response.text
assert response.json() == {
"session_id": "chat:c_uploads",
"backend": {"request_id": "add", "data": {"status": "accumulated"}},
}
content = backend.add_calls[0]["messages"][0]["content"]
assert content == [
{"type": "text", "text": "remember these attachments"},
{
"type": "image",
"name": "picture.png",
"ext": "png",
"base64": base64.b64encode(b"png bytes").decode("ascii"),
},
{
"type": "audio",
"name": "tone.wav",
"ext": "wav",
"base64": base64.b64encode(b"wav bytes").decode("ascii"),
},
]
attachments = repo.list_attachments_for_session("u_123", "chat:c_uploads")
assert [(item["name"], item["source"]) for item in attachments] == [
("picture.png", "memory_add_upload"),
("tone.wav", "memory_add_upload"),
]
for attachment in attachments:
path = Path(attachment["internal_uri"].removeprefix("file://"))
assert path.exists()
@pytest.mark.asyncio
async def test_add_memory_multipart_rejects_missing_upload_file(
config: GatewayConfig,
) -> None:
backend = FakeBackendClient()
messages = [
{
"sender_id": "u_123",
"role": "user",
"timestamp": 1234567890123,
"content": [
{"type": "image", "upload_id": "image_1", "name": "picture.png"}
],
}
]
async with app_client(config, backend) as client:
user_key = await create_user(client)
response = await client.post(
"/memories/add/multipart",
data={
"user_id": "u_123",
"user_key": user_key,
"session_id": "chat:c_missing_upload",
"messages": json.dumps(messages),
},
)
assert response.status_code == 422
assert "missing upload file for upload_id: image_1" in response.text
assert backend.add_calls == []
@pytest.mark.asyncio
async def test_add_memory_deduplicates_retried_base64_attachment(
config: GatewayConfig,