intelli_agent 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|