Label your agent steps

AUTHORS
Lanie Hei
PUBLISHED
Aug 12, 2026
DURATION
6 MIN
  • AI/ML
  • Durable Execution
  • Code Samples

Temporal provides more than fault tolerance during outages. It also gives you a durable trace of every agent call or tool use, making it easier to iterate quickly and debug production sessions.

When building agents on Temporal, a single reusable Activity for LLM and tool calls keeps the codebase clean, maintainable, and allows for more easily rate limiting a given API endpoint. When Workflow history grows, each step becomes indistinguishable from a glance without digging into the payloads.

This blog post outlines how to use an existing Temporal SDK feature to enhance observability and still leverage this reusable pattern.

Setting an Activity summary#

We’ll use the agentic example of coding agent. This follows a plan/edit/test/eval loop:

  1. Call an LLM API to plan the code change
  2. Edit the file
  3. Run tests
  4. Call an LLM API to judge if the tests pass
  5. Timer: Wait for CI to run

If the CI fails, it repeats this loop. Below is what this would look like in the Temporal UI if this agent completed this loop 3x. As the logic for a Workflow gets more complex, it very quickly gets more difficult for human operators to quickly scan for context.

Setting the Summary field on the Activity options improves this view significantly.

await workflow.execute_activity(
    call_llm,
    planner_prompt,
    summary="Plan changes",
    start_to_close_timeout=timedelta(seconds=60),
    retry_policy=retry,
)

The timeline and compact history view now has human and model-readable labels directly on the scheduled events without having to create custom Activity names for each agent type.

On an Activity failure, it’s now much more simple to see what step the Workflow was on before digging into payloads.

These labels also show under the Compact History View

Applying Labels to Adaptive Workflows#

Adaptive Workflows choose their execution path at runtime. For agentic systems, this is the typical case where nondeterministic decisions can change from one run to the next.

Recalling the coding agent example from above, it shows a happy path where every step eventually completes. If the Run tests ExecuteTool Activity is never going to pass, after this Activity fails, we may want to start a Recovery loop where an agent follows a diagnose/act/recheck loop in an effort to keep the agent from spending tokens on untrue assumptions.

During this loop, adding details about the debugging to the loop such as “restart test runner” to an ExecuteTool call shows what an agent was acting on without stepping through the entire debug session.

For more on setting the summary field, see your language’s Enriching UI docs:

SDK Documentation
Go Activity and Timer Summary with Go
Python Activity and Timer Summary with Python
TypeScript Activity and Timer Summary with TypeScript
Java Activity and Timer Summary with Java
.NET Activity and Timer Summary with .NET
PHP Activity and Timer Summary with PHP
Ruby Activity and Timer Summary with Ruby

Labelling Workflows#

A Workflow can also display a summary, along with two other useful fields for agent builders.

  1. Workflow Summary. The static_summary field is a general label for the Workflow. Consider using this as explanation for a generic Workflow, including child Workflows spawned as subagents to do work in parallel.

    This field is immutable after being set. This is for smaller bits of text up to 400 bytes.

handle = await client.start_workflow(
    CodingAgentWithLabels.run,
    task,
    id="coding-agent",
    task_queue="coding-agent-demo",
    static_summary="Coding agent: " + task,
)
  1. Workflow Details. The static_details field is a larger space for more general usage like model or configuration that is known at Workflow start.

    This field is immutable after being set. This is for medium length text up to 20KB.

handle = await client.start_workflow(
    CodingAgentWithLabels.run,
    task,
    id="coding-agent-with-labels",
    task_queue="coding-agent-demo",
    static_details="Task: " + task + "\nModel: Claude Sonnet\nMax iterations: 5",
)
  1. Current Details. This is the only mutable field after the Workflow is scheduled. It can be set within the Workflow code and each call replaces the previous value. It can be used to transfer information to a high level view.

    This value is only shown while the Workflow is in running state, and isn’t shown on Workflow completed, failed, or other terminal states. It’s stored as mutable Workflow state on the server, but not persisted to event history.

    It can be called as many times as is necessary in the Workflow, and it has a limit of 20 KB.

workflow.set_current_details(f"Step {i+1}/{max_iterations}: executing tools")
# ... run tools ...
workflow.set_current_details(f"Step {i+1}/{max_iterations}: judging completeness")
# ... run judge ...
workflow.set_current_details("Completed loop")

Workflow Summary and Details are used to label what the Workflow is, and Current Details is a way to track state.

Below is how the Workflow Summary, Details, and Current Details look in a Workflow under the User Metadata tab. Note that the Current Details are not visible because the Workflow is not in a Running state.

For more on setting Workflow User Metadata fields, refer to the SDK docs in your chosen language:

SDK Documentation
Go Workflow Information with Go
Python Workflow Information with Python
TypeScript Workflow Information with TypeScript
Java Workflow Information with Java
.NET Workflow Information with .NET
PHP Workflow Information with PHP
Ruby Workflow Information with Ruby

Labelling Timers#

Labels on Timers can also be useful to indicate to the operator why the Workflow is waiting. As a last example, this is how to add the Summary field to a Timer and indicate that we’re waiting for a CI to run before rechecking:

await workflow.sleep(timedelta(seconds=5), summary="Wait for CI")

This is visible both in the Timeline and the Compact History view

SDK Availability#

UserMetadata is available across all 7 SDKs. Refer to each SDK’s documentation for further information:

SDK Documentation
Go Enriching UI with Go
Python Enriching UI with Python
TypeScript Enriching UI with TypeScript
Java Enriching UI with Java
.NET Enriching UI with .NET
PHP Enriching UI with PHP
Ruby Enriching UI with Ruby

Temporal Cloud

Ready to see for yourself?

Sign up for Temporal Cloud today and get $1,000 in free credits.

Build invincible applications

It sounds like magic, we promise it's not.