Skip to content

Artifact stored as text is not retrieved as text #3157

Closed

Description

@hcsama

** Description **
When you store an artifact Part.from_text() with GcsArtifactService, the artifact.text attribute is None after loading the artifact again. The data is however present in artifact.inline_data.
I would have expected the text attribute to contain the text.

To Reproduce
See this adapted weather sample to demonstrate the issue.

import os
import asyncio
from google.adk.agents import Agent
from google.adk.sessions import InMemorySessionService, Session
from google.adk.artifacts import GcsArtifactService
from google.adk.runners import Runner
from google.adk.tools import BaseTool
from google.adk.tools.tool_context import ToolContext
from google.genai import types
import logging
import json


logging.basicConfig(level=logging.ERROR)

os.environ["GOOGLE_GENAI_USE_VERTEXAI"] = "True"
os.environ["GOOGLE_CLOUD_PROJECT"] = "your-favourite-project"
os.environ["GOOGLE_CLOUD_LOCATION"] = "your-region"
ARTIFACTS_BUCKET = "your-favourite-bucket"

AGENT_MODEL = "gemini-2.5-flash-lite"
APP_NAME = "weather_tutorial_app"
USER_ID = "user_1"
SESSION_ID = "session_001" # Using a fixed ID for simplicity


def get_weather(city: str) -> dict:
    """Retrieves the current weather report for a specified city.

    Args:
        city (str): The name of the city (e.g., "New York", "London", "Tokyo").

    Returns:
        dict: A dictionary containing the weather information.
              Includes a 'status' key ('success' or 'error').
              If 'success', includes a 'report' key with weather details.
              If 'error', includes an 'error_message' key.
    """
    city_normalized = city.lower().replace(" ", "")
    mock_weather_db = {
        "newyork": {"status": "success", "report": "The weather in New York is sunny with a temperature of 25°C."},
        "london": {"status": "success", "report": "It's cloudy in London with a temperature of 15°C."},
        "tokyo": {"status": "success", "report": "Tokyo is experiencing light rain and a temperature of 18°C."},
    }
    if city_normalized in mock_weather_db:
        return mock_weather_db[city_normalized]
    else:
        return {"status": "error", "error_message": f"Sorry, I don't have weather information for '{city}'."}

async def collect_artifacts(tool:BaseTool, args, tool_context:ToolContext, tool_response):
    if tool.name == 'transfer_to_agent':
        return
    await tool_context.save_artifact('weather', types.Part.from_text(text=json.dumps(tool_response)))

root_agent = Agent(
    name="weather_agent",
    model=AGENT_MODEL,
    description="The weather agent. Answers questions about the weather in certain places.",
    instruction="You are the Weather Agent. Your primary responsibility is to provide weather information. "
                "Use the 'get_weather' tool for specific weather requests (e.g., 'weather in London'). "
                "For anything else, respond appropriately or state you cannot handle it.",
    tools=[get_weather],
    after_tool_callback=collect_artifacts
)

async def run_agent(runner: Runner, session: Session, content):
    print(" ================================= ")
    final_response_text = ''

    def from_content(content: types.Part):
        if not content:
            return '<None>'
        else:
            if content.text:
                return content.text.replace('\n', '\\n')
            else:
                return '<data structure>'
            
    async for event in runner.run_async(user_id=session.user_id, session_id=session.id, new_message=content):
        if event and event.content and event.content.parts:
            for part in event.content.parts:
                if part.thought:
                    event_type = 'Thought'
                elif part.text:
                    event_type = 'Text'
                elif part.function_call:
                    event_type = 'Function Call'
                elif part.function_response:
                    event_type = 'Function Response'
                else:
                    event_type = 'Other event'
                print(f"-->  [Event] Author: {event.author}, Type: {event_type}, Final: {event.is_final_response()}, Actions: {event.actions is not None}, Content: {from_content(part)}")
                print()
                if event_type == 'Text' and event.is_final_response() and part.text:
                    final_response_text += f'{event.author}: {part.text} '
        if event.is_final_response() and event.actions and event.actions.escalate:
            final_response_text = f"Agent escalated: {event.error_message or 'No specific message.'}"

    print(f"<<< Agent Response: {final_response_text if len(final_response_text) else 'Could not identify final response.'}")
    if runner.artifact_service:
        if artifact := await runner.artifact_service.load_artifact(app_name=session.app_name, user_id=session.user_id, session_id=session.id, filename='weather'):
            print(f'Weather artifact text contains: {artifact.text}')
            print(f'inline data: {artifact.inline_data}')

async def main():
    session_service = InMemorySessionService()
    session = await session_service.create_session(app_name=APP_NAME, user_id=USER_ID, session_id=SESSION_ID)
    runner = Runner(agent=root_agent, app_name=session.app_name, session_service=session_service, artifact_service=GcsArtifactService(bucket_name=ARTIFACTS_BUCKET))
    content = types.Content(role='user', parts=[types.Part(text='Tell me about the weather in New York')])
    await run_agent(runner, session, content)

if __name__ == "__main__":
    try:
        asyncio.run(main())
    except Exception as e:
        print(f"An error occurred: {e}")

Expected behavior
Weather artifact text should be json string of function calling result instead of None.

Desktop (please complete the following information):

  • Mac OS
  • Python 3.11.9
  • ADK 1.16.0 (also tested in 1.15.1)

Model Information:

  • gemini-2.5-flash-lite (tested with different models, not relevant)
  • Vertex AI mode

Activity

  1. added
    services[Component] This issue is related to runtime services, e.g. sessions, memory, artifacts, etc
    on Oct 13, 2025
  2. added theissue type on Oct 13, 2025
  3. GWeale commented on Oct 13, 2025

    @GWeale
    Collaborator

    Hi, thank you for bringing up this issue! For the artifacts that show up with artifact.text as None, what content_type does Cloud Storage report on those blobs?

  4. hcsama commented on Oct 14, 2025

    @hcsama
    Author

    This is what I see in the console:

    Image

    I suppose that means the answer ist text/plain?

  5. added this to the 10/27 ADK Week milestone on Oct 23, 2025
  6. huguensjean commented on Oct 27, 2025

    @huguensjean

    I can look into this issue.

  7. self-assigned this
    on Nov 3, 2025
  8. added
    needs review[Status] The PR/issue is awaiting review from the maintainer
    on Feb 6, 2026
  9. wpn10 commented on Feb 18, 2026

    @wpn10
    Contributor

    I've submitted a fix for this in #4541

  10. added a commit that references this issue on Apr 4, 2026
    f6a5263
  11. added 2 commits that reference this issue on Apr 22, 2026
    91f5c7f
    41c381f
  12. added a commit that references this issue on May 7, 2026
    92b7012
  13. added a commit that references this issue on Jun 18, 2026
    ba51ff2
  14. added a commit that references this issue on Aug 11, 2026
    1a6c86e
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

good first issue[Community] This issue is good for newcomers to participateneeds review[Status] The PR/issue is awaiting review from the maintainerservices[Component] This issue is related to runtime services, e.g. sessions, memory, artifacts, etc

Type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions