easy_talk 3.3.0 → 3.3.1
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 +4 -4
- data/CHANGELOG.md +16 -0
- data/README.md +191 -31
- data/examples/ruby_llm/Gemfile +12 -0
- data/examples/ruby_llm/structured_output.rb +47 -0
- data/examples/ruby_llm/tools_integration.rb +49 -0
- data/lib/easy_talk/extensions/ruby_llm_compatibility.rb +58 -0
- data/lib/easy_talk/model.rb +15 -0
- data/lib/easy_talk/version.rb +1 -1
- metadata +5 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f1b72ef842cb6e49f4cbc0d1eab096e737f26c118e715170c35e791ceb28a0cd
|
|
4
|
+
data.tar.gz: 800ce6db8a8d0607589250fb76a0834bc1372de11617f2746abad2c00496bc77
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1cb143e9d16027929bcaf119cdcc12254fd4324f2f902a493be7a55095cfce1f8d721bd44c5233fb5ef62cde19aab3017f6fdc78cb66c57ab670a304293b6fb0
|
|
7
|
+
data.tar.gz: 2968e2ab36843d8237759d9b7528cbe9a72388123b677b8c8117c27192c51d50f577df884a0a96d9cc7e308f2119e2485bcbf0b13bb5742675fb5cd1338ae31a
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
## [3.3.1] - 2026-02-03
|
|
2
|
+
|
|
3
|
+
### Added
|
|
4
|
+
|
|
5
|
+
- **RubyLLM Compatibility Extension**: Seamless integration between EasyTalk models and RubyLLM's tool and structured output features (#122)
|
|
6
|
+
- New `RubyLLMCompatibility` module adds class method `to_json_schema` for `with_schema` support
|
|
7
|
+
- New `RubyLLMToolOverrides` module for classes inheriting from `RubyLLM::Tool`
|
|
8
|
+
- Overrides `description` and `params_schema` methods to use EasyTalk schema definitions
|
|
9
|
+
- Automatically included when using `EasyTalk::Model`
|
|
10
|
+
- Tools inherit from `RubyLLM::Tool` directly, gaining full access to features like `halt`, `call`, `provider_params`
|
|
11
|
+
- New example files: `examples/ruby_llm/tools_integration.rb`, `examples/ruby_llm/structured_output.rb`
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- **Documentation**: Updated README with improved examples and documentation
|
|
16
|
+
|
|
1
17
|
## [3.3.0] - 2026-01-12
|
|
2
18
|
|
|
3
19
|
### Added
|
data/README.md
CHANGED
|
@@ -52,13 +52,43 @@ EasyTalk makes the schema definition the single source of truth, so you can:
|
|
|
52
52
|
- **RFC 7807** problem details
|
|
53
53
|
- **JSON:API** error objects
|
|
54
54
|
|
|
55
|
-
- **LLM tool/function schemas without a second schema layer**
|
|
56
|
-
Use the same contract to generate JSON Schema for function/tool calling.
|
|
55
|
+
- **LLM tool/function schemas without a second schema layer**
|
|
56
|
+
Use the same contract to generate JSON Schema for function/tool calling. See [RubyLLM Integration](#rubyllm-integration).
|
|
57
57
|
|
|
58
58
|
EasyTalk is for teams who want their data contracts to be **correct, reusable, and boring** (the good kind of boring).
|
|
59
59
|
|
|
60
60
|
---
|
|
61
61
|
|
|
62
|
+
## Table of Contents
|
|
63
|
+
|
|
64
|
+
- [Installation](#installation)
|
|
65
|
+
- [Quick start](#quick-start)
|
|
66
|
+
- [Property constraints](#property-constraints)
|
|
67
|
+
- [Core concepts](#core-concepts)
|
|
68
|
+
- [Required vs optional vs nullable](#required-vs-optional-vs-nullable-dont-get-tricked)
|
|
69
|
+
- [Nested models](#nested-models-and-automatic-instantiation)
|
|
70
|
+
- [Tuple arrays](#tuple-arrays-fixed-position-types)
|
|
71
|
+
- [Composition (AnyOf / OneOf / AllOf)](#composition-anyof--oneof--allof)
|
|
72
|
+
- [Validations](#validations)
|
|
73
|
+
- [Automatic validations](#automatic-validations-default)
|
|
74
|
+
- [Per-model validation control](#per-model-validation-control)
|
|
75
|
+
- [Per-property validation control](#per-property-validation-control)
|
|
76
|
+
- [Validation adapters](#validation-adapters)
|
|
77
|
+
- [Error formatting](#error-formatting)
|
|
78
|
+
- [Schema-only mode](#schema-only-mode)
|
|
79
|
+
- [RubyLLM Integration](#rubyllm-integration)
|
|
80
|
+
- [Configuration highlights](#configuration-highlights)
|
|
81
|
+
- [Advanced topics](#advanced-topics)
|
|
82
|
+
- [JSON Schema drafts, `$id`, and `$ref`](#json-schema-drafts-id-and-ref)
|
|
83
|
+
- [Additional properties with types](#additional-properties-with-types)
|
|
84
|
+
- [Object-level constraints](#object-level-constraints)
|
|
85
|
+
- [Custom type builders](#custom-type-builders)
|
|
86
|
+
- [Known limitations](#known-limitations)
|
|
87
|
+
- [Contributing](#contributing)
|
|
88
|
+
- [License](#license)
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
62
92
|
## Installation
|
|
63
93
|
|
|
64
94
|
### Requirements
|
|
@@ -80,6 +110,14 @@ bundle install
|
|
|
80
110
|
|
|
81
111
|
## Quick start
|
|
82
112
|
|
|
113
|
+
<table>
|
|
114
|
+
<tr>
|
|
115
|
+
<th>EasyTalk Model</th>
|
|
116
|
+
<th>Generated JSON Schema</th>
|
|
117
|
+
</tr>
|
|
118
|
+
<tr>
|
|
119
|
+
<td>
|
|
120
|
+
|
|
83
121
|
```ruby
|
|
84
122
|
require "easy_talk"
|
|
85
123
|
|
|
@@ -96,14 +134,10 @@ class User
|
|
|
96
134
|
property :age, Integer, minimum: 18
|
|
97
135
|
end
|
|
98
136
|
end
|
|
99
|
-
|
|
100
|
-
User.json_schema # => Ruby Hash (JSON Schema)
|
|
101
|
-
user = User.new(name: "A") # invalid: min_length is 2
|
|
102
|
-
user.valid? # => false
|
|
103
|
-
user.errors # => ActiveModel::Errors
|
|
104
137
|
```
|
|
105
138
|
|
|
106
|
-
|
|
139
|
+
</td>
|
|
140
|
+
<td>
|
|
107
141
|
|
|
108
142
|
```json
|
|
109
143
|
{
|
|
@@ -120,6 +154,17 @@ user.errors # => ActiveModel::Errors
|
|
|
120
154
|
}
|
|
121
155
|
```
|
|
122
156
|
|
|
157
|
+
</td>
|
|
158
|
+
</tr>
|
|
159
|
+
</table>
|
|
160
|
+
|
|
161
|
+
```ruby
|
|
162
|
+
User.json_schema # => Ruby Hash (JSON Schema)
|
|
163
|
+
user = User.new(name: "A") # invalid: min_length is 2
|
|
164
|
+
user.valid? # => false
|
|
165
|
+
user.errors # => ActiveModel::Errors
|
|
166
|
+
```
|
|
167
|
+
|
|
123
168
|
---
|
|
124
169
|
|
|
125
170
|
## Property constraints
|
|
@@ -240,6 +285,14 @@ end
|
|
|
240
285
|
|
|
241
286
|
Use `T::Tuple` for arrays where each position has a specific type (e.g., coordinates, CSV rows, database records):
|
|
242
287
|
|
|
288
|
+
<table>
|
|
289
|
+
<tr>
|
|
290
|
+
<th>EasyTalk Model</th>
|
|
291
|
+
<th>Generated JSON Schema</th>
|
|
292
|
+
</tr>
|
|
293
|
+
<tr>
|
|
294
|
+
<td>
|
|
295
|
+
|
|
243
296
|
```ruby
|
|
244
297
|
class GeoLocation
|
|
245
298
|
include EasyTalk::Model
|
|
@@ -257,7 +310,8 @@ location = GeoLocation.new(
|
|
|
257
310
|
)
|
|
258
311
|
```
|
|
259
312
|
|
|
260
|
-
|
|
313
|
+
</td>
|
|
314
|
+
<td>
|
|
261
315
|
|
|
262
316
|
```json
|
|
263
317
|
{
|
|
@@ -273,6 +327,10 @@ location = GeoLocation.new(
|
|
|
273
327
|
}
|
|
274
328
|
```
|
|
275
329
|
|
|
330
|
+
</td>
|
|
331
|
+
</tr>
|
|
332
|
+
</table>
|
|
333
|
+
|
|
276
334
|
**Mixed-type tuples:**
|
|
277
335
|
|
|
278
336
|
```ruby
|
|
@@ -469,6 +527,66 @@ Use this for documentation, OpenAPI generation, or when validation happens elsew
|
|
|
469
527
|
|
|
470
528
|
---
|
|
471
529
|
|
|
530
|
+
## RubyLLM Integration
|
|
531
|
+
|
|
532
|
+
EasyTalk integrates seamlessly with [RubyLLM](https://github.com/crmne/ruby_llm) for structured outputs and tool definitions.
|
|
533
|
+
|
|
534
|
+
### Structured Outputs
|
|
535
|
+
|
|
536
|
+
Use any EasyTalk model with RubyLLM's `with_schema` to get structured JSON responses:
|
|
537
|
+
|
|
538
|
+
```ruby
|
|
539
|
+
class Recipe
|
|
540
|
+
include EasyTalk::Model
|
|
541
|
+
|
|
542
|
+
define_schema do
|
|
543
|
+
description "A cooking recipe"
|
|
544
|
+
property :name, String, description: "Name of the dish"
|
|
545
|
+
property :ingredients, T::Array[String], description: "List of ingredients"
|
|
546
|
+
property :prep_time_minutes, Integer, description: "Preparation time in minutes"
|
|
547
|
+
end
|
|
548
|
+
end
|
|
549
|
+
|
|
550
|
+
chat = RubyLLM.chat.with_schema(Recipe)
|
|
551
|
+
response = chat.ask("Give me a simple pasta recipe")
|
|
552
|
+
|
|
553
|
+
# RubyLLM returns parsed JSON - instantiate with EasyTalk model
|
|
554
|
+
recipe = Recipe.new(response.content)
|
|
555
|
+
recipe.name # => "Spaghetti Aglio e Olio"
|
|
556
|
+
recipe.ingredients # => ["spaghetti", "garlic", "olive oil", ...]
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
### Tools
|
|
560
|
+
|
|
561
|
+
Create LLM tools by inheriting from `RubyLLM::Tool` and including `EasyTalk::Model`:
|
|
562
|
+
|
|
563
|
+
```ruby
|
|
564
|
+
class Weather < RubyLLM::Tool
|
|
565
|
+
include EasyTalk::Model
|
|
566
|
+
|
|
567
|
+
define_schema do
|
|
568
|
+
description 'Gets current weather for a location'
|
|
569
|
+
property :latitude, String, description: 'Latitude (e.g., 52.5200)'
|
|
570
|
+
property :longitude, String, description: 'Longitude (e.g., 13.4050)'
|
|
571
|
+
end
|
|
572
|
+
|
|
573
|
+
def execute(latitude:, longitude:)
|
|
574
|
+
# Fetch weather data from API...
|
|
575
|
+
{ temperature: 22, conditions: "sunny" }
|
|
576
|
+
end
|
|
577
|
+
end
|
|
578
|
+
|
|
579
|
+
chat = RubyLLM.chat.with_tool(Weather)
|
|
580
|
+
response = chat.ask("What's the weather in Berlin?")
|
|
581
|
+
```
|
|
582
|
+
|
|
583
|
+
This pattern gives you:
|
|
584
|
+
- Full access to `RubyLLM::Tool` features (`halt`, `call`, etc.)
|
|
585
|
+
- EasyTalk's schema DSL for parameter definitions
|
|
586
|
+
- Automatic JSON Schema generation for the LLM
|
|
587
|
+
|
|
588
|
+
---
|
|
589
|
+
|
|
472
590
|
## Configuration highlights
|
|
473
591
|
|
|
474
592
|
```ruby
|
|
@@ -517,6 +635,14 @@ end
|
|
|
517
635
|
|
|
518
636
|
Use external URIs in `$ref` for modular, reusable schemas:
|
|
519
637
|
|
|
638
|
+
<table>
|
|
639
|
+
<tr>
|
|
640
|
+
<th>EasyTalk Model</th>
|
|
641
|
+
<th>Generated JSON Schema</th>
|
|
642
|
+
</tr>
|
|
643
|
+
<tr>
|
|
644
|
+
<td>
|
|
645
|
+
|
|
520
646
|
```ruby
|
|
521
647
|
EasyTalk.configure do |config|
|
|
522
648
|
config.use_refs = true
|
|
@@ -544,20 +670,34 @@ class Customer
|
|
|
544
670
|
end
|
|
545
671
|
|
|
546
672
|
Customer.json_schema
|
|
547
|
-
# =>
|
|
548
|
-
# {
|
|
549
|
-
# "properties": {
|
|
550
|
-
# "address": { "$ref": "https://example.com/schemas/address" }
|
|
551
|
-
# },
|
|
552
|
-
# "$defs": {
|
|
553
|
-
# "Address": {
|
|
554
|
-
# "$id": "https://example.com/schemas/address",
|
|
555
|
-
# "properties": { "street": {...}, "city": {...} }
|
|
556
|
-
# }
|
|
557
|
-
# }
|
|
558
|
-
# }
|
|
559
673
|
```
|
|
560
674
|
|
|
675
|
+
</td>
|
|
676
|
+
<td>
|
|
677
|
+
|
|
678
|
+
```json
|
|
679
|
+
{
|
|
680
|
+
"properties": {
|
|
681
|
+
"address": {
|
|
682
|
+
"$ref": "https://example.com/schemas/address"
|
|
683
|
+
}
|
|
684
|
+
},
|
|
685
|
+
"$defs": {
|
|
686
|
+
"Address": {
|
|
687
|
+
"$id": "https://example.com/schemas/address",
|
|
688
|
+
"properties": {
|
|
689
|
+
"street": { "type": "string" },
|
|
690
|
+
"city": { "type": "string" }
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
```
|
|
696
|
+
|
|
697
|
+
</td>
|
|
698
|
+
</tr>
|
|
699
|
+
</table>
|
|
700
|
+
|
|
561
701
|
**Explicit schema IDs:**
|
|
562
702
|
|
|
563
703
|
```ruby
|
|
@@ -608,6 +748,14 @@ config.as_json
|
|
|
608
748
|
|
|
609
749
|
**With constraints:**
|
|
610
750
|
|
|
751
|
+
<table>
|
|
752
|
+
<tr>
|
|
753
|
+
<th>EasyTalk Model</th>
|
|
754
|
+
<th>Generated JSON Schema</th>
|
|
755
|
+
</tr>
|
|
756
|
+
<tr>
|
|
757
|
+
<td>
|
|
758
|
+
|
|
611
759
|
```ruby
|
|
612
760
|
class StrictConfig
|
|
613
761
|
include EasyTalk::Model
|
|
@@ -615,22 +763,34 @@ class StrictConfig
|
|
|
615
763
|
define_schema do
|
|
616
764
|
property :id, Integer
|
|
617
765
|
# Integer values between 0 and 100 only
|
|
618
|
-
additional_properties Integer,
|
|
766
|
+
additional_properties Integer,
|
|
767
|
+
minimum: 0, maximum: 100
|
|
619
768
|
end
|
|
620
769
|
end
|
|
621
770
|
|
|
622
771
|
StrictConfig.json_schema
|
|
623
|
-
# =>
|
|
624
|
-
# {
|
|
625
|
-
# "properties": { "id": { "type": "integer" } },
|
|
626
|
-
# "additionalProperties": {
|
|
627
|
-
# "type": "integer",
|
|
628
|
-
# "minimum": 0,
|
|
629
|
-
# "maximum": 100
|
|
630
|
-
# }
|
|
631
|
-
# }
|
|
632
772
|
```
|
|
633
773
|
|
|
774
|
+
</td>
|
|
775
|
+
<td>
|
|
776
|
+
|
|
777
|
+
```json
|
|
778
|
+
{
|
|
779
|
+
"properties": {
|
|
780
|
+
"id": { "type": "integer" }
|
|
781
|
+
},
|
|
782
|
+
"additionalProperties": {
|
|
783
|
+
"type": "integer",
|
|
784
|
+
"minimum": 0,
|
|
785
|
+
"maximum": 100
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
```
|
|
789
|
+
|
|
790
|
+
</td>
|
|
791
|
+
</tr>
|
|
792
|
+
</table>
|
|
793
|
+
|
|
634
794
|
**Nested models as additional properties:**
|
|
635
795
|
|
|
636
796
|
```ruby
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
source 'https://rubygems.org'
|
|
4
|
+
|
|
5
|
+
# EasyTalk from the parent directory
|
|
6
|
+
gem 'easy_talk', path: '../..'
|
|
7
|
+
|
|
8
|
+
# RubyLLM for LLM interactions
|
|
9
|
+
gem 'ruby_llm'
|
|
10
|
+
|
|
11
|
+
# HTTP client for API calls (used in tools example)
|
|
12
|
+
gem 'faraday'
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'bundler/setup'
|
|
4
|
+
require 'ruby_llm'
|
|
5
|
+
require 'easy_talk'
|
|
6
|
+
|
|
7
|
+
# Example: Structured Outputs
|
|
8
|
+
# Demonstrates using EasyTalk models to generate structured JSON responses.
|
|
9
|
+
|
|
10
|
+
RubyLLM.configure do |config|
|
|
11
|
+
config.openai_api_key = ENV.fetch('OPENAI_API_KEY', nil)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# 1. Define the Schema using EasyTalk
|
|
15
|
+
class Recipe
|
|
16
|
+
include EasyTalk::Model
|
|
17
|
+
|
|
18
|
+
define_schema do
|
|
19
|
+
description "A simple cooking recipe"
|
|
20
|
+
property :name, String, description: "Name of the dish"
|
|
21
|
+
property :ingredients, T::Array[String], description: "List of ingredients"
|
|
22
|
+
property :prep_time_minutes, Integer, description: "Preparation time in minutes"
|
|
23
|
+
property :steps, T::Array[String], description: "Step by step cooking instructions"
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
puts "--- Structured Output Example ---"
|
|
28
|
+
|
|
29
|
+
# 2. Use the EasyTalk model as the output schema
|
|
30
|
+
# RubyLLM uses the schema to force the LLM to reply with a matching JSON structure.
|
|
31
|
+
# Our compatibility layer ensures 'Recipe' responds to to_json_schema as RubyLLM expects.
|
|
32
|
+
chat = RubyLLM.chat.with_schema(Recipe)
|
|
33
|
+
|
|
34
|
+
puts "User: Give me a simple spaghetti carbonara recipe."
|
|
35
|
+
response = chat.ask "Give me a simple spaghetti carbonara recipe."
|
|
36
|
+
|
|
37
|
+
# 3. Access the structured data
|
|
38
|
+
# RubyLLM returns parsed JSON as a Hash, so we instantiate the model with it
|
|
39
|
+
recipe = Recipe.new(response.content)
|
|
40
|
+
|
|
41
|
+
puts "\nGenerated Recipe:"
|
|
42
|
+
puts "Name: #{recipe.name}"
|
|
43
|
+
puts "Time: #{recipe.prep_time_minutes} mins"
|
|
44
|
+
puts "Ingredients:"
|
|
45
|
+
recipe.ingredients.each { |ing| puts "- #{ing}" }
|
|
46
|
+
puts "Steps:"
|
|
47
|
+
recipe.steps.each_with_index { |step, i| puts "#{i + 1}. #{step}" }
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'bundler/setup'
|
|
4
|
+
require 'ruby_llm'
|
|
5
|
+
require 'easy_talk'
|
|
6
|
+
require 'faraday'
|
|
7
|
+
|
|
8
|
+
# Example: Tools Integration
|
|
9
|
+
# Demonstrates using EasyTalk models as Tools for RubyLLM.
|
|
10
|
+
#
|
|
11
|
+
# To create a tool, inherit from RubyLLM::Tool and include EasyTalk::Model.
|
|
12
|
+
# This gives you:
|
|
13
|
+
# - Full access to RubyLLM::Tool features like halt()
|
|
14
|
+
# - EasyTalk's schema DSL for defining parameters
|
|
15
|
+
# - Automatic integration with RubyLLM's with_tool method
|
|
16
|
+
|
|
17
|
+
RubyLLM.configure do |config|
|
|
18
|
+
config.openai_api_key = ENV.fetch('OPENAI_API_KEY', nil)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
class Weather < RubyLLM::Tool
|
|
22
|
+
include EasyTalk::Model
|
|
23
|
+
|
|
24
|
+
define_schema do
|
|
25
|
+
description 'Gets current weather for a location'
|
|
26
|
+
property :latitude, String, description: 'Latitude (e.g., 52.5200)'
|
|
27
|
+
property :longitude, String, description: 'Longitude (e.g., 13.4050)'
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def execute(latitude:, longitude:)
|
|
31
|
+
puts "Executing Weather Tool for #{latitude}, #{longitude}"
|
|
32
|
+
url = "https://api.open-meteo.com/v1/forecast?latitude=#{latitude}&longitude=#{longitude}¤t=temperature_2m,wind_speed_10m"
|
|
33
|
+
response = Faraday.get(url)
|
|
34
|
+
data = JSON.parse(response.body)
|
|
35
|
+
data.to_s
|
|
36
|
+
rescue StandardError => e
|
|
37
|
+
{ error: e.message }
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
puts '--- Tools Integration Example ---'
|
|
42
|
+
puts
|
|
43
|
+
|
|
44
|
+
chat = RubyLLM.chat.with_tool(Weather)
|
|
45
|
+
|
|
46
|
+
puts 'User: What is the weather in Berlin (Lat: 52.52, Long: 13.405)?'
|
|
47
|
+
response = chat.ask 'What is the weather in Berlin (Lat: 52.52, Long: 13.405)?'
|
|
48
|
+
|
|
49
|
+
puts "Assistant: #{response.content}"
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module EasyTalk
|
|
4
|
+
module Extensions
|
|
5
|
+
# Class methods for RubyLLM compatibility.
|
|
6
|
+
# These are added to the model class via `extend`.
|
|
7
|
+
module RubyLLMCompatibility
|
|
8
|
+
# Returns a Hash representing the schema in a format compatible with RubyLLM.
|
|
9
|
+
# RubyLLM expects an object that responds to #to_json_schema and returns
|
|
10
|
+
# a hash with :name, :description, and :schema keys.
|
|
11
|
+
#
|
|
12
|
+
# @return [Hash] The RubyLLM-compatible schema representation
|
|
13
|
+
def to_json_schema
|
|
14
|
+
{
|
|
15
|
+
name: name,
|
|
16
|
+
description: schema_definition.schema[:description] || "Schema for #{name}",
|
|
17
|
+
schema: json_schema
|
|
18
|
+
}
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Overrides for classes that inherit from RubyLLM::Tool.
|
|
23
|
+
# Only overrides schema-related methods, allowing all other RubyLLM::Tool
|
|
24
|
+
# functionality (halt, call, etc.) to work normally.
|
|
25
|
+
#
|
|
26
|
+
# Usage:
|
|
27
|
+
# class WeatherTool < RubyLLM::Tool
|
|
28
|
+
# include EasyTalk::Model
|
|
29
|
+
#
|
|
30
|
+
# define_schema do
|
|
31
|
+
# description 'Gets current weather'
|
|
32
|
+
# property :latitude, String
|
|
33
|
+
# property :longitude, String
|
|
34
|
+
# end
|
|
35
|
+
#
|
|
36
|
+
# def execute(latitude:, longitude:)
|
|
37
|
+
# # Can use halt() since we inherit from RubyLLM::Tool
|
|
38
|
+
# halt "Weather at #{latitude}, #{longitude}"
|
|
39
|
+
# end
|
|
40
|
+
# end
|
|
41
|
+
module RubyLLMToolOverrides
|
|
42
|
+
# Override to use EasyTalk's schema description.
|
|
43
|
+
#
|
|
44
|
+
# @return [String] The tool description from EasyTalk schema
|
|
45
|
+
def description
|
|
46
|
+
schema_def = self.class.schema_definition
|
|
47
|
+
schema_def.schema[:description] || "Tool: #{self.class.name}"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Override to use EasyTalk's JSON schema for parameters.
|
|
51
|
+
#
|
|
52
|
+
# @return [Hash] The JSON schema for parameters
|
|
53
|
+
def params_schema
|
|
54
|
+
self.class.json_schema
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
data/lib/easy_talk/model.rb
CHANGED
|
@@ -12,6 +12,7 @@ require_relative 'builders/object_builder'
|
|
|
12
12
|
require_relative 'schema_definition'
|
|
13
13
|
require_relative 'validation_builder'
|
|
14
14
|
require_relative 'error_formatter'
|
|
15
|
+
require_relative 'extensions/ruby_llm_compatibility'
|
|
15
16
|
|
|
16
17
|
module EasyTalk
|
|
17
18
|
# The `Model` module is a mixin that provides functionality for defining and accessing the schema of a model.
|
|
@@ -38,12 +39,18 @@ module EasyTalk
|
|
|
38
39
|
module Model
|
|
39
40
|
def self.included(base)
|
|
40
41
|
base.extend(ClassMethods)
|
|
42
|
+
base.extend(EasyTalk::Extensions::RubyLLMCompatibility) # Add class-level methods
|
|
41
43
|
|
|
42
44
|
base.include ActiveModel::API
|
|
43
45
|
base.include ActiveModel::Validations
|
|
44
46
|
base.extend ActiveModel::Callbacks
|
|
45
47
|
base.include(InstanceMethods)
|
|
46
48
|
base.include(ErrorFormatter::InstanceMethods)
|
|
49
|
+
|
|
50
|
+
# If inheriting from RubyLLM::Tool, override schema methods to use EasyTalk's schema
|
|
51
|
+
return unless defined?(RubyLLM::Tool) && base < RubyLLM::Tool
|
|
52
|
+
|
|
53
|
+
base.include(EasyTalk::Extensions::RubyLLMToolOverrides)
|
|
47
54
|
end
|
|
48
55
|
|
|
49
56
|
# Instance methods mixed into models that include EasyTalk::Model
|
|
@@ -150,6 +157,14 @@ module EasyTalk
|
|
|
150
157
|
to_hash.merge(@additional_properties)
|
|
151
158
|
end
|
|
152
159
|
|
|
160
|
+
# Returns a Hash representing the schema in a format compatible with RubyLLM.
|
|
161
|
+
# Delegates to the class method. Required for RubyLLM's with_schema method.
|
|
162
|
+
#
|
|
163
|
+
# @return [Hash] The RubyLLM-compatible schema representation
|
|
164
|
+
def to_json_schema
|
|
165
|
+
self.class.to_json_schema
|
|
166
|
+
end
|
|
167
|
+
|
|
153
168
|
# Allow comparison with hashes
|
|
154
169
|
def ==(other)
|
|
155
170
|
case other
|
data/lib/easy_talk/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: easy_talk
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.3.
|
|
4
|
+
version: 3.3.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sergio Bayona
|
|
@@ -106,6 +106,9 @@ files:
|
|
|
106
106
|
- docs/primitive-schema-rfc.md
|
|
107
107
|
- docs/property-types.markdown
|
|
108
108
|
- docs/schema-definition.markdown
|
|
109
|
+
- examples/ruby_llm/Gemfile
|
|
110
|
+
- examples/ruby_llm/structured_output.rb
|
|
111
|
+
- examples/ruby_llm/tools_integration.rb
|
|
109
112
|
- lib/easy_talk.rb
|
|
110
113
|
- lib/easy_talk/builders/base_builder.rb
|
|
111
114
|
- lib/easy_talk/builders/boolean_builder.rb
|
|
@@ -132,6 +135,7 @@ files:
|
|
|
132
135
|
- lib/easy_talk/error_formatter/rfc7807.rb
|
|
133
136
|
- lib/easy_talk/errors.rb
|
|
134
137
|
- lib/easy_talk/errors_helper.rb
|
|
138
|
+
- lib/easy_talk/extensions/ruby_llm_compatibility.rb
|
|
135
139
|
- lib/easy_talk/json_schema_equality.rb
|
|
136
140
|
- lib/easy_talk/keywords.rb
|
|
137
141
|
- lib/easy_talk/model.rb
|