Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 18 additions & 24 deletions internal/cmd/sandbox_box.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,21 @@ type sandboxCreateInput struct {
ProxyConfig string
}

var sandboxBoxDetailRender = structured.PropertyList{
Properties: []structured.Property{
{Label: "Name", Template: "{{.Name}}"},
{Label: "ID", Template: "{{.ID}}"},
{Label: "Status", Template: "{{.Status}}"},
{Label: "Size", Template: "{{.SizeClass}}"},
{Label: "VCPUs", Template: "{{formatCount .Vcpus}}"},
{Label: "Memory", Template: "{{formatBytesOrDash .MemBytes}}"},
{Label: "Rootfs", Template: "{{formatBytesOrDash .FsCapacityBytes}}"},
{Label: "Snapshot", Template: "{{shortID .SnapshotID}}"},
{Label: "Idle TTL", Template: "{{formatCount .IdleTtlSeconds}}s"},
{Label: "Created", Template: "{{formatTime .CreatedAt}}"},
},
}

var sandboxCreateCommand = structured.Command[*sandboxCreateInput]{
Use: "create <name>",
Short: "Create a sandbox VM from a snapshot",
Expand Down Expand Up @@ -137,14 +152,7 @@ Examples:

return resp, nil
},
Render: structured.Template(`Name: {{.Name}}
Status: {{.Status}}
VCPUs: {{formatCount .Vcpus}}
Memory: {{formatBytesOrDash .MemBytes}}
Rootfs: {{formatBytesOrDash .FsCapacityBytes}}
Snapshot: {{shortID .SnapshotID}}
Created: {{formatTime .CreatedAt}}
`),
Render: sandboxBoxDetailRender,
}

var sandboxListCommand = structured.Command[struct{}]{
Expand Down Expand Up @@ -194,14 +202,7 @@ var sandboxGetCommand = structured.Command[struct{}]{

return resp, nil
},
Render: structured.Template(`Name: {{.Name}}
Status: {{.Status}}
VCPUs: {{formatCount .Vcpus}}
Memory: {{formatBytesOrDash .MemBytes}}
Rootfs: {{formatBytesOrDash .FsCapacityBytes}}
Snapshot: {{shortID .SnapshotID}}
Created: {{formatTime .CreatedAt}}
`),
Render: sandboxBoxDetailRender,
}

type sandboxUpdateInput struct {
Expand Down Expand Up @@ -273,14 +274,7 @@ for the proxy config JSON format.`,

return resp, nil
},
Render: structured.Template(`Name: {{.Name}}
Status: {{.Status}}
VCPUs: {{formatCount .Vcpus}}
Memory: {{formatBytesOrDash .MemBytes}}
Rootfs: {{formatBytesOrDash .FsCapacityBytes}}
Snapshot: {{shortID .SnapshotID}}
Created: {{formatTime .CreatedAt}}
`),
Render: sandboxBoxDetailRender,
}

var sandboxDeleteCommand = structured.Command[struct{}]{
Expand Down
78 changes: 78 additions & 0 deletions internal/cmd/sandbox_test.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package cmd

import (
"bytes"
"encoding/json"
"os"
"path/filepath"
"testing"

langsmith "github.com/langchain-ai/langsmith-go"
"github.com/stretchr/testify/require"
)

// ==================== parseByteSize ====================
Expand Down Expand Up @@ -184,6 +188,80 @@ func TestSandboxCreateCmd_SizeFlags(t *testing.T) {
}
}

func TestSandboxBoxDetailRenderSupportsSDKResponseTypes(t *testing.T) {
tests := []struct {
name string
model any
wantID string
wantTTL string
}{
{
name: "new response",
model: langsmith.SandboxBoxNewResponse{
ID: "box-new",
Name: "new-vm",
Status: "running",
SizeClass: "small",
Vcpus: 2,
MemBytes: 512 * 1024 * 1024,
FsCapacityBytes: 4 * 1024 * 1024 * 1024,
SnapshotID: "1234567890abcdef",
IdleTtlSeconds: 900,
CreatedAt: "2026-05-11T12:00:00Z",
},
wantID: "ID: box-new",
wantTTL: "Idle TTL: 900s",
},
{
name: "get response",
model: langsmith.SandboxBoxGetResponse{
ID: "box-get",
Name: "get-vm",
Status: "running",
SizeClass: "medium",
Vcpus: 4,
MemBytes: 1024 * 1024 * 1024,
FsCapacityBytes: 8 * 1024 * 1024 * 1024,
SnapshotID: "abcdef1234567890",
IdleTtlSeconds: 1800,
CreatedAt: "2026-05-11T12:00:00Z",
},
wantID: "ID: box-get",
wantTTL: "Idle TTL: 1800s",
},
{
name: "update response",
model: langsmith.SandboxBoxUpdateResponse{
ID: "box-update",
Name: "update-vm",
Status: "stopped",
SizeClass: "large",
Vcpus: 8,
MemBytes: 2 * 1024 * 1024 * 1024,
FsCapacityBytes: 16 * 1024 * 1024 * 1024,
SnapshotID: "fedcba0987654321",
IdleTtlSeconds: 3600,
CreatedAt: "2026-05-11T12:00:00Z",
},
wantID: "ID: box-update",
wantTTL: "Idle TTL: 3600s",
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
var out bytes.Buffer

err := sandboxBoxDetailRender.RenderText(&out, tc.model)

require.NoError(t, err)
require.Contains(t, out.String(), tc.wantID)
require.Contains(t, out.String(), "Size:")
require.Contains(t, out.String(), tc.wantTTL)
})
}
}

func TestSandboxUpdateCmd_SizeFlags(t *testing.T) {
cmd := sandboxUpdateCommand.Cobra()
for _, name := range []string{"memory", "rootfs-capacity"} {
Expand Down
Loading