intelli_agent 0.0.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 +7 -0
- data/README.md +1 -0
- data/lib/ai/agent.rb +71 -0
- data/lib/ai/agent.rb:Zone.Identifier +0 -0
- data/lib/ai/agent_test.rb_ +77 -0
- data/lib/ai/agent_test.rb_:Zone.Identifier +0 -0
- data/lib/ai.rb +56 -0
- data/lib/ai.rb:Zone.Identifier +0 -0
- metadata +63 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 3fca7e6fcb2e2360ccd76c9d09506f73db72dd525dfd771322a19a6982eedd52
|
4
|
+
data.tar.gz: 2bcb9b1cc62b6dfb9a6c4ecc634dab04e9c1c27a2941dd2feb6a0f8aad858934
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3de9eaddade5b5d5f16e385ef4cbff9bd7e7eade087b4bbc04c5c8ae2c3d0cc15ef79b518536d023f3153b62a4b748e53f735b7f33a338450db403d824c86f06
|
7
|
+
data.tar.gz: aa27675fcfc8c0bcab9701b1f0e8ca6ec09eb03f8c4fd141b9c0b63465c196f9bfcf85ad8c401eeb2c32e82930f310c3ae0fbac445f43f1e5d4dd6aa6c1622e7
|
data/README.md
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# AI Agent
|
data/lib/ai/agent.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
class AI::Agent
|
2
|
+
attr_reader :assistant, :thread, :instructions, :vector_store_id
|
3
|
+
|
4
|
+
def initialize(assistant_id: nil, thread_id: nil, thread_instructions: nil, vector_store_id: nil)
|
5
|
+
@openai_client = OpenAI::Client.new
|
6
|
+
|
7
|
+
assistant_id ||= ENV.fetch('OPENAI_AKAPU_CORE_ASSISTANT_ID')
|
8
|
+
@assistant = @openai_client.assistants.retrieve(id: assistant_id)
|
9
|
+
|
10
|
+
thread_params = {}
|
11
|
+
|
12
|
+
# Only one vector store can be attached, according to the OpenAI API documentation
|
13
|
+
@vector_store_id = vector_store_id
|
14
|
+
thread_params = { tool_resources: { file_search: { vector_store_ids: [vector_store_id] } } } if @vector_store_id
|
15
|
+
|
16
|
+
thread_id ||= @openai_client.threads.create(parameters: thread_params)['id']
|
17
|
+
@thread = @openai_client.threads.retrieve(id: thread_id)
|
18
|
+
|
19
|
+
@instructions = thread_instructions || @assistant['instructions']
|
20
|
+
end
|
21
|
+
|
22
|
+
def add_message(text, role: 'user')
|
23
|
+
@openai_client.messages.create(thread_id: @thread['id'], parameters: { role: role, content: text })
|
24
|
+
end
|
25
|
+
|
26
|
+
def messages
|
27
|
+
@openai_client.messages.list(thread_id: @thread['id'])
|
28
|
+
end
|
29
|
+
|
30
|
+
def last_message
|
31
|
+
messages['data'].first['content'].first['text']['value']
|
32
|
+
end
|
33
|
+
|
34
|
+
def run(instructions: nil, additional_instructions: nil, additional_message: nil, model: nil, tool_choice: nil)
|
35
|
+
params = { assistant_id: @assistant['id'] }
|
36
|
+
|
37
|
+
params[:instructions] = instructions || @instructions
|
38
|
+
params[:additional_instructions] = additional_instructions unless additional_instructions.nil?
|
39
|
+
params[:tool_choice] = tool_choice unless tool_choice.nil?
|
40
|
+
|
41
|
+
params[:additional_messages] = [{ role: :user, content: additional_message }] unless additional_message.nil?
|
42
|
+
|
43
|
+
params[:model] = model || @assistant['model']
|
44
|
+
|
45
|
+
run_id = @openai_client.runs.create(thread_id: @thread['id'], parameters: params)['id']
|
46
|
+
|
47
|
+
loop do
|
48
|
+
response = @openai_client.runs.retrieve(id: run_id, thread_id: @thread['id'])
|
49
|
+
|
50
|
+
case response['status']
|
51
|
+
when 'queued', 'in_progress', 'cancelling'
|
52
|
+
puts 'Status: Waiting AI Processing finish'
|
53
|
+
sleep 1
|
54
|
+
when 'completed'
|
55
|
+
puts last_message
|
56
|
+
break
|
57
|
+
when 'requires_action'
|
58
|
+
# Handle tool calls (see below)
|
59
|
+
when 'cancelled', 'failed', 'expired'
|
60
|
+
puts response['last_error'].inspect
|
61
|
+
break # or `exit`
|
62
|
+
else
|
63
|
+
puts "Unknown status response: #{status}"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def runs
|
69
|
+
@openai_client.runs.list(thread_id: @thread['id'])
|
70
|
+
end
|
71
|
+
end
|
File without changes
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'openai'
|
3
|
+
|
4
|
+
class AI::AgentTest < ActiveSupport::TestCase
|
5
|
+
def setup
|
6
|
+
@assistant_id = 'your_assistant_id'
|
7
|
+
@thread_id = 'your_thread_id'
|
8
|
+
@thread_instructions = 'your_thread_instructions'
|
9
|
+
@agent = AI::Agent.new(assistant_id: @assistant_id, thread_id: @thread_id, thread_instructions: @thread_instructions)
|
10
|
+
end
|
11
|
+
|
12
|
+
test 'add_message should create a new message in the thread' do
|
13
|
+
text = 'Hello, world!'
|
14
|
+
role = 'user'
|
15
|
+
message_params = { thread_id: @thread_id, parameters: { role: role, content: text } }
|
16
|
+
|
17
|
+
OpenAI::Client.any_instance.expects(:messages).returns(stub(create: true))
|
18
|
+
@agent.add_message(text, role: role)
|
19
|
+
|
20
|
+
assert_received(OpenAI::Client) { |expect| expect.messages.create(message_params) }
|
21
|
+
end
|
22
|
+
|
23
|
+
test 'messages should return a list of messages in the thread' do
|
24
|
+
messages_params = { thread_id: @thread_id }
|
25
|
+
|
26
|
+
OpenAI::Client.any_instance.expects(:messages).returns(stub(list: true))
|
27
|
+
@agent.messages
|
28
|
+
|
29
|
+
assert_received(OpenAI::Client) { |expect| expect.messages.list(messages_params) }
|
30
|
+
end
|
31
|
+
|
32
|
+
test 'last_message should return the content of the last message in the thread' do
|
33
|
+
message_content = 'Hello, world!'
|
34
|
+
messages_response = { 'data' => [{ 'content' => [{ 'text' => { 'value' => message_content } }] }] }
|
35
|
+
|
36
|
+
OpenAI::Client.any_instance.expects(:messages).returns(stub(list: messages_response))
|
37
|
+
assert_equal message_content, @agent.last_message
|
38
|
+
end
|
39
|
+
|
40
|
+
test 'run should create a new run in the thread' do
|
41
|
+
instructions = 'your_instructions'
|
42
|
+
additional_instructions = 'your_additional_instructions'
|
43
|
+
model = 'your_model'
|
44
|
+
run_params = { assistant_id: @assistant_id, instructions: instructions, additional_instructions: additional_instructions, model: model }
|
45
|
+
|
46
|
+
OpenAI::Client.any_instance.expects(:runs).returns(stub(create: true))
|
47
|
+
@agent.run(instructions: instructions, additional_instructions: additional_instructions, model: model)
|
48
|
+
|
49
|
+
assert_received(OpenAI::Client) { |expect| expect.runs.create(run_params) }
|
50
|
+
end
|
51
|
+
|
52
|
+
test 'runs should return a list of runs in the thread' do
|
53
|
+
runs_params = { thread_id: @thread_id }
|
54
|
+
|
55
|
+
OpenAI::Client.any_instance.expects(:runs).returns(stub(list: true))
|
56
|
+
@agent.runs
|
57
|
+
|
58
|
+
assert_received(OpenAI::Client) { |expect| expect.runs.list(runs_params) }
|
59
|
+
end
|
60
|
+
endrequire 'test_helper'
|
61
|
+
require 'artificial_intelligence/ai/agent'
|
62
|
+
|
63
|
+
class AI::AgentTest < ActiveSupport::TestCase
|
64
|
+
def setup
|
65
|
+
@agent = AI::Agent.new
|
66
|
+
end
|
67
|
+
|
68
|
+
test "agent can perform action" do
|
69
|
+
# Add your test logic here
|
70
|
+
end
|
71
|
+
|
72
|
+
test "agent can learn from experience" do
|
73
|
+
# Add your test logic here
|
74
|
+
end
|
75
|
+
|
76
|
+
# Add more tests as needed
|
77
|
+
end
|
File without changes
|
data/lib/ai.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
# In the future, this became a bus to more than one AI provider
|
2
|
+
module AI
|
3
|
+
BASIC_MODEL = ENV.fetch('OPENAI_BASIC_MODEL')
|
4
|
+
ADVANCED_MODEL = ENV.fetch('OPENAI_ADVANCED_MODEL')
|
5
|
+
|
6
|
+
def self.embed(input, model: 'text-embedding-3-large')
|
7
|
+
response = OpenAI::Client.new.embeddings(parameters: { input:, model: })
|
8
|
+
response.dig('data', 0, 'embedding')
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.single_prompt(prompt:, model: AI::BASIC_MODEL, response_format: nil)
|
12
|
+
parameters = { model:, messages: [{ role: 'user', content: prompt }] }
|
13
|
+
|
14
|
+
parameters[:response_format] = { type: 'json_object' } if response_format.eql?(:json)
|
15
|
+
|
16
|
+
response = OpenAI::Client.new.chat(parameters:)
|
17
|
+
response.dig('choices', 0, 'message', 'content').strip
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.vision(prompt:, image_url:, response_format: nil)
|
21
|
+
messages = [{ type: :text, text: prompt },
|
22
|
+
{ type: :image_url, image_url: { url: image_url } }]
|
23
|
+
|
24
|
+
parameters = { model: AI::ADVANCED_MODEL, messages: [{ role: :user, content: messages }] }
|
25
|
+
parameters[:response_format] = { type: 'json_object' } if response_format.eql?(:json)
|
26
|
+
|
27
|
+
response = OpenAI::Client.new.chat(parameters:)
|
28
|
+
|
29
|
+
response.dig('choices', 0, 'message', 'content').strip
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.single_chat(system:, user:, model: AI::BASIC_MODEL, response_format: nil)
|
33
|
+
parameters = { model:,
|
34
|
+
messages: [
|
35
|
+
{ role: 'system', content: system },
|
36
|
+
{ role: 'user', content: user }
|
37
|
+
] }
|
38
|
+
|
39
|
+
parameters[:response_format] = { type: 'json_object' } if response_format.eql?(:json)
|
40
|
+
|
41
|
+
response = OpenAI::Client.new.chat(parameters:)
|
42
|
+
response.dig('choices', 0, 'message', 'content').strip
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.chat(messages, model: AI::BASIC_MODEL, response_format: nil)
|
46
|
+
parameters = { model:, messages: }
|
47
|
+
parameters[:response_format] = { type: 'json_object' } if response_format.eql?(:json)
|
48
|
+
|
49
|
+
response = OpenAI::Client.new.chat(parameters:)
|
50
|
+
response.dig('choices', 0, 'message', 'content').strip
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.models
|
54
|
+
OpenAI::Client.new.models.list
|
55
|
+
end
|
56
|
+
end
|
File without changes
|
metadata
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: intelli_agent
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Gedean Dias
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-07-22 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: ruby-openai
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '7.1'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '7.1'
|
27
|
+
description: AI Agent.
|
28
|
+
email: gedean.dias@gmail.com
|
29
|
+
executables: []
|
30
|
+
extensions: []
|
31
|
+
extra_rdoc_files: []
|
32
|
+
files:
|
33
|
+
- README.md
|
34
|
+
- lib/ai.rb
|
35
|
+
- lib/ai.rb:Zone.Identifier
|
36
|
+
- lib/ai/agent.rb
|
37
|
+
- lib/ai/agent.rb:Zone.Identifier
|
38
|
+
- lib/ai/agent_test.rb_
|
39
|
+
- lib/ai/agent_test.rb_:Zone.Identifier
|
40
|
+
homepage: https://github.com/gedean/intelli_agent
|
41
|
+
licenses:
|
42
|
+
- MIT
|
43
|
+
metadata: {}
|
44
|
+
post_install_message: Please check readme file for use instructions.
|
45
|
+
rdoc_options: []
|
46
|
+
require_paths:
|
47
|
+
- lib
|
48
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '3'
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '0'
|
58
|
+
requirements: []
|
59
|
+
rubygems_version: 3.5.16
|
60
|
+
signing_key:
|
61
|
+
specification_version: 4
|
62
|
+
summary: AI Agent
|
63
|
+
test_files: []
|