fix: add null checks for runtime.context in middlewares and tools (#1269)

Add defensive null checks before accessing runtime.context.get() to
prevent AttributeError when runtime.context is None. This affects:
- UploadsMiddleware
- MemoryMiddleware
- LoopDetectionMiddleware
- SandboxMiddleware
- sandbox tools
- setup_agent_tool
- present_file_tool
- task_tool

Also adds .env loading in serve.sh for environment variable support.

Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
This commit is contained in:
Matthew
2026-03-25 08:46:42 +08:00
committed by GitHub
parent f499f37e94
commit 2eca58bd86
9 changed files with 15 additions and 8 deletions

View File

@@ -106,7 +106,7 @@ class LoopDetectionMiddleware(AgentMiddleware[AgentState]):
def _get_thread_id(self, runtime: Runtime) -> str:
"""Extract thread_id from runtime context for per-thread tracking."""
thread_id = runtime.context.get("thread_id")
thread_id = runtime.context.get("thread_id") if runtime.context else None
if thread_id:
return thread_id
return "default"

View File

@@ -120,7 +120,7 @@ class MemoryMiddleware(AgentMiddleware[MemoryMiddlewareState]):
return None
# Get thread ID from runtime context
thread_id = runtime.context.get("thread_id")
thread_id = runtime.context.get("thread_id") if runtime.context else None
if not thread_id:
print("MemoryMiddleware: No thread_id in context, skipping memory update")
return None

View File

@@ -146,7 +146,7 @@ class UploadsMiddleware(AgentMiddleware[UploadsMiddlewareState]):
return None
# Resolve uploads directory for existence checks
thread_id = runtime.context.get("thread_id")
thread_id = runtime.context.get("thread_id") if runtime.context else None
uploads_dir = self._paths.sandbox_uploads_dir(thread_id) if thread_id else None
# Get newly uploaded files from the current message's additional_kwargs.files

View File

@@ -71,7 +71,7 @@ class SandboxMiddleware(AgentMiddleware[SandboxMiddlewareState]):
get_sandbox_provider().release(sandbox_id)
return None
if runtime.context.get("sandbox_id") is not None:
if runtime.context and runtime.context.get("sandbox_id") is not None:
sandbox_id = runtime.context.get("sandbox_id")
logger.info(f"Releasing sandbox {sandbox_id} from context")
get_sandbox_provider().release(sandbox_id)

View File

@@ -483,7 +483,7 @@ def ensure_sandbox_initialized(runtime: ToolRuntime[ContextT, ThreadState] | Non
# Sandbox was released, fall through to acquire new one
# Lazy acquisition: get thread_id and acquire sandbox
thread_id = runtime.context.get("thread_id")
thread_id = runtime.context.get("thread_id") if runtime.context else None
if thread_id is None:
raise SandboxRuntimeError("Thread ID not available in runtime context")

View File

@@ -33,7 +33,7 @@ def _normalize_presented_filepath(
if runtime.state is None:
raise ValueError("Thread runtime state is not available")
thread_id = runtime.context.get("thread_id")
thread_id = runtime.context.get("thread_id") if runtime.context else None
if not thread_id:
raise ValueError("Thread ID is not available in runtime context")

View File

@@ -24,7 +24,7 @@ def setup_agent(
description: One-line description of what the agent does.
"""
agent_name: str | None = runtime.context.get("agent_name")
agent_name: str | None = runtime.context.get("agent_name") if runtime.context else None
try:
paths = get_paths()

View File

@@ -85,7 +85,7 @@ def task_tool(
if runtime is not None:
sandbox_state = runtime.state.get("sandbox")
thread_data = runtime.state.get("thread_data")
thread_id = runtime.context.get("thread_id")
thread_id = runtime.context.get("thread_id") if runtime.context else None
# Try to get parent model from configurable
metadata = runtime.config.get("metadata", {})

View File

@@ -9,6 +9,13 @@ set -e
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$REPO_ROOT"
# ── Load environment variables from .env ──────────────────────────────────────
if [ -f "$REPO_ROOT/.env" ]; then
set -a
source "$REPO_ROOT/.env"
set +a
fi
# ── Argument parsing ─────────────────────────────────────────────────────────
DEV_MODE=true