{{ 'from __future__ import annotations' if future_import else '' }} from typing import * import pickle import sys import base64 import struct import hashlib import asyncio {# Additional imports to support agent state #} {% if inject_agent_state %} import letta from letta import * {% endif %} {# Add schema code if available #} {{ schema_imports or '' }} {# Load agent state #} agent_state = {{ 'pickle.loads(' ~ agent_state_pickle ~ ')' if agent_state_pickle else 'None' }} {{ tool_args }} {# The tool's source code #} {{ tool_source_code }} {# Async wrapper to handle the function call and store the result #} async def _async_wrapper(): _function_result = await {{ invoke_function_call }} {# Use a temporary Pydantic wrapper to recursively serialize any nested Pydantic objects #} try: from pydantic import BaseModel, ConfigDict from typing import Any class _TempResultWrapper(BaseModel): model_config = ConfigDict(arbitrary_types_allowed=True) result: Any _wrapped = _TempResultWrapper(result=_function_result) _serialized_result = _wrapped.model_dump()['result'] except ImportError: # Pydantic not available in sandbox, fall back to string conversion print("Pydantic not available in sandbox environment, falling back to string conversion") _serialized_result = str(_function_result) except Exception as e: # If wrapping fails, print the error and stringify the result print(f"Failed to serialize result with Pydantic wrapper: {e}") _serialized_result = str(_function_result) return { "results": _serialized_result, "agent_state": agent_state } {# Run the async function - method depends on environment #} {% if use_top_level_await %} {# Environment with running event loop (like E2B) - use top-level await #} {{ local_sandbox_result_var_name }} = await _async_wrapper() {% else %} {# Local execution environment - use asyncio.run #} {{ local_sandbox_result_var_name }} = asyncio.run(_async_wrapper()) {% endif %} {{ local_sandbox_result_var_name }}_pkl = pickle.dumps({{ local_sandbox_result_var_name }}) {% if wrap_print_with_markers %} {# Combine everything to flush and write at once. #} data_checksum = hashlib.md5({{ local_sandbox_result_var_name }}_pkl).hexdigest().encode('ascii') {{ local_sandbox_result_var_name }}_msg = ( {{ start_marker }} + struct.pack('>I', len({{ local_sandbox_result_var_name }}_pkl)) + data_checksum + {{ local_sandbox_result_var_name }}_pkl ) sys.stdout.buffer.write({{ local_sandbox_result_var_name }}_msg) sys.stdout.buffer.flush() {% else %} base64.b64encode({{ local_sandbox_result_var_name }}_pkl).decode('utf-8') {% endif %}