lmnr-cli 0.1.8 → 0.1.9

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.
package/README.md CHANGED
@@ -1,395 +1,60 @@
1
1
  # lmnr-cli
2
2
 
3
- Language-agnostic CLI for Laminar AI agent debugging.
4
-
5
- ## Overview
6
-
7
- The Laminar CLI is a pure orchestrator that coordinates debugging sessions between your code and the Laminar backend. It is designed to be completely language-agnostic, delegating language-specific execution to worker processes.
3
+ CLI for the [Laminar](https://lmnr.ai) agent observability platform.
8
4
 
9
5
  ## Installation
10
6
 
11
7
  ```bash
12
8
  # Run directly with npx
13
- npx lmnr-cli@latest dev agent.ts
9
+ npx lmnr-cli@latest <command>
14
10
 
15
11
  # Or install globally
16
12
  npm install -g lmnr-cli
17
- lmnr-cli dev agent.ts
18
13
  ```
19
14
 
20
- ## Usage
15
+ ## Commands
21
16
 
22
- ```bash
23
- lmnr-cli dev [file] [options]
24
- # OR
25
- lmnr-cli dev -m <python-module> [options]
26
- ```
27
-
28
- ### Options
29
-
30
- - `-m, --python-module <module>` - Python module path (e.g., `src.myfile`)
31
- - `--function <name>` - Specific function to serve (if multiple entrypoint functions found)
32
- - `--project-api-key <key>` - Project API key (or set `LMNR_PROJECT_API_KEY` env variable)
33
- - `--base-url <url>` - Base URL for the Laminar API (default: https://api.lmnr.ai)
34
- - `--port <port>` - Port for the Laminar API (default: 443)
35
- - `--grpc-port <port>` - Port for the Laminar gRPC backend (default: 8443)
36
- - `--frontend-port <port>` - Port for the Laminar frontend (default: 5667)
37
- - `--external-packages <packages...>` - [ADVANCED] Packages to pass as external to esbuild
38
- - `--dynamic-imports-to-skip <modules...>` - [ADVANCED] Dynamic imports to skip
39
- - `--command <command>` - [ADVANCED] Custom worker command (e.g., `python3`, `node`)
40
- - `--command-args <args...>` - [ADVANCED] Arguments for the custom command
17
+ ### [`sql`](src/commands/sql/README.md) - SQL Queries
41
18
 
42
- ### Examples
19
+ Run SQL queries against your Laminar project data (spans, traces, events, and more).
43
20
 
44
21
  ```bash
45
- # TypeScript
46
- npx lmnr-cli@latest dev agent.ts
47
-
48
- # JavaScript (extracts parameter names at runtime)
49
- npx lmnr-cli@latest dev agent.js
50
-
51
- # Python - Script mode
52
- npx lmnr-cli@latest dev agent.py
53
-
54
- # Python - Module mode
55
- npx lmnr-cli@latest dev -m src.agent
22
+ lmnr-cli sql query "SELECT * FROM spans LIMIT 10" --json
23
+ lmnr-cli sql schema # Show available tables
56
24
  ```
57
25
 
58
- ## Architecture
59
-
60
- The CLI orchestrates three components:
26
+ ### [`dev`](src/commands/dev/README.md) - Agent Debugger
61
27
 
62
- 1. **SSE Client**: Connects to Laminar backend and receives run events
63
- 2. **Cache Server**: Local HTTP server (port 35667) that provides cached spans to workers
64
- 3. **Worker Process**: Language-specific subprocess that executes your code
65
-
66
- ```
67
- ┌─────────────────┐
68
- │ Laminar API │
69
- └────────┬────────┘
70
- │ SSE
71
-
72
- ┌────────▼────────┐ ┌──────────────┐
73
- │ CLI Process │◄────►│ Cache Server │
74
- │ (Orchestrator) │ │ (HTTP:35667)│
75
- └────────┬────────┘ └──────▲───────┘
76
- │ │
77
- │ spawn │ HTTP
78
- │ │
79
- ┌────────▼────────┐ ┌──────┴───────┐
80
- │ Worker Process │─────►│ Your Code │
81
- │ (TS/Python/etc) │ │ (agent.ts) │
82
- └─────────────────┘ └──────────────┘
83
- ```
84
-
85
- ## Worker Protocol
86
-
87
- The CLI communicates with workers using a simple JSON protocol over stdin/stdout.
88
-
89
- ### Input (via stdin)
90
-
91
- The CLI sends a single JSON line to the worker's stdin containing the configuration:
92
-
93
- ```typescript
94
- {
95
- filePath: string; // Path to the file to execute
96
- functionName?: string; // Specific function to run
97
- args: Record<string, any> | any[]; // Arguments for the function
98
- env: Record<string, string>; // Environment variables
99
- cacheServerPort: number; // Port of the cache server
100
- baseUrl: string; // Laminar API base URL
101
- projectApiKey?: string; // Project API key
102
- httpPort: number; // HTTP port for Laminar API
103
- grpcPort: number; // gRPC port for Laminar API
104
- externalPackages?: string[]; // External packages (TS-specific)
105
- dynamicImportsToSkip?: string[]; // Dynamic imports to skip (TS-specific)
106
- }
107
- ```
108
-
109
- ### Output (via stdout)
110
-
111
- Workers send messages prefixed with `__LMNR_WORKER__:` to stdout:
112
-
113
- #### Log Message
114
- ```typescript
115
- {
116
- type: 'log';
117
- level: 'info' | 'debug' | 'error' | 'warn';
118
- message: string;
119
- }
120
- ```
121
-
122
- #### Result Message
123
- ```typescript
124
- {
125
- type: 'result';
126
- data: any; // Function return value
127
- }
128
- ```
129
-
130
- #### Error Message
131
- ```typescript
132
- {
133
- type: 'error';
134
- error: string; // Error message
135
- stack?: string; // Stack trace
136
- }
137
- ```
138
-
139
- ### User Output
140
-
141
- Any stdout without the `__LMNR_WORKER__:` prefix is considered user output (e.g., `console.log()`) and passed through transparently.
142
-
143
- ### Environment Variables
144
-
145
- The CLI sets these environment variables for the worker:
146
-
147
- - `LMNR_ROLLOUT_SESSION_ID`: Session ID for this debugger run
148
- - `LMNR_ROLLOUT_STATE_SERVER_ADDRESS`: Cache server URL (http://localhost:35667)
149
-
150
- ### Cache Server API
151
-
152
- Workers can query the cache server for cached spans:
153
-
154
- **Endpoint**: `POST /cached`
155
-
156
- **Request**:
157
- ```json
158
- {
159
- "path": "string", // Span path
160
- "index": number // Span index
161
- }
162
- ```
163
-
164
- **Response**:
165
- ```json
166
- {
167
- "span": {
168
- "name": "string",
169
- "input": "string", // JSON string
170
- "output": "string", // JSON string
171
- "attributes": {} // Parsed attributes
172
- },
173
- "pathToCount": {
174
- "path1": 5,
175
- "path2": 3
176
- },
177
- "overrides": {
178
- "spanName": {
179
- "system": "string or array",
180
- "tools": [{
181
- "name": "string",
182
- "description": "string",
183
- "parameters": {}
184
- }]
185
- }
186
- }
187
- }
188
- ```
189
-
190
- ## Implementing a Worker
191
-
192
- To support a new language, implement a worker that:
193
-
194
- 1. Reads JSON configuration from stdin
195
- 2. Sets environment variables from `config.env`
196
- 3. Loads and executes the specified function
197
- 4. Initializes your SDK's tracing (reads `LMNR_ROLLOUT_STATE_SERVER_ADDRESS`)
198
- 5. Sends protocol messages to stdout (prefixed with `__LMNR_WORKER__:`)
199
- 6. Exits with code 0 on success, non-zero on failure
200
-
201
- ### Example: TypeScript Worker
202
-
203
- The TypeScript worker is included in `@lmnr-ai/lmnr`:
204
-
205
- ```typescript
206
- // Read config from stdin
207
- const config = JSON.parse(await readStdin());
208
-
209
- // Set environment variables
210
- for (const [key, value] of Object.entries(config.env)) {
211
- process.env[key] = value;
212
- }
213
-
214
- // Initialize SDK
215
- Laminar.initialize({
216
- baseUrl: config.baseUrl,
217
- projectApiKey: config.projectApiKey,
218
- // ...
219
- });
220
-
221
- // Load and execute function
222
- const module = require(config.filePath);
223
- const result = await module[config.functionName](...config.args);
224
-
225
- // Send result
226
- sendMessage({ type: 'result', data: result });
227
-
228
- // Exit successfully
229
- process.exit(0);
230
- ```
231
-
232
- ### Example: Python Worker (Future)
233
-
234
- ```python
235
- # python -m lmnr.cli.worker
236
-
237
- import json
238
- import sys
239
- import os
240
-
241
- # Read config from stdin
242
- config = json.loads(sys.stdin.readline())
243
-
244
- # Set environment variables
245
- for key, value in config['env'].items():
246
- os.environ[key] = value
247
-
248
- # Initialize SDK
249
- import lmnr
250
- lmnr.initialize(
251
- base_url=config['baseUrl'],
252
- project_api_key=config['projectApiKey'],
253
- )
254
-
255
- # Load and execute function
256
- module = __import__(config['filePath'])
257
- result = getattr(module, config['functionName'])(*config['args'])
258
-
259
- # Send result
260
- send_message({'type': 'result', 'data': result})
261
-
262
- # Exit successfully
263
- sys.exit(0)
264
- ```
265
-
266
- ## Default Worker Resolution
267
-
268
- The CLI automatically resolves workers based on file extension:
269
-
270
- | Extension | Worker Command |
271
- |-----------|----------------|
272
- | `.ts`, `.tsx` | `node @lmnr-ai/lmnr/dist/cli/worker.cjs` |
273
- | `.js`, `.mjs`, `.cjs` | `node @lmnr-ai/lmnr/dist/cli/worker.cjs` |
274
- | `.py` | `python3 -m lmnr.cli.worker` |
275
-
276
- Custom workers can be specified with `--command` and `--command-args`.
277
-
278
- ## Python Language Support
279
-
280
- ### Metadata Discovery
281
-
282
- The CLI needs to discover function metadata (name and parameters) to provide a rich UI experience. For Python files, this is done by calling the `lmnr` Python package.
283
-
284
- #### Required Command Interface
285
-
286
- The Python `lmnr` package must implement the following CLI command:
287
-
288
- ```bash
289
- lmnr discover --file <filepath> [--function <name>]
290
- # OR
291
- lmnr discover --module <module> [--function <name>]
292
- ```
293
-
294
- **Arguments:**
295
-
296
- - `--file <filepath>`: Path to the Python file containing entrypoint functions (script mode)
297
- - `--module <module>`: Python module path like `src.myfile` (module mode)
298
- - `--function <name>`: (Optional) Specific function name to discover. If omitted, discover all.
299
-
300
- **Note:** Exactly one of `--file` or `--module` must be provided.
301
-
302
- **Output Format (JSON to stdout):**
303
-
304
- ```json
305
- {
306
- "name": "my_agent",
307
- "params": [
308
- {
309
- "name": "query",
310
- "type": "string"
311
- },
312
- {
313
- "name": "max_tokens",
314
- "type": "number"
315
- }
316
- ]
317
- }
318
- ```
319
-
320
- **Exit Codes:**
321
-
322
- - `0`: Success
323
- - Non-zero: Error (stderr contains error message)
324
-
325
- #### Python Execution Modes
326
-
327
- Python code can be executed in two modes, affecting how imports work:
328
-
329
- **Script Mode (default):**
330
-
331
- ```bash
332
- npx lmnr-cli dev src/myfile.py
333
- # Internally executes as: python src/myfile.py
334
- # Discovery uses: lmnr discover --file src/myfile.py
335
- ```
336
-
337
- - Works with relative imports: `from .utils import helper`
338
- - File is executed as a script
339
- - Best for standalone files and simple packages
340
-
341
- **Module Mode:**
28
+ Start a language-agnostic debugging session for your AI agents. Connects to the Laminar backend, spawns a worker process for your code, and orchestrates the debugging flow.
342
29
 
343
30
  ```bash
344
- npx lmnr-cli dev -m src.myfile
345
- # Internally executes as: python -m src.myfile
346
- # Discovery uses: lmnr discover --module src.myfile
31
+ lmnr-cli dev agent.ts # TypeScript file
32
+ lmnr-cli dev agent.py # Python script mode
33
+ lmnr-cli dev -m src.agent # Python module mode
34
+ lmnr-cli dev agent.ts --function myAgent # Specific function
347
35
  ```
348
36
 
349
- - Requires absolute imports: `from src.utils import helper`
350
- - Module is executed via Python's `-m` flag
351
- - Best for packages with complex import structures
352
- - Requires proper `__init__.py` files in package directories
37
+ ### [`dataset`](src/commands/dataset/README.md) - Dataset Management
353
38
 
354
- **Examples:**
39
+ List, push, pull, and create datasets in your Laminar project.
355
40
 
356
41
  ```bash
357
- # Script mode - use file path with relative imports
358
- npx lmnr-cli dev agents/customer_support.py
359
-
360
- # Module mode - use module syntax with absolute imports
361
- npx lmnr-cli dev -m agents.customer_support
362
-
363
- # Specify a particular function
364
- npx lmnr-cli dev -m agents.customer_support --function run_agent
365
- ```
366
-
367
- ### Python Worker Requirements
368
-
369
- The Python `lmnr` package must implement a worker that executes entrypoint functions:
370
-
371
- ```bash
372
- python -m lmnr.cli.worker
42
+ lmnr-cli dataset list --json # List all datasets
43
+ lmnr-cli dataset push data.jsonl -n my-dataset --json # Push data to a dataset
44
+ lmnr-cli dataset pull output.jsonl -n my-dataset --json # Pull data from a dataset
45
+ lmnr-cli dataset create my-dataset data.jsonl -o out.jsonl
373
46
  ```
374
47
 
375
- The worker should:
48
+ ## Global Options
376
49
 
377
- 1. Read JSON configuration from stdin containing either `filePath` (script mode) or `modulePath` (module mode)
378
- 2. Set environment variables from config
379
- 3. Initialize the `lmnr` SDK
380
- 4. Load and execute the specified function based on the mode
381
- 5. Send protocol messages to stdout (see [Worker Protocol](#worker-protocol))
382
- 6. Exit with appropriate code
50
+ - `-v, --version` - Display version number
51
+ - `-h, --help` - Display help
383
52
 
384
- **Worker Configuration:**
53
+ Each command also accepts:
385
54
 
386
- The CLI will pass either:
387
- - `filePath`: Path to Python file (script mode)
388
- - `modulePath`: Python module path (module mode)
389
-
390
- The worker must detect which field is present and execute accordingly.
391
-
392
- See the [Worker Protocol](#worker-protocol) section for detailed communication protocol.
55
+ - `--project-api-key <key>` - Project API key (or set `LMNR_PROJECT_API_KEY` env variable)
56
+ - `--base-url <url>` - Base URL for the Laminar API (default: https://api.lmnr.ai)
57
+ - `--port <port>` - Port for the Laminar API (default: 443)
393
58
 
394
59
  ## Development
395
60
 
@@ -401,7 +66,10 @@ pnpm install
401
66
  pnpm build
402
67
 
403
68
  # Run locally
404
- node dist/index.cjs dev examples/agent.ts
69
+ node dist/index.cjs <command>
70
+
71
+ # Run tests
72
+ pnpm test
405
73
  ```
406
74
 
407
75
  ## License