lf-cli 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 14d28df3a9c60a7b537c3a808b62cde87c7c3a475bd0b09351dd9256349fe41e
4
- data.tar.gz: 220ff83b225a5b7d1f09572e5d29d23d21f86f3e6623a2666f4164e8985aeecd
3
+ metadata.gz: 06ff677435b9202de2481d4aa72805639508431a90805be2d0adbb50e54bbcff
4
+ data.tar.gz: 425bcfc9371f4c6c497f50b2082f0d54e7d0a85b7fcd737988ff60d7f9edfac2
5
5
  SHA512:
6
- metadata.gz: 1332550a6e5beb94c1ec966f1e2adacf84d68cb0ec4656387e0608f71be83dddd444e4792083ad3728d6ec0bef1e00f0fae46afe650c118d7f61137393bbb0c0
7
- data.tar.gz: 0ad77d7fd57a2c758d3c2521d501a699601ba161bc01136f0539cd0d1254e067d2de1a5d489751db0b770775afbfd8a4a2f775eb772fde7f421291b407b689ed
6
+ metadata.gz: 64c05599e12dc8ee8f9a414519d14f5912dddfa969a0cfaaaf7c5f81bb689a7c7587de7886716739bfb2e82d04063447655f840b9c9c9577d6d4fa7875c98600
7
+ data.tar.gz: 345323d04554a45007cff5936ff300dd8df0d29dcca874fd155122a94150b2b4c1f8f224d279c7c405924edefd838b59faf343b9c6f9cf5ca60615ef8a356a32
data/CHANGELOG.md CHANGED
@@ -14,6 +14,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
14
14
  - Creating/updating scores via CLI
15
15
  - Integration with other observability tools
16
16
 
17
+ ## [1.0.2] - 2026-02-11
18
+
19
+ ### Changed
20
+ - `json` is now the default output format for all commands.
21
+ - Removed `markdown` as a supported output format.
22
+ - `lf traces get` now always returns an `observations` field in output.
23
+
24
+ ### Removed
25
+ - Removed `--with-observations` / `--no-with-observations` from `lf traces get`.
26
+
17
27
  ## [1.0.1] - 2026-02-10
18
28
 
19
29
  ### Added
data/README.md CHANGED
@@ -21,7 +21,7 @@ This project is not affiliated with, endorsed by, or sponsored by Langfuse GmbH.
21
21
  - 🎯 **Inspect Observations** - List LLM generations, spans, and events
22
22
  - 📈 **Query Metrics** - Run analytics queries with custom aggregations and dimensions
23
23
  - ⭐ **View Scores** - Access quality scores and evaluation metrics
24
- - 🎨 **Multiple Output Formats** - Table, JSON, CSV, or Markdown
24
+ - 🎨 **Multiple Output Formats** - JSON, Table, or CSV
25
25
  - 🔐 **Multi-Profile Support** - Manage credentials for dev, staging, and production
26
26
  - 🌐 **Interactive Setup** - Browser-integrated credential configuration
27
27
  - ⚡ **Type-Safe** - Built with Sorbet Runtime for reliability
@@ -191,7 +191,7 @@ lf metrics query \
191
191
  All commands support these global options:
192
192
 
193
193
  ```bash
194
- -f, --format [table|json|csv|markdown] # Output format (default: table)
194
+ -f, --format [json|table|csv] # Output format (default: json)
195
195
  -o, --output FILE # Save output to file
196
196
  -l, --limit N # Limit number of results
197
197
  -P, --profile PROFILE # Use specific profile
@@ -216,21 +216,21 @@ Supports both ISO 8601 and natural language:
216
216
 
217
217
  ## Output Formats
218
218
 
219
- ### Table (Default)
219
+ ### JSON (Default)
220
220
 
221
221
  ```bash
222
- lf traces list --format table
222
+ lf traces list --format json
223
223
  ```
224
224
 
225
- Outputs a formatted ASCII table - great for terminal viewing.
225
+ Perfect for piping to `jq` or other tools.
226
226
 
227
- ### JSON
227
+ ### Table
228
228
 
229
229
  ```bash
230
- lf traces list --format json
230
+ lf traces list --format table
231
231
  ```
232
232
 
233
- Perfect for piping to `jq` or other tools:
233
+ Outputs a formatted ASCII table - great for terminal viewing.
234
234
 
235
235
  ```bash
236
236
  lf traces list --format json | jq '.[] | select(.name == "chat")'
@@ -244,14 +244,6 @@ lf traces list --format csv --output data.csv
244
244
 
245
245
  Import into spreadsheets or data analysis tools.
246
246
 
247
- ### Markdown
248
-
249
- ```bash
250
- lf traces list --format markdown
251
- ```
252
-
253
- Great for documentation and reports.
254
-
255
247
  ## Configuration
256
248
 
257
249
  ### Configuration File
@@ -264,7 +256,7 @@ profiles:
264
256
  host: https://cloud.langfuse.com
265
257
  public_key: pk_...
266
258
  secret_key: sk_...
267
- output_format: table
259
+ output_format: json
268
260
  page_limit: 50
269
261
 
270
262
  production:
@@ -337,7 +329,7 @@ This section mirrors the depth of a `llms-full.txt` so AI assistants can answer
337
329
  | `-P, --profile PROFILE` | Selects a saved profile. | Defaults to `default`. |
338
330
  | `--public-key KEY` / `--secret-key KEY` | Inject credentials without touching config files. | Highest priority source. |
339
331
  | `--host URL` | Override Langfuse host. | Combine with `--profile` to temporarily test another region. |
340
- | `-f, --format FORMAT` | `table` (default), `json`, `csv`, `markdown`. | Applies to every command; CSV/Markdown require structured arrays. |
332
+ | `-f, --format FORMAT` | `json` (default), `table`, `csv`. | Applies to every command. |
341
333
  | `-o, --output PATH` | Write output to a file. | Respects format; prints “Output written…” when `--verbose`. |
342
334
  | `-l, --limit N` | Caps number of records pulled per command. | Pagination helper, defaults to API `limit` (50) when omitted. |
343
335
  | `-p, --page N` | Start from an explicit page. | Useful when you know an offset. |
@@ -350,9 +342,8 @@ Pagination strategy: the client keeps fetching pages until it collects the reque
350
342
  ### Output & Files
351
343
 
352
344
  - `table` renders ASCII tables via `Formatters::TableFormatter` and truncates oversized cells for terminal safety.
353
- - `json` prints pretty JSON to stdout for direct piping to `jq`.
354
- - `csv` and `markdown` use dedicated formatters and require array-like data (single hashes are wrapped automatically).
355
- - `markdown` escapes pipes, normalizes newlines to `<br>`, and truncates oversized cells.
345
+ - `json` is the default output and prints pretty JSON to stdout for direct piping to `jq`.
346
+ - `csv` uses a dedicated formatter and requires array-like data (single hashes are wrapped automatically).
356
347
  - `--output` writes to a file; JSON output is written in compact form to reduce memory pressure on large payloads.
357
348
  - Use `lf ... --format json | jq ...` for automation recipes.
358
349
 
@@ -374,7 +365,7 @@ Each command inherits the global flags above. API errors exit with status code `
374
365
  | Subcommand | Purpose |
375
366
  | --- | --- |
376
367
  | `lf traces list` | Lists traces with filters/pagination. |
377
- | `lf traces get TRACE_ID [--with-observations]` | Fetches a single trace. The `--with-observations` flag is accepted for forward compatibility but currently behaves the same as the default API payload. |
368
+ | `lf traces get TRACE_ID` | Fetches a single trace with `observations` included. |
378
369
 
379
370
  `traces list` options:
380
371
 
@@ -522,7 +513,6 @@ lib/langfuse/cli/
522
513
  ├── formatters/ # Output formatters
523
514
  │ ├── table_formatter.rb
524
515
  │ ├── csv_formatter.rb
525
- │ └── markdown_formatter.rb
526
516
  └── commands/ # Command modules
527
517
  ├── traces.rb
528
518
  ├── sessions.rb
@@ -146,7 +146,7 @@ module Langfuse
146
146
  end
147
147
 
148
148
  def output_result(data)
149
- format_type = parent_options[:format] || 'table'
149
+ format_type = parent_options[:format] || 'json'
150
150
 
151
151
  if parent_options[:output]
152
152
  write_output(parent_options[:output], data, format_type)
@@ -156,16 +156,13 @@ module Langfuse
156
156
  end
157
157
  end
158
158
 
159
- def format_output(data, format_type: 'table')
159
+ def format_output(data, format_type: 'json')
160
160
  case format_type
161
161
  when 'json'
162
162
  JSON.pretty_generate(data)
163
163
  when 'csv'
164
164
  require_relative '../formatters/csv_formatter'
165
165
  Formatters::CSVFormatter.format(data)
166
- when 'markdown'
167
- require_relative '../formatters/markdown_formatter'
168
- Formatters::MarkdownFormatter.format(data)
169
166
  else # table
170
167
  require_relative '../formatters/table_formatter'
171
168
  Formatters::TableFormatter.format(data)
@@ -112,7 +112,7 @@ module Langfuse
112
112
  end
113
113
 
114
114
  def output_result(data)
115
- format_type = parent_options[:format] || 'table'
115
+ format_type = parent_options[:format] || 'json'
116
116
 
117
117
  if parent_options[:output]
118
118
  write_output(parent_options[:output], data, format_type)
@@ -122,16 +122,13 @@ module Langfuse
122
122
  end
123
123
  end
124
124
 
125
- def format_output(data, format_type: 'table')
125
+ def format_output(data, format_type: 'json')
126
126
  case format_type
127
127
  when 'json'
128
128
  JSON.pretty_generate(data)
129
129
  when 'csv'
130
130
  require_relative '../formatters/csv_formatter'
131
131
  Formatters::CSVFormatter.format(data)
132
- when 'markdown'
133
- require_relative '../formatters/markdown_formatter'
134
- Formatters::MarkdownFormatter.format(data)
135
132
  else # table
136
133
  require_relative '../formatters/table_formatter'
137
134
  Formatters::TableFormatter.format(data)
@@ -73,7 +73,7 @@ module Langfuse
73
73
  end
74
74
 
75
75
  def output_result(data)
76
- format_type = parent_options[:format] || 'table'
76
+ format_type = parent_options[:format] || 'json'
77
77
 
78
78
  if parent_options[:output]
79
79
  write_output(parent_options[:output], data, format_type)
@@ -83,16 +83,13 @@ module Langfuse
83
83
  end
84
84
  end
85
85
 
86
- def format_output(data, format_type: 'table')
86
+ def format_output(data, format_type: 'json')
87
87
  case format_type
88
88
  when 'json'
89
89
  JSON.pretty_generate(data)
90
90
  when 'csv'
91
91
  require_relative '../formatters/csv_formatter'
92
92
  Formatters::CSVFormatter.format(data)
93
- when 'markdown'
94
- require_relative '../formatters/markdown_formatter'
95
- Formatters::MarkdownFormatter.format(data)
96
93
  else # table
97
94
  require_relative '../formatters/table_formatter'
98
95
  Formatters::TableFormatter.format(data)
@@ -72,7 +72,7 @@ module Langfuse
72
72
  end
73
73
 
74
74
  def output_result(data)
75
- format_type = parent_options[:format] || 'table'
75
+ format_type = parent_options[:format] || 'json'
76
76
 
77
77
  if parent_options[:output]
78
78
  write_output(parent_options[:output], data, format_type)
@@ -82,16 +82,13 @@ module Langfuse
82
82
  end
83
83
  end
84
84
 
85
- def format_output(data, format_type: 'table')
85
+ def format_output(data, format_type: 'json')
86
86
  case format_type
87
87
  when 'json'
88
88
  JSON.pretty_generate(data)
89
89
  when 'csv'
90
90
  require_relative '../formatters/csv_formatter'
91
91
  Formatters::CSVFormatter.format(data)
92
- when 'markdown'
93
- require_relative '../formatters/markdown_formatter'
94
- Formatters::MarkdownFormatter.format(data)
95
92
  else # table
96
93
  require_relative '../formatters/table_formatter'
97
94
  Formatters::TableFormatter.format(data)
@@ -29,7 +29,7 @@ module Langfuse
29
29
  --from, --to: Time range (ISO 8601 or relative like "1 hour ago")
30
30
 
31
31
  OUTPUT OPTIONS:
32
- Global options: --format [table|json|csv|markdown], --output FILE
32
+ Global options: --format [json|table|csv], --output FILE
33
33
 
34
34
  EXAMPLES:
35
35
 
@@ -66,11 +66,10 @@ module Langfuse
66
66
  raise_cli_error("Error: #{e.message}")
67
67
  end
68
68
 
69
- desc 'get TRACE_ID', 'Get a specific trace'
70
- option :with_observations, type: :boolean, default: false, desc: 'Include all observations'
69
+ desc 'get TRACE_ID', 'Get a specific trace with observations'
71
70
  def get(trace_id)
72
71
  trace = client.get_trace(trace_id)
73
- output_result(trace)
72
+ output_result(ensure_observations(trace))
74
73
  rescue Client::NotFoundError => _e
75
74
  raise_cli_error("Trace not found - #{trace_id}")
76
75
  rescue Client::APIError => e
@@ -116,7 +115,7 @@ module Langfuse
116
115
  end
117
116
 
118
117
  def output_result(data)
119
- format_type = parent_options[:format] || 'table'
118
+ format_type = parent_options[:format] || 'json'
120
119
 
121
120
  if parent_options[:output]
122
121
  write_output(parent_options[:output], data, format_type)
@@ -126,16 +125,13 @@ module Langfuse
126
125
  end
127
126
  end
128
127
 
129
- def format_output(data, format_type: 'table')
128
+ def format_output(data, format_type: 'json')
130
129
  case format_type
131
130
  when 'json'
132
131
  JSON.pretty_generate(data)
133
132
  when 'csv'
134
133
  require_relative '../formatters/csv_formatter'
135
134
  Formatters::CSVFormatter.format(data)
136
- when 'markdown'
137
- require_relative '../formatters/markdown_formatter'
138
- Formatters::MarkdownFormatter.format(data)
139
135
  else # table
140
136
  require_relative '../formatters/table_formatter'
141
137
  Formatters::TableFormatter.format(data)
@@ -150,6 +146,12 @@ module Langfuse
150
146
  end
151
147
  end
152
148
 
149
+ def ensure_observations(trace)
150
+ return trace unless trace.is_a?(Hash)
151
+
152
+ trace.merge('observations' => trace['observations'] || [])
153
+ end
154
+
153
155
  def parent_options
154
156
  @parent_options ||= begin
155
157
  # Try to get parent options from Thor
@@ -10,7 +10,7 @@ module Langfuse
10
10
  attr_accessor :public_key, :secret_key, :host, :profile, :output_format, :page_limit
11
11
 
12
12
  DEFAULT_HOST = 'https://cloud.langfuse.com'
13
- DEFAULT_OUTPUT_FORMAT = 'table'
13
+ DEFAULT_OUTPUT_FORMAT = 'json'
14
14
  DEFAULT_PAGE_LIMIT = 50
15
15
  CONFIG_DIR = File.expand_path('~/.langfuse')
16
16
  CONFIG_FILE = File.join(CONFIG_DIR, 'config.yml')
@@ -66,7 +66,6 @@ module Langfuse
66
66
  Table = new('table')
67
67
  JSON = new('json')
68
68
  CSV = new('csv')
69
- Markdown = new('markdown')
70
69
  end
71
70
  end
72
71
 
@@ -1,5 +1,5 @@
1
1
  module Langfuse
2
2
  module CLI
3
- VERSION = "1.0.1"
3
+ VERSION = "1.0.2"
4
4
  end
5
5
  end
data/lib/langfuse/cli.rb CHANGED
@@ -28,8 +28,8 @@ module Langfuse
28
28
  class_option :format,
29
29
  type: :string,
30
30
  aliases: '-f',
31
- enum: %w[table json csv markdown],
32
- default: 'table',
31
+ enum: %w[json table csv],
32
+ default: 'json',
33
33
  desc: 'Output format'
34
34
  class_option :output,
35
35
  type: :string,
@@ -111,7 +111,7 @@ module Langfuse
111
111
  end
112
112
 
113
113
  def output_result(data)
114
- format_type = options[:format] || 'table'
114
+ format_type = options[:format] || 'json'
115
115
 
116
116
  if options[:output]
117
117
  write_output(options[:output], data, format_type)
@@ -121,7 +121,7 @@ module Langfuse
121
121
  end
122
122
  end
123
123
 
124
- def format_output(data, format_type: 'table')
124
+ def format_output(data, format_type: 'json')
125
125
  case format_type
126
126
  when 'json'
127
127
  JSON.pretty_generate(data)
@@ -129,9 +129,6 @@ module Langfuse
129
129
  # CSV formatting will be implemented in formatters
130
130
  require_relative 'cli/formatters/csv_formatter'
131
131
  Formatters::CSVFormatter.format(data)
132
- when 'markdown'
133
- require_relative 'cli/formatters/markdown_formatter'
134
- Formatters::MarkdownFormatter.format(data)
135
132
  else # table
136
133
  require_relative 'cli/formatters/table_formatter'
137
134
  Formatters::TableFormatter.format(data)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lf-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vicente Reig Rincon de Arellano
@@ -271,7 +271,6 @@ files:
271
271
  - lib/langfuse/cli/commands/traces.rb
272
272
  - lib/langfuse/cli/config.rb
273
273
  - lib/langfuse/cli/formatters/csv_formatter.rb
274
- - lib/langfuse/cli/formatters/markdown_formatter.rb
275
274
  - lib/langfuse/cli/formatters/table_formatter.rb
276
275
  - lib/langfuse/cli/types.rb
277
276
  - lib/langfuse/cli/version.rb
@@ -1,78 +0,0 @@
1
- require 'json'
2
- require 'date'
3
- require 'sorbet-runtime'
4
-
5
- module Langfuse
6
- module CLI
7
- module Formatters
8
- class MarkdownFormatter
9
- extend T::Sig
10
-
11
- DEFAULT_MAX_CELL_BYTES = 2048
12
-
13
- sig { params(data: T.untyped, max_cell_bytes: Integer).returns(String) }
14
- def self.format(data, max_cell_bytes: DEFAULT_MAX_CELL_BYTES)
15
- return "No data to display" if data.nil? || (data.is_a?(Array) && data.empty?)
16
-
17
- # Convert single hash to array for consistent handling
18
- data = [data] unless data.is_a?(Array)
19
-
20
- # Get all unique keys from all rows
21
- headers = data.flat_map(&:keys).uniq
22
-
23
- # Build markdown table
24
- output = []
25
-
26
- # Header row
27
- output << "| #{headers.join(' | ')} |"
28
-
29
- # Separator row
30
- output << "| #{headers.map { '---' }.join(' | ')} |"
31
-
32
- # Data rows
33
- data.each do |row|
34
- values = headers.map { |header| escape_pipes(format_value(row[header], max_cell_bytes: max_cell_bytes)) }
35
- output << "| #{values.join(' | ')} |"
36
- end
37
-
38
- output.join("\n")
39
- end
40
-
41
- private
42
-
43
- sig { params(value: T.untyped, max_cell_bytes: Integer).returns(String) }
44
- def self.format_value(value, max_cell_bytes:)
45
- case value
46
- when nil
47
- ''
48
- when Hash, Array
49
- normalize(truncate(value.to_json, max_cell_bytes))
50
- when Time, DateTime
51
- normalize(truncate(value.iso8601, max_cell_bytes))
52
- else
53
- normalize(truncate(value.to_s, max_cell_bytes))
54
- end
55
- end
56
-
57
- sig { params(str: String).returns(String) }
58
- def self.escape_pipes(str)
59
- # Escape pipe characters for markdown tables
60
- str.gsub('|', '\\|')
61
- end
62
-
63
- sig { params(value: String, max_cell_bytes: Integer).returns(String) }
64
- def self.truncate(value, max_cell_bytes)
65
- return value if value.bytesize <= max_cell_bytes
66
-
67
- visible = value.byteslice(0, max_cell_bytes)
68
- "#{visible}...[truncated #{value.bytesize - max_cell_bytes} bytes]"
69
- end
70
-
71
- sig { params(value: String).returns(String) }
72
- def self.normalize(value)
73
- value.gsub(/\r\n?|\n/, '<br>')
74
- end
75
- end
76
- end
77
- end
78
- end