langsmithrb 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 690abea56aa77b88aacff5ec66936e3e9a7dcb2c72b3aadf5a88fa4d45d469d6
4
+ data.tar.gz: 7ee637182e89738d54366520fe536891c3add80c0239b0841862ac7204635cc8
5
+ SHA512:
6
+ metadata.gz: cc8d65163bd826bc11aabc3bb84a4962c65b21985cc875885d44507fb901cdd5f9dc8cd9aac0dcd21ac932e8d38f3464daa88314666dfcc37fc90ab0a52f0e58
7
+ data.tar.gz: 9fd9a7069982e9ad8001b37e227f0a5c6a6615e9af7adb7c4522150554765734bb83e25af6feb39f49ae58de98e01b4f4ca14c801848a803943a457230f10435
data/README.md ADDED
@@ -0,0 +1,626 @@
1
+ # 💎🔗 LangSmith for Ruby
2
+
3
+ âš¡ The fastest way to integrate LangSmith tracing and evaluations into your Ruby applications âš¡
4
+
5
+ This gem provides a comprehensive Ruby client for [LangSmith](https://smith.langchain.com/), a platform for debugging, testing, evaluating, and monitoring LLM applications.
6
+
7
+ [![Tests status](https://github.com/cdaviis/langsmithrb/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/cdaviis/langsmithrb/actions)
8
+ [![Gem Version](https://badge.fury.io/rb/langsmithrb.svg)](https://badge.fury.io/rb/langsmithrb)
9
+ [![License](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/cdaviis/langsmithrb/blob/main/LICENSE.txt)
10
+
11
+ ## Use Cases
12
+
13
+ - Trace and monitor LLM applications
14
+ - Create and manage datasets for testing
15
+ - Run evaluations on LLM outputs
16
+ - Collect and analyze feedback on LLM responses
17
+ - Manage teams, webhooks, and API keys
18
+ - Perform bulk operations on runs
19
+ - Access analytics for projects and datasets
20
+ - Integrate with your Ruby applications
21
+
22
+ ## Table of Contents
23
+
24
+ - [Installation](#installation)
25
+ - [Configuration](#configuration)
26
+ - [Usage](#usage)
27
+ - [Client](#client)
28
+ - [Runs](#runs)
29
+ - [Projects](#projects)
30
+ - [Datasets](#datasets)
31
+ - [Evaluations](#evaluations)
32
+ - [Feedback](#feedback)
33
+ - [Tracer Sessions](#tracer-sessions)
34
+ - [Organizations](#organizations)
35
+ - [API Keys](#api-keys)
36
+ - [Tenants](#tenants)
37
+ - [Tags](#tags)
38
+ - [Prompts](#prompts)
39
+ - [Annotation Queues](#annotation-queues)
40
+ - [Feedback Configurations](#feedback-configurations)
41
+ - [Analytics](#analytics)
42
+ - [Comments](#comments)
43
+ - [Events](#events)
44
+ - [Settings](#settings)
45
+ - [Bulk Operations](#bulk-operations)
46
+ - [Webhooks](#webhooks)
47
+ - [Team Management](#team-management)
48
+ - [Error Handling](#error-handling)
49
+ - [Development](#development)
50
+ - [Contributing](#contributing)
51
+ - [License](#license)
52
+
53
+ ## Dependencies
54
+
55
+ * Ruby 3.1+
56
+
57
+ ## Installation
58
+
59
+ Add this line to your application's Gemfile:
60
+
61
+ ```ruby
62
+ gem 'langsmithrb'
63
+ ```
64
+
65
+ And then execute:
66
+
67
+ ```bash
68
+ $ bundle install
69
+ ```
70
+
71
+ Or install it yourself as:
72
+
73
+ ```bash
74
+ $ gem install langsmithrb
75
+ ```
76
+
77
+ ## Configuration
78
+
79
+ You'll need a LangSmith API key to use this gem. You can get one by signing up at [LangSmith](https://smith.langchain.com/).
80
+
81
+ There are several ways to configure the LangSmith client:
82
+
83
+ ### Environment Variables
84
+
85
+ Set the following environment variables:
86
+
87
+ ```bash
88
+ LANGSMITH_API_KEY=your_api_key
89
+ LANGSMITH_API_URL=https://api.smith.langchain.com # Optional, this is the default
90
+ ```
91
+
92
+ ### Global Configuration
93
+
94
+ ```ruby
95
+ require 'langsmith'
96
+
97
+ Langsmith.api_key = "your_api_key"
98
+ Langsmith.api_url = "https://api.smith.langchain.com" # Optional
99
+ ```
100
+
101
+ ### Client Instance Configuration
102
+
103
+ ```ruby
104
+ require 'langsmith'
105
+
106
+ client = Langsmith::Client.new(
107
+ api_key: "your_api_key",
108
+ api_url: "https://api.smith.langchain.com" # Optional
109
+ )
110
+ ```
111
+
112
+ ## Usage
113
+
114
+ ### Client
115
+
116
+ The `Langsmith::Client` class is the main interface for interacting with the LangSmith API:
117
+
118
+ ```ruby
119
+ require 'langsmith'
120
+
121
+ # Initialize the client
122
+ client = Langsmith::Client.new(api_key: "your_api_key")
123
+
124
+ # Create a new project
125
+ project = client.create_project(name: "my-project", description: "My awesome LLM project")
126
+
127
+ # List all projects
128
+ projects = client.list_projects
129
+ ```
130
+
131
+ ### Runs
132
+
133
+ Runs represent individual executions of LLM calls, chains, or tools:
134
+
135
+ ```ruby
136
+ # Create a new run
137
+ run = client.create_run(
138
+ name: "llm-call",
139
+ run_type: "llm",
140
+ project_name: "my-project",
141
+ inputs: { prompt: "Tell me a joke about Ruby programming" }
142
+ )
143
+
144
+ # Update a run with outputs
145
+ run.end(outputs: { response: "Why did the Ruby developer go broke? Because he used all his gems!" })
146
+
147
+ # Or update with an error
148
+ run.end(error: "API connection failed")
149
+
150
+ # Get a run by ID
151
+ run = client.get_run(run_id: "run_123")
152
+
153
+ # List runs in a project
154
+ runs = client.list_runs(project_name: "my-project", limit: 10)
155
+ ```
156
+
157
+ ### Projects
158
+
159
+ Projects help you organize related runs:
160
+
161
+ ```ruby
162
+ # Create a new project
163
+ project = client.create_project(name: "my-project", description: "My awesome LLM project")
164
+
165
+ # Get a project by name
166
+ project = client.get_project(name: "my-project")
167
+
168
+ # List all projects
169
+ projects = client.list_projects(limit: 10)
170
+
171
+ # Create a run in a specific project
172
+ run = project.create_run(
173
+ name: "llm-call",
174
+ run_type: "llm",
175
+ inputs: { prompt: "Tell me a joke about Ruby programming" }
176
+ )
177
+
178
+ # List runs in a project
179
+ runs = project.list_runs(limit: 10)
180
+ ```
181
+
182
+ ### Datasets
183
+
184
+ Datasets allow you to store examples for testing and evaluation:
185
+
186
+ ```ruby
187
+ # Create a new dataset
188
+ dataset = client.create_dataset(name: "qa-dataset", description: "Question-answering examples")
189
+
190
+ # Add examples to the dataset
191
+ dataset.create_example(
192
+ inputs: { question: "What is Ruby?" },
193
+ outputs: { answer: "Ruby is a dynamic, open source programming language with a focus on simplicity and productivity." }
194
+ )
195
+
196
+ # List examples in the dataset
197
+ examples = dataset.list_examples(limit: 10)
198
+ ```
199
+
200
+ ### Evaluations
201
+
202
+ Evaluations help you assess the quality of your LLM outputs:
203
+
204
+ ```ruby
205
+ # Create an evaluation run
206
+ evaluation = dataset.create_evaluation_run(
207
+ evaluator_name: "correctness",
208
+ run_ids: ["run_123", "run_456"]
209
+ )
210
+
211
+ # Check if the evaluation is complete
212
+ evaluation.completed?
213
+
214
+ # Wait for the evaluation to complete
215
+ evaluation.wait_for_completion(timeout: 300)
216
+
217
+ # Get the evaluation results
218
+ results = evaluation.results
219
+ ```
220
+
221
+ ### Feedback
222
+
223
+ Feedback allows you to collect human or automated assessments of runs:
224
+
225
+ ```ruby
226
+ # Add feedback to a run
227
+ feedback = client.create_feedback(
228
+ run_id: "run_123",
229
+ key: "helpfulness",
230
+ score: 0.95,
231
+ comment: "Very helpful response!"
232
+ )
233
+
234
+ # Get feedback for a run
235
+ feedback_list = client.get_feedback(run_id: "run_123")
236
+
237
+ # Add feedback directly to a run
238
+ run.add_feedback(key: "correctness", score: 0.8, comment: "Mostly correct")
239
+
240
+ # Get feedback for a run
241
+ feedback_list = run.get_feedback
242
+ ```
243
+
244
+ ### Tracer Sessions
245
+
246
+ Tracer sessions help you organize and manage traces of your LLM applications:
247
+
248
+ ```ruby
249
+ # Create a new tracer session
250
+ tracer_session = client.create_tracer_session(
251
+ name: "my-tracer-session",
252
+ description: "Tracing my LLM application"
253
+ )
254
+
255
+ # Get a tracer session by ID
256
+ tracer_session = client.get_tracer_session(tracer_session_id: "ts_123")
257
+
258
+ # List tracer sessions
259
+ tracer_sessions = client.list_tracer_sessions(limit: 10)
260
+
261
+ # Update a tracer session
262
+ updated_session = client.update_tracer_session(
263
+ tracer_session_id: "ts_123",
264
+ name: "updated-tracer-session",
265
+ description: "Updated description"
266
+ )
267
+
268
+ # Delete a tracer session
269
+ client.delete_tracer_session(tracer_session_id: "ts_123")
270
+ ```
271
+
272
+ ### Organizations
273
+
274
+ Manage organizations in LangSmith:
275
+
276
+ ```ruby
277
+ # Get the current organization
278
+ org = client.get_current_organization
279
+
280
+ # List organizations
281
+ orgs = client.list_organizations
282
+
283
+ # Get an organization by ID
284
+ org = client.get_organization(organization_id: "org_123")
285
+ ```
286
+
287
+ ### API Keys
288
+
289
+ Manage API keys for accessing LangSmith:
290
+
291
+ ```ruby
292
+ # List API keys
293
+ keys = client.list_api_keys
294
+
295
+ # Create a new API key
296
+ new_key = client.create_api_key(name: "my-api-key")
297
+
298
+ # Delete an API key
299
+ client.delete_api_key(api_key_id: "key_123")
300
+ ```
301
+
302
+ ### Tenants
303
+
304
+ Manage tenants within your organization:
305
+
306
+ ```ruby
307
+ # Get a tenant by ID
308
+ tenant = client.get_tenant(tenant_id: "tenant_123")
309
+
310
+ # List tenants
311
+ tenants = client.list_tenants(limit: 10)
312
+
313
+ # Create a new tenant
314
+ new_tenant = client.create_tenant(
315
+ name: "my-tenant",
316
+ description: "My team's tenant"
317
+ )
318
+
319
+ # Update a tenant
320
+ updated_tenant = client.update_tenant(
321
+ tenant_id: "tenant_123",
322
+ name: "updated-tenant",
323
+ description: "Updated description"
324
+ )
325
+ ```
326
+
327
+ ### Tags
328
+
329
+ Manage tags for organizing runs and other resources:
330
+
331
+ ```ruby
332
+ # Create a new tag
333
+ tag = client.create_tag(name: "important")
334
+
335
+ # Get a tag by ID
336
+ tag = client.get_tag(tag_id: "tag_123")
337
+
338
+ # List tags
339
+ tags = client.list_tags(limit: 10)
340
+
341
+ # Delete a tag
342
+ client.delete_tag(tag_id: "tag_123")
343
+ ```
344
+
345
+ ### Prompts
346
+
347
+ Manage prompt templates in LangSmith:
348
+
349
+ ```ruby
350
+ # Create a new prompt
351
+ prompt = client.create_prompt(
352
+ name: "qa-prompt",
353
+ prompt_template: "Answer the following question: {{question}}",
354
+ description: "A simple Q&A prompt template"
355
+ )
356
+
357
+ # Get a prompt by ID
358
+ prompt = client.get_prompt(prompt_id: "prompt_123")
359
+
360
+ # List prompts
361
+ prompts = client.list_prompts(limit: 10)
362
+
363
+ # Update a prompt
364
+ updated_prompt = client.update_prompt(
365
+ prompt_id: "prompt_123",
366
+ name: "updated-prompt",
367
+ prompt_template: "Please answer this question: {{question}}",
368
+ description: "Updated description"
369
+ )
370
+
371
+ # Delete a prompt
372
+ client.delete_prompt(prompt_id: "prompt_123")
373
+ ```
374
+
375
+ ### Annotation Queues
376
+
377
+ Manage annotation queues for human feedback:
378
+
379
+ ```ruby
380
+ # Create a new annotation queue
381
+ queue = client.create_annotation_queue(
382
+ name: "feedback-queue",
383
+ description: "Queue for human feedback"
384
+ )
385
+
386
+ # Get an annotation queue by ID
387
+ queue = client.get_annotation_queue(annotation_queue_id: "queue_123")
388
+
389
+ # List annotation queues
390
+ queues = client.list_annotation_queues(limit: 10)
391
+
392
+ # Update an annotation queue
393
+ updated_queue = client.update_annotation_queue(
394
+ annotation_queue_id: "queue_123",
395
+ name: "updated-queue",
396
+ description: "Updated description"
397
+ )
398
+
399
+ # Delete an annotation queue
400
+ client.delete_annotation_queue(annotation_queue_id: "queue_123")
401
+ ```
402
+
403
+ ### Feedback Configurations
404
+
405
+ Manage feedback configurations for collecting structured feedback:
406
+
407
+ ```ruby
408
+ # Create a new feedback configuration
409
+ config = client.create_feedback_configuration(
410
+ name: "helpfulness",
411
+ description: "Measure helpfulness of responses",
412
+ criteria: "How helpful was this response?"
413
+ )
414
+
415
+ # Get a feedback configuration by ID
416
+ config = client.get_feedback_configuration(feedback_configuration_id: "config_123")
417
+
418
+ # List feedback configurations
419
+ configs = client.list_feedback_configurations(limit: 10)
420
+
421
+ # Update a feedback configuration
422
+ updated_config = client.update_feedback_configuration(
423
+ feedback_configuration_id: "config_123",
424
+ name: "updated-config",
425
+ description: "Updated description",
426
+ criteria: "Updated criteria"
427
+ )
428
+
429
+ # Delete a feedback configuration
430
+ client.delete_feedback_configuration(feedback_configuration_id: "config_123")
431
+ ```
432
+
433
+ ### Analytics
434
+
435
+ Access analytics data for projects and datasets:
436
+
437
+ ```ruby
438
+ # Get project analytics
439
+ analytics = client.get_project_analytics(
440
+ project_id: "proj_123",
441
+ start_time: Time.now - 86400, # 24 hours ago
442
+ end_time: Time.now,
443
+ group_by: "run_type",
444
+ metrics: ["latency", "token_usage"]
445
+ )
446
+
447
+ # Get dataset analytics
448
+ analytics = client.get_dataset_analytics(
449
+ dataset_id: "ds_123",
450
+ start_time: Time.now - 86400, # 24 hours ago
451
+ end_time: Time.now,
452
+ group_by: "example_id"
453
+ )
454
+ ```
455
+
456
+ ### Comments
457
+
458
+ Manage comments on runs:
459
+
460
+ ```ruby
461
+ # Create a comment on a run
462
+ comment = client.create_run_comment(
463
+ run_id: "run_123",
464
+ comment: "This run looks promising",
465
+ metadata: { source: "code review" }
466
+ )
467
+
468
+ # List comments for a run
469
+ comments = client.list_run_comments(run_id: "run_123")
470
+
471
+ # Delete a comment
472
+ client.delete_run_comment(run_id: "run_123", comment_id: "comment_123")
473
+ ```
474
+
475
+ ### Events
476
+
477
+ Manage events in LangSmith:
478
+
479
+ ```ruby
480
+ # Create an event
481
+ event = client.create_event(
482
+ event_type: "user_feedback",
483
+ payload: { score: 0.9, comment: "Great response!" }
484
+ )
485
+
486
+ # List events
487
+ events = client.list_events(
488
+ event_type: "user_feedback",
489
+ start_time: Time.now - 86400, # 24 hours ago
490
+ end_time: Time.now
491
+ )
492
+ ```
493
+
494
+ ### Settings
495
+
496
+ Manage LangSmith settings:
497
+
498
+ ```ruby
499
+ # Get settings
500
+ settings = client.get_settings
501
+
502
+ # Update settings
503
+ updated_settings = client.update_settings(
504
+ default_project_id: "proj_123",
505
+ default_dataset_id: "ds_123"
506
+ )
507
+ ```
508
+
509
+ ### Bulk Operations
510
+
511
+ Perform bulk operations on runs:
512
+
513
+ ```ruby
514
+ # Bulk tag runs
515
+ result = client.bulk_tag_runs(
516
+ run_ids: ["run_123", "run_456", "run_789"],
517
+ tag_ids: ["tag_123", "tag_456"]
518
+ )
519
+
520
+ # Bulk untag runs
521
+ result = client.bulk_untag_runs(
522
+ run_ids: ["run_123", "run_456"],
523
+ tag_ids: ["tag_123"]
524
+ )
525
+
526
+ # Bulk delete runs
527
+ result = client.bulk_delete_runs(
528
+ run_ids: ["run_123", "run_456", "run_789"]
529
+ )
530
+ ```
531
+
532
+ ### Webhooks
533
+
534
+ Manage webhooks for LangSmith events:
535
+
536
+ ```ruby
537
+ # Create a webhook
538
+ webhook = client.create_webhook(
539
+ url: "https://example.com/webhook",
540
+ event_types: ["run.created", "run.updated"],
541
+ metadata: { description: "Notify our system when runs are created or updated" }
542
+ )
543
+
544
+ # Get a webhook by ID
545
+ webhook = client.get_webhook(webhook_id: "webhook_123")
546
+
547
+ # List webhooks
548
+ webhooks = client.list_webhooks(limit: 10)
549
+
550
+ # Update a webhook
551
+ updated_webhook = client.update_webhook(
552
+ webhook_id: "webhook_123",
553
+ url: "https://updated-example.com/webhook",
554
+ event_types: ["run.created", "run.updated", "run.deleted"],
555
+ metadata: { description: "Updated webhook configuration" }
556
+ )
557
+
558
+ # Delete a webhook
559
+ client.delete_webhook(webhook_id: "webhook_123")
560
+ ```
561
+
562
+ ### Team Management
563
+
564
+ Manage team members in your organization:
565
+
566
+ ```ruby
567
+ # List team members
568
+ members = client.list_team_members(organization_id: "org_123", limit: 10)
569
+
570
+ # Invite a team member
571
+ invite = client.invite_team_member(
572
+ organization_id: "org_123",
573
+ email: "new-member@example.com",
574
+ role: "member"
575
+ )
576
+
577
+ # Remove a team member
578
+ client.remove_team_member(
579
+ organization_id: "org_123",
580
+ user_id: "user_123"
581
+ )
582
+ ```
583
+
584
+ ## Error Handling
585
+
586
+ The LangSmith Ruby gem provides robust error handling through several error classes:
587
+
588
+ ```ruby
589
+ require 'langsmith'
590
+
591
+ begin
592
+ client = Langsmith::Client.new(api_key: "invalid_key")
593
+ client.list_projects
594
+ rescue Langsmith::Errors::AuthenticationError => e
595
+ puts "Authentication failed: #{e.message}"
596
+ rescue Langsmith::Errors::ResourceNotFoundError => e
597
+ puts "Resource not found: #{e.message}"
598
+ rescue Langsmith::Errors::APIError => e
599
+ puts "API error: #{e.message}"
600
+ rescue StandardError => e
601
+ puts "Unexpected error: #{e.message}"
602
+ end
603
+ ```
604
+
605
+ The gem defines the following error classes:
606
+
607
+ - `Langsmith::Errors::BaseError` - Base class for all LangSmith errors
608
+ - `Langsmith::Errors::AuthenticationError` - Raised when authentication fails (e.g., invalid API key)
609
+ - `Langsmith::Errors::ResourceNotFoundError` - Raised when a requested resource is not found
610
+ - `Langsmith::Errors::APIError` - Raised for other API errors with status codes outside the 200-299 range
611
+
612
+ Each error includes the response body to help diagnose the issue.
613
+
614
+ ## Development
615
+
616
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
617
+
618
+ To install this gem onto your local machine, run `bundle exec rake install`.
619
+
620
+ ## Contributing
621
+
622
+ Bug reports and pull requests are welcome on GitHub at https://github.com/cdaviis/langsmithrb. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/cdaviis/langsmithrb/blob/main/CODE_OF_CONDUCT.md).
623
+
624
+ ## License
625
+
626
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec