rach 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7f427f0e11f94e869ea14d6d7ed35bd5d73311212fd958daa52b1d8964886fc3
4
- data.tar.gz: b0fbf4e2dfcc18c9aa39c6e23b8ebc5edafa62deb125a4b0d25bb0c0eeb5ba4c
3
+ metadata.gz: 54430271658860452dad9e146c8aed72752de64c546a888b5784724bc47fb1c8
4
+ data.tar.gz: 34ea312840fa1b5aa08104f3f3696cacad5a2488039bd1d99e87c48c7949650b
5
5
  SHA512:
6
- metadata.gz: 0abf7aa58e283fa66cf18b322c9711f250365760b6f77b25d1276e77daf28a0f0640f98050b0bc2ccee38b181735398572e21c95d3f0872a770e6f545ce40cd5
7
- data.tar.gz: 2a2553158981ff4f425ada8381c3e61635f302faf5b88c9d952247a60ea126dda4ddc91440dd32324194a94a80d86aad283d0a74bc2a1b3c48066348447f96ae
6
+ metadata.gz: b7ced2382782e8f422d1c959f5ca6a7348110f542fd9d50cd9a350c3177575583a26641599ff5b584fba4f8fe6219b27bf2a610966a6bb941404026f97919516
7
+ data.tar.gz: 718302171ac286fe03df1030f745bcdac07e3b319bb09f15abb034d6258bf2f32a7c46ac2dfb6063d7ff385d4935968eb94ffd4a00a3f4b03708e57318f07d60
data/README.md CHANGED
@@ -2,11 +2,125 @@
2
2
 
3
3
  A lightweight Ruby framework for OpenAI interactions, focusing on simplicity and clean design.
4
4
 
5
+ ## Installation
5
6
 
6
- ## Configuration
7
+ Add this line to your application's Gemfile:
7
8
 
8
- 1. Copy the example environment file:
9
+ ```ruby
10
+ gem 'rach'
9
11
  ```
10
- cp .env.example .env
12
+
13
+ And then execute:
14
+ ```bash
15
+ $ bundle install
16
+ ```
17
+
18
+ Or install it yourself as:
19
+ ```bash
20
+ $ gem install rach
21
+ ```
22
+
23
+ ## Usage
24
+
25
+ ### Basic Chat
26
+
27
+ ```ruby
28
+ require 'rach'
29
+ client = Rach::Client.new(access_token: YOUR_OPENAI_API_KEY)
30
+ response = client.chat("Hello, how are you?")
31
+ puts response.content
32
+ ```
33
+
34
+ ### Conversations
35
+
36
+ Rach supports stateful conversations with memory:
37
+
38
+ ```ruby
39
+ require 'rach'
40
+
41
+ client = Rach::Client.new(access_token: YOUR_OPENAI_API_KEY)
42
+ convo = Rach::Conversation.new
43
+ convo.system "You teach the German language."
44
+ convo.user "Translate: There are two birds singing outside my window."
45
+
46
+ response = client.chat(convo)
47
+ response.content
48
+ # => "Es gibt zwei Vögel, die draußen vor meinem Fenster singen."
49
+
50
+ convo.add_response(response)
51
+
52
+ # Continue the conversation...
53
+ convo.user "What are the verbs in your translation?"
54
+ client.chat(convo)
55
+
56
+
57
+ # Remove the last message from the conversation history and continue
58
+ convo.pop
59
+ convo.user "Explain the structure of your translation."
60
+ client.chat(convo)
11
61
  ```
12
- 2. Set your OpenAI API key in the `.env` file.
62
+
63
+ ### Response Formatting
64
+
65
+ Define structured response schemas for type-safe AI responses:
66
+
67
+ ```ruby
68
+ class GermanTranslatorSchema
69
+ include Rach::ResponseFormat
70
+
71
+ def explain_structure
72
+ object do
73
+ array :structure_explanation do
74
+ items type: :string
75
+ description "A step by step explanation of the structure of the translation."
76
+ end
77
+ string :final_translation
78
+ end
79
+ end
80
+ end
81
+
82
+ response = client.chat(convo, response_format: GermanTranslatorSchema.render(:explain_structure))
83
+ JSON.load(response.content)
84
+ # => {"structure_explanation"=> ["The phrase starts with 'Es gibt' which translates to 'There are'. 'Es' is a pronoun that means 'it', and 'gibt' is the third person singular form of the verb 'geben' (to give), meaning 'there are' in this context.", "'zwei Vögel' means 'two birds'. 'zwei' is the number 'two' and 'Vögel' is the plural form of 'Vogel' (bird).", "The relative clause 'die draußen vor meinem Fenster singen' describes the birds. 'die' is a relative pronoun meaning 'that' or 'which',' 'draußen' means 'outside', and 'vor meinem Fenster' means 'in front of my window'.", "'singen' is the infinitive form of the verb 'sing' (to sing). It tells us what the birds are doing."], "final_translation"=>"Es gibt zwei Vögel, die draußen vor meinem Fenster singen."}
85
+ ```
86
+
87
+ ### Function Calling / Tools
88
+
89
+ Rach supports OpenAI's function calling feature:
90
+
91
+ ```ruby
92
+ class GetWeather
93
+ include Rach::Function
94
+
95
+ def function_name
96
+ "get_current_weather"
97
+ end
98
+
99
+ def function_description
100
+ "Get the current weather in a given location"
101
+ end
102
+
103
+ def schema
104
+ object do
105
+ string :location, description: "The city and state, e.g. San Francisco, CA"
106
+ string :unit, enum: %w[celsius fahrenheit]
107
+ end
108
+ end
109
+
110
+ def execute(location:, unit: "fahrenheit")
111
+ # Implementation of weather fetching logic
112
+ "The weather in #{location} is nice 🌞 #{unit}"
113
+ end
114
+ end
115
+
116
+ response = client.chat("What is the weather in San Francisco?", tools: [GetWeather.function_schema])
117
+ response.tool_calls
118
+ # => [{"id"=>"call_8v3MuUICwn0AjPRy1wZMCXtf",
119
+ # "type"=>"function",
120
+ # "function"=>{"name"=>"get_current_weather", "arguments"=>"{\"location\":\"San Francisco, CA\",\"unit\":\"celsius\"}"}}]
121
+ ```
122
+
123
+
124
+ ## License
125
+
126
+ Rach is available as open source under the terms of the MIT License.
data/lib/rach/client.rb CHANGED
@@ -10,6 +10,7 @@ module Rach
10
10
 
11
11
  def chat(prompt, response_format: nil, tools: nil)
12
12
  messages = format_messages(prompt)
13
+ formatted_tools = tools&.map(&:function_schema)
13
14
 
14
15
  response = Response.new(
15
16
  @client.chat(
@@ -17,7 +18,7 @@ module Rach
17
18
  model: @model,
18
19
  messages:,
19
20
  response_format:,
20
- tools:,
21
+ tools: formatted_tools,
21
22
  }.compact
22
23
  )
23
24
  )
@@ -39,11 +39,14 @@ module Rach
39
39
 
40
40
  def clear
41
41
  @messages.clear
42
- self
43
42
  end
44
43
 
45
44
  def empty?
46
45
  @messages.empty?
47
46
  end
47
+
48
+ def pop
49
+ @messages.pop
50
+ end
48
51
  end
49
52
  end
data/lib/rach/function.rb CHANGED
@@ -80,5 +80,11 @@ module Rach
80
80
  def function_description
81
81
  raise NotImplementedError, "#{self.class} must implement #function_description"
82
82
  end
83
+
84
+ def validate_arguments!(arguments)
85
+ unless schema.validate(arguments)
86
+ raise ArgumentError, "Invalid arguments for function #{function_name}"
87
+ end
88
+ end
83
89
  end
84
90
  end
data/lib/rach/response.rb CHANGED
@@ -46,6 +46,23 @@ module Rach
46
46
  usage&.fetch("total_tokens", 0)
47
47
  end
48
48
 
49
+ def on_function(function_class = nil, &block)
50
+ return self unless function_call?
51
+
52
+ function = function_class.new
53
+ return self unless function.function_name == function_name
54
+
55
+ args = function_arguments.transform_keys(&:to_sym)
56
+ function.validate_arguments!(args)
57
+ block.call(function, args)
58
+ self
59
+ end
60
+
61
+ def on_content(&block)
62
+ block.call(content) if content
63
+ self
64
+ end
65
+
49
66
  private
50
67
 
51
68
  def message
data/lib/rach/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Rach
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rach
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Roger Garcia
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-10-30 00:00:00.000000000 Z
11
+ date: 2024-11-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -103,14 +103,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
103
103
  requirements:
104
104
  - - ">="
105
105
  - !ruby/object:Gem::Version
106
- version: '0'
106
+ version: '3.0'
107
107
  required_rubygems_version: !ruby/object:Gem::Requirement
108
108
  requirements:
109
109
  - - ">="
110
110
  - !ruby/object:Gem::Version
111
111
  version: '0'
112
112
  requirements: []
113
- rubygems_version: 3.5.3
113
+ rubygems_version: 3.5.22
114
114
  signing_key:
115
115
  specification_version: 4
116
116
  summary: Orchestrate AI agents like a virtuoso