Skip to content

add langsmith tracing initialized from environment variables#6271

Open
mmattu-wd wants to merge 1 commit intomainfrom
feat/add-environment-variable-langsmith-tracing
Open

add langsmith tracing initialized from environment variables#6271
mmattu-wd wants to merge 1 commit intomainfrom
feat/add-environment-variable-langsmith-tracing

Conversation

@mmattu-wd
Copy link
Copy Markdown
Contributor

@mmattu-wd mmattu-wd commented Apr 22, 2026

FLOWISE-565

Problem

When langchain is provided with certain environment variables it automatically starts auto tracing requests for Langsmith. See this. This results in Agentflow logging to show single record traces, for every node execution in the agent.

Solution

A new tracingEnv module reads LangSmith settings from the environment (both LANGSMITH_* and legacy LANGCHAIN_* prefixes) and strips the LangChain tracing-flag vars out of process.env on first read so the built-in auto-tracer can no longer fire. applyEnvTracingProviders shapes env configs into the same provider entries the UI produces and merges them into additionalCallbacks and AnalyticHandler.init(), with UI winning on conflict and env-injected providers supplying credentials inline.

This will essentially treat the environment variable as if it were loaded via the UI. Tracing works the exact same.

Verification

Plugged into Langsmith environment. All runs are in there but here is the data.

Before

Before any changes made

Case: Chatflow image
Case: Agentflow image

After

Case: Agentflow - UI Configured 42c73afb-782d-43a3-b41b-b70855988db9
Case: Agentflow - Env Var Configured 9d59a742-7a0d-4618-874b-13367f54f803
Case: Chatflow - UI Configured 4b9b3081-c58c-4101-a2c5-2e738084c362
Case: Chatflow - Env Var Configured fc7de669-deaa-45cf-9ba0-8fc249a84eb0
Case: Multistep Agent - Env Var Configured d81f647d-6d6a-40bb-b8e4-1c0d1b379c58
Case: Multistep Agent - UI Configured bd98377a-b94b-4983-8f2f-1ada56c3953b

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces the ability to configure tracing providers, specifically LangSmith, via environment variables. It adds a new tracingEnv utility to handle environment variable detection, memoization, and merging with UI-based configurations. The PR also fixes a critical bug in AnalyticHandler where recursive onChainStart calls would overwrite the chainRun map, leading to orphaned traces in nested agent flows. A review comment suggests improving the consistency of environment variable detection to ensure all relevant flags are checked before clearing them, preventing potential duplicate traces.

Comment on lines +58 to +59
const tracingFlag = getEnvironmentVariable('LANGSMITH_TRACING') ?? getEnvironmentVariable('LANGCHAIN_TRACING_V2')
if (tracingFlag !== 'true') return undefined
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.

medium

The tracingFlag check only evaluates LANGSMITH_TRACING and LANGCHAIN_TRACING_V2. However, the LANGCHAIN_TRACING_FLAG_VARS array (defined on line 46 and cleared on line 71) includes other variables like LANGSMITH_TRACING_V2 and LANGCHAIN_TRACING (v1).

If a user attempts to enable tracing using one of these other variables, Flowise will not detect it, the function will return undefined, and the environment variables will not be cleared. This would allow LangChain's internal auto-tracer to run, causing the duplicate tracing issue this PR intends to solve. It is better to check all variables in the flag list to ensure consistency.

Suggested change
const tracingFlag = getEnvironmentVariable('LANGSMITH_TRACING') ?? getEnvironmentVariable('LANGCHAIN_TRACING_V2')
if (tracingFlag !== 'true') return undefined
const tracingFlag = LANGCHAIN_TRACING_FLAG_VARS.map((v) => getEnvironmentVariable(v)).find((val) => val === 'true')
if (tracingFlag !== 'true') return undefined

@mmattu-wd mmattu-wd force-pushed the feat/add-environment-variable-langsmith-tracing branch from 5f2568a to a692436 Compare April 22, 2026 18:46
Copy link
Copy Markdown
Contributor

@jocelynlin-wd jocelynlin-wd left a comment

Choose a reason for hiding this comment

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

Thanks for the fix — the env-var tracing approach and the chainRun bug fix are both solid additions.

One thing worth flagging for maintainability: the LangSmith env var names are currently spread across four separate places — which vars activate tracing (getLangSmithEnvConfig), which to delete (LANGCHAIN_TRACING_FLAG_VARS), which to read for config (inline reads for apiKey/endpoint/projectName), and which to register as CLI flags (base.ts). These lists need to stay in sync manually, and they've already drifted slightly in this PR — the delete list has 4 vars but the read logic only checks 2.

A single schema object per provider could help keep everything aligned:

const LANGSMITH_ENV_SCHEMA = {
    tracingFlags: ['LANGSMITH_TRACING', 'LANGCHAIN_TRACING_V2'],
    apiKey:       ['LANGSMITH_API_KEY',  'LANGCHAIN_API_KEY'],
    endpoint:     ['LANGSMITH_ENDPOINT', 'LANGCHAIN_ENDPOINT'],
    projectName:  ['LANGSMITH_PROJECT',  'LANGCHAIN_PROJECT'],
} as const

Every operation — reading, deleting, CLI flag registration — would derive from this one definition, making drift between the lists impossible.

Co-reviewed by Claude Sonnet 4.6

* `process.env` so the auto-tracer doesn't emit duplicate top-level runs alongside Flowise's
* manual `onLLMStart`/`onToolStart` child RunTrees.
*/
const LANGCHAIN_TRACING_FLAG_VARS = ['LANGSMITH_TRACING', 'LANGCHAIN_TRACING_V2', 'LANGSMITH_TRACING_V2', 'LANGCHAIN_TRACING'] as const
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.

LANGCHAIN_TRACING_FLAG_VARS deletes 4 vars (LANGSMITH_TRACING, LANGCHAIN_TRACING_V2, LANGSMITH_TRACING_V2, LANGCHAIN_TRACING), but getLangSmithEnvConfig only checks LANGSMITH_TRACING and LANGCHAIN_TRACING_V2 as activation flags (line 58). A user with LANGSMITH_TRACING_V2=true would have their var silently deleted with no tracing activated. Either check all 4 as valid activation flags, or remove the unchecked ones from the delete list.

Co-reviewed by Claude Sonnet 4.6

// emission from this point on; leaving the flags set would letLangChain's auto-tracer fire on
// every `.invoke()`/`.call()` and produce orphan top-level runs next to the manually-emitted
// parent/child RunTree.
for (const k of LANGCHAIN_TRACING_FLAG_VARS) delete process.env[k]
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.

This function violates Command-Query Separation — it's named like a query (get...) but mutates global state (process.env) as a side effect. Callers don't expect a read function to delete env vars. Consider splitting into two functions: a pure readLangSmithEnvConfig() that only reads, and a separate clearLangChainTracingFlags() called explicitly by the caller. This also makes the side effect visible at the call site rather than hidden inside a getter.

Co-reviewed by Claude Sonnet 4.6

}

/** @internal Test-only: drop cached env-var tracing configs so a subsequent call re-reads env. */
export const resetTracingEnvCache = (): void => {
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.

resetTracingEnvCache exists only because tracingEnvConfigCache is hidden module-level global state. Exporting a test-only reset function is a sign the design is hard to test cleanly. Consider dependency injection — accept the cache or resolver as a parameter — so tests can pass a fresh instance without needing a reset hook.

Co-reviewed by Claude Sonnet 4.6

* activate the same provider. Returns a credentialData map for env-injected providers so the loop
* can skip DB credential loading for those entries.
*/
export const applyEnvTracingProviders = (
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.

applyEnvTracingProviders implies mutation, but this is a pure transform — it returns a new object and explicitly does not mutate its input (there's even a test verifying this). A name like mergeEnvTracingProviders or resolveTracingProviders better reflects what it does.

Co-reviewed by Claude Sonnet 4.6

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