diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 403c731de..03b609359 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,5 +1,4 @@ * @temporalio/sdk -/langgraph_plugin/ @temporalio/sdk @temporalio/ai-sdk # SDK & Nexus own the README, pyproject.toml, and uv.lock /README.md @temporalio/sdk @temporalio/nexus diff --git a/README.md b/README.md index d39428dc7..5bd8ce329 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,10 @@ This is a collection of samples showing how to use the [Python SDK](https://gith Prerequisites: * [uv](https://docs.astral.sh/uv/) -* [Temporal CLI installed](https://docs.temporal.io/cli#install) -* [Local Temporal server running](https://docs.temporal.io/cli/server#start-dev) +* [Temporal CLI](https://docs.temporal.io/cli) with a local dev server running: + ``` + temporal server start-dev + ``` The SDK requires Python >= 3.10. You can install Python using uv. For example, diff --git a/bedrock/README.md b/bedrock/README.md index 42a1f4d50..5b294d64e 100644 --- a/bedrock/README.md +++ b/bedrock/README.md @@ -12,7 +12,11 @@ Demonstrates how Temporal and Amazon Bedrock can be used to quickly build bullet 1. An AWS account with Bedrock enabled. 2. A machine that has access to Bedrock. -3. A local Temporal server running on the same machine. See [Temporal's dev server docs](https://docs.temporal.io/cli#start-dev-server) for more information. +3. A local Temporal server running on the same machine, started with the [Temporal CLI](https://docs.temporal.io/cli): + + ``` + temporal server start-dev + ``` These examples use Amazon's Python SDK (Boto3). To configure Boto3 to use your AWS credentials, follow the instructions in [the Boto3 documentation](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html). diff --git a/external_storage/README.md b/external_storage/README.md index 8e6eaf770..9da616252 100644 --- a/external_storage/README.md +++ b/external_storage/README.md @@ -25,7 +25,7 @@ on demand for the Temporal Web UI. ## Prerequisites * [uv](https://docs.astral.sh/uv/) -* [Temporal CLI](https://docs.temporal.io/cli#install) with a local dev server running: +* [Temporal CLI](https://docs.temporal.io/cli) with a local dev server running: ``` temporal server start-dev ``` diff --git a/google_adk_agents/README.md b/google_adk_agents/README.md index 5a7ed3173..7d71ba64b 100644 --- a/google_adk_agents/README.md +++ b/google_adk_agents/README.md @@ -23,7 +23,10 @@ model turn is durable and observable. ## Prerequisites -- Temporal server [running locally](https://docs.temporal.io/cli/server#start-dev) +- [Temporal CLI](https://docs.temporal.io/cli) with a local dev server running: + ``` + temporal server start-dev + ``` - Dependencies installed via `uv sync --group google-adk` - Google API key set as an environment variable: `export GOOGLE_API_KEY=your_key_here` @@ -49,6 +52,6 @@ To run any scenario, start its worker in one terminal and its workflow starter in another: ```bash -uv run python -m google_adk_agents..run_worker -uv run python -m google_adk_agents..run__workflow +uv run google_adk_agents//run_worker.py +uv run google_adk_agents//run__workflow.py ``` diff --git a/google_adk_agents/agent_patterns/README.md b/google_adk_agents/agent_patterns/README.md index 7da938d87..d4c7b92e9 100644 --- a/google_adk_agents/agent_patterns/README.md +++ b/google_adk_agents/agent_patterns/README.md @@ -15,13 +15,13 @@ Before running, review the [prerequisites in the suite README](../README.md) Start the worker in one terminal: ```bash -uv run python -m google_adk_agents.agent_patterns.run_worker +uv run google_adk_agents/agent_patterns/run_worker.py ``` Then start the workflow in another terminal: ```bash -uv run python -m google_adk_agents.agent_patterns.run_multi_agent_workflow +uv run google_adk_agents/agent_patterns/run_multi_agent_workflow.py ``` ## What to expect diff --git a/google_adk_agents/agent_patterns/run_multi_agent_workflow.py b/google_adk_agents/agent_patterns/run_multi_agent_workflow.py index c9bc8677b..0ff13edc1 100644 --- a/google_adk_agents/agent_patterns/run_multi_agent_workflow.py +++ b/google_adk_agents/agent_patterns/run_multi_agent_workflow.py @@ -1,4 +1,5 @@ import asyncio +import os from temporalio.client import Client from temporalio.contrib.google_adk_agents import GoogleAdkPlugin @@ -9,7 +10,10 @@ async def main(): - client = await Client.connect("localhost:7233", plugins=[GoogleAdkPlugin()]) + client = await Client.connect( + os.environ.get("TEMPORAL_ADDRESS", "localhost:7233"), + plugins=[GoogleAdkPlugin()], + ) result = await client.execute_workflow( MultiAgentWorkflow.run, diff --git a/google_adk_agents/agent_patterns/run_worker.py b/google_adk_agents/agent_patterns/run_worker.py index a6c199238..48eb6e030 100644 --- a/google_adk_agents/agent_patterns/run_worker.py +++ b/google_adk_agents/agent_patterns/run_worker.py @@ -1,6 +1,7 @@ from __future__ import annotations import asyncio +import os from temporalio.client import Client from temporalio.contrib.google_adk_agents import GoogleAdkPlugin @@ -14,7 +15,9 @@ async def main(): plugin = GoogleAdkPlugin() - client = await Client.connect("localhost:7233", plugins=[plugin]) + client = await Client.connect( + os.environ.get("TEMPORAL_ADDRESS", "localhost:7233"), plugins=[plugin] + ) worker = Worker( client, diff --git a/google_adk_agents/basic/README.md b/google_adk_agents/basic/README.md index 283e379b7..f9b6e2707 100644 --- a/google_adk_agents/basic/README.md +++ b/google_adk_agents/basic/README.md @@ -17,13 +17,13 @@ Before running, review the [prerequisites in the suite README](../README.md) Start the worker in one terminal: ```bash -uv run python -m google_adk_agents.basic.run_worker +uv run google_adk_agents/basic/run_worker.py ``` Then start the workflow in another terminal: ```bash -uv run python -m google_adk_agents.basic.run_hello_world_workflow +uv run google_adk_agents/basic/run_hello_world_workflow.py ``` ## What to expect diff --git a/google_adk_agents/basic/run_hello_world_workflow.py b/google_adk_agents/basic/run_hello_world_workflow.py index 60d141eb7..c7fa34697 100644 --- a/google_adk_agents/basic/run_hello_world_workflow.py +++ b/google_adk_agents/basic/run_hello_world_workflow.py @@ -1,4 +1,5 @@ import asyncio +import os from temporalio.client import Client from temporalio.contrib.google_adk_agents import GoogleAdkPlugin @@ -10,7 +11,10 @@ async def main(): # @@@SNIPSTART google-adk-agents-basic-starter - client = await Client.connect("localhost:7233", plugins=[GoogleAdkPlugin()]) + client = await Client.connect( + os.environ.get("TEMPORAL_ADDRESS", "localhost:7233"), + plugins=[GoogleAdkPlugin()], + ) result = await client.execute_workflow( HelloWorldAgentWorkflow.run, diff --git a/google_adk_agents/basic/run_worker.py b/google_adk_agents/basic/run_worker.py index f368b8ec5..4044b4baa 100644 --- a/google_adk_agents/basic/run_worker.py +++ b/google_adk_agents/basic/run_worker.py @@ -1,6 +1,7 @@ from __future__ import annotations import asyncio +import os from temporalio.client import Client from temporalio.contrib.google_adk_agents import GoogleAdkPlugin @@ -15,7 +16,9 @@ async def main(): # @@@SNIPSTART google-adk-agents-basic-worker plugin = GoogleAdkPlugin() - client = await Client.connect("localhost:7233", plugins=[plugin]) + client = await Client.connect( + os.environ.get("TEMPORAL_ADDRESS", "localhost:7233"), plugins=[plugin] + ) worker = Worker( client, diff --git a/google_adk_agents/chatbot/README.md b/google_adk_agents/chatbot/README.md index 28400b433..7f3510e78 100644 --- a/google_adk_agents/chatbot/README.md +++ b/google_adk_agents/chatbot/README.md @@ -21,13 +21,13 @@ Before running, review the [prerequisites in the suite README](../README.md) Start the worker in one terminal: ```bash -uv run python -m google_adk_agents.chatbot.run_worker +uv run google_adk_agents/chatbot/run_worker.py ``` Then start the interactive client in another terminal: ```bash -uv run python -m google_adk_agents.chatbot.run_chatbot_workflow +uv run google_adk_agents/chatbot/run_chatbot_workflow.py ``` ## What to expect diff --git a/google_adk_agents/chatbot/run_chatbot_workflow.py b/google_adk_agents/chatbot/run_chatbot_workflow.py index 61d0d6313..00d841f3b 100644 --- a/google_adk_agents/chatbot/run_chatbot_workflow.py +++ b/google_adk_agents/chatbot/run_chatbot_workflow.py @@ -1,4 +1,5 @@ import asyncio +import os from temporalio.client import Client from temporalio.contrib.google_adk_agents import GoogleAdkPlugin @@ -10,7 +11,10 @@ async def main(): # @@@SNIPSTART google-adk-agents-chatbot-starter - client = await Client.connect("localhost:7233", plugins=[GoogleAdkPlugin()]) + client = await Client.connect( + os.environ.get("TEMPORAL_ADDRESS", "localhost:7233"), + plugins=[GoogleAdkPlugin()], + ) handle = await client.start_workflow( ChatbotAgentWorkflow.run, diff --git a/google_adk_agents/chatbot/run_worker.py b/google_adk_agents/chatbot/run_worker.py index 18a95d39e..c199835ff 100644 --- a/google_adk_agents/chatbot/run_worker.py +++ b/google_adk_agents/chatbot/run_worker.py @@ -1,6 +1,7 @@ from __future__ import annotations import asyncio +import os from temporalio.client import Client from temporalio.contrib.google_adk_agents import GoogleAdkPlugin @@ -15,7 +16,9 @@ async def main(): # @@@SNIPSTART google-adk-agents-chatbot-worker plugin = GoogleAdkPlugin() - client = await Client.connect("localhost:7233", plugins=[plugin]) + client = await Client.connect( + os.environ.get("TEMPORAL_ADDRESS", "localhost:7233"), plugins=[plugin] + ) worker = Worker( client, diff --git a/google_adk_agents/mcp/README.md b/google_adk_agents/mcp/README.md index b26423002..8dfa58b7b 100644 --- a/google_adk_agents/mcp/README.md +++ b/google_adk_agents/mcp/README.md @@ -28,13 +28,13 @@ server, `uv sync --group google-adk`, and `export GOOGLE_API_KEY=...`). Start the worker in one terminal: ```bash -uv run python -m google_adk_agents.mcp.run_worker +uv run google_adk_agents/mcp/run_worker.py ``` Then start the workflow in another terminal: ```bash -uv run python -m google_adk_agents.mcp.run_echo_workflow +uv run google_adk_agents/mcp/run_echo_workflow.py ``` The worker spawns `echo_mcp_server.py` itself; you don't need to start it diff --git a/google_adk_agents/mcp/run_echo_workflow.py b/google_adk_agents/mcp/run_echo_workflow.py index b8bfd01dc..d6a8c8b5d 100644 --- a/google_adk_agents/mcp/run_echo_workflow.py +++ b/google_adk_agents/mcp/run_echo_workflow.py @@ -1,4 +1,5 @@ import asyncio +import os from temporalio.client import Client from temporalio.contrib.google_adk_agents import GoogleAdkPlugin @@ -7,7 +8,10 @@ async def main(): - client = await Client.connect("localhost:7233", plugins=[GoogleAdkPlugin()]) + client = await Client.connect( + os.environ.get("TEMPORAL_ADDRESS", "localhost:7233"), + plugins=[GoogleAdkPlugin()], + ) result = await client.execute_workflow( EchoMcpWorkflow.run, diff --git a/google_adk_agents/mcp/run_worker.py b/google_adk_agents/mcp/run_worker.py index 380b07504..8c8f6c2a2 100644 --- a/google_adk_agents/mcp/run_worker.py +++ b/google_adk_agents/mcp/run_worker.py @@ -1,6 +1,7 @@ from __future__ import annotations import asyncio +import os from temporalio.client import Client from temporalio.contrib.google_adk_agents import ( @@ -19,7 +20,9 @@ async def main(): toolset_providers=[TemporalMcpToolSetProvider("echo", echo_toolset)] ) - client = await Client.connect("localhost:7233", plugins=[plugin]) + client = await Client.connect( + os.environ.get("TEMPORAL_ADDRESS", "localhost:7233"), plugins=[plugin] + ) worker = Worker( client, diff --git a/google_adk_agents/streaming/README.md b/google_adk_agents/streaming/README.md index 47675438f..09e75a577 100644 --- a/google_adk_agents/streaming/README.md +++ b/google_adk_agents/streaming/README.md @@ -18,13 +18,13 @@ Before running, review the [prerequisites in the suite README](../README.md) Start the worker in one terminal: ```bash -uv run python -m google_adk_agents.streaming.run_worker +uv run google_adk_agents/streaming/run_worker.py ``` Then start the workflow in another terminal: ```bash -uv run python -m google_adk_agents.streaming.run_streaming_workflow +uv run google_adk_agents/streaming/run_streaming_workflow.py ``` ## What to expect diff --git a/google_adk_agents/streaming/run_streaming_workflow.py b/google_adk_agents/streaming/run_streaming_workflow.py index 157c105a2..b371e96e6 100644 --- a/google_adk_agents/streaming/run_streaming_workflow.py +++ b/google_adk_agents/streaming/run_streaming_workflow.py @@ -1,4 +1,5 @@ import asyncio +import os from datetime import timedelta from google.adk.models.llm_response import LlmResponse @@ -14,7 +15,10 @@ async def main(): - client = await Client.connect("localhost:7233", plugins=[GoogleAdkPlugin()]) + client = await Client.connect( + os.environ.get("TEMPORAL_ADDRESS", "localhost:7233"), + plugins=[GoogleAdkPlugin()], + ) handle = await client.start_workflow( StreamingAgentWorkflow.run, diff --git a/google_adk_agents/streaming/run_worker.py b/google_adk_agents/streaming/run_worker.py index 5a30034bb..cbf8f76af 100644 --- a/google_adk_agents/streaming/run_worker.py +++ b/google_adk_agents/streaming/run_worker.py @@ -1,6 +1,7 @@ from __future__ import annotations import asyncio +import os from temporalio.client import Client from temporalio.contrib.google_adk_agents import GoogleAdkPlugin @@ -14,7 +15,9 @@ async def main(): plugin = GoogleAdkPlugin() - client = await Client.connect("localhost:7233", plugins=[plugin]) + client = await Client.connect( + os.environ.get("TEMPORAL_ADDRESS", "localhost:7233"), plugins=[plugin] + ) worker = Worker( client, diff --git a/google_adk_agents/tools/README.md b/google_adk_agents/tools/README.md index c35e3a698..006efe108 100644 --- a/google_adk_agents/tools/README.md +++ b/google_adk_agents/tools/README.md @@ -14,13 +14,13 @@ Before running, review the [prerequisites in the suite README](../README.md) Start the worker in one terminal: ```bash -uv run python -m google_adk_agents.tools.run_worker +uv run google_adk_agents/tools/run_worker.py ``` Then start the workflow in another terminal: ```bash -uv run python -m google_adk_agents.tools.run_weather_workflow +uv run google_adk_agents/tools/run_weather_workflow.py ``` ## What to expect diff --git a/google_adk_agents/tools/run_weather_workflow.py b/google_adk_agents/tools/run_weather_workflow.py index db15ecf16..e775a0db1 100644 --- a/google_adk_agents/tools/run_weather_workflow.py +++ b/google_adk_agents/tools/run_weather_workflow.py @@ -1,4 +1,5 @@ import asyncio +import os from temporalio.client import Client from temporalio.contrib.google_adk_agents import GoogleAdkPlugin @@ -7,7 +8,10 @@ async def main(): - client = await Client.connect("localhost:7233", plugins=[GoogleAdkPlugin()]) + client = await Client.connect( + os.environ.get("TEMPORAL_ADDRESS", "localhost:7233"), + plugins=[GoogleAdkPlugin()], + ) result = await client.execute_workflow( WeatherAgentWorkflow.run, diff --git a/google_adk_agents/tools/run_worker.py b/google_adk_agents/tools/run_worker.py index 4e56e426e..71aee072e 100644 --- a/google_adk_agents/tools/run_worker.py +++ b/google_adk_agents/tools/run_worker.py @@ -1,6 +1,7 @@ from __future__ import annotations import asyncio +import os from temporalio.client import Client from temporalio.contrib.google_adk_agents import GoogleAdkPlugin @@ -14,7 +15,9 @@ async def main(): # @@@SNIPSTART google-adk-agents-tools-worker plugin = GoogleAdkPlugin() - client = await Client.connect("localhost:7233", plugins=[plugin]) + client = await Client.connect( + os.environ.get("TEMPORAL_ADDRESS", "localhost:7233"), plugins=[plugin] + ) worker = Worker( client, diff --git a/langgraph_plugin/README.md b/langgraph_plugin/README.md index a242e943f..8bb8d2c51 100644 --- a/langgraph_plugin/README.md +++ b/langgraph_plugin/README.md @@ -27,7 +27,7 @@ Samples are organized by API style: uv sync --group langgraph ``` -2. Start a [Temporal dev server](https://docs.temporal.io/cli#start-dev-server): +2. Start a local dev server with the [Temporal CLI](https://docs.temporal.io/cli): ```bash temporal server start-dev diff --git a/langgraph_plugin/graph_api/streaming/README.md b/langgraph_plugin/graph_api/streaming/README.md index 2065a6a36..d34f3e240 100644 --- a/langgraph_plugin/graph_api/streaming/README.md +++ b/langgraph_plugin/graph_api/streaming/README.md @@ -1,6 +1,6 @@ # Streaming (Graph API) -Streams a LangGraph run to an external client while the workflow is still running, using Temporal's durable, offset-addressed [`WorkflowStream`](https://docs.temporal.io/). The graph writes a short story about a topic and emits both fine-grained tokens and node-completion progress on separate topics. +Streams a LangGraph run to an external client while the workflow is still running, using Temporal's durable, offset-addressed [`WorkflowStream`](https://github.com/temporalio/sdk-python/tree/main/temporalio/contrib/workflow_streams). The graph writes a short story about a topic and emits both fine-grained tokens and node-completion progress on separate topics. ## What This Sample Demonstrates diff --git a/openai_agents/README.md b/openai_agents/README.md index 9404278fd..599d097ce 100644 --- a/openai_agents/README.md +++ b/openai_agents/README.md @@ -17,7 +17,10 @@ This approach ensures that AI agent workflows are durable, observable, and can h ## Prerequisites -- Temporal server [running locally](https://docs.temporal.io/cli/server#start-dev) +- [Temporal CLI](https://docs.temporal.io/cli) with a local dev server running: + ``` + temporal server start-dev + ``` - Required dependencies installed via `uv sync --group openai-agents` - OpenAI API key set as environment variable: `export OPENAI_API_KEY=your_key_here` diff --git a/strands_plugin/README.md b/strands_plugin/README.md index d4eaf558a..3fb4e2de7 100644 --- a/strands_plugin/README.md +++ b/strands_plugin/README.md @@ -24,12 +24,6 @@ These samples demonstrate the [Temporal Strands plugin](https://github.com/tempo uv sync --group strands-agents ``` - > The `strands` extra of `temporalio` is shipping in an upcoming release. Until then, install the SDK from the strands branch: - > - > ```bash - > uv pip install -e ../sdk-python --extra strands-agents --extra pydantic - > ``` - 2. Configure AWS credentials. The samples use the plugin's default `BedrockModel()`, which picks up the standard AWS SDK credential chain. Make sure the credentials grant access to a Bedrock model in your selected region (e.g., `us-west-2`). ```bash @@ -39,7 +33,7 @@ These samples demonstrate the [Temporal Strands plugin](https://github.com/tempo You can pick a specific model by passing it to `BedrockModel(model_id="...")` in each sample's worker. -3. Start a [Temporal dev server](https://docs.temporal.io/cli#start-dev-server): +3. Start a local dev server with the [Temporal CLI](https://docs.temporal.io/cli): ```bash temporal server start-dev diff --git a/strands_plugin/activity_interrupt/workflow.py b/strands_plugin/activity_interrupt/workflow.py index f017fc3ac..bf815630b 100644 --- a/strands_plugin/activity_interrupt/workflow.py +++ b/strands_plugin/activity_interrupt/workflow.py @@ -10,7 +10,6 @@ """ from datetime import timedelta -from typing import Optional from strands.interrupt import Interrupt, InterruptException from strands.types.interrupt import InterruptResponseContent @@ -54,15 +53,15 @@ def __init__(self) -> None: ), ], ) - self._approval: Optional[str] = None - self._pending_reason: Optional[str] = None + self._approval: str | None = None + self._pending_reason: str | None = None @workflow.signal def approve(self, response: str) -> None: self._approval = response @workflow.query - def pending_approval(self) -> Optional[str]: + def pending_approval(self) -> str | None: return self._pending_reason @workflow.run diff --git a/strands_plugin/continue_as_new/README.md b/strands_plugin/continue_as_new/README.md index 84e663a56..bffae4aee 100644 --- a/strands_plugin/continue_as_new/README.md +++ b/strands_plugin/continue_as_new/README.md @@ -1,6 +1,6 @@ # Continue-as-new -A chat-style workflow accumulates history with every turn and will eventually hit Temporal's per-workflow history limit. `workflow.info().is_continue_as_new_suggested()` flips `True` once the server decides history has grown large enough; this sample checks it after each turn and hands off to a fresh run with `agent.messages` as input. +A chat-style workflow accumulates history with every turn and will eventually hit Temporal's per-workflow history limit. `workflow.info().is_continue_as_new_suggested()` flips `True` once the server decides history has grown large enough; this sample waits on it — alongside the `end_chat` signal — with `workflow.wait_condition(...)`, then hands off to a fresh run with `agent.messages` as input. ## What This Sample Demonstrates diff --git a/strands_plugin/human_in_the_loop/workflow.py b/strands_plugin/human_in_the_loop/workflow.py index 8c21b0869..edeec98b0 100644 --- a/strands_plugin/human_in_the_loop/workflow.py +++ b/strands_plugin/human_in_the_loop/workflow.py @@ -6,7 +6,6 @@ """ from datetime import timedelta -from typing import Optional from strands import tool from strands.hooks import HookProvider, HookRegistry @@ -49,15 +48,15 @@ def __init__(self) -> None: tools=[delete_file], hooks=[ApprovalHook()], ) - self._approval: Optional[str] = None - self._pending_reason: Optional[str] = None + self._approval: str | None = None + self._pending_reason: str | None = None @workflow.signal def approve(self, response: str) -> None: self._approval = response @workflow.query - def pending_approval(self) -> Optional[str]: + def pending_approval(self) -> str | None: return self._pending_reason @workflow.run diff --git a/strands_plugin/tools/README.md b/strands_plugin/tools/README.md index 400eff2c2..13fc32d84 100644 --- a/strands_plugin/tools/README.md +++ b/strands_plugin/tools/README.md @@ -13,7 +13,7 @@ A single prompt exercises all three. The resulting Temporal history shows an `in ## What This Sample Demonstrates - Three coexisting tool surfaces on one agent -- `workflow.activity_as_tool` carrying per-tool activity options (timeouts) +- `activity_as_tool` (from `temporalio.contrib.strands.workflow`) carrying per-tool activity options (timeouts) - Wrapping `strands_tools` tools so runtime host access happens in an activity ## Running the Sample