You've already forked adk-python
mirror of
https://github.com/encounter/adk-python.git
synced 2026-03-30 10:57:20 -07:00
fix(web): allow session resume without new message
Merge https://github.com/google/adk-python/pull/4185 **Description** This PR resolves #4100 by making the `new_message` field optional in the `RunAgentRequest` model. **The Problem:** When attempting to resume an agent session via the FastAPI web server, the request would fail with a `422 Unprocessable Entity` if `new_message` was omitted. This prevented "resume-only" workflows where a user just wants to wake up an existing session. **The Solution:** Updated `RunAgentRequest.new_message` to be `Optional[types.Content] = None`. The underlying `runner.run_async` logic already supports `None` for resuming purposes, so no further logic changes were required. **Verification:** Verified that `RunAgentRequest` now validates successfully when `new_message` is missing, defaulting the field to `None`. Co-authored-by: Liang Wu <wuliang@google.com> COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/4185 from Akshat8510:fix/fastapi-resume-4100 b6d252636aa5f96186507fccf47a278fe733a362 PiperOrigin-RevId: 869761179
This commit is contained in:
committed by
Copybara-Service
parent
ede925b502
commit
30b2ed3ef8
@@ -204,7 +204,7 @@ class RunAgentRequest(common.BaseModel):
|
||||
app_name: str
|
||||
user_id: str
|
||||
session_id: str
|
||||
new_message: types.Content
|
||||
new_message: Optional[types.Content] = None
|
||||
streaming: bool = False
|
||||
state_delta: Optional[dict[str, Any]] = None
|
||||
# for resume long-running functions
|
||||
|
||||
@@ -18,9 +18,7 @@ import logging
|
||||
import os
|
||||
from pathlib import Path
|
||||
import signal
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
from typing import Any
|
||||
from typing import Optional
|
||||
from unittest.mock import AsyncMock
|
||||
@@ -38,14 +36,12 @@ from google.adk.errors.input_validation_error import InputValidationError
|
||||
from google.adk.evaluation.eval_case import EvalCase
|
||||
from google.adk.evaluation.eval_case import Invocation
|
||||
from google.adk.evaluation.eval_result import EvalSetResult
|
||||
from google.adk.evaluation.eval_set import EvalSet
|
||||
from google.adk.evaluation.in_memory_eval_sets_manager import InMemoryEvalSetsManager
|
||||
from google.adk.events.event import Event
|
||||
from google.adk.events.event_actions import EventActions
|
||||
from google.adk.runners import Runner
|
||||
from google.adk.sessions.in_memory_session_service import InMemorySessionService
|
||||
from google.adk.sessions.session import Session
|
||||
from google.adk.sessions.state import State
|
||||
from google.genai import types
|
||||
from pydantic import BaseModel
|
||||
import pytest
|
||||
@@ -1530,6 +1526,23 @@ def test_builder_save_rejects_traversal(builder_test_client, tmp_path):
|
||||
assert not (tmp_path / "app" / "tmp" / "escape.yaml").exists()
|
||||
|
||||
|
||||
def test_agent_run_resume_without_message_success(
|
||||
test_app, create_test_session
|
||||
):
|
||||
"""Test that /run allows resuming a session with only an invocation_id, without a new message."""
|
||||
info = create_test_session
|
||||
url = "/run"
|
||||
payload = {
|
||||
"app_name": info["app_name"],
|
||||
"user_id": info["user_id"],
|
||||
"session_id": info["session_id"],
|
||||
"invocation_id": "test_invocation_id",
|
||||
"streaming": False,
|
||||
}
|
||||
response = test_app.post(url, json=payload)
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
def test_health_endpoint(test_app):
|
||||
"""Test the health endpoint."""
|
||||
response = test_app.get("/health")
|
||||
|
||||
Reference in New Issue
Block a user