Skip to content

Add LangSmith tracing sample#292

Merged
xumaple merged 14 commits intomainfrom
maplexu/langsmith-sample
Apr 22, 2026
Merged

Add LangSmith tracing sample#292
xumaple merged 14 commits intomainfrom
maplexu/langsmith-sample

Conversation

@xumaple
Copy link
Copy Markdown
Contributor

@xumaple xumaple commented Apr 17, 2026

Summary

  • Adds langsmith_tracing/ sample demonstrating temporalio.contrib.langsmith.LangSmithPlugin
  • basic/: one-shot LLM workflow (prompt → OpenAI activity → result)
  • chatbot/: conversational loop with save_note/read_note tools, signals, queries, and dynamic LangSmith trace names
  • Includes mocked tests, README, and langsmith-tracing dependency group
  • Declares langchain and langsmith-tracing as conflicting groups in [tool.uv] to avoid version conflicts

Test plan

  • poe format — passes
  • mypy on langsmith_tracing/ and tests/langsmith_tracing/ — passes
  • pytest tests/langsmith_tracing/ — basic test passes, chatbot tests skip (pending SDK plugin release)
  • Manual test: run worker + starter for both basic and chatbot examples

🤖 Generated with Claude Code

Comment thread langsmith_tracing/basic/activities.py
Comment thread langsmith_tracing/basic/worker.py Outdated
Comment thread langsmith_tracing/basic/README.md
Comment thread langsmith_tracing/basic/worker.py Outdated
Comment thread langsmith_tracing/basic/workflows.py Outdated
Comment thread langsmith_tracing/chatbot/starter.py Outdated
Comment thread langsmith_tracing/chatbot/workflows.py Outdated
Comment thread langsmith_tracing/chatbot/workflows.py Outdated
xumaple and others added 13 commits April 21, 2026 09:46
Demonstrates the LangSmithPlugin for automatic LangSmith tracing in
Temporal workflows. Includes two examples:
- basic/: one-shot LLM workflow (prompt → OpenAI → result)
- chatbot/: conversational loop with save_note/read_note tools,
  signals, queries, and dynamic trace names

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add @Traceable with metadata, tags, and run_type variety to workflows
- Add client-side @Traceable on starters for end-to-end trace linking
- Add --temporal-runs flag to workers and starters for add_temporal_runs toggle
- Use run_type="llm" for OpenAI calls, "tool" for save_note, "chain" for orchestration
- Add trace tree diagrams to README showing both add_temporal_runs modes
- Add "Three Layers of Tracing" section to README (wrap_openai, @Traceable, Temporal plugin)
- Skip all tests when temporalio.contrib.langsmith is unavailable (pending SDK release)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Split top-level README into per-sample READMEs (basic/ and chatbot/)
  with detailed trace structure diagrams and screenshot placeholders
- Add replay safety comment on @workflow.run methods explaining why
  @Traceable must wrap an inner function
- Make read_note a proper activity for LangSmith trace visibility
- Change save_note/read_note to use NoteRequest dataclass (single arg)
- Fix misplaced comments in activities (wrap_openai, run_type docs)
- Add links to LangSmith docs and Temporal SDK plugin docs
- Add add_temporal_runs explanation section to top-level README

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Audit findings addressed:
- Remove max_cached_workflows=0 (debugging leftover, not needed)
- Expand replay safety comment to explain why (I/O on replay)
- Tighten type annotations: str|list[dict[str,Any]], dict[str,Any]
- Clarify read_note docstring (passthrough for tracing visibility)
- Clarify activity docstrings (retries handled by Temporal, not OpenAI)
- Make trace tree annotations consistent across basic/chatbot READMEs
- Extract shared test helpers (make_text_response, poll_last_response)
- Add TimeoutError on poll failure instead of silent assertion
- Fix "simplest possible" wording to "very simple"

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Changed from explaining internals (I/O on replay) to describing what
the user would see: duplicate or orphaned traces. Also swept all other
comments for outcome-focus — no further changes needed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- save_note and read_note are now @Traceable methods on ChatbotWorkflow,
  not activities. Notes live in workflow state (durable via event history).
- Remove NoteRequest dataclass and activity registrations
- Fix wrap_openai comment placement (describes child span, not parent)
- Remove retry policy from basic workflow (unnecessary for simple example)
- Add comment highlighting that non-@workflow.run methods can use @Traceable
- Update chatbot README trace trees to reflect workflow methods vs activities

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove skip markers from tests — CI should fail loudly if deps missing
- Pin temporalio[pydantic,langsmith]>=1.26.0 (plugin is released)
- Rename kwargs to response_args in chatbot activity
- Remove notes CLI command from chatbot starter
- Update chatbot README trace trees for accuracy
- Change input prompt from "You: " to "> "

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- StartWorkflow/RunWorkflow are siblings, not parent-child
- StartActivity/RunActivity are siblings under RunWorkflow
- @Traceable activity spans nest under RunActivity
- Signal/query traces are separate roots (or under client @Traceable)
- Merge client-side and worker-side into unified trees
- add_temporal_runs=False: only @Traceable spans, all under client root

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
temporalio>=1.26.0 requires openai-agents>=0.14.0 but the openai-agents
group pins ==0.3.2, causing a resolution failure.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Without the group flag, uv resolves the base temporalio dep (1.23.0)
which doesn't have contrib.langsmith.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Simplify basic/worker.py to use asyncio.run(main()) pattern
- Basic activity now returns str instead of Response (drops pydantic dep)
- Remove pydantic_data_converter from basic worker/starter
- Replace chatbot signal+poll with update handler (message_from_user)
- Wrap update handler body in @Traceable for input/output capture
- Inline RetryPolicy in chatbot workflow (no separate RETRY constant)
- Add comment about alternative traceable() function-call style
- Make PROJECT_NAME a shared constant in starters, pass to client-side
  @Traceable so traces go to the right LangSmith project
- Update READMEs with correct trace hierarchies based on real output
- Fix wrap_openai span name (ChatOpenAI, not openai.responses.create)
- Simplify tests (mocks match new str return type, use execute_update)
- Remove poll_last_response helper

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@xumaple xumaple force-pushed the maplexu/langsmith-sample branch from 160c8f8 to 5d7612f Compare April 22, 2026 03:45
@xumaple xumaple marked this pull request as ready for review April 22, 2026 04:46
@xumaple xumaple requested a review from a team as a code owner April 22, 2026 04:46
@xumaple xumaple force-pushed the maplexu/langsmith-sample branch from 950a551 to 5d7612f Compare April 22, 2026 04:55
The langchain sample's langsmith<0.4 pin conflicts with langsmith-tracing's
langsmith>=0.7.0. The langchain sample uses an older custom-interceptor
approach that's superseded by the new LangSmithPlugin demonstrated in
langsmith_tracing/. Removing it eliminates the dep conflict and the
related [tool.uv] conflicts declaration.

Also relax openai pin from <2 to no upper bound so it resolves alongside
the openai-agents group (which now requires openai>=2.26.0).

Add inline comment on max_retries=0 explaining Temporal handles retries.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Comment on lines +32 to +47
@traceable(
name="Basic LLM Request",
run_type="chain",
# CRITICAL: Client-side @traceable runs outside the LangSmithPlugin's scope.
# Make sure client-side traces use the same project_name as what is given to
# # the plugin.
project_name=PROJECT_NAME,
tags=["client-side"],
)
async def run_workflow(prompt: str) -> str:
return await client.execute_workflow(
BasicLLMWorkflow.run,
prompt,
id="langsmith-basic-workflow-id",
task_queue="langsmith-basic-task-queue",
)
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.

probably worth just making this func top-level since it doesn't require the @traceable(...) decorator closing over anything

Copy link
Copy Markdown
Contributor

@JasonSteving99 JasonSteving99 left a comment

Choose a reason for hiding this comment

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

Had one minor suggestion leftover, but LGTM!

@xumaple xumaple merged commit b199e50 into main Apr 22, 2026
11 checks passed
@xumaple xumaple deleted the maplexu/langsmith-sample branch April 22, 2026 18:04
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.

3 participants