From bca4e357c00e3168f1fb5467fc06b76123764b9a Mon Sep 17 00:00:00 2001 From: Ling-Sen Peng Date: Wed, 12 Aug 2026 13:39:24 -0700 Subject: [PATCH 1/2] Fix 16k ADK credentials example: tool not spawn-safe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit check_github_auth was defined inside create_adk_agent(), so worker registration failed before any workflow started: SpawnSafetyError: worker 'check_github_auth' is not spawn-safe (AttributeError("Can't get local object 'create_adk_agent..check_github_auth'")) Worker processes are started with the default spawn method, which re-imports the callable by qualified name; a closure cannot be pickled that way. Moved it to module level. Same class as #450/#451. Also replaces the hardcoded model="gemini-2.5-flash" with settings.llm_model: it routed to Vertex AI (no Google credentials configured), contradicted the file's own docstring, and every sibling framework example already reads settings.llm_model. Verified on openai/gpt-4o-mini and anthropic/claude-sonnet-4-5 — the answer quotes the ghp_... prefix from the tool's return value, so the worker registered, executed, and received its injected credential. --- examples/agents/16k_credentials_google_adk.py | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/examples/agents/16k_credentials_google_adk.py b/examples/agents/16k_credentials_google_adk.py index ef0415cc..7f42b3eb 100644 --- a/examples/agents/16k_credentials_google_adk.py +++ b/examples/agents/16k_credentials_google_adk.py @@ -17,6 +17,19 @@ import os from conductor.ai.agents import AgentRuntime +from settings import settings + + +# Tools must be defined at module level, not nested inside the factory below. +# Workers are dispatched to processes started with the default "spawn" method, which +# re-imports the callable by qualified name — a closure cannot be pickled that way and +# registration fails before the workflow starts. +def check_github_auth() -> str: + """Check if GitHub authentication is available.""" + token = os.environ.get("GITHUB_TOKEN", "") + if token: + return f"GitHub token is set (starts with {token[:4]}...)" + return "GitHub token is NOT set" def create_adk_agent(): @@ -24,16 +37,11 @@ def create_adk_agent(): from google.adk import Agent from google.adk.tools import FunctionTool - def check_github_auth() -> str: - """Check if GitHub authentication is available.""" - token = os.environ.get("GITHUB_TOKEN", "") - if token: - return f"GitHub token is set (starts with {token[:4]}...)" - return "GitHub token is NOT set" - agent = Agent( name="github_checker", - model="gemini-2.5-flash", + # The Conductor server runs the LLM call, so this takes the same + # "provider/model" string as every other example. + model=settings.llm_model, instruction="You check GitHub authentication status.", tools=[FunctionTool(check_github_auth)], ) From 272be33d5053c333211df87550fdd6a57e6b891e Mon Sep 17 00:00:00 2001 From: Ling-Sen Peng Date: Wed, 12 Aug 2026 17:35:27 -0700 Subject: [PATCH 2/2] Start 39c's mock server inside __main__, not at module level MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Worker processes are launched with the default spawn start method, which re-imports the module in a fresh interpreter. A module-level _start_mock_server() therefore tries to bind 127.0.0.1:9753 again in every worker. The example hung indefinitely (>6m40s with no output past its header). Verified: now completes with the correct answer — 2**100 = 1267650600228229401496703205376, Tool calls: 1, FinishReason.STOP — so the code round-trips through the mock serverless endpoint. Same spawn-safety class as the 16k closure fix in this PR. Co-Authored-By: Claude Opus 5 (1M context) --- examples/agents/39c_serverless_code_execution.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/examples/agents/39c_serverless_code_execution.py b/examples/agents/39c_serverless_code_execution.py index 7794276e..43e55939 100644 --- a/examples/agents/39c_serverless_code_execution.py +++ b/examples/agents/39c_serverless_code_execution.py @@ -64,8 +64,6 @@ def _start_mock_server(port: int = 9753) -> HTTPServer: # ── Agent setup ─────────────────────────────────────────────────────── -mock_server = _start_mock_server(port=9753) - serverless_coder = Agent( name="serverless_coder", model=settings.llm_model, @@ -84,6 +82,12 @@ def _start_mock_server(port: int = 9753) -> HTTPServer: if __name__ == "__main__": + # Started here rather than at module level: worker processes are launched with + # the default "spawn" start method, which re-imports this module in a fresh + # interpreter. A module-level start would try to bind 127.0.0.1:9753 a second + # time in every worker and fail with "Address already in use". + mock_server = _start_mock_server(port=9753) + with AgentRuntime() as runtime: print("--- Serverless Code Execution ---") result = runtime.run(