Context
In May 2026, we released SmithDB, a new observability database built for modern AI agents. SmithDB delivers industry-leading performance across every key observability workload, making core LangSmith experiences dramatically faster. SmithDB-powered methods are now available to SDK users in eligible regions.Deployment support
| Deployment | Status |
|---|---|
| US SaaS | Available. Methods are fully SmithDB-backed. |
| EU and other SaaS regions | Methods are available but not yet backed by SmithDB. |
| Self-hosted | Supported starting with self-hosted version 0.16.0. |
Minimum SDK version
The SmithDB-backed methods require a minimum SDK version:| Language | Package | Minimum version |
|---|---|---|
| Python | langsmith | >=0.9.8 |
| TypeScript | langsmith | >=0.7.15 |
| Java | langsmith-java | 0.1.0-beta.11 |
| Go | langsmith-go | v0.17.0 |
Migrate with an AI agent
This guide is written to be fetched and applied directly by an AI coding agent. Copy the following prompt into your agent to migrate your codebase to the SmithDB-backed methods.Migrate this codebase's LangSmith SDK usage to the new SmithDB-backed methods.
Fetch https://docs.langchain.com/langsmith/smithdb-sdk-migration.md and treat it
as the source of truth for what changed, including which methods and
parameters are affected, what replaces them, and deployment support.
1. Check the installed LangSmith SDK version against the minimum version
required for the SmithDB-backed methods per the guide, and upgrade the
dependency if it does not meet that minimum.
2. Identify every call site in this codebase that uses a method the guide
marks as migrated, in whichever language(s) this codebase uses.
3. For each call site, apply the corresponding before/after change from the
guide, including any added, removed, or renamed parameters.
If a call site or parameter is not covered by the guide, stop and ask rather
than guessing.
Runs: query
Query runs from a project with optional filtering and field projection. Returns a paginated result set.Main changes
Method name
- Python
- TypeScript
- Java
- Go
- cURL
| Before | After |
|---|---|
client.list_runs() | client.runs.query() |
| Before | After |
|---|---|
client.listRuns() | client.runs.query() |
| Before | After |
|---|---|
client.runs().query() | client.runs().queryV2() |
| Before | After |
|---|---|
client.Runs.Query() | client.Runs.QueryV2() |
| Before | After |
|---|---|
POST /api/v1/runs/query | POST /v2/runs/query |
Query parameters
- Python
- TypeScript
- Java
- Go
- cURL
project_name is not supported in runs.query. Pass project_ids with the project UUID instead. To look up a UUID by name, use client.read_project(project_name="my-project"), or await client.aread_project(project_name="my-project") in async code.min_start_time defaults to 1 day ago when omitted. list_runs with no start_time returned all historical runs; runs.query without min_start_time silently scopes the query to the last 24 hours. Pass an explicit min_start_time if you need a wider window.Before (list_runs) | After (runs.query) | Notes |
|---|---|---|
project_name | (removed) | Use project_ids with UUID(s)—see warning above |
project_id | project_ids | Now takes a list; mutually exclusive with reference_dataset_id |
run_type | run_type | Values must now be uppercase: "LLM", "CHAIN", "TOOL", "RETRIEVER", "EMBEDDING", "PROMPT", "PARSER" |
trace_id | trace_id | Unchanged |
reference_example_id | reference_examples | Now takes a list of UUIDs |
query | (removed) | No equivalent |
filter | filter | Syntax unchanged |
trace_filter | trace_filter | Unchanged |
tree_filter | tree_filter | Unchanged |
is_root | is_root | Unchanged |
parent_run_id | (removed) | No equivalent |
start_time | min_start_time | Renamed; defaults to 1 day ago—see warning above |
error | has_error | Renamed |
run_ids | ids | Renamed |
select | selects | Field names are now uppercase ("NAME", "STATUS", etc.) |
limit | (removed) | Use page_size for per-request batch size |
| (not available) | max_start_time | Upper bound for start_time; defaults to now |
| (not available) | page_size | Per-request result count (default 100, max 1000) |
| (not available) | reference_dataset_id | Alternative to project_ids; mutually exclusive |
| (not available) | cursor | Pass next_cursor from previous response to fetch next page |
projectName is not supported in client.runs.query. Pass project_ids with the project UUID instead. To look up a UUID by name, use client.readProject({ projectName: "my-project" }).min_start_time defaults to 1 day ago when omitted. listRuns with no startTime returned all historical runs; client.runs.query without min_start_time silently scopes the query to the last 24 hours. Pass an explicit min_start_time if you need a wider window.Before (listRuns) | After (client.runs.query) | Notes |
|---|---|---|
projectName | (removed) | Use project_ids with UUID(s)—see warning above |
projectId | project_ids | Renamed to snake_case; now takes a list; mutually exclusive with reference_dataset_id |
runType | run_type | Renamed to snake_case; values must now be uppercase: "LLM", "CHAIN", "TOOL", "RETRIEVER", "EMBEDDING", "PROMPT", "PARSER" |
traceId | trace_id | Renamed to snake_case |
referenceExampleId | reference_examples | Renamed to snake_case; now takes a list of UUIDs |
query | (removed) | No equivalent |
filter | filter | Syntax unchanged |
traceFilter | trace_filter | Renamed to snake_case |
treeFilter | tree_filter | Renamed to snake_case |
isRoot | is_root | Renamed to snake_case |
parentRunId | (removed) | No equivalent |
startTime | min_start_time | Renamed to snake_case; defaults to 1 day ago—see warning above |
error | has_error | Renamed |
id | ids | Renamed |
select | selects | Field names are now uppercase ("NAME", "STATUS", etc.) |
limit | (removed) | Use page_size for per-request batch size |
order | (removed) | No equivalent |
executionOrder | (removed) | No equivalent |
| (not available) | max_start_time | Upper bound for start_time; defaults to now |
| (not available) | page_size | Per-request result count (default 100, max 1000) |
| (not available) | reference_dataset_id | Alternative to project_ids; mutually exclusive |
| (not available) | cursor | Pass next_cursor from previous response to fetch next page |
minStartTime() defaults to 1 day ago when omitted. query() with no startTime() returned all historical runs; queryV2() without minStartTime() silently scopes the query to the last 24 hours. Pass an explicit minStartTime() if you need a wider window.Before (RunQueryParams) | After (RunQueryV2Params) | Notes |
|---|---|---|
session() | projectIds() | Renamed; now takes explicit project UUIDs |
runType() | runType() | Values must now be uppercase |
trace() | traceId() | Renamed |
referenceExample() | referenceExamples() | Renamed to plural |
query() | (removed) | No equivalent |
filter() | filter() | Syntax unchanged |
traceFilter() | traceFilter() | Unchanged |
treeFilter() | treeFilter() | Unchanged |
isRoot() | isRoot() | Unchanged |
parentRun() | (removed) | No equivalent |
startTime() | minStartTime() | Renamed; defaults to 1 day ago—see warning above |
error() | hasError() | Renamed |
id() | ids() | Renamed |
select() | selects() | Field names are now uppercase |
limit() | (removed) | Use pageSize() |
order() | (removed) | No equivalent |
executionOrder() | (removed) | No equivalent |
cursor() | cursor() | Unchanged |
| (not available) | maxStartTime() | Upper bound for start time; defaults to now |
| (not available) | pageSize() | Per-request result count (default 100, max 1000) |
| (not available) | referenceDatasetId() | Alternative to projectIds() |
MinStartTime defaults to 1 day ago when omitted. Query() with no StartTime returned all historical runs; QueryV2() without MinStartTime silently scopes the query to the last 24 hours. Pass an explicit MinStartTime if you need a wider window.Before (RunQueryParams) | After (RunQueryV2Params) | Notes |
|---|---|---|
Session | ProjectIDs | Renamed; now takes explicit project UUIDs |
RunType | RunType | Values must now be uppercase: RunQueryV2ParamsRunTypeLLM, RunQueryV2ParamsRunTypeChain, etc. |
Trace | TraceID | Renamed |
ReferenceExample | ReferenceExamples | Renamed to plural |
Query | (removed) | No equivalent |
Filter | Filter | Unchanged |
TraceFilter | TraceFilter | Unchanged |
TreeFilter | TreeFilter | Unchanged |
IsRoot | IsRoot | Unchanged |
ParentRun | (removed) | No equivalent |
StartTime | MinStartTime | Renamed; defaults to 1 day ago—see warning above |
Error | HasError | Renamed |
ID | IDs | Renamed |
Select | Selects | Field name constants are now uppercase (e.g., RunQueryV2ParamsSelectName) |
Limit | (removed) | Use PageSize |
Order | (removed) | No equivalent |
ExecutionOrder | (removed) | No equivalent |
Cursor | Cursor | Unchanged |
| (not available) | MaxStartTime | Upper bound for start time; defaults to now |
| (not available) | PageSize | Per-request result count (default 100, max 1000) |
| (not available) | ReferenceDatasetID | Alternative to ProjectIDs |
min_start_time defaults to 1 day ago when omitted. POST /api/v1/runs/query with no start_time returned all historical runs; POST /v2/runs/query without min_start_time silently scopes the query to the last 24 hours. Pass an explicit min_start_time if you need a wider window.Before (v1 POST /api/v1/runs/query body field) | After (v2 POST /v2/runs/query body field) | Notes |
|---|---|---|
session | project_ids | Renamed; both take an array of project UUIDs. project_ids is mutually exclusive with reference_dataset_id |
run_type | run_type | Values must now be uppercase: "LLM", "CHAIN", "TOOL", "RETRIEVER", "EMBEDDING", "PROMPT", "PARSER" |
trace | trace_id | Renamed |
reference_example | reference_examples | Renamed to plural; now takes an array of UUIDs |
query | (removed) | No equivalent |
filter | filter | Syntax unchanged |
trace_filter | trace_filter | Unchanged |
tree_filter | tree_filter | Unchanged |
is_root | is_root | Unchanged |
parent_run | (removed) | No equivalent |
start_time | min_start_time | Renamed; defaults to 1 day ago—see warning above |
error | has_error | Renamed |
id | ids | Renamed to plural |
select | selects | Field names are now uppercase ("NAME", "STATUS", etc.) |
limit | (removed) | Use page_size for per-request batch size |
| (not available) | max_start_time | Upper bound for start_time; defaults to now |
| (not available) | page_size | Per-request result count (default 100, max 1000) |
| (not available) | reference_dataset_id | Alternative to project_ids; mutually exclusive |
| (not available) | cursor | Pass next_cursor from previous response to fetch next page |
Response fields
- Python
- TypeScript
- Java
- Go
- cURL
Pass SCREAMING_SNAKE_CASE strings to
selects (eg. "ID", "NAME", "STATUS") to control which fields are populated on each Run; only selected fields are non-None. Default selects contains only "ID".Before (v1 Run attribute) | After (v2 Run attribute) | Notes |
|---|---|---|
run.id | run.id | Unchanged; returned by default when selects is omitted |
run.name | run.name | Unchanged |
run.run_type | run.run_type | Values are now uppercase Literals: "LLM", "CHAIN", etc. |
run.status | run.status | Values: "SUCCESS", "ERROR", "PENDING" |
run.start_time | run.start_time | Unchanged |
run.end_time | run.end_time | Unchanged |
run.error | run.error | Unchanged |
run.inputs | run.inputs | Unchanged |
run.outputs | run.outputs | Unchanged |
run.tags | run.tags | Unchanged |
run.extra | run.extra | Unchanged |
run.metadata | run.metadata | Unchanged |
run.events | run.events | Unchanged |
run.reference_example_id | run.reference_example_id | Unchanged |
run.trace_id | run.trace_id | Unchanged |
run.dotted_order | run.dotted_order | Unchanged |
run.parent_run_id | (removed) | Use run.parent_run_ids (list of all ancestor UUIDs, root first) |
run.parent_run_ids | run.parent_run_ids | Unchanged |
run.session_id | run.project_id | Renamed; session_id was the project UUID |
run.feedback_stats | run.feedback_stats | Unchanged |
run.app_path | run.app_path | Unchanged |
run.attachments | run.attachments | v2 returns pre-signed download URLs instead of raw bytes |
run.total_tokens | run.total_tokens | Unchanged |
run.prompt_tokens | run.prompt_tokens | Unchanged |
run.completion_tokens | run.completion_tokens | Unchanged |
run.total_cost | run.total_cost | Unchanged |
run.prompt_cost | run.prompt_cost | Unchanged |
run.completion_cost | run.completion_cost | Unchanged |
run.first_token_time | run.first_token_time | Unchanged |
run.latency (property) | run.latency_seconds | Renamed; was a computed timedelta property, now a native float field |
run.in_dataset | run.is_in_dataset | Renamed |
run.child_run_ids | (removed) | No equivalent |
run.child_runs | (removed) | No equivalent |
run.serialized | (removed) | Use run.manifest |
run.manifest_id | (removed) | Use run.manifest |
| (not available) | run.is_root | New |
| (not available) | run.manifest | New: full manifest object (replaces serialized and manifest_id) |
| (not available) | run.error_preview | New: truncated error snippet |
| (not available) | run.inputs_preview | New: truncated inputs preview |
| (not available) | run.outputs_preview | New: truncated outputs preview |
| (not available) | run.thread_id | New: conversation thread UUID |
| (not available) | run.reference_dataset_id | New: dataset UUID for the reference example |
| (not available) | run.share_url | New: public share URL (only set when the run has been shared) |
run.prompt_token_details | run.prompt_token_details.raw | Field now wraps the dict; access .raw to get dict[str, int] (element type unchanged) |
run.completion_token_details | run.completion_token_details.raw | Field now wraps the dict; access .raw to get dict[str, int] (element type unchanged) |
run.prompt_cost_details | run.prompt_cost_details.raw | Field now wraps the dict; access .raw to get dict[str, float] (was dict[str, Decimal]) |
run.completion_cost_details | run.completion_cost_details.raw | Field now wraps the dict; access .raw to get dict[str, float] (was dict[str, Decimal]) |
Pass SCREAMING_SNAKE_CASE strings to
selects (eg. "ID", "NAME", "STATUS") to control which fields are populated on each Run. Default selects contains only "ID".Before (v1 Run property) | After (v2 Run property) | Notes |
|---|---|---|
run.id | run.id | Unchanged |
run.name | run.name | Unchanged |
run.runType | run.run_type | Renamed to snake_case; values are now uppercase: "LLM", "CHAIN", etc. |
run.status | run.status | Values: "SUCCESS", "ERROR", "PENDING" |
run.startTime | run.start_time | Renamed to snake_case |
run.endTime | run.end_time | Renamed to snake_case |
run.error | run.error | Unchanged |
run.inputs | run.inputs | Unchanged |
run.outputs | run.outputs | Unchanged |
run.tags | run.tags | Unchanged |
run.extra | run.extra | Unchanged |
| (not available) | run.metadata | New: previously accessed via run.extra.metadata |
run.events | run.events | Unchanged |
run.referenceExampleId | run.reference_example_id | Renamed to snake_case |
run.traceId | run.trace_id | Renamed to snake_case |
run.dottedOrder | run.dotted_order | Renamed to snake_case |
run.parentRunId | (removed) | Use run.parent_run_ids (list of all ancestor UUIDs, root first) |
run.parentRunIds | run.parent_run_ids | Renamed to snake_case |
run.sessionId | run.project_id | Renamed; sessionId was the project UUID |
run.feedbackStats | run.feedback_stats | Renamed to snake_case |
run.appPath | run.app_path | Renamed to snake_case |
run.attachments | run.attachments | v2 returns pre-signed download URLs instead of raw bytes |
run.totalTokens | run.total_tokens | Renamed to snake_case |
run.promptTokens | run.prompt_tokens | Renamed to snake_case |
run.completionTokens | run.completion_tokens | Renamed to snake_case |
run.totalCost | run.total_cost | Renamed to snake_case |
run.promptCost | run.prompt_cost | Renamed to snake_case |
run.completionCost | run.completion_cost | Renamed to snake_case |
run.firstTokenTime | run.first_token_time | Renamed to snake_case |
run.latency | run.latency_seconds | Renamed; was a computed property, now a native number field (seconds) |
run.inDataset | run.is_in_dataset | Renamed |
run.childRunIds | (removed) | No equivalent |
run.childRuns | (removed) | No equivalent |
run.serialized | (removed) | Use run.manifest |
run.manifestId | (removed) | Use run.manifest |
run.shareToken | (removed) | Use run.share_url (full URL, only set when the run has been shared) |
| (not available) | run.is_root | New |
| (not available) | run.manifest | New: full manifest object (replaces serialized and manifestId) |
| (not available) | run.error_preview | New: truncated error snippet |
| (not available) | run.inputs_preview | New: truncated inputs preview |
| (not available) | run.outputs_preview | New: truncated outputs preview |
| (not available) | run.thread_id | New: conversation thread UUID |
| (not available) | run.reference_dataset_id | New: dataset UUID for the reference example |
| (not available) | run.share_url | New: public share URL (only set when the run has been shared) |
| (not available) | run.prompt_token_details | New: per-category prompt token breakdown |
| (not available) | run.completion_token_details | New: per-category completion token breakdown |
| (not available) | run.prompt_cost_details | New: per-category prompt cost breakdown |
| (not available) | run.completion_cost_details | New: per-category completion cost breakdown |
Add
RunQueryV2Params.Select values (eg. Select.NAME, Select.STATUS) via .addSelect(...) to control which fields are populated; unselected fields return empty Optional values. selects() defaults to ID only.Before (RunSchema method) | After (Run method) | Notes |
|---|---|---|
run.id() | run.id() | Unchanged |
run.name() | run.name() | Unchanged |
run.runType() | run.runType() | Values are now uppercase: "LLM", "CHAIN", etc. |
run.status() | run.status() | Values: "SUCCESS", "ERROR", "PENDING" |
run.startTime() | run.startTime() | Unchanged |
run.endTime() | run.endTime() | Unchanged |
run.error() | run.error() | Unchanged |
run.inputs() | run.inputs() | Unchanged |
run.outputs() | run.outputs() | Unchanged |
run.tags() | run.tags() | Unchanged |
run.extra() | run.extra() | Unchanged |
run.events() | run.events() | Unchanged |
run.feedbackStats() | run.feedbackStats() | Unchanged |
run.inputsPreview() | run.inputsPreview() | Unchanged |
run.outputsPreview() | run.outputsPreview() | Unchanged |
run.referenceExampleId() | run.referenceExampleId() | Unchanged |
run.traceId() | run.traceId() | Unchanged |
run.dottedOrder() | run.dottedOrder() | Unchanged |
run.parentRunId() | (removed) | Use run.parentRunIds() (list of all ancestor UUIDs, root first) |
run.parentRunIds() | run.parentRunIds() | Unchanged |
run.sessionId() | run.projectId() | Renamed; sessionId() returned the project UUID |
run.appPath() | run.appPath() | Unchanged |
run.firstTokenTime() | run.firstTokenTime() | Unchanged |
run.totalTokens() | run.totalTokens() | Unchanged |
run.promptTokens() | run.promptTokens() | Unchanged |
run.completionTokens() | run.completionTokens() | Unchanged |
run.totalCost() | run.totalCost() | Return type changed from Optional<String> to Optional<Double> |
run.promptCost() | run.promptCost() | Return type changed from Optional<String> to Optional<Double> |
run.completionCost() | run.completionCost() | Return type changed from Optional<String> to Optional<Double> |
run.promptTokenDetails() | run.promptTokenDetails() | Unchanged |
run.completionTokenDetails() | run.completionTokenDetails() | Unchanged |
run.promptCostDetails() | run.promptCostDetails() | Unchanged |
run.completionCostDetails() | run.completionCostDetails() | Unchanged |
run.priceModelId() | run.priceModelId() | Unchanged |
run.inDataset() | run.isInDataset() | Renamed |
run.referenceDatasetId() | run.referenceDatasetId() | Unchanged |
run.threadId() | run.threadId() | Unchanged |
run.shareToken() | (removed) | Use run.shareUrl() (full URL, only set when the run has been shared) |
run.childRunIds() | (removed) | No equivalent |
run.directChildRunIds() | (removed) | No equivalent |
run.serialized() | (removed) | Use run.manifest() |
run.manifestId() | (removed) | Use run.manifest() |
run.messages() | (removed) | No equivalent |
run.executionOrder() | (removed) | No equivalent |
run.lastQueuedAt() | (removed) | No equivalent |
run.traceFirstReceivedAt() | (removed) | No equivalent |
run.traceMaxStartTime() | (removed) | No equivalent |
run.traceMinStartTime() | (removed) | No equivalent |
run.traceTier() | (removed) | No equivalent |
run.traceUpgrade() | (removed) | No equivalent |
run.ttlSeconds() | (removed) | No equivalent |
| (not available) | run.attachments() | New: pre-signed download URLs for attachments (replaces S3 URL fields) |
| (not available) | run.latencySeconds() | New: wall-clock duration in seconds |
| (not available) | run.isRoot() | New |
| (not available) | run.errorPreview() | New: truncated error snippet |
| (not available) | run.manifest() | New: full manifest, typed as Optional<Manifest> (replaces serialized() and manifestId()) |
| (not available) | run.metadata() | New: metadata, typed as Optional<Metadata> (was derived from extra.metadata) |
| (not available) | run.shareUrl() | New: public share URL (only set when the run has been shared) |
| (not available) | run.threadEvaluationTime() | New |
Pass
RunQueryV2ParamsSelect constants (eg. RunQueryV2ParamsSelectName, RunQueryV2ParamsSelectStatus) to Selects to control which fields are populated; unselected fields are zero-valued on the returned struct. Selects defaults to ID only.Before (RunSchema field) | After (Run field) | Notes |
|---|---|---|
run.ID | run.ID | Unchanged |
run.Name | run.Name | Unchanged |
run.RunType | run.RunType | Values changed to uppercase: "LLM", "CHAIN", etc. |
run.Status | run.Status | Values: "SUCCESS", "ERROR", "PENDING" |
run.TraceID | run.TraceID | Unchanged |
run.DottedOrder | run.DottedOrder | Unchanged |
run.AppPath | run.AppPath | Unchanged |
run.StartTime | run.StartTime | Unchanged |
run.EndTime | run.EndTime | Unchanged |
run.Error | run.Error | Unchanged |
run.Events | run.Events | Unchanged; element type is now RunEvent (was map[string]interface{}) |
run.Extra | run.Extra | Unchanged; type is now interface{} (was map[string]interface{}) |
run.FeedbackStats | run.FeedbackStats | Unchanged; element type is now RunFeedbackStat |
run.FirstTokenTime | run.FirstTokenTime | Unchanged |
run.Inputs | run.Inputs | Unchanged; type is now interface{} (was map[string]interface{}) |
run.InputsPreview | run.InputsPreview | Unchanged |
run.Outputs | run.Outputs | Unchanged; type is now interface{} (was map[string]interface{}) |
run.OutputsPreview | run.OutputsPreview | Unchanged |
run.ParentRunIDs | run.ParentRunIDs | Unchanged |
run.PriceModelID | run.PriceModelID | Unchanged |
run.PromptCost | run.PromptCost | Unchanged |
run.PromptCostDetails | run.PromptCostDetails.Raw | Field now wraps the map; access .Raw to get map[string]float64 (was map[string]string) |
run.PromptTokenDetails | run.PromptTokenDetails.Raw | Field now wraps the map; access .Raw to get map[string]int64 (element type unchanged) |
run.PromptTokens | run.PromptTokens | Unchanged |
run.CompletionCost | run.CompletionCost | Unchanged |
run.CompletionCostDetails | run.CompletionCostDetails.Raw | Field now wraps the map; access .Raw to get map[string]float64 (was map[string]string) |
run.CompletionTokenDetails | run.CompletionTokenDetails.Raw | Field now wraps the map; access .Raw to get map[string]int64 (element type unchanged) |
run.CompletionTokens | run.CompletionTokens | Unchanged |
run.TotalCost | run.TotalCost | Unchanged |
run.TotalTokens | run.TotalTokens | Unchanged |
run.ReferenceDatasetID | run.ReferenceDatasetID | Unchanged |
run.ReferenceExampleID | run.ReferenceExampleID | Unchanged |
run.Tags | run.Tags | Unchanged |
run.ThreadID | run.ThreadID | Unchanged |
run.SessionID | run.ProjectID | Renamed |
run.InDataset | run.IsInDataset | Renamed |
run.ChildRunIDs | (removed) | No equivalent |
run.DirectChildRunIDs | (removed) | No equivalent |
run.ExecutionOrder | (removed) | No equivalent |
run.InputsS3URLs | (removed) | Internal storage URL; not exposed in v2 |
run.LastQueuedAt | (removed) | No equivalent |
run.ManifestID | (removed) | Use run.Manifest |
run.ManifestS3ID | (removed) | Internal storage URL; not exposed in v2 |
run.Messages | (removed) | No equivalent |
run.OutputsS3URLs | (removed) | Internal storage URL; not exposed in v2 |
run.ParentRunID | (removed) | Use run.ParentRunIDs |
run.S3URLs | (removed) | Internal storage URL; not exposed in v2 |
run.Serialized | (removed) | Use run.Manifest |
run.ShareToken | (removed) | Use run.ShareURL |
run.TraceFirstReceivedAt | (removed) | No equivalent |
run.TraceMaxStartTime | (removed) | No equivalent |
run.TraceMinStartTime | (removed) | No equivalent |
run.TraceTier | (removed) | No equivalent |
run.TraceUpgrade | (removed) | No equivalent |
run.TtlSeconds | (removed) | No equivalent |
| (not available) | run.Attachments | New: maps attachment filename to pre-signed download URL |
| (not available) | run.ErrorPreview | New: truncated error snippet |
| (not available) | run.IsRoot | New |
| (not available) | run.LatencySeconds | New: wall-clock duration in seconds |
| (not available) | run.Manifest | New: full manifest object (replaces Serialized and ManifestID) |
| (not available) | run.Metadata | New: arbitrary user-defined JSON metadata |
| (not available) | run.ShareURL | New: public share URL (only set when the run has been shared) |
| (not available) | run.ThreadEvaluationTime | New |
Field names in the JSON response match Python
snake_case.Pass SCREAMING_SNAKE_CASE strings in the selects JSON array (eg. "ID", "NAME", "STATUS") to control which fields are populated. Default selects contains only "ID".| Before (v1 response field) | After (v2 response field) | Notes |
|---|---|---|
id | id | Unchanged |
name | name | Unchanged |
run_type | run_type | Values changed to uppercase: "LLM", "CHAIN", etc. |
status | status | Values: "SUCCESS", "ERROR", "PENDING" |
trace_id | trace_id | Unchanged |
dotted_order | dotted_order | Unchanged |
app_path | app_path | Unchanged |
start_time | start_time | Unchanged |
end_time | end_time | Unchanged |
error | error | Unchanged |
events | events | Unchanged |
extra | extra | Unchanged |
feedback_stats | feedback_stats | Unchanged |
first_token_time | first_token_time | Unchanged |
inputs | inputs | Unchanged |
inputs_preview | inputs_preview | Unchanged |
outputs | outputs | Unchanged |
outputs_preview | outputs_preview | Unchanged |
parent_run_ids | parent_run_ids | Unchanged |
price_model_id | price_model_id | Unchanged |
prompt_cost | prompt_cost | Unchanged |
prompt_cost_details | prompt_cost_details.raw | Field now wraps the object; read .raw for the same {category: cost} mapping, now with numeric values (was strings) |
prompt_token_details | prompt_token_details.raw | Field now wraps the object; read .raw for the same {category: count} mapping (values unchanged) |
prompt_tokens | prompt_tokens | Unchanged |
completion_cost | completion_cost | Unchanged |
completion_cost_details | completion_cost_details.raw | Field now wraps the object; read .raw for the same {category: cost} mapping, now with numeric values (was strings) |
completion_token_details | completion_token_details.raw | Field now wraps the object; read .raw for the same {category: count} mapping (values unchanged) |
completion_tokens | completion_tokens | Unchanged |
total_cost | total_cost | Unchanged |
total_tokens | total_tokens | Unchanged |
reference_dataset_id | reference_dataset_id | Unchanged |
reference_example_id | reference_example_id | Unchanged |
tags | tags | Unchanged |
thread_id | thread_id | Unchanged |
session_id | project_id | Renamed |
in_dataset | is_in_dataset | Renamed |
child_run_ids | (removed) | No equivalent |
direct_child_run_ids | (removed) | No equivalent |
execution_order | (removed) | No equivalent |
inputs_s3_urls | (removed) | Internal storage URL; not exposed in v2 |
last_queued_at | (removed) | No equivalent |
manifest_id | (removed) | Use manifest |
manifest_s3_id | (removed) | Internal storage URL; not exposed in v2 |
messages | (removed) | No equivalent |
outputs_s3_urls | (removed) | Internal storage URL; not exposed in v2 |
parent_run_id | (removed) | Use parent_run_ids |
s3_urls | (removed) | Internal storage URL; not exposed in v2 |
serialized | (removed) | Use manifest |
share_token | (removed) | Use share_url |
trace_first_received_at | (removed) | No equivalent |
trace_max_start_time | (removed) | No equivalent |
trace_min_start_time | (removed) | No equivalent |
trace_tier | (removed) | No equivalent |
trace_upgrade | (removed) | No equivalent |
ttl_seconds | (removed) | No equivalent |
| (not available) | attachments | New: maps attachment filename to pre-signed download URL |
| (not available) | error_preview | New: truncated error snippet |
| (not available) | is_root | New |
| (not available) | latency_seconds | New: wall-clock duration in seconds |
| (not available) | manifest | New: full manifest object (replaces serialized and manifest_id) |
| (not available) | metadata | New: previously nested under extra.metadata |
| (not available) | share_url | New: public share URL (only set when the run has been shared) |
| (not available) | thread_evaluation_time | New |
Examples
List all runs in a project
- Python
- TypeScript
- Java
- Go
- cURL
runs.query does not accept a project name directly. Resolve the project UUID with client.aread_project() first, then pass it as a string in project_ids.- Before
- After
Before
from langsmith import Client
client = Client()
runs = client.list_runs(project_name="default")
After
import asyncio
from langsmith import Client
async def main():
client = Client()
project = await client.aread_project(project_name="default")
runs = client.runs.query(project_ids=[str(project.id)])
asyncio.run(main())
client.runs.query does not accept a project name directly. Resolve the project UUID with client.readProject() first, then pass it as a string in project_ids.- Before
- After
Before
import { Client } from "langsmith";
const client = new Client();
const runs = client.listRuns({ projectName: "default" });
After
import { Client } from "langsmith";
const client = new Client();
const project = await client.readProject({ projectName: "default" });
const runs = client.runs.query({ project_ids: [project.id] });
queryV2() does not accept a project name directly. Resolve the project UUID with client.sessions().list() first, then pass it as a string in projectIds().- Before
- After
Before
import com.langchain.smith.client.LangsmithClient
import com.langchain.smith.client.okhttp.LangsmithOkHttpClient
import com.langchain.smith.models.runs.RunQueryParams
import com.langchain.smith.models.sessions.SessionListParams
val client: LangsmithClient = LangsmithOkHttpClient.fromEnv()
val project = client.sessions().list(
SessionListParams.builder().name("default").limit(1L).build()
).items().first()
val runs = client.runs().query(
RunQueryParams.builder().addSession(project.id()).build()
).items()
After
import com.langchain.smith.client.LangsmithClient
import com.langchain.smith.client.okhttp.LangsmithOkHttpClient
import com.langchain.smith.models.runs.RunQueryV2Params
import com.langchain.smith.models.sessions.SessionListParams
val client: LangsmithClient = LangsmithOkHttpClient.fromEnv()
val project = client.sessions().list(
SessionListParams.builder().name("default").limit(1L).build()
).items().first()
val runs = client.runs().queryV2(
RunQueryV2Params.builder().addProjectId(project.id()).build()
).items()
QueryV2() does not accept a project name directly. Resolve the project UUID with client.Sessions.List() first, then pass it as a string in ProjectIDs.- Before
- After
Before
package main
import (
"context"
"github.com/langchain-ai/langsmith-go"
)
ctx := context.Background()
client := langsmith.NewClient()
sessions, err := client.Sessions.List(ctx, langsmith.SessionListParams{
Name: langsmith.F("default"),
Limit: langsmith.F(int64(1)),
})
project := sessions.Items[0]
runs, err := client.Runs.Query(ctx, langsmith.RunQueryParams{
Session: langsmith.F([]string{project.ID}),
})
After
package main
import (
"context"
"github.com/langchain-ai/langsmith-go"
)
ctx := context.Background()
client := langsmith.NewClient()
sessions, err := client.Sessions.List(ctx, langsmith.SessionListParams{
Name: langsmith.F("default"),
Limit: langsmith.F(int64(1)),
})
project := sessions.Items[0]
runs, err := client.Runs.QueryV2(ctx, langsmith.RunQueryV2Params{
ProjectIDs: langsmith.F([]string{project.ID}),
})
POST /v2/runs/query does not accept a project name directly. Resolve the project UUID with a GET /api/v1/sessions request first, then pass it as a string in project_ids.- Before
- After
PROJECT_ID=$(curl -s "https://api.smith.langchain.com/api/v1/sessions?name=default&limit=1" \
-H "x-api-key: $LANGSMITH_API_KEY" | jq -r '.[0].id')
curl -X POST "https://api.smith.langchain.com/api/v1/runs/query" \
-H "x-api-key: $LANGSMITH_API_KEY" \
-H "Content-Type: application/json" \
-d "$(jq -n --arg pid "$PROJECT_ID" '{"session": [$pid]}')"
PROJECT_ID=$(curl -s "https://api.smith.langchain.com/api/v1/sessions?name=default&limit=1" \
-H "x-api-key: $LANGSMITH_API_KEY" | jq -r '.[0].id')
curl -X POST "https://api.smith.langchain.com/v2/runs/query" \
-H "x-api-key: $LANGSMITH_API_KEY" \
-H "Content-Type: application/json" \
-d "$(jq -n --arg pid "$PROJECT_ID" '{"project_ids": [$pid]}')"
Selecting fields
- Python
- TypeScript
- Java
- Go
- cURL
list_runs returns a default set of fields with no selection needed. runs.query returns only id by default—pass selects=[...] to request more. Field names are now uppercase ("name" → "NAME").- Before
- After
Before
from langsmith import Client
client = Client()
# returns a default set of fields; no explicit selection needed
runs = client.list_runs(project_name="default")
for run in runs:
print(run.id, run.name, run.run_type, run.status, run.start_time, run.inputs, run.error)
After
import asyncio
from langsmith import Client
async def main():
client = Client()
project = await client.aread_project(project_name="default")
# must explicitly list every field needed; default returns only id
async for run in client.runs.query(
project_ids=[str(project.id)],
selects=["ID", "NAME", "RUN_TYPE", "STATUS", "START_TIME", "INPUTS", "ERROR"],
):
print(run.id, run.name, run.run_type, run.status, run.start_time, run.inputs, run.error)
asyncio.run(main())
listRuns returns a default set of fields with no selection needed. client.runs.query returns only id by default—pass selects: [...] to request more. Field names are now uppercase ("name" → "NAME").- Before
- After
Before
import { Client } from "langsmith";
const client = new Client();
// returns a default set of fields; no explicit selection needed
const runs = client.listRuns({ projectName: "default" });
for await (const run of runs) {
console.log(run.id, run.name, run.run_type, run.status, run.start_time, run.inputs, run.error);
}
After
import { Client } from "langsmith";
const client = new Client();
const project = await client.readProject({ projectName: "default" });
// must explicitly list every field needed; default returns only id
for await (const run of client.runs.query({
project_ids: [project.id],
selects: ["ID", "NAME", "RUN_TYPE", "STATUS", "START_TIME", "INPUTS", "ERROR"],
})) {
console.log(run.id, run.name, run.run_type, run.status, run.start_time, run.inputs, run.error);
}
query() returns a default set of fields with no selection needed. queryV2() returns only id by default—call .addSelect(RunQueryV2Params.Select.X) for each field you need.- Before
- After
Before
import com.langchain.smith.client.LangsmithClient
import com.langchain.smith.client.okhttp.LangsmithOkHttpClient
import com.langchain.smith.models.runs.RunQueryParams
import com.langchain.smith.models.sessions.SessionListParams
val client: LangsmithClient = LangsmithOkHttpClient.fromEnv()
val project = client.sessions().list(
SessionListParams.builder().name("default").limit(1L).build()
).items().first()
// returns a default set of fields; no explicit selection needed
val runs = client.runs().query(
RunQueryParams.builder().addSession(project.id()).build()
).items()
for (run in runs) {
println("${run.id()} ${run.name()} ${run.runType()} ${run.status()} ${run.startTime()} ${run.inputs()} ${run.error()}")
}
After
import com.langchain.smith.client.LangsmithClient
import com.langchain.smith.client.okhttp.LangsmithOkHttpClient
import com.langchain.smith.models.runs.RunQueryV2Params
import com.langchain.smith.models.sessions.SessionListParams
val client: LangsmithClient = LangsmithOkHttpClient.fromEnv()
val project = client.sessions().list(
SessionListParams.builder().name("default").limit(1L).build()
).items().first()
// must explicitly list every field needed; default returns only id
val runs = client.runs().queryV2(
RunQueryV2Params.builder()
.addProjectId(project.id())
.addSelect(RunQueryV2Params.Select.ID)
.addSelect(RunQueryV2Params.Select.NAME)
.addSelect(RunQueryV2Params.Select.RUN_TYPE)
.addSelect(RunQueryV2Params.Select.STATUS)
.addSelect(RunQueryV2Params.Select.START_TIME)
.addSelect(RunQueryV2Params.Select.INPUTS)
.addSelect(RunQueryV2Params.Select.ERROR)
.build()
).items()
for (run in runs) {
println("${run.id()} ${run.name()} ${run.runType()} ${run.status()} ${run.startTime()} ${run.inputs()} ${run.error()}")
}
Query returns a default set of fields with no selection needed. QueryV2 returns only ID by default—pass Selects with the uppercase field constants you need (e.g. RunQueryV2ParamsSelectName).- Before
- After
Before
package main
import (
"context"
"fmt"
"github.com/langchain-ai/langsmith-go"
)
ctx := context.Background()
client := langsmith.NewClient()
sessions, err := client.Sessions.List(ctx, langsmith.SessionListParams{
Name: langsmith.F("default"),
Limit: langsmith.F(int64(1)),
})
project := sessions.Items[0]
// returns a default set of fields; no explicit selection needed
runs, err := client.Runs.Query(ctx, langsmith.RunQueryParams{
Session: langsmith.F([]string{project.ID}),
})
for _, run := range runs.Runs {
fmt.Println(run.ID, run.Name, run.RunType, run.Status, run.StartTime, run.Inputs, run.Error)
}
After
package main
import (
"context"
"fmt"
"github.com/langchain-ai/langsmith-go"
)
ctx := context.Background()
client := langsmith.NewClient()
sessions, err := client.Sessions.List(ctx, langsmith.SessionListParams{
Name: langsmith.F("default"),
Limit: langsmith.F(int64(1)),
})
project := sessions.Items[0]
// must explicitly list every field needed; default returns only id
runs, err := client.Runs.QueryV2(ctx, langsmith.RunQueryV2Params{
ProjectIDs: langsmith.F([]string{project.ID}),
Selects: langsmith.F([]langsmith.RunQueryV2ParamsSelect{
langsmith.RunQueryV2ParamsSelectID,
langsmith.RunQueryV2ParamsSelectName,
langsmith.RunQueryV2ParamsSelectRunType,
langsmith.RunQueryV2ParamsSelectStatus,
langsmith.RunQueryV2ParamsSelectStartTime,
langsmith.RunQueryV2ParamsSelectInputs,
langsmith.RunQueryV2ParamsSelectError,
}),
})
for _, run := range runs.Items {
fmt.Println(run.ID, run.Name, run.RunType, run.Status, run.StartTime, run.Inputs, run.Error)
}
POST /api/v1/runs/query returns a default set of fields with no selection needed. POST /v2/runs/query returns only id by default—pass selects with the uppercase field names you need (e.g. "NAME").- Before
- After
PROJECT_ID=$(curl -s "https://api.smith.langchain.com/api/v1/sessions?name=default&limit=1" \
-H "x-api-key: $LANGSMITH_API_KEY" | jq -r '.[0].id')
curl -X POST "https://api.smith.langchain.com/api/v1/runs/query" \
-H "x-api-key: $LANGSMITH_API_KEY" \
-H "Content-Type: application/json" \
-d "$(jq -n --arg pid "$PROJECT_ID" '{"session": [$pid]}')"
PROJECT_ID=$(curl -s "https://api.smith.langchain.com/api/v1/sessions?name=default&limit=1" \
-H "x-api-key: $LANGSMITH_API_KEY" | jq -r '.[0].id')
curl -X POST "https://api.smith.langchain.com/v2/runs/query" \
-H "x-api-key: $LANGSMITH_API_KEY" \
-H "Content-Type: application/json" \
-d "$(jq -n --arg pid "$PROJECT_ID" '{"project_ids": [$pid], "selects": ["ID", "NAME", "RUN_TYPE", "STATUS", "START_TIME", "INPUTS", "ERROR"]}')"
Filter by run type and time range
- Python
- TypeScript
- Java
- Go
- cURL
start_time is renamed to min_start_time, and run_type values are now uppercase ("llm" → "LLM").- Before
- After
Before
from datetime import datetime, timedelta
from langsmith import Client
client = Client()
runs = client.list_runs(
project_name="default",
start_time=datetime.now() - timedelta(days=1),
run_type="llm",
)
After
import asyncio
from datetime import datetime, timedelta
from langsmith import Client
async def main():
client = Client()
project = await client.aread_project(project_name="default")
runs = client.runs.query(
project_ids=[str(project.id)],
min_start_time=datetime.now() - timedelta(days=1),
run_type="LLM",
)
asyncio.run(main())
startTime (camelCase) becomes min_start_time (snake_case, matching the v2 request body), and runType values are now uppercase ("llm" → "LLM").- Before
- After
Before
import { Client } from "langsmith";
const client = new Client();
const runs = client.listRuns({
projectName: "default",
startTime: new Date(Date.now() - 24 * 60 * 60 * 1000),
runType: "llm",
});
After
import { Client } from "langsmith";
const client = new Client();
const project = await client.readProject({ projectName: "default" });
const oneDayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000);
const runs = client.runs.query({
project_ids: [project.id],
min_start_time: oneDayAgo.toISOString(),
run_type: "LLM",
});
.startTime() is renamed to .minStartTime(), and .runType() now takes the new RunQueryV2Params.RunType enum instead of RunTypeEnum.- Before
- After
Before
import java.time.OffsetDateTime
import com.langchain.smith.client.LangsmithClient
import com.langchain.smith.client.okhttp.LangsmithOkHttpClient
import com.langchain.smith.models.runs.RunQueryParams
import com.langchain.smith.models.runs.RunTypeEnum
import com.langchain.smith.models.sessions.SessionListParams
val client: LangsmithClient = LangsmithOkHttpClient.fromEnv()
val project = client.sessions().list(
SessionListParams.builder().name("default").limit(1L).build()
).items().first()
val runs = client.runs().query(
RunQueryParams.builder()
.addSession(project.id())
.startTime(OffsetDateTime.now().minusDays(1))
.runType(RunTypeEnum.LLM)
.build()
).items()
After
import java.time.OffsetDateTime
import com.langchain.smith.client.LangsmithClient
import com.langchain.smith.client.okhttp.LangsmithOkHttpClient
import com.langchain.smith.models.runs.RunQueryV2Params
import com.langchain.smith.models.sessions.SessionListParams
val client: LangsmithClient = LangsmithOkHttpClient.fromEnv()
val project = client.sessions().list(
SessionListParams.builder().name("default").limit(1L).build()
).items().first()
val runs = client.runs().queryV2(
RunQueryV2Params.builder()
.addProjectId(project.id())
.minStartTime(OffsetDateTime.now().minusDays(1))
.runType(RunQueryV2Params.RunType.LLM)
.build()
).items()
StartTime is renamed to MinStartTime, and RunType now takes the new RunQueryV2ParamsRunType enum instead of RunTypeEnum.- Before
- After
Before
package main
import (
"context"
"time"
"github.com/langchain-ai/langsmith-go"
)
ctx := context.Background()
client := langsmith.NewClient()
sessions, err := client.Sessions.List(ctx, langsmith.SessionListParams{
Name: langsmith.F("default"),
Limit: langsmith.F(int64(1)),
})
project := sessions.Items[0]
runs, err := client.Runs.Query(ctx, langsmith.RunQueryParams{
Session: langsmith.F([]string{project.ID}),
StartTime: langsmith.F(time.Now().Add(-24 * time.Hour)),
RunType: langsmith.F(langsmith.RunTypeEnumLlm),
})
After
package main
import (
"context"
"time"
"github.com/langchain-ai/langsmith-go"
)
ctx := context.Background()
client := langsmith.NewClient()
sessions, err := client.Sessions.List(ctx, langsmith.SessionListParams{
Name: langsmith.F("default"),
Limit: langsmith.F(int64(1)),
})
project := sessions.Items[0]
runs, err := client.Runs.QueryV2(ctx, langsmith.RunQueryV2Params{
ProjectIDs: langsmith.F([]string{project.ID}),
MinStartTime: langsmith.F(time.Now().Add(-24 * time.Hour)),
RunType: langsmith.F(langsmith.RunQueryV2ParamsRunTypeLlm),
})
start_time is renamed to min_start_time, and run_type values are now uppercase ("llm" → "LLM").- Before
- After
PROJECT_ID=$(curl -s "https://api.smith.langchain.com/api/v1/sessions?name=default&limit=1" \
-H "x-api-key: $LANGSMITH_API_KEY" | jq -r '.[0].id')
curl -X POST "https://api.smith.langchain.com/api/v1/runs/query" \
-H "x-api-key: $LANGSMITH_API_KEY" \
-H "Content-Type: application/json" \
-d "$(jq -n --arg pid "$PROJECT_ID" '{"session": [$pid], "run_type": "llm", "start_time": "2025-01-01T00:00:00Z"}')"
PROJECT_ID=$(curl -s "https://api.smith.langchain.com/api/v1/sessions?name=default&limit=1" \
-H "x-api-key: $LANGSMITH_API_KEY" | jq -r '.[0].id')
curl -X POST "https://api.smith.langchain.com/v2/runs/query" \
-H "x-api-key: $LANGSMITH_API_KEY" \
-H "Content-Type: application/json" \
-d "$(jq -n --arg pid "$PROJECT_ID" '{"project_ids": [$pid], "run_type": "LLM", "min_start_time": "2025-01-01T00:00:00Z"}')"
Filter root runs only
- Python
- TypeScript
- Java
- Go
- cURL
is_root is unchanged.- Before
- After
Before
from langsmith import Client
client = Client()
runs = client.list_runs(project_name="default", is_root=True)
After
import asyncio
from langsmith import Client
async def main():
client = Client()
project = await client.aread_project(project_name="default")
runs = client.runs.query(project_ids=[str(project.id)], is_root=True)
asyncio.run(main())
isRoot (camelCase) becomes is_root (snake_case, matching the v2 request body).- Before
- After
Before
import { Client } from "langsmith";
const client = new Client();
const runs = client.listRuns({ projectName: "default", isRoot: true });
After
import { Client } from "langsmith";
const client = new Client();
const project = await client.readProject({ projectName: "default" });
const runs = client.runs.query({
project_ids: [project.id],
is_root: true,
});
.isRoot() is unchanged.- Before
- After
Before
import com.langchain.smith.client.LangsmithClient
import com.langchain.smith.client.okhttp.LangsmithOkHttpClient
import com.langchain.smith.models.runs.RunQueryParams
import com.langchain.smith.models.sessions.SessionListParams
val client: LangsmithClient = LangsmithOkHttpClient.fromEnv()
val project = client.sessions().list(
SessionListParams.builder().name("default").limit(1L).build()
).items().first()
val runs = client.runs().query(
RunQueryParams.builder().addSession(project.id()).isRoot(true).build()
).items()
After
import com.langchain.smith.client.LangsmithClient
import com.langchain.smith.client.okhttp.LangsmithOkHttpClient
import com.langchain.smith.models.runs.RunQueryV2Params
import com.langchain.smith.models.sessions.SessionListParams
val client: LangsmithClient = LangsmithOkHttpClient.fromEnv()
val project = client.sessions().list(
SessionListParams.builder().name("default").limit(1L).build()
).items().first()
val runs = client.runs().queryV2(
RunQueryV2Params.builder().addProjectId(project.id()).isRoot(true).build()
).items()
IsRoot is unchanged.- Before
- After
Before
package main
import (
"context"
"github.com/langchain-ai/langsmith-go"
)
ctx := context.Background()
client := langsmith.NewClient()
sessions, err := client.Sessions.List(ctx, langsmith.SessionListParams{
Name: langsmith.F("default"),
Limit: langsmith.F(int64(1)),
})
project := sessions.Items[0]
runs, err := client.Runs.Query(ctx, langsmith.RunQueryParams{
Session: langsmith.F([]string{project.ID}),
IsRoot: langsmith.F(true),
})
After
package main
import (
"context"
"github.com/langchain-ai/langsmith-go"
)
ctx := context.Background()
client := langsmith.NewClient()
sessions, err := client.Sessions.List(ctx, langsmith.SessionListParams{
Name: langsmith.F("default"),
Limit: langsmith.F(int64(1)),
})
project := sessions.Items[0]
runs, err := client.Runs.QueryV2(ctx, langsmith.RunQueryV2Params{
ProjectIDs: langsmith.F([]string{project.ID}),
IsRoot: langsmith.F(true),
})
is_root is unchanged.- Before
- After
PROJECT_ID=$(curl -s "https://api.smith.langchain.com/api/v1/sessions?name=default&limit=1" \
-H "x-api-key: $LANGSMITH_API_KEY" | jq -r '.[0].id')
curl -X POST "https://api.smith.langchain.com/api/v1/runs/query" \
-H "x-api-key: $LANGSMITH_API_KEY" \
-H "Content-Type: application/json" \
-d "$(jq -n --arg pid "$PROJECT_ID" '{"session": [$pid], "is_root": true}')"
PROJECT_ID=$(curl -s "https://api.smith.langchain.com/api/v1/sessions?name=default&limit=1" \
-H "x-api-key: $LANGSMITH_API_KEY" | jq -r '.[0].id')
curl -X POST "https://api.smith.langchain.com/v2/runs/query" \
-H "x-api-key: $LANGSMITH_API_KEY" \
-H "Content-Type: application/json" \
-d "$(jq -n --arg pid "$PROJECT_ID" '{"project_ids": [$pid], "is_root": true}')"
Fetch runs by ID list
- Python
- TypeScript
- Java
- Go
- cURL
id=[...] is renamed to ids=[...]. project_ids is now required even when filtering by run IDs—v1 allowed omitting the project context.- Before
- After
Before
from langsmith import Client
client = Client()
runs = client.list_runs(id=["<run-id-1>", "<run-id-2>"])
After
import asyncio
from langsmith import Client
async def main():
client = Client()
project = await client.aread_project(project_name="default")
runs = client.runs.query(
project_ids=[str(project.id)],
ids=["<run-id-1>", "<run-id-2>"],
)
asyncio.run(main())
id: [...] is renamed to ids: [...]. project_ids is now required even when filtering by run IDs—v1 allowed omitting the project context.- Before
- After
Before
import { Client } from "langsmith";
const client = new Client();
const runs = client.listRuns({ id: ["<run-id-1>", "<run-id-2>"] });
After
import { Client } from "langsmith";
const client = new Client();
const project = await client.readProject({ projectName: "default" });
const runs = client.runs.query({
project_ids: [project.id],
ids: ["<run-id-1>", "<run-id-2>"],
});
.addId(...) is unchanged—call it once per run ID. .addProjectId(...) is now required even when filtering by run IDs—v1 allowed omitting the project context.- Before
- After
Before
import com.langchain.smith.client.LangsmithClient
import com.langchain.smith.client.okhttp.LangsmithOkHttpClient
import com.langchain.smith.models.runs.RunQueryParams
import com.langchain.smith.models.sessions.SessionListParams
val client: LangsmithClient = LangsmithOkHttpClient.fromEnv()
val project = client.sessions().list(
SessionListParams.builder().name("default").limit(1L).build()
).items().first()
var runId1 = "<run-id-1>"
var runId2 = "<run-id-2>"
val runs = client.runs().query(
RunQueryParams.builder()
.addSession(project.id())
.addId(runId1)
.addId(runId2)
.build()
).items()
After
import com.langchain.smith.client.LangsmithClient
import com.langchain.smith.client.okhttp.LangsmithOkHttpClient
import com.langchain.smith.models.runs.RunQueryV2Params
import com.langchain.smith.models.sessions.SessionListParams
val client: LangsmithClient = LangsmithOkHttpClient.fromEnv()
val project = client.sessions().list(
SessionListParams.builder().name("default").limit(1L).build()
).items().first()
val runs = client.runs().queryV2(
RunQueryV2Params.builder()
.addProjectId(project.id())
.addId("<run-id-1>")
.addId("<run-id-2>")
.build()
).items()
ID: [...] is renamed to IDs: [...]. ProjectIDs is now required even when filtering by run IDs—v1 allowed omitting the project context.- Before
- After
Before
package main
import (
"context"
"github.com/langchain-ai/langsmith-go"
)
ctx := context.Background()
client := langsmith.NewClient()
sessions, err := client.Sessions.List(ctx, langsmith.SessionListParams{
Name: langsmith.F("default"),
Limit: langsmith.F(int64(1)),
})
project := sessions.Items[0]
runID1 := "<run-id-1>"
runID2 := "<run-id-2>"
runs, err := client.Runs.Query(ctx, langsmith.RunQueryParams{
Session: langsmith.F([]string{project.ID}),
ID: langsmith.F([]string{runID1, runID2}),
})
After
package main
import (
"context"
"github.com/langchain-ai/langsmith-go"
)
ctx := context.Background()
client := langsmith.NewClient()
sessions, err := client.Sessions.List(ctx, langsmith.SessionListParams{
Name: langsmith.F("default"),
Limit: langsmith.F(int64(1)),
})
project := sessions.Items[0]
runID1 := "<run-id-1>"
runID2 := "<run-id-2>"
runs, err := client.Runs.QueryV2(ctx, langsmith.RunQueryV2Params{
ProjectIDs: langsmith.F([]string{project.ID}),
IDs: langsmith.F([]string{runID1, runID2}),
})
id is renamed to ids. project_ids is now required in the request body even when filtering by run IDs—v1 allowed omitting the project context.- Before
- After
RUN_ID_1="<run-id-1>"
RUN_ID_2="<run-id-2>"
curl -X POST "https://api.smith.langchain.com/api/v1/runs/query" \
-H "x-api-key: $LANGSMITH_API_KEY" \
-H "Content-Type: application/json" \
-d "$(jq -n --arg r1 "$RUN_ID_1" --arg r2 "$RUN_ID_2" '{"id": [$r1, $r2]}')"
PROJECT_ID=$(curl -s "https://api.smith.langchain.com/api/v1/sessions?name=default&limit=1" \
-H "x-api-key: $LANGSMITH_API_KEY" | jq -r '.[0].id')
RUN_ID_1="<run-id-1>"
RUN_ID_2="<run-id-2>"
curl -X POST "https://api.smith.langchain.com/v2/runs/query" \
-H "x-api-key: $LANGSMITH_API_KEY" \
-H "Content-Type: application/json" \
-d "$(jq -n --arg pid "$PROJECT_ID" --arg r1 "$RUN_ID_1" --arg r2 "$RUN_ID_2" '{"project_ids": [$pid], "ids": [$r1, $r2]}')"
Iterate through runs
- Python
- TypeScript
- Java
- Go
- cURL
list_runs auto-paginates transparently, fetching up to 100 runs per API call and stopping once limit results are returned. runs.query does not accept a total limit; iterate with async for and break once you have enough, or use the returned page’s has_next_page()/get_next_page() for manual page-by-page control.- Before
- After
Before
from langsmith import Client
client = Client()
runs = client.list_runs(project_name="default", limit=150)
After
import asyncio
from langsmith import Client
async def main():
client = Client()
project = await client.aread_project(project_name="default")
runs = []
async for run in client.runs.query(
project_ids=[str(project.id)],
):
runs.append(run)
if len(runs) >= 150:
break
asyncio.run(main())
listRuns auto-paginates transparently. client.runs.query returns an async iterable of individual runs—use for await and break once you have enough.- Before
- After
Before
import { Client } from "langsmith";
const client = new Client();
const runs: unknown[] = [];
for await (const run of client.listRuns({ projectName: "default" })) {
runs.push(run);
if (runs.length >= 150) break;
}
After
import { Client } from "langsmith";
const client = new Client();
const project = await client.readProject({ projectName: "default" });
const runs: unknown[] = [];
for await (const run of client.runs.query({
project_ids: [project.id],
})) {
runs.push(run);
if (runs.length >= 150) break;
}
.autoPager() is used the same way on both query() and queryV2()—break out of the loop once you have enough runs.- Before
- After
Before
import com.langchain.smith.client.LangsmithClient
import com.langchain.smith.client.okhttp.LangsmithOkHttpClient
import com.langchain.smith.models.runs.RunQueryParams
import com.langchain.smith.models.sessions.SessionListParams
val client: LangsmithClient = LangsmithOkHttpClient.fromEnv()
val project = client.sessions().list(
SessionListParams.builder().name("default").limit(1L).build()
).items().first()
val runs = mutableListOf<Any>()
for (run in client.runs().query(
RunQueryParams.builder().addSession(project.id()).build()
).autoPager()) {
runs.add(run)
if (runs.size >= 150) break
}
After
import com.langchain.smith.client.LangsmithClient
import com.langchain.smith.client.okhttp.LangsmithOkHttpClient
import com.langchain.smith.models.runs.RunQueryV2Params
import com.langchain.smith.models.sessions.SessionListParams
val client: LangsmithClient = LangsmithOkHttpClient.fromEnv()
val project = client.sessions().list(
SessionListParams.builder().name("default").limit(1L).build()
).items().first()
val runs = mutableListOf<Any>()
for (run in client.runs().queryV2(
RunQueryV2Params.builder().addProjectId(project.id()).build()
).autoPager()) {
runs.add(run)
if (runs.size >= 150) break
}
QueryAutoPaging is renamed to QueryV2AutoPaging; both use the same iter.Next()/iter.Current() pattern—break out of the loop once you have enough runs.- Before
- After
Before
package main
import (
"context"
"github.com/langchain-ai/langsmith-go"
)
ctx := context.Background()
client := langsmith.NewClient()
sessions, err := client.Sessions.List(ctx, langsmith.SessionListParams{
Name: langsmith.F("default"),
Limit: langsmith.F(int64(1)),
})
project := sessions.Items[0]
runs := []langsmith.RunSchema{}
iter := client.Runs.QueryAutoPaging(ctx, langsmith.RunQueryParams{
Session: langsmith.F([]string{project.ID}),
})
for iter.Next() {
runs = append(runs, iter.Current())
if len(runs) >= 150 {
break
}
}
After
package main
import (
"context"
"github.com/langchain-ai/langsmith-go"
)
ctx := context.Background()
client := langsmith.NewClient()
sessions, err := client.Sessions.List(ctx, langsmith.SessionListParams{
Name: langsmith.F("default"),
Limit: langsmith.F(int64(1)),
})
project := sessions.Items[0]
runs := []langsmith.Run{}
iter := client.Runs.QueryV2AutoPaging(ctx, langsmith.RunQueryV2Params{
ProjectIDs: langsmith.F([]string{project.ID}),
})
for iter.Next() {
runs = append(runs, iter.Current())
if len(runs) >= 150 {
break
}
}
The v1 API returns all matching runs in one response with no cursor. The v2 API paginates—pass the
cursor from a response’s next_cursor field to fetch the next page.- Before
- After
PROJECT_ID=$(curl -s "https://api.smith.langchain.com/api/v1/sessions?name=default&limit=1" \
-H "x-api-key: $LANGSMITH_API_KEY" | jq -r '.[0].id')
curl -X POST "https://api.smith.langchain.com/api/v1/runs/query" \
-H "x-api-key: $LANGSMITH_API_KEY" \
-H "Content-Type: application/json" \
-d "$(jq -n --arg pid "$PROJECT_ID" '{"session": [$pid], "limit": 150}')"
PROJECT_ID=$(curl -s "https://api.smith.langchain.com/api/v1/sessions?name=default&limit=1" \
-H "x-api-key: $LANGSMITH_API_KEY" | jq -r '.[0].id')
# Fetch pages, passing the cursor from each response's next_cursor field
# to fetch the next page, until 150 runs are collected or pages run out.
TOTAL=0
CURSOR=""
while :; do
BODY=$(jq -n --arg pid "$PROJECT_ID" --arg cursor "$CURSOR" \
'if $cursor == "" then {"project_ids": [$pid]} else {"project_ids": [$pid], "cursor": $cursor} end')
RESPONSE=$(curl -s -X POST "https://api.smith.langchain.com/v2/runs/query" \
-H "x-api-key: $LANGSMITH_API_KEY" \
-H "Content-Type: application/json" \
-d "$BODY")
TOTAL=$((TOTAL + $(echo "$RESPONSE" | jq '.items | length')))
CURSOR=$(echo "$RESPONSE" | jq -r '.next_cursor // empty')
[ "$TOTAL" -lt 150 ] && [ -n "$CURSOR" ] || break
done
Filter runs with errors
- Python
- TypeScript
- Java
- Go
- cURL
error=True/False is renamed to has_error=True/False.- Before
- After
Before
from langsmith import Client
client = Client()
runs = client.list_runs(project_name="default", error=True)
After
import asyncio
from langsmith import Client
async def main():
client = Client()
project = await client.aread_project(project_name="default")
runs = client.runs.query(project_ids=[str(project.id)], has_error=True)
asyncio.run(main())
error: true/false is renamed to has_error: true/false.- Before
- After
Before
import { Client } from "langsmith";
const client = new Client();
const runs = client.listRuns({ projectName: "default", error: true });
After
import { Client } from "langsmith";
const client = new Client();
const project = await client.readProject({ projectName: "default" });
const runs = client.runs.query({
project_ids: [project.id],
has_error: true,
});
.error(true/false) is renamed to .hasError(true/false).- Before
- After
Before
import com.langchain.smith.client.LangsmithClient
import com.langchain.smith.client.okhttp.LangsmithOkHttpClient
import com.langchain.smith.models.runs.RunQueryParams
import com.langchain.smith.models.sessions.SessionListParams
val client: LangsmithClient = LangsmithOkHttpClient.fromEnv()
val project = client.sessions().list(
SessionListParams.builder().name("default").limit(1L).build()
).items().first()
val runs = client.runs().query(
RunQueryParams.builder().addSession(project.id()).error(true).build()
).items()
After
import com.langchain.smith.client.LangsmithClient
import com.langchain.smith.client.okhttp.LangsmithOkHttpClient
import com.langchain.smith.models.runs.RunQueryV2Params
import com.langchain.smith.models.sessions.SessionListParams
val client: LangsmithClient = LangsmithOkHttpClient.fromEnv()
val project = client.sessions().list(
SessionListParams.builder().name("default").limit(1L).build()
).items().first()
val runs = client.runs().queryV2(
RunQueryV2Params.builder().addProjectId(project.id()).hasError(true).build()
).items()
Error is renamed to HasError.- Before
- After
Before
package main
import (
"context"
"github.com/langchain-ai/langsmith-go"
)
ctx := context.Background()
client := langsmith.NewClient()
sessions, err := client.Sessions.List(ctx, langsmith.SessionListParams{
Name: langsmith.F("default"),
Limit: langsmith.F(int64(1)),
})
project := sessions.Items[0]
runs, err := client.Runs.Query(ctx, langsmith.RunQueryParams{
Session: langsmith.F([]string{project.ID}),
Error: langsmith.F(true),
})
After
package main
import (
"context"
"github.com/langchain-ai/langsmith-go"
)
ctx := context.Background()
client := langsmith.NewClient()
sessions, err := client.Sessions.List(ctx, langsmith.SessionListParams{
Name: langsmith.F("default"),
Limit: langsmith.F(int64(1)),
})
project := sessions.Items[0]
runs, err := client.Runs.QueryV2(ctx, langsmith.RunQueryV2Params{
ProjectIDs: langsmith.F([]string{project.ID}),
HasError: langsmith.F(true),
})
error is renamed to has_error.- Before
- After
PROJECT_ID=$(curl -s "https://api.smith.langchain.com/api/v1/sessions?name=default&limit=1" \
-H "x-api-key: $LANGSMITH_API_KEY" | jq -r '.[0].id')
curl -X POST "https://api.smith.langchain.com/api/v1/runs/query" \
-H "x-api-key: $LANGSMITH_API_KEY" \
-H "Content-Type: application/json" \
-d "$(jq -n --arg pid "$PROJECT_ID" '{"session": [$pid], "error": true}')"
PROJECT_ID=$(curl -s "https://api.smith.langchain.com/api/v1/sessions?name=default&limit=1" \
-H "x-api-key: $LANGSMITH_API_KEY" | jq -r '.[0].id')
curl -X POST "https://api.smith.langchain.com/v2/runs/query" \
-H "x-api-key: $LANGSMITH_API_KEY" \
-H "Content-Type: application/json" \
-d "$(jq -n --arg pid "$PROJECT_ID" '{"project_ids": [$pid], "has_error": true}')"
Filter by metadata
- Python
- TypeScript
- Java
- Go
- cURL
The
filter string syntax is unchanged: eq(metadata_key, ...) checks for key presence, combined with eq(metadata_value, ...) to match a specific value.- Before
- After
Before
from langsmith import Client
client = Client()
filter_str = 'and(eq(metadata_key, "user_id"), eq(metadata_value, "u_123"))'
runs = client.list_runs(project_name="default", filter=filter_str)
After
import asyncio
from langsmith import Client
async def main():
client = Client()
filter_str = 'and(eq(metadata_key, "user_id"), eq(metadata_value, "u_123"))'
project = await client.aread_project(project_name="default")
runs = client.runs.query(project_ids=[str(project.id)], filter=filter_str)
asyncio.run(main())
The
filter string syntax is unchanged: eq(metadata_key, ...) checks for key presence, combined with eq(metadata_value, ...) to match a specific value.- Before
- After
Before
import { Client } from "langsmith";
const client = new Client();
const filterStr = 'and(eq(metadata_key, "user_id"), eq(metadata_value, "u_123"))';
const runs = client.listRuns({ projectName: "default", filter: filterStr });
After
import { Client } from "langsmith";
const client = new Client();
const filterStr = 'and(eq(metadata_key, "user_id"), eq(metadata_value, "u_123"))';
const project = await client.readProject({ projectName: "default" });
const runs = client.runs.query({
project_ids: [project.id],
filter: filterStr,
});
The
.filter(...) string syntax is unchanged: eq(metadata_key, ...) checks for key presence, combined with eq(metadata_value, ...) to match a specific value.- Before
- After
Before
import com.langchain.smith.client.LangsmithClient
import com.langchain.smith.client.okhttp.LangsmithOkHttpClient
import com.langchain.smith.models.runs.RunQueryParams
import com.langchain.smith.models.sessions.SessionListParams
val client: LangsmithClient = LangsmithOkHttpClient.fromEnv()
val project = client.sessions().list(
SessionListParams.builder().name("default").limit(1L).build()
).items().first()
val filterStr = "and(eq(metadata_key, \"user_id\"), eq(metadata_value, \"u_123\"))"
val runs = client.runs().query(
RunQueryParams.builder().addSession(project.id()).filter(filterStr).build()
).items()
After
import com.langchain.smith.client.LangsmithClient
import com.langchain.smith.client.okhttp.LangsmithOkHttpClient
import com.langchain.smith.models.runs.RunQueryV2Params
import com.langchain.smith.models.sessions.SessionListParams
val client: LangsmithClient = LangsmithOkHttpClient.fromEnv()
val project = client.sessions().list(
SessionListParams.builder().name("default").limit(1L).build()
).items().first()
val filterStr = "and(eq(metadata_key, \"user_id\"), eq(metadata_value, \"u_123\"))"
val runs = client.runs().queryV2(
RunQueryV2Params.builder().addProjectId(project.id()).filter(filterStr).build()
).items()
The
Filter string syntax is unchanged: eq(metadata_key, ...) checks for key presence, combined with eq(metadata_value, ...) to match a specific value.- Before
- After
Before
package main
import (
"context"
"github.com/langchain-ai/langsmith-go"
)
ctx := context.Background()
client := langsmith.NewClient()
sessions, err := client.Sessions.List(ctx, langsmith.SessionListParams{
Name: langsmith.F("default"),
Limit: langsmith.F(int64(1)),
})
project := sessions.Items[0]
filterStr := `and(eq(metadata_key, "user_id"), eq(metadata_value, "u_123"))`
runs, err := client.Runs.Query(ctx, langsmith.RunQueryParams{
Session: langsmith.F([]string{project.ID}),
Filter: langsmith.F(filterStr),
})
After
package main
import (
"context"
"github.com/langchain-ai/langsmith-go"
)
ctx := context.Background()
client := langsmith.NewClient()
sessions, err := client.Sessions.List(ctx, langsmith.SessionListParams{
Name: langsmith.F("default"),
Limit: langsmith.F(int64(1)),
})
project := sessions.Items[0]
filterStr := `and(eq(metadata_key, "user_id"), eq(metadata_value, "u_123"))`
runs, err := client.Runs.QueryV2(ctx, langsmith.RunQueryV2Params{
ProjectIDs: langsmith.F([]string{project.ID}),
Filter: langsmith.F(filterStr),
})
The
filter string syntax is unchanged: eq(metadata_key, ...) checks for key presence, combined with eq(metadata_value, ...) to match a specific value.- Before
- After
PROJECT_ID=$(curl -s "https://api.smith.langchain.com/api/v1/sessions?name=default&limit=1" \
-H "x-api-key: $LANGSMITH_API_KEY" | jq -r '.[0].id')
FILTER='and(eq(metadata_key, "user_id"), eq(metadata_value, "u_123"))'
curl -X POST "https://api.smith.langchain.com/api/v1/runs/query" \
-H "x-api-key: $LANGSMITH_API_KEY" \
-H "Content-Type: application/json" \
-d "$(jq -n --arg pid "$PROJECT_ID" --arg f "$FILTER" '{"session": [$pid], "filter": $f}')"
PROJECT_ID=$(curl -s "https://api.smith.langchain.com/api/v1/sessions?name=default&limit=1" \
-H "x-api-key: $LANGSMITH_API_KEY" | jq -r '.[0].id')
FILTER='and(eq(metadata_key, "user_id"), eq(metadata_value, "u_123"))'
curl -X POST "https://api.smith.langchain.com/v2/runs/query" \
-H "x-api-key: $LANGSMITH_API_KEY" \
-H "Content-Type: application/json" \
-d "$(jq -n --arg pid "$PROJECT_ID" --arg f "$FILTER" '{"project_ids": [$pid], "filter": $f}')"
Complex boolean filters
- Python
- TypeScript
- Java
- Go
- cURL
Nested
and() / or() filter expressions are unchanged.- Before
- After
Before
from langsmith import Client
client = Client()
filter_str = (
'and(gt(start_time, "2023-07-15T12:34:56Z"),'
' or(neq(status, "error"),'
' and(eq(feedback_key, "Correctness"), eq(feedback_score, 0.0))))'
)
runs = client.list_runs(project_name="default", filter=filter_str)
After
import asyncio
from langsmith import Client
async def main():
client = Client()
filter_str = (
'and(gt(start_time, "2023-07-15T12:34:56Z"),'
' or(neq(status, "error"),'
' and(eq(feedback_key, "Correctness"), eq(feedback_score, 0.0))))'
)
project = await client.aread_project(project_name="default")
runs = client.runs.query(project_ids=[str(project.id)], filter=filter_str)
asyncio.run(main())
Nested
and() / or() filter expressions are unchanged.- Before
- After
Before
import { Client } from "langsmith";
const client = new Client();
const filterStr =
'and(gt(start_time, "2023-07-15T12:34:56Z"),' +
' or(neq(status, "error"),' +
' and(eq(feedback_key, "Correctness"), eq(feedback_score, 0.0))))';
const runs = client.listRuns({ projectName: "default", filter: filterStr });
After
import { Client } from "langsmith";
const client = new Client();
const filterStr =
'and(gt(start_time, "2023-07-15T12:34:56Z"),' +
' or(neq(status, "error"),' +
' and(eq(feedback_key, "Correctness"), eq(feedback_score, 0.0))))';
const project = await client.readProject({ projectName: "default" });
const runs = client.runs.query({
project_ids: [project.id],
filter: filterStr,
});
Nested
and() / or() filter expressions are unchanged.- Before
- After
Before
import com.langchain.smith.client.LangsmithClient
import com.langchain.smith.client.okhttp.LangsmithOkHttpClient
import com.langchain.smith.models.runs.RunQueryParams
import com.langchain.smith.models.sessions.SessionListParams
val client: LangsmithClient = LangsmithOkHttpClient.fromEnv()
val project = client.sessions().list(
SessionListParams.builder().name("default").limit(1L).build()
).items().first()
val filterStr = "and(gt(start_time, \"2023-07-15T12:34:56Z\")," +
" or(neq(status, \"error\")," +
" and(eq(feedback_key, \"Correctness\"), eq(feedback_score, 0.0))))"
val runs = client.runs().query(
RunQueryParams.builder().addSession(project.id()).filter(filterStr).build()
).items()
After
import com.langchain.smith.client.LangsmithClient
import com.langchain.smith.client.okhttp.LangsmithOkHttpClient
import com.langchain.smith.models.runs.RunQueryV2Params
import com.langchain.smith.models.sessions.SessionListParams
val client: LangsmithClient = LangsmithOkHttpClient.fromEnv()
val project = client.sessions().list(
SessionListParams.builder().name("default").limit(1L).build()
).items().first()
val filterStr = "and(gt(start_time, \"2023-07-15T12:34:56Z\")," +
" or(neq(status, \"error\")," +
" and(eq(feedback_key, \"Correctness\"), eq(feedback_score, 0.0))))"
val runs = client.runs().queryV2(
RunQueryV2Params.builder().addProjectId(project.id()).filter(filterStr).build()
).items()
Nested
and() / or() filter expressions are unchanged.- Before
- After
Before
package main
import (
"context"
"github.com/langchain-ai/langsmith-go"
)
ctx := context.Background()
client := langsmith.NewClient()
sessions, err := client.Sessions.List(ctx, langsmith.SessionListParams{
Name: langsmith.F("default"),
Limit: langsmith.F(int64(1)),
})
project := sessions.Items[0]
filterStr := `and(gt(start_time, "2023-07-15T12:34:56Z"), or(neq(status, "error"), and(eq(feedback_key, "Correctness"), eq(feedback_score, 0.0))))`
runs, err := client.Runs.Query(ctx, langsmith.RunQueryParams{
Session: langsmith.F([]string{project.ID}),
Filter: langsmith.F(filterStr),
})
After
package main
import (
"context"
"github.com/langchain-ai/langsmith-go"
)
ctx := context.Background()
client := langsmith.NewClient()
sessions, err := client.Sessions.List(ctx, langsmith.SessionListParams{
Name: langsmith.F("default"),
Limit: langsmith.F(int64(1)),
})
project := sessions.Items[0]
filterStr := `and(gt(start_time, "2023-07-15T12:34:56Z"), or(neq(status, "error"), and(eq(feedback_key, "Correctness"), eq(feedback_score, 0.0))))`
runs, err := client.Runs.QueryV2(ctx, langsmith.RunQueryV2Params{
ProjectIDs: langsmith.F([]string{project.ID}),
Filter: langsmith.F(filterStr),
})
Nested
and() / or() filter expressions are unchanged.- Before
- After
PROJECT_ID=$(curl -s "https://api.smith.langchain.com/api/v1/sessions?name=default&limit=1" \
-H "x-api-key: $LANGSMITH_API_KEY" | jq -r '.[0].id')
FILTER='and(gt(start_time, "2023-07-15T12:34:56Z"), or(neq(status, "error"), and(eq(feedback_key, "Correctness"), eq(feedback_score, 0.0))))'
curl -X POST "https://api.smith.langchain.com/api/v1/runs/query" \
-H "x-api-key: $LANGSMITH_API_KEY" \
-H "Content-Type: application/json" \
-d "$(jq -n --arg pid "$PROJECT_ID" --arg f "$FILTER" '{"session": [$pid], "filter": $f}')"
PROJECT_ID=$(curl -s "https://api.smith.langchain.com/api/v1/sessions?name=default&limit=1" \
-H "x-api-key: $LANGSMITH_API_KEY" | jq -r '.[0].id')
FILTER='and(gt(start_time, "2023-07-15T12:34:56Z"), or(neq(status, "error"), and(eq(feedback_key, "Correctness"), eq(feedback_score, 0.0))))'
curl -X POST "https://api.smith.langchain.com/v2/runs/query" \
-H "x-api-key: $LANGSMITH_API_KEY" \
-H "Content-Type: application/json" \
-d "$(jq -n --arg pid "$PROJECT_ID" --arg f "$FILTER" '{"project_ids": [$pid], "filter": $f}')"
Scoped filters: filter, trace_filter, tree_filter
- Python
- TypeScript
- Java
- Go
- cURL
filter, trace_filter, and tree_filter are unchanged. filter applies to the matched run, trace_filter to the root of its trace, and tree_filter to other runs in the trace tree (siblings and children).- Before
- After
Before
from langsmith import Client
client = Client()
runs = client.list_runs(
project_name="default",
filter='eq(name, "RetrieveDocs")',
trace_filter='and(eq(feedback_key, "user_score"), eq(feedback_score, 1))',
tree_filter='eq(name, "ExpandQuery")',
)
After
import asyncio
from langsmith import Client
async def main():
client = Client()
project = await client.aread_project(project_name="default")
runs = client.runs.query(
project_ids=[str(project.id)],
filter='eq(name, "RetrieveDocs")',
trace_filter='and(eq(feedback_key, "user_score"), eq(feedback_score, 1))',
tree_filter='eq(name, "ExpandQuery")',
)
asyncio.run(main())
filter, trace_filter, and tree_filter are unchanged. filter applies to the matched run, trace_filter to the root of its trace, and tree_filter to other runs in the trace tree (siblings and children).- Before
- After
Before
import { Client } from "langsmith";
const client = new Client();
const runs = client.listRuns({
projectName: "default",
filter: 'eq(name, "RetrieveDocs")',
traceFilter: 'and(eq(feedback_key, "user_score"), eq(feedback_score, 1))',
treeFilter: 'eq(name, "ExpandQuery")',
});
After
import { Client } from "langsmith";
const client = new Client();
const project = await client.readProject({ projectName: "default" });
const runs = client.runs.query({
project_ids: [project.id],
filter: 'eq(name, "RetrieveDocs")',
trace_filter: 'and(eq(feedback_key, "user_score"), eq(feedback_score, 1))',
tree_filter: 'eq(name, "ExpandQuery")',
});
.filter(), .traceFilter(), and .treeFilter() are unchanged. filter applies to the matched run, traceFilter to the root of its trace, and treeFilter to other runs in the trace tree (siblings and children).- Before
- After
Before
import com.langchain.smith.client.LangsmithClient
import com.langchain.smith.client.okhttp.LangsmithOkHttpClient
import com.langchain.smith.models.runs.RunQueryParams
import com.langchain.smith.models.sessions.SessionListParams
val client: LangsmithClient = LangsmithOkHttpClient.fromEnv()
val project = client.sessions().list(
SessionListParams.builder().name("default").limit(1L).build()
).items().first()
val runs = client.runs().query(
RunQueryParams.builder()
.addSession(project.id())
.filter("eq(name, \"RetrieveDocs\")")
.traceFilter("and(eq(feedback_key, \"user_score\"), eq(feedback_score, 1))")
.treeFilter("eq(name, \"ExpandQuery\")")
.build()
).items()
After
import com.langchain.smith.client.LangsmithClient
import com.langchain.smith.client.okhttp.LangsmithOkHttpClient
import com.langchain.smith.models.runs.RunQueryV2Params
import com.langchain.smith.models.sessions.SessionListParams
val client: LangsmithClient = LangsmithOkHttpClient.fromEnv()
val project = client.sessions().list(
SessionListParams.builder().name("default").limit(1L).build()
).items().first()
val runs = client.runs().queryV2(
RunQueryV2Params.builder()
.addProjectId(project.id())
.filter("eq(name, \"RetrieveDocs\")")
.traceFilter("and(eq(feedback_key, \"user_score\"), eq(feedback_score, 1))")
.treeFilter("eq(name, \"ExpandQuery\")")
.build()
).items()
Filter, TraceFilter, and TreeFilter are unchanged. Filter applies to the matched run, TraceFilter to the root of its trace, and TreeFilter to other runs in the trace tree (siblings and children).- Before
- After
Before
package main
import (
"context"
"github.com/langchain-ai/langsmith-go"
)
ctx := context.Background()
client := langsmith.NewClient()
sessions, err := client.Sessions.List(ctx, langsmith.SessionListParams{
Name: langsmith.F("default"),
Limit: langsmith.F(int64(1)),
})
project := sessions.Items[0]
runs, err := client.Runs.Query(ctx, langsmith.RunQueryParams{
Session: langsmith.F([]string{project.ID}),
Filter: langsmith.F(`eq(name, "RetrieveDocs")`),
TraceFilter: langsmith.F(`and(eq(feedback_key, "user_score"), eq(feedback_score, 1))`),
TreeFilter: langsmith.F(`eq(name, "ExpandQuery")`),
})
After
package main
import (
"context"
"github.com/langchain-ai/langsmith-go"
)
ctx := context.Background()
client := langsmith.NewClient()
sessions, err := client.Sessions.List(ctx, langsmith.SessionListParams{
Name: langsmith.F("default"),
Limit: langsmith.F(int64(1)),
})
project := sessions.Items[0]
runs, err := client.Runs.QueryV2(ctx, langsmith.RunQueryV2Params{
ProjectIDs: langsmith.F([]string{project.ID}),
Filter: langsmith.F(`eq(name, "RetrieveDocs")`),
TraceFilter: langsmith.F(`and(eq(feedback_key, "user_score"), eq(feedback_score, 1))`),
TreeFilter: langsmith.F(`eq(name, "ExpandQuery")`),
})
filter, trace_filter, and tree_filter are unchanged. filter applies to the matched run, trace_filter to the root of its trace, and tree_filter to other runs in the trace tree (siblings and children).- Before
- After
PROJECT_ID=$(curl -s "https://api.smith.langchain.com/api/v1/sessions?name=default&limit=1" \
-H "x-api-key: $LANGSMITH_API_KEY" | jq -r '.[0].id')
FILTER='eq(name, "RetrieveDocs")'
TRACE_FILTER='and(eq(feedback_key, "user_score"), eq(feedback_score, 1))'
TREE_FILTER='eq(name, "ExpandQuery")'
curl -X POST "https://api.smith.langchain.com/api/v1/runs/query" \
-H "x-api-key: $LANGSMITH_API_KEY" \
-H "Content-Type: application/json" \
-d "$(jq -n \
--arg pid "$PROJECT_ID" \
--arg f "$FILTER" \
--arg tf "$TRACE_FILTER" \
--arg treef "$TREE_FILTER" \
'{"session": [$pid], "filter": $f, "trace_filter": $tf, "tree_filter": $treef}')"
PROJECT_ID=$(curl -s "https://api.smith.langchain.com/api/v1/sessions?name=default&limit=1" \
-H "x-api-key: $LANGSMITH_API_KEY" | jq -r '.[0].id')
FILTER='eq(name, "RetrieveDocs")'
TRACE_FILTER='and(eq(feedback_key, "user_score"), eq(feedback_score, 1))'
TREE_FILTER='eq(name, "ExpandQuery")'
curl -X POST "https://api.smith.langchain.com/v2/runs/query" \
-H "x-api-key: $LANGSMITH_API_KEY" \
-H "Content-Type: application/json" \
-d "$(jq -n \
--arg pid "$PROJECT_ID" \
--arg f "$FILTER" \
--arg tf "$TRACE_FILTER" \
--arg treef "$TREE_FILTER" \
'{"project_ids": [$pid], "filter": $f, "trace_filter": $tf, "tree_filter": $treef}')"
Runs: retrieve
Fetch a single run by ID. Returns only the run ID by default—specify a field selection list to retrieve additional data.Main changes
Method name
- Python
- TypeScript
- Java
- Go
- cURL
| Before | After |
|---|---|
client.read_run() | client.runs.retrieve() |
| Before | After |
|---|---|
client.readRun() | client.runs.retrieve() |
| Before | After |
|---|---|
client.runs().retrieve() | client.runs().retrieveV2() |
| Before | After |
|---|---|
client.Runs.Get() | client.Runs.GetV2() |
| Before | After |
|---|---|
GET /api/v1/runs/{run_id} | GET /v2/runs/{run_id} |
Query parameters
- Python
- TypeScript
- Java
- Go
- cURL
runs.retrieve requires two new fields—project_id and start_time—that read_run did not need. Both are required to locate the run in SmithDB.Before (read_run) | After (runs.retrieve) | Notes |
|---|---|---|
run_id | run_id | Unchanged |
load_child_runs | (removed) | No equivalent |
| (not available) | project_id | Required—UUID of the project that owns the run |
| (not available) | start_time | Required—run’s start time (RFC3339), used with project_id to locate the run |
| (all fields returned by default) | selects | Field projection; defaults to ["ID"] only; field names are uppercase |
client.runs.retrieve requires two new fields—project_id and start_time—that readRun did not need. Both are required to locate the run in SmithDB.Before (readRun) | After (client.runs.retrieve) | Notes |
|---|---|---|
runId | runId | Unchanged (positional parameter) |
options.loadChildRuns | (removed) | No equivalent |
| (not available) | project_id | Required—snake_case; UUID of the project that owns the run |
| (not available) | start_time | Required—snake_case; run’s start time (RFC3339), used to locate the run |
| (all fields returned by default) | selects | Field projection; defaults to ["ID"] only; field names are uppercase |
retrieveV2() requires projectId(), which replaces the removed sessionId(), and makes startTime() required (previously optional). Both are needed to locate the run in SmithDB.Before (RunRetrieveParams) | After (RunRetrieveV2Params) | Notes |
|---|---|---|
runId() | runId() | Unchanged |
sessionId() | (removed) | Replaced by projectId() |
startTime() | startTime() | Now required; used with projectId() to locate the run in SmithDB |
excludeS3StoredAttributes() | (removed) | No equivalent |
excludeSerialized() | (removed) | No equivalent |
includeMessages() | (removed) | No equivalent |
| (not available) | projectId() | Required—UUID of the project that owns the run |
| (all fields returned by default) | selects() | Field projection; defaults to ["ID"] only; field names are uppercase |
GetV2() requires ProjectID, which replaces the removed SessionID, and makes StartTime required (previously optional). Both are needed to locate the run in SmithDB.Before (RunGetParams) | After (RunGetV2Params) | Notes |
|---|---|---|
runID (positional) | runID (positional) | Unchanged |
ExcludeS3StoredAttributes | (removed) | No equivalent |
ExcludeSerialized | (removed) | No equivalent |
IncludeMessages | (removed) | No equivalent |
SessionID | (removed) | Replaced by ProjectID |
StartTime | StartTime | Now required; used with ProjectID to locate the run in SmithDB |
| (not available) | ProjectID | Required—UUID of the project that owns the run |
| (all fields returned by default) | Selects | Field projection; defaults to ["ID"] only; field name constants are uppercase (e.g., RunGetV2ParamsSelectName) |
run_id remains in the URL path. All other parameters are query string values with snake_case names.GET /v2/runs/{run_id} requires a new project_id query param and makes start_time required (previously optional). Both are needed to locate the run in SmithDB.Before (GET /api/v1/runs/{run_id} param) | After (GET /v2/runs/{run_id} param) | Notes |
|---|---|---|
run_id (path) | run_id (path) | Unchanged |
load_child_runs (query) | (removed) | No equivalent |
| (not available) | project_id (query) | Required—UUID of the project that owns the run |
start_time (query) | start_time (query) | Now required; used with project_id to locate the run in SmithDB |
| (all fields returned by default) | selects (query, repeatable) | Field projection; defaults to ["ID"] only; field names are uppercase |
Response fields
- Python
- TypeScript
- Java
- Go
- cURL
Pass SCREAMING_SNAKE_CASE strings to
selects (eg. "ID", "NAME", "STATUS") to control which fields are populated on the returned Run; only selected fields are non-None. Default selects contains only "ID".Before (v1 Run attribute) | After (v2 Run attribute) | Notes |
|---|---|---|
run.id | run.id | Unchanged; returned by default when selects is omitted |
run.name | run.name | Unchanged |
run.run_type | run.run_type | Values are now uppercase Literals: "LLM", "CHAIN", etc. |
run.status | run.status | Values: "SUCCESS", "ERROR", "PENDING" |
run.start_time | run.start_time | Unchanged |
run.end_time | run.end_time | Unchanged |
run.error | run.error | Unchanged |
run.inputs | run.inputs | Unchanged |
run.outputs | run.outputs | Unchanged |
run.tags | run.tags | Unchanged |
run.extra | run.extra | Unchanged |
run.metadata | run.metadata | Unchanged |
run.events | run.events | Unchanged |
run.reference_example_id | run.reference_example_id | Unchanged |
run.trace_id | run.trace_id | Unchanged |
run.dotted_order | run.dotted_order | Unchanged |
run.parent_run_id | (removed) | Use run.parent_run_ids (list of all ancestor UUIDs, root first) |
run.parent_run_ids | run.parent_run_ids | Unchanged |
run.session_id | run.project_id | Renamed; session_id was the project UUID |
run.feedback_stats | run.feedback_stats | Unchanged |
run.app_path | run.app_path | Unchanged |
run.attachments | run.attachments | v2 returns pre-signed download URLs instead of raw bytes |
run.total_tokens | run.total_tokens | Unchanged |
run.prompt_tokens | run.prompt_tokens | Unchanged |
run.completion_tokens | run.completion_tokens | Unchanged |
run.total_cost | run.total_cost | Unchanged |
run.prompt_cost | run.prompt_cost | Unchanged |
run.completion_cost | run.completion_cost | Unchanged |
run.first_token_time | run.first_token_time | Unchanged |
run.latency (property) | run.latency_seconds | Renamed; was a computed timedelta property, now a native float field |
run.in_dataset | run.is_in_dataset | Renamed |
run.child_run_ids | (removed) | No equivalent |
run.child_runs | (removed) | No equivalent |
run.serialized | (removed) | Use run.manifest |
run.manifest_id | (removed) | Use run.manifest |
| (not available) | run.is_root | New |
| (not available) | run.manifest | New: full manifest object (replaces serialized and manifest_id) |
| (not available) | run.error_preview | New: truncated error snippet |
| (not available) | run.inputs_preview | New: truncated inputs preview |
| (not available) | run.outputs_preview | New: truncated outputs preview |
| (not available) | run.thread_id | New: conversation thread UUID |
| (not available) | run.reference_dataset_id | New: dataset UUID for the reference example |
| (not available) | run.share_url | New: public share URL (only set when the run has been shared) |
run.prompt_token_details | run.prompt_token_details.raw | Field now wraps the dict; access .raw to get dict[str, int] (element type unchanged) |
run.completion_token_details | run.completion_token_details.raw | Field now wraps the dict; access .raw to get dict[str, int] (element type unchanged) |
run.prompt_cost_details | run.prompt_cost_details.raw | Field now wraps the dict; access .raw to get dict[str, float] (was dict[str, Decimal]) |
run.completion_cost_details | run.completion_cost_details.raw | Field now wraps the dict; access .raw to get dict[str, float] (was dict[str, Decimal]) |
Pass SCREAMING_SNAKE_CASE strings to
selects (eg. "ID", "NAME", "STATUS") to control which fields are populated on the returned Run. Default selects contains only "ID".Before (v1 Run property) | After (v2 Run property) | Notes |
|---|---|---|
run.id | run.id | Unchanged |
run.name | run.name | Unchanged |
run.runType | run.run_type | Renamed to snake_case; values are now uppercase: "LLM", "CHAIN", etc. |
run.status | run.status | Values: "SUCCESS", "ERROR", "PENDING" |
run.startTime | run.start_time | Renamed to snake_case |
run.endTime | run.end_time | Renamed to snake_case |
run.error | run.error | Unchanged |
run.inputs | run.inputs | Unchanged |
run.outputs | run.outputs | Unchanged |
run.tags | run.tags | Unchanged |
run.extra | run.extra | Unchanged |
| (not available) | run.metadata | New: previously accessed via run.extra.metadata |
run.events | run.events | Unchanged |
run.referenceExampleId | run.reference_example_id | Renamed to snake_case |
run.traceId | run.trace_id | Renamed to snake_case |
run.dottedOrder | run.dotted_order | Renamed to snake_case |
run.parentRunId | (removed) | Use run.parent_run_ids (list of all ancestor UUIDs, root first) |
run.parentRunIds | run.parent_run_ids | Renamed to snake_case |
run.sessionId | run.project_id | Renamed; sessionId was the project UUID |
run.feedbackStats | run.feedback_stats | Renamed to snake_case |
run.appPath | run.app_path | Renamed to snake_case |
run.attachments | run.attachments | v2 returns pre-signed download URLs instead of raw bytes |
run.totalTokens | run.total_tokens | Renamed to snake_case |
run.promptTokens | run.prompt_tokens | Renamed to snake_case |
run.completionTokens | run.completion_tokens | Renamed to snake_case |
run.totalCost | run.total_cost | Renamed to snake_case |
run.promptCost | run.prompt_cost | Renamed to snake_case |
run.completionCost | run.completion_cost | Renamed to snake_case |
run.firstTokenTime | run.first_token_time | Renamed to snake_case |
run.latency | run.latency_seconds | Renamed; was a computed property, now a native number field (seconds) |
run.inDataset | run.is_in_dataset | Renamed |
run.childRunIds | (removed) | No equivalent |
run.childRuns | (removed) | No equivalent |
run.serialized | (removed) | Use run.manifest |
run.manifestId | (removed) | Use run.manifest |
run.shareToken | (removed) | Use run.share_url (full URL, only set when the run has been shared) |
| (not available) | run.is_root | New |
| (not available) | run.manifest | New: full manifest object (replaces serialized and manifestId) |
| (not available) | run.error_preview | New: truncated error snippet |
| (not available) | run.inputs_preview | New: truncated inputs preview |
| (not available) | run.outputs_preview | New: truncated outputs preview |
| (not available) | run.thread_id | New: conversation thread UUID |
| (not available) | run.reference_dataset_id | New: dataset UUID for the reference example |
| (not available) | run.share_url | New: public share URL (only set when the run has been shared) |
| (not available) | run.prompt_token_details | New: per-category prompt token breakdown |
| (not available) | run.completion_token_details | New: per-category completion token breakdown |
| (not available) | run.prompt_cost_details | New: per-category prompt cost breakdown |
| (not available) | run.completion_cost_details | New: per-category completion cost breakdown |
Add
RunRetrieveV2Params.Select values (eg. Select.NAME, Select.STATUS) via .addSelect(...) to control which fields are populated; unselected fields return empty Optional values. selects() defaults to ID only.Before (RunSchema method) | After (Run method) | Notes |
|---|---|---|
run.id() | run.id() | Unchanged |
run.name() | run.name() | Unchanged |
run.runType() | run.runType() | Values are now uppercase: "LLM", "CHAIN", etc. |
run.status() | run.status() | Values: "SUCCESS", "ERROR", "PENDING" |
run.startTime() | run.startTime() | Unchanged |
run.endTime() | run.endTime() | Unchanged |
run.error() | run.error() | Unchanged |
run.inputs() | run.inputs() | Unchanged |
run.outputs() | run.outputs() | Unchanged |
run.tags() | run.tags() | Unchanged |
run.extra() | run.extra() | Unchanged |
run.events() | run.events() | Unchanged |
run.feedbackStats() | run.feedbackStats() | Unchanged |
run.inputsPreview() | run.inputsPreview() | Unchanged |
run.outputsPreview() | run.outputsPreview() | Unchanged |
run.referenceExampleId() | run.referenceExampleId() | Unchanged |
run.traceId() | run.traceId() | Unchanged |
run.dottedOrder() | run.dottedOrder() | Unchanged |
run.parentRunId() | (removed) | Use run.parentRunIds() (list of all ancestor UUIDs, root first) |
run.parentRunIds() | run.parentRunIds() | Unchanged |
run.sessionId() | run.projectId() | Renamed; sessionId() returned the project UUID |
run.appPath() | run.appPath() | Unchanged |
run.firstTokenTime() | run.firstTokenTime() | Unchanged |
run.totalTokens() | run.totalTokens() | Unchanged |
run.promptTokens() | run.promptTokens() | Unchanged |
run.completionTokens() | run.completionTokens() | Unchanged |
run.totalCost() | run.totalCost() | Return type changed from Optional<String> to Optional<Double> |
run.promptCost() | run.promptCost() | Return type changed from Optional<String> to Optional<Double> |
run.completionCost() | run.completionCost() | Return type changed from Optional<String> to Optional<Double> |
run.promptTokenDetails() | run.promptTokenDetails() | Unchanged |
run.completionTokenDetails() | run.completionTokenDetails() | Unchanged |
run.promptCostDetails() | run.promptCostDetails() | Unchanged |
run.completionCostDetails() | run.completionCostDetails() | Unchanged |
run.priceModelId() | run.priceModelId() | Unchanged |
run.inDataset() | run.isInDataset() | Renamed |
run.referenceDatasetId() | run.referenceDatasetId() | Unchanged |
run.threadId() | run.threadId() | Unchanged |
run.shareToken() | (removed) | Use run.shareUrl() (full URL, only set when the run has been shared) |
run.childRunIds() | (removed) | No equivalent |
run.directChildRunIds() | (removed) | No equivalent |
run.serialized() | (removed) | Use run.manifest() |
run.manifestId() | (removed) | Use run.manifest() |
run.messages() | (removed) | No equivalent |
run.executionOrder() | (removed) | No equivalent |
run.lastQueuedAt() | (removed) | No equivalent |
run.traceFirstReceivedAt() | (removed) | No equivalent |
run.traceMaxStartTime() | (removed) | No equivalent |
run.traceMinStartTime() | (removed) | No equivalent |
run.traceTier() | (removed) | No equivalent |
run.traceUpgrade() | (removed) | No equivalent |
run.ttlSeconds() | (removed) | No equivalent |
| (not available) | run.attachments() | New: pre-signed download URLs for attachments (replaces S3 URL fields) |
| (not available) | run.latencySeconds() | New: wall-clock duration in seconds |
| (not available) | run.isRoot() | New |
| (not available) | run.errorPreview() | New: truncated error snippet |
| (not available) | run.manifest() | New: full manifest, typed as Optional<Manifest> (replaces serialized() and manifestId()) |
| (not available) | run.metadata() | New: metadata, typed as Optional<Metadata> (was derived from extra.metadata) |
| (not available) | run.shareUrl() | New: public share URL (only set when the run has been shared) |
| (not available) | run.threadEvaluationTime() | New |
Pass
RunGetV2ParamsSelect constants (eg. RunGetV2ParamsSelectName, RunGetV2ParamsSelectStatus) to Selects to control which fields are populated; unselected fields are zero-valued on the returned struct. Selects defaults to ID only.Before (RunSchema field) | After (Run field) | Notes |
|---|---|---|
run.ID | run.ID | Unchanged |
run.Name | run.Name | Unchanged |
run.RunType | run.RunType | Values changed to uppercase: "LLM", "CHAIN", etc. |
run.Status | run.Status | Values: "SUCCESS", "ERROR", "PENDING" |
run.TraceID | run.TraceID | Unchanged |
run.DottedOrder | run.DottedOrder | Unchanged |
run.AppPath | run.AppPath | Unchanged |
run.StartTime | run.StartTime | Unchanged |
run.EndTime | run.EndTime | Unchanged |
run.Error | run.Error | Unchanged |
run.Events | run.Events | Unchanged; element type is now RunEvent (was map[string]interface{}) |
run.Extra | run.Extra | Unchanged; type is now interface{} (was map[string]interface{}) |
run.FeedbackStats | run.FeedbackStats | Unchanged; element type is now RunFeedbackStat |
run.FirstTokenTime | run.FirstTokenTime | Unchanged |
run.Inputs | run.Inputs | Unchanged; type is now interface{} (was map[string]interface{}) |
run.InputsPreview | run.InputsPreview | Unchanged |
run.Outputs | run.Outputs | Unchanged; type is now interface{} (was map[string]interface{}) |
run.OutputsPreview | run.OutputsPreview | Unchanged |
run.ParentRunIDs | run.ParentRunIDs | Unchanged |
run.PriceModelID | run.PriceModelID | Unchanged |
run.PromptCost | run.PromptCost | Unchanged |
run.PromptCostDetails | run.PromptCostDetails.Raw | Field now wraps the map; access .Raw to get map[string]float64 (was map[string]string) |
run.PromptTokenDetails | run.PromptTokenDetails.Raw | Field now wraps the map; access .Raw to get map[string]int64 (element type unchanged) |
run.PromptTokens | run.PromptTokens | Unchanged |
run.CompletionCost | run.CompletionCost | Unchanged |
run.CompletionCostDetails | run.CompletionCostDetails.Raw | Field now wraps the map; access .Raw to get map[string]float64 (was map[string]string) |
run.CompletionTokenDetails | run.CompletionTokenDetails.Raw | Field now wraps the map; access .Raw to get map[string]int64 (element type unchanged) |
run.CompletionTokens | run.CompletionTokens | Unchanged |
run.TotalCost | run.TotalCost | Unchanged |
run.TotalTokens | run.TotalTokens | Unchanged |
run.ReferenceDatasetID | run.ReferenceDatasetID | Unchanged |
run.ReferenceExampleID | run.ReferenceExampleID | Unchanged |
run.Tags | run.Tags | Unchanged |
run.ThreadID | run.ThreadID | Unchanged |
run.SessionID | run.ProjectID | Renamed |
run.InDataset | run.IsInDataset | Renamed |
run.ChildRunIDs | (removed) | No equivalent |
run.DirectChildRunIDs | (removed) | No equivalent |
run.ExecutionOrder | (removed) | No equivalent |
run.InputsS3URLs | (removed) | Internal storage URL; not exposed in v2 |
run.LastQueuedAt | (removed) | No equivalent |
run.ManifestID | (removed) | Use run.Manifest |
run.ManifestS3ID | (removed) | Internal storage URL; not exposed in v2 |
run.Messages | (removed) | No equivalent |
run.OutputsS3URLs | (removed) | Internal storage URL; not exposed in v2 |
run.ParentRunID | (removed) | Use run.ParentRunIDs |
run.S3URLs | (removed) | Internal storage URL; not exposed in v2 |
run.Serialized | (removed) | Use run.Manifest |
run.ShareToken | (removed) | Use run.ShareURL |
run.TraceFirstReceivedAt | (removed) | No equivalent |
run.TraceMaxStartTime | (removed) | No equivalent |
run.TraceMinStartTime | (removed) | No equivalent |
run.TraceTier | (removed) | No equivalent |
run.TraceUpgrade | (removed) | No equivalent |
run.TtlSeconds | (removed) | No equivalent |
| (not available) | run.Attachments | New: maps attachment filename to pre-signed download URL |
| (not available) | run.ErrorPreview | New: truncated error snippet |
| (not available) | run.IsRoot | New |
| (not available) | run.LatencySeconds | New: wall-clock duration in seconds |
| (not available) | run.Manifest | New: full manifest object (replaces Serialized and ManifestID) |
| (not available) | run.Metadata | New: arbitrary user-defined JSON metadata |
| (not available) | run.ShareURL | New: public share URL (only set when the run has been shared) |
| (not available) | run.ThreadEvaluationTime | New |
Pass SCREAMING_SNAKE_CASE strings as repeated
selects query parameters (eg. selects=NAME&selects=STATUS) to control which fields are populated. Default selects contains only "ID".| Before (v1 response field) | After (v2 response field) | Notes |
|---|---|---|
id | id | Unchanged |
name | name | Unchanged |
run_type | run_type | Values changed to uppercase: "LLM", "CHAIN", etc. |
status | status | Values: "SUCCESS", "ERROR", "PENDING" |
trace_id | trace_id | Unchanged |
dotted_order | dotted_order | Unchanged |
app_path | app_path | Unchanged |
start_time | start_time | Unchanged |
end_time | end_time | Unchanged |
error | error | Unchanged |
events | events | Unchanged |
extra | extra | Unchanged |
feedback_stats | feedback_stats | Unchanged |
first_token_time | first_token_time | Unchanged |
inputs | inputs | Unchanged |
inputs_preview | inputs_preview | Unchanged |
outputs | outputs | Unchanged |
outputs_preview | outputs_preview | Unchanged |
parent_run_ids | parent_run_ids | Unchanged |
price_model_id | price_model_id | Unchanged |
prompt_cost | prompt_cost | Unchanged |
prompt_cost_details | prompt_cost_details.raw | Field now wraps the object; read .raw for the same {category: cost} mapping, now with numeric values (was strings) |
prompt_token_details | prompt_token_details.raw | Field now wraps the object; read .raw for the same {category: count} mapping (values unchanged) |
prompt_tokens | prompt_tokens | Unchanged |
completion_cost | completion_cost | Unchanged |
completion_cost_details | completion_cost_details.raw | Field now wraps the object; read .raw for the same {category: cost} mapping, now with numeric values (was strings) |
completion_token_details | completion_token_details.raw | Field now wraps the object; read .raw for the same {category: count} mapping (values unchanged) |
completion_tokens | completion_tokens | Unchanged |
total_cost | total_cost | Unchanged |
total_tokens | total_tokens | Unchanged |
reference_dataset_id | reference_dataset_id | Unchanged |
reference_example_id | reference_example_id | Unchanged |
tags | tags | Unchanged |
thread_id | thread_id | Unchanged |
session_id | project_id | Renamed |
in_dataset | is_in_dataset | Renamed |
child_run_ids | (removed) | No equivalent |
direct_child_run_ids | (removed) | No equivalent |
execution_order | (removed) | No equivalent |
inputs_s3_urls | (removed) | Internal storage URL; not exposed in v2 |
last_queued_at | (removed) | No equivalent |
manifest_id | (removed) | Use manifest |
manifest_s3_id | (removed) | Internal storage URL; not exposed in v2 |
messages | (removed) | No equivalent |
outputs_s3_urls | (removed) | Internal storage URL; not exposed in v2 |
parent_run_id | (removed) | Use parent_run_ids |
s3_urls | (removed) | Internal storage URL; not exposed in v2 |
serialized | (removed) | Use manifest |
share_token | (removed) | Use share_url |
trace_first_received_at | (removed) | No equivalent |
trace_max_start_time | (removed) | No equivalent |
trace_min_start_time | (removed) | No equivalent |
trace_tier | (removed) | No equivalent |
trace_upgrade | (removed) | No equivalent |
ttl_seconds | (removed) | No equivalent |
| (not available) | attachments | New: maps attachment filename to pre-signed download URL |
| (not available) | error_preview | New: truncated error snippet |
| (not available) | is_root | New |
| (not available) | latency_seconds | New: wall-clock duration in seconds |
| (not available) | manifest | New: full manifest object (replaces serialized and manifest_id) |
| (not available) | metadata | New: previously nested under extra.metadata |
| (not available) | share_url | New: public share URL (only set when the run has been shared) |
| (not available) | thread_evaluation_time | New |
Examples
Fetch a single run by ID
- Python
- TypeScript
- Java
- Go
- cURL
runs.retrieve requires two additional parameters that read_run did not need: project_id (UUID) and start_time. Both are required by the SmithDB storage model to locate a run efficiently. Resolve the project UUID via client.aread_project() first.- Before
- After
Before
from langsmith import Client
client = Client()
run_id = "<run-id>"
run = client.read_run(run_id)
After
import asyncio
from langsmith import Client
async def main():
client = Client()
project = await client.aread_project(project_name="default")
run_id = "<run-id>"
start_time = "2026-06-01T12:00:00Z"
run = await client.runs.retrieve(
run_id=run_id,
project_id=str(project.id),
start_time=start_time,
)
asyncio.run(main())
client.runs.retrieve requires two additional parameters that readRun did not need: project_id (UUID) and start_time. Both are required by the SmithDB storage model to locate a run efficiently. Resolve the project UUID via client.readProject() first.- Before
- After
Before
import { Client } from "langsmith";
const client = new Client();
let runId = "<run-id>";
await client.readRun(runId);
After
import { Client } from "langsmith";
const client = new Client();
const project = await client.readProject({ projectName: "default" });
let runId = "<run-id>";
let startTime = "2026-06-01T12:00:00Z";
await client.runs.retrieve(runId, {
project_id: project.id,
start_time: startTime,
});
retrieveV2() requires two additional parameters that client.runs().retrieve() did not need: projectId() (UUID) and startTime(). Both are required by the SmithDB storage model to locate a run efficiently. Resolve the project UUID via client.sessions().list() first.- Before
- After
Before
import com.langchain.smith.client.LangsmithClient
import com.langchain.smith.client.okhttp.LangsmithOkHttpClient
val client: LangsmithClient = LangsmithOkHttpClient.fromEnv()
var runId = "<run-id>"
client.runs().retrieve(runId)
After
import java.time.OffsetDateTime
import com.langchain.smith.client.LangsmithClient
import com.langchain.smith.client.okhttp.LangsmithOkHttpClient
import com.langchain.smith.models.runs.RunRetrieveV2Params
import com.langchain.smith.models.sessions.SessionListParams
val client: LangsmithClient = LangsmithOkHttpClient.fromEnv()
val project = client.sessions().list(
SessionListParams.builder().name("default").limit(1L).build()
).items().first()
var runId = "<run-id>"
var startTime = "<run-start-time-rfc3339>"
client.runs().retrieveV2(
runId,
RunRetrieveV2Params.builder()
.projectId(project.id())
.startTime(OffsetDateTime.parse(startTime))
.build()
)
GetV2() requires two additional parameters that client.Runs.Get() did not need: ProjectID (UUID) and StartTime. Both are required by the SmithDB storage model to locate a run efficiently. Resolve the project UUID via client.Sessions.List() first.- Before
- After
Before
package main
import (
"context"
"github.com/langchain-ai/langsmith-go"
)
ctx := context.Background()
client := langsmith.NewClient()
runID := "<run-id>"
run, err := client.Runs.Get(ctx, runID, langsmith.RunGetParams{})
After
package main
import (
"context"
"time"
"github.com/langchain-ai/langsmith-go"
)
ctx := context.Background()
client := langsmith.NewClient()
runID := "<run-id>"
startTime := time.Date(2026, 6, 1, 12, 0, 0, 0, time.UTC)
projectID := "<project-id>"
run, err := client.Runs.GetV2(ctx, runID, langsmith.RunGetV2Params{
ProjectID: langsmith.F(projectID),
StartTime: langsmith.F(startTime),
})
GET /v2/runs/{run_id} requires two additional query parameters that GET /api/v1/runs/{run_id} did not need: project_id (UUID) and start_time. Both are required by the SmithDB storage model to locate a run efficiently. Resolve the project UUID via a GET /api/v1/sessions request first.- Before
- After
RUN_ID="<run-id>"
curl "https://api.smith.langchain.com/api/v1/runs/$RUN_ID" \
-H "x-api-key: $LANGSMITH_API_KEY"
PROJECT_ID=$(curl -s "https://api.smith.langchain.com/api/v1/sessions?name=default&limit=1" \
-H "x-api-key: $LANGSMITH_API_KEY" | jq -r '.[0].id')
RUN_ID="<run-id>"
START_TIME="2025-01-01T12:00:00Z"
curl "https://api.smith.langchain.com/v2/runs/$RUN_ID?project_id=$PROJECT_ID&start_time=$START_TIME" \
-H "x-api-key: $LANGSMITH_API_KEY"
Selecting fields
- Python
- TypeScript
- Java
- Go
- cURL
read_run returns a full run object with no selection needed. runs.retrieve returns only id by default—pass selects=[...] to request more.- Before
- After
Before
from langsmith import Client
client = Client()
run_id = "<run-id>"
run = client.read_run(run_id=run_id)
print(run.name, run.status, run.total_tokens)
After
import asyncio
from langsmith import Client
async def main():
client = Client()
project = await client.aread_project(project_name="default")
run_id = "<run-id>"
start_time = "2026-06-01T12:00:00Z"
run = await client.runs.retrieve(
run_id=run_id,
project_id=str(project.id),
start_time=start_time,
selects=["NAME", "STATUS", "TOTAL_TOKENS"],
)
print(run.name, run.status, run.total_tokens)
asyncio.run(main())
readRun returns a full run object with no selection needed. client.runs.retrieve returns only id by default—pass selects: [...] to request more.- Before
- After
Before
import { Client } from "langsmith";
const client = new Client();
let runId = "<run-id>";
const retrievedRun = await client.readRun(runId);
console.log(retrievedRun.name, retrievedRun.status, retrievedRun.total_tokens);
After
import { Client } from "langsmith";
const client = new Client();
let runId = "<run-id>";
let startTime = "2026-06-01T12:00:00Z";
let projectId = "<project-id>";
const retrievedRun = await client.runs.retrieve(runId, {
project_id: projectId,
start_time: startTime,
selects: ["NAME", "STATUS", "TOTAL_TOKENS"],
});
console.log(retrievedRun.name, retrievedRun.status, retrievedRun.total_tokens);
.retrieve() returns a full run object with no selection needed. .retrieveV2() returns only id by default—call .addSelect(...) for each field you need.- Before
- After
Before
import com.langchain.smith.client.LangsmithClient
import com.langchain.smith.client.okhttp.LangsmithOkHttpClient
val client: LangsmithClient = LangsmithOkHttpClient.fromEnv()
var runId = "<run-id>"
val run = client.runs().retrieve(runId)
println("${run.name()} ${run.status()} ${run.totalTokens()}")
After
import java.time.OffsetDateTime
import com.langchain.smith.client.LangsmithClient
import com.langchain.smith.client.okhttp.LangsmithOkHttpClient
import com.langchain.smith.models.runs.RunRetrieveV2Params
import com.langchain.smith.models.sessions.SessionListParams
val client: LangsmithClient = LangsmithOkHttpClient.fromEnv()
val project = client.sessions().list(
SessionListParams.builder().name("default").limit(1L).build()
).items().first()
var runId = "<run-id>"
var startTime = "<run-start-time-rfc3339>"
val run = client.runs().retrieveV2(
runId,
RunRetrieveV2Params.builder()
.projectId(project.id())
.startTime(OffsetDateTime.parse(startTime))
.addSelect(RunRetrieveV2Params.Select.NAME)
.addSelect(RunRetrieveV2Params.Select.STATUS)
.addSelect(RunRetrieveV2Params.Select.TOTAL_TOKENS)
.build()
)
println("${run.name()} ${run.status()} ${run.totalTokens()}")
Get returns a full run struct with no selection needed. GetV2 returns only ID by default—pass Selects with the fields you need.- Before
- After
Before
package main
import (
"context"
"fmt"
"github.com/langchain-ai/langsmith-go"
)
ctx := context.Background()
client := langsmith.NewClient()
runID := "<run-id>"
run, err := client.Runs.Get(ctx, runID, langsmith.RunGetParams{})
fmt.Println(run.Name, run.Status, run.TotalTokens)
After
package main
import (
"context"
"fmt"
"time"
"github.com/langchain-ai/langsmith-go"
)
ctx := context.Background()
client := langsmith.NewClient()
runID := "<run-id>"
startTime := time.Date(2026, 6, 1, 12, 0, 0, 0, time.UTC)
projectID := "<project-id>"
run, err := client.Runs.GetV2(ctx, runID, langsmith.RunGetV2Params{
ProjectID: langsmith.F(projectID),
StartTime: langsmith.F(startTime),
Selects: langsmith.F([]langsmith.RunGetV2ParamsSelect{
langsmith.RunGetV2ParamsSelectName,
langsmith.RunGetV2ParamsSelectStatus,
langsmith.RunGetV2ParamsSelectTotalTokens,
}),
})
fmt.Println(run.Name, run.Status, run.TotalTokens)
GET /api/v1/runs/{run_id} returns a full run object with no selection needed. GET /v2/runs/{run_id} returns only id by default—pass selects query parameters for the fields you need.- Before
- After
RUN_ID="<run-id>"
curl "https://api.smith.langchain.com/api/v1/runs/$RUN_ID" \
-H "x-api-key: $LANGSMITH_API_KEY"
PROJECT_ID=$(curl -s "https://api.smith.langchain.com/api/v1/sessions?name=default&limit=1" \
-H "x-api-key: $LANGSMITH_API_KEY" | jq -r '.[0].id')
RUN_ID="<run-id>"
START_TIME="2026-06-01T12:00:00Z"
curl "https://api.smith.langchain.com/v2/runs/$RUN_ID?project_id=$PROJECT_ID&start_time=$START_TIME&selects=NAME&selects=STATUS&selects=TOTAL_TOKENS" \
-H "x-api-key: $LANGSMITH_API_KEY"
Connect these docs to Claude, VSCode, and more via MCP for real-time answers.

