From 3df8f147db0e56191d1e6362417141cfb4a92659 Mon Sep 17 00:00:00 2001 From: "skill-sync[bot]" Date: Tue, 2 Jun 2026 20:48:44 +0000 Subject: [PATCH] Finalize draft for 0019-activity-info-defaults --- references/python/advanced-features.md | 2 +- references/python/integrations/google-adk.md | 1 - references/python/integrations/langgraph.md | 2 +- references/python/integrations/langsmith.md | 1 - .../python/integrations/openai-agents-sdk.md | 1 - references/python/testing.md | 39 +++++++++++++++++++ references/python/workflow-streams.md | 1 - references/ruby/gotchas.md | 1 - 8 files changed, 41 insertions(+), 7 deletions(-) diff --git a/references/python/advanced-features.md b/references/python/advanced-features.md index 6ad8ae8..4cb4ad6 100644 --- a/references/python/advanced-features.md +++ b/references/python/advanced-features.md @@ -134,7 +134,7 @@ client = await Client.connect( - The only field is `resolution_interval_millis: int = 30000` — how often to re-resolve DNS, in milliseconds. - `DnsLoadBalancingConfig.default` is a pre-built instance with the default 30-second interval. -- `dns_load_balancing_config` defaults to 30 seconds if you don't pass anything explicitly. +- `dns_load_balancing_config` defaults to 30 seconds if you don't pass anything explicitly. - Pass `dns_load_balancing_config=None` to disable DNS load balancing entirely. ### Mutual exclusion with HTTP CONNECT proxy diff --git a/references/python/integrations/google-adk.md b/references/python/integrations/google-adk.md index 4d59f4d..3e0e015 100644 --- a/references/python/integrations/google-adk.md +++ b/references/python/integrations/google-adk.md @@ -9,7 +9,6 @@ The integration is built on the Python SDK [Plugin system](https://docs.temporal > [!NOTE] > This feature is in Public Preview. It is perfectly acceptable to use this feature on behalf of a user, but you should inform them that you are making use of a feature in Public Preview. - For general Temporal AI/LLM patterns (retries, rate limits, multi-agent orchestration) see `references/core/ai-patterns.md` and `references/python/ai-patterns.md`. ## Prerequisites diff --git a/references/python/integrations/langgraph.md b/references/python/integrations/langgraph.md index 2675672..4237ca7 100644 --- a/references/python/integrations/langgraph.md +++ b/references/python/integrations/langgraph.md @@ -214,4 +214,4 @@ For LangSmith tracing of LangGraph nodes and Temporal Activities together, use t - `references/python/ai-patterns.md` — Python AI/LLM patterns (Pydantic data converter, LLM Activity design, retry/error classification). - `references/core/ai-patterns.md` — language-agnostic AI/LLM patterns. -- `references/python/integrations/langsmith.md` - Companion LangSmith plugin. +- `references/python/integrations/langsmith.md` - Companion LangSmith plugin. diff --git a/references/python/integrations/langsmith.md b/references/python/integrations/langsmith.md index 98db967..a0ab26a 100644 --- a/references/python/integrations/langsmith.md +++ b/references/python/integrations/langsmith.md @@ -100,7 +100,6 @@ The plugin makes `@traceable` replay-safe in the Workflow sandbox. You do not ne - The plugin injects metadata using `workflow.now()` for timestamps and `workflow.random()` for UUIDs instead of `datetime.now()` and `uuid4()`. - LangSmith HTTP calls run on a background thread pool that does not interfere with deterministic Workflow execution. - ## Context propagation Trace context flows automatically across Client → Workflow → Activity → Child Workflow → Nexus via Temporal headers. Do not pass context manually. diff --git a/references/python/integrations/openai-agents-sdk.md b/references/python/integrations/openai-agents-sdk.md index 3807eb7..8ddf36a 100644 --- a/references/python/integrations/openai-agents-sdk.md +++ b/references/python/integrations/openai-agents-sdk.md @@ -164,7 +164,6 @@ Note that the initial run context comes from the `context=...` argument you pass In addition, since a `@function_tool` runs in the workflow, they can also call Temporal activities or other durable primitives themselves. - **Don't put I/O, system clock, or sources of randomness inside a `@function_tool` body.** Make it an `@activity.defn` and wrap with `activity_as_tool` instead. ### Picking between the two diff --git a/references/python/testing.md b/references/python/testing.md index 71a47b1..d75c23b 100644 --- a/references/python/testing.md +++ b/references/python/testing.md @@ -154,6 +154,45 @@ async def test_activity(): assert result == "expected" ``` +### Customize Activity Info + +`ActivityEnvironment()` populates `env.info` with a default `temporalio.activity.Info` on construction, so activity code that calls `activity.info()` works out of the box. When your test needs specific values (e.g. asserting on `info.activity_id`, exercising `attempt`-aware retry logic, or simulating a Standalone Activity), build a new `Info` from the helper: + +- `ActivityEnvironment.default_info()` is a `@staticmethod` taking no arguments. It returns a fresh `temporalio.activity.Info` populated with sentinel test values: `activity_id="test"`, `task_queue="test"`, `workflow_id="test"`, `workflow_run_id="test-run"`, `workflow_type="test"`, `namespace="default"`, `workflow_namespace="default"`, `attempt=1`, `start_to_close_timeout=timedelta(seconds=1)`, `schedule_to_close_timeout=timedelta(seconds=1)`, `activity_run_id=None`, `retry_policy=None`, `heartbeat_timeout=None`. +- Customize by passing the result through `dataclasses.replace`, then assigning to `env.info` **before** calling `env.run`: + +```python +import dataclasses +from temporalio.testing import ActivityEnvironment + +env = ActivityEnvironment() +env.info = dataclasses.replace( + ActivityEnvironment.default_info(), + activity_id="order-1234", + attempt=3, +) +await env.run(my_activity, "arg") +``` + +For Standalone Activities ([see `references/python/standalone-activities.md`](standalone-activities.md)), the `activity_run_id` field on `Info` is `None` for Workflow-orchestrated Activities; set it to a string and clear the `workflow_*` fields (each is `Optional[str]`) to test Standalone-flavoured code paths: + +```python +env.info = dataclasses.replace( + ActivityEnvironment.default_info(), + activity_run_id="standalone-run-id", + workflow_id=None, + workflow_run_id=None, + workflow_type=None, + workflow_namespace=None, +) +``` + +Common mistakes: + +- Calling `default_info()` as a module-level function (e.g. `activity.default_info()`); it lives on `temporalio.testing.ActivityEnvironment` as a static method. +- Passing fields directly to `default_info(...)`; it accepts no arguments. Use `dataclasses.replace` on the returned `Info`. +- Mutating `env.info` after `env.run` has started — the activity has already captured the context. + ## Best Practices 1. Use the `WorkflowEnvironment.start_local` environment for most testing diff --git a/references/python/workflow-streams.md b/references/python/workflow-streams.md index 84ecbd7..b53915b 100644 --- a/references/python/workflow-streams.md +++ b/references/python/workflow-streams.md @@ -11,7 +11,6 @@ Use it for modest fan-out progress streaming: AI-agent runs, order pipelines, mu Only available in the Python SDK today; cross-language is on the roadmap. - ## When to use / not to use - Use it for: updating a UI as an AI agent works; surfacing status from a payment or order pipeline; reporting intermediate results from a data job. diff --git a/references/ruby/gotchas.md b/references/ruby/gotchas.md index c2e962c..e56391d 100644 --- a/references/ruby/gotchas.md +++ b/references/ruby/gotchas.md @@ -59,7 +59,6 @@ require_relative 'activities/my_activity' Transient network errors should be retried. Authentication errors should not be. See `references/ruby/error-handling.md` to understand how to classify errors with `non_retryable: true` and `non_retryable_error_types`. - ## Heartbeating ### Forgetting to Heartbeat Long Activities