Skip to content

feat(docs): python support agent cookbook example#3623

Merged
abelanger5 merged 12 commits intohatchet-dev:mainfrom
BloggerBust:feat/python-support-agent-example
Apr 21, 2026
Merged

feat(docs): python support agent cookbook example#3623
abelanger5 merged 12 commits intohatchet-dev:mainfrom
BloggerBust:feat/python-support-agent-example

Conversation

@BloggerBust
Copy link
Copy Markdown
Contributor

Description

Adds a new cookbook docs page for building a support agent with Hatchet, along with the supporting Python example and trigger/example files.

This PR introduces a practical end-to-end workflow example that:

  • receives a support ticket
  • triages it
  • generates an initial reply
  • waits for either a customer reply event or a timeout
  • resolves when a reply arrives
  • escalates when the timeout fires first

It also adds a new Workflow Patterns section to the cookbooks index so this example is separate from the existing webhook-focused cookbook entries.

The Python example uses the snippet markers and was validated locally against a live Hatchet instance. The current implementation supports live Claude interaction when ANTHROPIC_API_KEY is set, and a fixed fallback reply when it is not.

Type of change

  • Documentation change (pure documentation change)

What's Changed

  • Add a new cookbook page: workflow-support-agent.mdx
  • Add a new "Workflow Patterns" section to the cookbooks index
  • Add a Python support agent example under examples/python/support_agent/
  • Add a snippet region for the trigger script
  • Register the support agent example in the central Python example worker
  • Add E2E coverage for the resolved and timeout/escalation paths
  • Document a durable workflow pattern that uses consider_events_since to safely capture early reply events

@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 15, 2026

@BloggerBust is attempting to deploy a commit to the Hatchet Team on Vercel.

A member of the Team first needs to authorize it.

@BloggerBust BloggerBust changed the title Feat/python support agent example feat(docs): python support agent cookbook example Apr 15, 2026
@BloggerBust BloggerBust force-pushed the feat/python-support-agent-example branch from ec71b43 to 6e320ec Compare April 15, 2026 18:51
promptless-for-oss pushed a commit to Promptless/oss-contrib-hatchet-dev-hatchet that referenced this pull request Apr 15, 2026
This adds the new workflow-support-agent page to the cookbooks sidebar
with a "Workflow Patterns" separator to match the section added to
the cookbooks index in PR hatchet-dev#3623.
@BloggerBust BloggerBust force-pushed the feat/python-support-agent-example branch from 6e320ec to 9998a39 Compare April 15, 2026 18:51
@promptless-for-oss
Copy link
Copy Markdown

Promptless prepared a documentation update related to this change.

Triggered by PR #3623

The PR adds the cookbook page but is missing the sidebar navigation update in _meta.js. This suggestion adds the "Workflow Patterns" separator and the workflow-support-agent entry so the new cookbook page will appear in the docs site navigation.

Review: Add support agent meta entry

@BloggerBust BloggerBust force-pushed the feat/python-support-agent-example branch 2 times, most recently from 6c74e04 to 98eef2b Compare April 15, 2026 21:03
@BloggerBust
Copy link
Copy Markdown
Contributor Author

Added the Workflow Patterns separator and the support agent entry to frontend/docs/pages/cookbooks/_meta.js.

@BloggerBust BloggerBust force-pushed the feat/python-support-agent-example branch from 78bd25d to 2a375ab Compare April 16, 2026 17:03
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 16, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
hatchet-docs Ready Ready Preview, Comment Apr 21, 2026 8:58pm

Request Review

Copy link
Copy Markdown
Contributor

@mrkaye97 mrkaye97 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

left a couple of small comments on the python side! looks great broadly though, very cool

text = subject + " " + body

if any(word in text for word in ["bill", "charge", "payment", "invoice"]):
category = "billing"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe we can make this and the priority into enums if we're always returning one of a few categories? doesn't super duper matter, but one of those things that if we're going to be making recommendations via these examples for how to structure things, I'd love to recommend

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the feedback Matt! I considered enums here, but I kept these as simple strings to keep the example compact and focused on the workflow pattern, and to avoid adding extra modeling overhead in a small cookbook example.

@hatchet.task(input_validator=SupportTicketInput)
async def generate_reply(input: SupportTicketInput, ctx: Context) -> ReplyOutput:
"""Generate an initial support reply using Claude."""
api_key = os.environ.get("ANTHROPIC_API_KEY")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ideally we'd prefer pydantic-settings for managing config IMO, or at the very least, read this on worker start and crash immediately so we don't fail tasks at runtime

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense in production, but for this cookbook example I intentionally kept the provider / API key optional and supplied a fixed fallback response when it is not provided. I wanted the example to remain runnable even for users who do not have an Anthropic API key, so they can still see the intended workflow behavior end to end.

Comment on lines +87 to +90
import importlib

anthropic = importlib.import_module("anthropic")
client = anthropic.AsyncAnthropic(api_key=api_key)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's the reason for burying this import? so we don't need to add any deps? (if yes totally fine, although maybe we could also set this example up as an extra or an optional dep so we could rework here a bit)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is correct. I kept the Anthropic import local so the dependency remains optional for this cookbook example, which lets users run the example even if they do not have an API key or do not want to install the provider dependency just to follow the workflow pattern.

@hatchet.durable_task(input_validator=SupportTicketInput)
async def support_agent(
input: SupportTicketInput, ctx: DurableContext
) -> dict[str, Any]:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would be great to return a pydantic model here too if we can

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I agree that a typed Pydantic return model could be a nice refinement here. I left the workflow return as a simple dict to keep the example smaller and focused on the control-flow pattern.

Comment on lines +144 to +159
wait_result = await ctx.aio_wait_for(
"await-customer-reply",
or_(
SleepCondition(timedelta(seconds=TIMEOUT_SECONDS)),
UserEventCondition(
event_key=REPLY_EVENT_KEY,
scope=input.ticket_id,
consider_events_since=consider_events_since,
),
),
)

# The or-group result is {"CREATE": {"<condition_key>": ...}}.
# Check whether the reply event condition was the one that resolved.
resolved_key = list(wait_result["CREATE"].keys())[0]
customer_replied = resolved_key == REPLY_EVENT_KEY
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so this is an issue on the SDK for sure, and I need to think about how to fix it, but what's the objective here? is it basically to wait for the event with a timeout? the raw aio_wait_for with an or group kind of sucks because it returns this thing that really should be internal, as you've discovered, so I might need to cook up some better way of doing this sort of thing... I wonder if adding a timeout: timedelta parameter to the wait could work, or something like that... I'm not too sure. I think this is okay for now, but ideally we could do this in a way where we don't need to use the internal CREATE match object, although that might be challenging

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, exactly, the objective here is to wait for the customer reply event with a timeout. I agree the raw aio_wait_for(... or_(...)) result is a bit awkward to expose in an example, but this seemed like the most direct way to express the branching with the current SDK. As the SDK improves I would be happy to revisit the example.

Copy link
Copy Markdown
Contributor

@abelanger5 abelanger5 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💯 this looks great! Left some small comments and going to let @mrkaye97 leave comments on the code. In general I think explaining concepts a bit more and adding internal links to docs would be really helpful, but I like the clear and direct tone and it's easy to follow along.

Comment thread frontend/docs/pages/cookbooks/workflow-support-agent.mdx Outdated
Comment thread frontend/docs/pages/cookbooks/workflow-support-agent.mdx Outdated
Comment thread frontend/docs/pages/cookbooks/workflow-support-agent.mdx Outdated
Comment thread frontend/docs/pages/cookbooks/workflow-support-agent.mdx Outdated
Comment thread frontend/docs/pages/cookbooks/workflow-support-agent.mdx Outdated
Comment thread frontend/docs/pages/cookbooks/workflow-support-agent.mdx Outdated
@abelanger5 abelanger5 merged commit 950aaca into hatchet-dev:main Apr 21, 2026
24 checks passed
wsehl pushed a commit to wsehl/hatchet that referenced this pull request Apr 23, 2026
* feat(python): add support_agent example with durable reply handling

- add support_agent durable workflow example
- add triage, reply generation, and escalation tasks
- use consider_events_since for early scoped reply events
- add trigger script for the example
- add E2E tests for resolved and timeout paths
- register support_agent workflows in the central example worker

* docs(cookbooks): add support agent workflow cookbook and example snippets

* docs(cookbooks): add support agent sidebar entry

* docs(cookbooks): minor improvement to support agent intro and fallback wording

* docs(cookbooks): document support agent worker registration

* docs(cookbooks): document support agent worker registration

* docs(lint): Fixed black errors

* docs(cookbooks): Improve phrasing and explanations

Also include how to run the tests themselves.

* docs(cookbooks): replace ASCII diagram with Mermaid

* docs(cookbooks): Generalize intro beyond support workflows

* docs(cookbooks): add links to support agent cookbook

* docs(cookbooks): clarify durable workflow rationale
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants