Skip to content

Commit 76bbf1f

Browse files
Palashioclaude
andcommitted
feat: add deployment command to list agent version history
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 5590e03 commit 76bbf1f

2 files changed

Lines changed: 88 additions & 0 deletions

File tree

internal/cmd/deployment.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package cmd
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"time"
7+
8+
"github.com/langchain-ai/langsmith-cli/internal/output"
9+
"github.com/spf13/cobra"
10+
)
11+
12+
type deploymentEntry struct {
13+
CommitSHA string `json:"commit_sha"`
14+
FirstSeenAt time.Time `json:"first_seen_at"`
15+
}
16+
17+
func newDeploymentCmd() *cobra.Command {
18+
cmd := &cobra.Command{
19+
Use: "deployment",
20+
Short: "Inspect agent deployment history for a tracing project",
21+
Long: `Inspect which agent versions (commit SHAs) have been active in a tracing project.
22+
23+
Deployments are recorded automatically when traces include the LANGSMITH_AGENT_VERSION
24+
metadata key on root runs. Each unique commit SHA seen in a project is recorded as a
25+
deployment with the timestamp of the earliest trace that carried that version.
26+
27+
Examples:
28+
langsmith deployment list --project my-agent
29+
langsmith deployment list --project my-agent --format pretty`,
30+
}
31+
32+
cmd.AddCommand(newDeploymentListCmd())
33+
return cmd
34+
}
35+
36+
func newDeploymentListCmd() *cobra.Command {
37+
var (
38+
projectName string
39+
outputFile string
40+
)
41+
42+
cmd := &cobra.Command{
43+
Use: "list",
44+
Short: "List agent deployments for a tracing project",
45+
Run: func(cmd *cobra.Command, args []string) {
46+
if projectName == "" {
47+
exitError("--project is required")
48+
}
49+
50+
c := mustGetClient()
51+
ctx := context.Background()
52+
53+
sessionID, err := c.ResolveSessionID(ctx, projectName)
54+
if err != nil {
55+
exitErrorf("resolving project: %v", err)
56+
}
57+
58+
var deployments []deploymentEntry
59+
if err := c.RawGet(ctx, fmt.Sprintf("/api/v1/sessions/%s/deployments", sessionID), &deployments); err != nil {
60+
exitErrorf("fetching deployments: %v", err)
61+
}
62+
63+
if getFormat() == "pretty" {
64+
columns := []string{"Commit SHA", "First Seen At"}
65+
var rows [][]string
66+
for _, d := range deployments {
67+
rows = append(rows, []string{d.CommitSHA, formatTimeShort(d.FirstSeenAt)})
68+
}
69+
output.OutputTable(columns, rows, fmt.Sprintf("Agent Deployments — %s", projectName))
70+
} else {
71+
var data []map[string]any
72+
for _, d := range deployments {
73+
data = append(data, map[string]any{
74+
"commit_sha": d.CommitSHA,
75+
"first_seen_at": formatTimeISO(d.FirstSeenAt),
76+
})
77+
}
78+
output.OutputJSON(data, outputFile)
79+
}
80+
},
81+
}
82+
83+
cmd.Flags().StringVarP(&projectName, "project", "p", "", "Tracing project name (required)")
84+
cmd.Flags().StringVarP(&outputFile, "output", "o", "", "Write JSON output to a file")
85+
86+
return cmd
87+
}

internal/cmd/root.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ Output:
6161
rootCmd.AddCommand(newEvaluatorCmd())
6262
rootCmd.AddCommand(newExperimentCmd())
6363
rootCmd.AddCommand(newSandboxCmd())
64+
rootCmd.AddCommand(newDeploymentCmd())
6465

6566
return rootCmd
6667
}

0 commit comments

Comments
 (0)