activeai 0.1.2 → 0.1.3
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/README.md +6 -0
- data/lib/activeai/behavior/llm/conversation.rb +1 -1
- data/lib/activeai/behavior/llm/follow_structured_examples.rb +3 -3
- data/lib/activeai/behavior/llm/write_function_call.rb +35 -0
- data/lib/activeai/behavior/llm.rb +3 -2
- data/lib/activeai/controller.rb +21 -8
- data/lib/activeai/router.rb +33 -17
- data/lib/activeai/version.rb +1 -1
- data/lib/activeai.rb +12 -0
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a327faafb1ed168dfbbfce2c3f5beed3b6090c8ed5c95d24913d988e39227143
|
4
|
+
data.tar.gz: f3bb5b04eabc7838193f099e649f5dbe48ae3f151537b28469d1b6738848fb00
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c3530fdce13cab64414b9b921a49672cd2dae8c170e6f50af5486fe30b33055403a1ef37b6a8c2e3172178ff61ac8c4d26292a3708877111d329cecb0dc59a72
|
7
|
+
data.tar.gz: 9dc7550488f4dab988b11719a065f0e7fd0c17afa2712c6670b97e8300969fb9d218ac47e2939d295134e5313594f00f45e8838c34c5d9fb178237e3292adcce
|
data/README.md
CHANGED
@@ -39,6 +39,12 @@ puts result
|
|
39
39
|
#=> 'tomatoes, jam'
|
40
40
|
```
|
41
41
|
|
42
|
+
### Behavior: WriteFunctionCall
|
43
|
+
|
44
|
+
#### TODO
|
45
|
+
|
46
|
+
This lets you use `code-davinci-002` or `code-cushman-001` to run logic. The router uses this internally. Supply a list of example pairs that are a "description" and "code", and then you can complete another one.
|
47
|
+
|
42
48
|
### TODO: with other patterns
|
43
49
|
|
44
50
|
### TODO: auto-detected behavior pattern from config
|
@@ -20,7 +20,7 @@ class ActiveAI::Behavior::LLM::Conversation < ActiveAI::Behavior::LLM
|
|
20
20
|
# TODO use the label key they provide in the yml file
|
21
21
|
end,
|
22
22
|
"Conversation:\n" + @state['conversation']
|
23
|
-
].join(
|
23
|
+
].join(LINE_SEPARATOR)
|
24
24
|
end
|
25
25
|
|
26
26
|
def add(speaker, message)
|
@@ -15,12 +15,12 @@ class ActiveAI::Behavior::LLM::FollowStructuredExamples < ActiveAI::Behavior::LL
|
|
15
15
|
example.map do |key, value|
|
16
16
|
"#{key}: #{value}"
|
17
17
|
end.join("\n")
|
18
|
-
end.join(
|
19
|
-
].join(
|
18
|
+
end.join(LINE_SEPARATOR)
|
19
|
+
].join(LINE_SEPARATOR)
|
20
20
|
end
|
21
21
|
|
22
22
|
def call(input={}, extract: []) # TODO cool splat stuff?
|
23
|
-
prompt = base_prompt +
|
23
|
+
prompt = base_prompt + LINE_SEPARATOR
|
24
24
|
|
25
25
|
prompt += input.map do |key, value|
|
26
26
|
"#{key}: #{value}"
|
@@ -0,0 +1,35 @@
|
|
1
|
+
class ActiveAI::Behavior::LLM::WriteFunctionCall < ActiveAI::Behavior::LLM
|
2
|
+
def initialize(llm, state)
|
3
|
+
super(llm)
|
4
|
+
@state = state
|
5
|
+
# TODO raise errors if not expected thingies available in the config
|
6
|
+
end
|
7
|
+
|
8
|
+
def base_prompt
|
9
|
+
@state[:examples].map do |example|
|
10
|
+
[
|
11
|
+
"// #{example[:description]}",
|
12
|
+
example[:code]
|
13
|
+
].join("\n")
|
14
|
+
end.join("\n\n") + "\n\n"
|
15
|
+
end
|
16
|
+
|
17
|
+
def call(comment)
|
18
|
+
prompt = base_prompt + "\n\n"
|
19
|
+
prompt += "//#{comment}\n"
|
20
|
+
complete_result = complete(prompt, stop: "\n")
|
21
|
+
|
22
|
+
# TODO stop \n works for the router but not for other stuff, later
|
23
|
+
|
24
|
+
completion = complete_result['choices'][0]['text']
|
25
|
+
|
26
|
+
matcher = /(.*)\((.*)\)/
|
27
|
+
matches = matcher.match(completion)
|
28
|
+
|
29
|
+
return {
|
30
|
+
text: completion.strip,
|
31
|
+
path: matches[1],
|
32
|
+
params: matches[2].presence && JSON.parse(matches[2])
|
33
|
+
}
|
34
|
+
end
|
35
|
+
end
|
@@ -7,7 +7,7 @@ class ActiveAI::Behavior::LLM < ActiveAI::Behavior::Base
|
|
7
7
|
@llm.complete(prompt: prompt, stop: stop)
|
8
8
|
end
|
9
9
|
|
10
|
-
|
10
|
+
LINE_SEPARATOR = "\n\n###\n\n"
|
11
11
|
|
12
12
|
def extract_keys(completion, extract)
|
13
13
|
matcher_string = extract.map{ |key| "#{key}:(.*)" }.join
|
@@ -25,5 +25,6 @@ class ActiveAI::Behavior::LLM < ActiveAI::Behavior::Base
|
|
25
25
|
end
|
26
26
|
|
27
27
|
require_relative "llm/conversation"
|
28
|
-
require_relative "llm/unstructured"
|
29
28
|
require_relative "llm/follow_structured_examples"
|
29
|
+
require_relative "llm/unstructured"
|
30
|
+
require_relative "llm/write_function_call"
|
data/lib/activeai/controller.rb
CHANGED
@@ -9,20 +9,33 @@ class ActiveAI::Controller
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def self.load_routing(routes_config)
|
12
|
-
@llm = ActiveAI::NeuralNetwork::GPT3.new(ActiveAI.config[:gpt3_token], model: '
|
13
|
-
|
12
|
+
@llm = ActiveAI::NeuralNetwork::GPT3.new(ActiveAI.config[:gpt3_token], model: 'code-davinci-002', temperature: 0.2)
|
13
|
+
|
14
|
+
examples = ActiveAI.route_examples_to_function_call_examples(routes_config['examples'])
|
15
|
+
self.routing_behavior = ActiveAI::Behavior::LLM::WriteFunctionCall.new(@llm, { examples: examples })
|
14
16
|
end
|
15
17
|
|
16
18
|
attr_accessor :params
|
17
19
|
|
18
20
|
def prepare_action(request)
|
19
|
-
|
20
|
-
|
21
|
+
# samples to parse:
|
22
|
+
# plugins.slack.send_message({ \"channel\": \"#general\", \"text\": \"Hi\" })
|
23
|
+
# unmatched()
|
24
|
+
|
25
|
+
function = self.class.routing_behavior.call(request)
|
26
|
+
*controller_path, action_name = function[:path].split(".")
|
27
|
+
controller_name = controller_path.join("/").presence
|
28
|
+
|
21
29
|
# TODO verify it's the right controller and the action name exists and it's not a reserved / internal thing
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
30
|
+
|
31
|
+
if controller_name.present?
|
32
|
+
return {
|
33
|
+
action: action_name,
|
34
|
+
params: function[:params]
|
35
|
+
}
|
36
|
+
else
|
37
|
+
return nil
|
38
|
+
end
|
26
39
|
end
|
27
40
|
|
28
41
|
def call(request)
|
data/lib/activeai/router.rb
CHANGED
@@ -4,7 +4,7 @@ class ActiveAI::Router
|
|
4
4
|
|
5
5
|
def initialize
|
6
6
|
@routings = []
|
7
|
-
@llm = ActiveAI::NeuralNetwork::GPT3.new(ActiveAI.config[:gpt3_token], model: '
|
7
|
+
@llm = ActiveAI::NeuralNetwork::GPT3.new(ActiveAI.config[:gpt3_token], model: 'code-davinci-002', temperature: 0.2)
|
8
8
|
end
|
9
9
|
|
10
10
|
def add_controller_routing(routing)
|
@@ -24,26 +24,42 @@ class ActiveAI::Router
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def behavior
|
27
|
-
|
28
|
-
'
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
}
|
37
|
-
|
38
|
-
ActiveAI::Behavior::LLM::FollowStructuredExamples.new(@llm, config)
|
27
|
+
raw_examples = [UNMATCHED] + @routings.map do |routing|
|
28
|
+
routing['examples'].reject do |example|
|
29
|
+
example['Route'] == 'None'
|
30
|
+
end.map do |example|
|
31
|
+
example.slice('Match', 'Route')
|
32
|
+
end
|
33
|
+
end.flatten
|
34
|
+
examples = ActiveAI.route_examples_to_function_call_examples(raw_examples)
|
35
|
+
|
36
|
+
ActiveAI::Behavior::LLM::WriteFunctionCall.new(@llm, { examples: examples })
|
39
37
|
end
|
40
38
|
|
39
|
+
# def behavior_via_structured_examples
|
40
|
+
# config = {
|
41
|
+
# 'instruction' => INSTRUCTION,
|
42
|
+
# 'examples' => [UNMATCHED] + @routings.map do |routing|
|
43
|
+
# routing['examples'].reject do |example|
|
44
|
+
# example['Route'] == 'None'
|
45
|
+
# end.map do |example|
|
46
|
+
# example.slice('Match', 'Route')
|
47
|
+
# end
|
48
|
+
# end.flatten
|
49
|
+
# }
|
50
|
+
|
51
|
+
# ActiveAI::Behavior::LLM::FollowStructuredExamples.new(@llm, config)
|
52
|
+
# end
|
53
|
+
|
41
54
|
def find_controller(request)
|
42
|
-
# should return
|
43
|
-
routing = behavior.call({ 'Request' => request }, extract: %W[Route])
|
44
|
-
controller_name, action_name = routing['Route'].split('#')
|
55
|
+
function = behavior.call(request) # TODO maybe the behavior should return function and params as well. seems right
|
45
56
|
|
46
|
-
|
57
|
+
*controller_path, action_name = function[:path].split(".")
|
58
|
+
controller_name = controller_path.join("/").presence
|
59
|
+
|
60
|
+
# TODO verify it's the right controller and the action name exists and it's not a reserved / internal thing
|
61
|
+
|
62
|
+
if controller_name.blank? || action_name.blank? || action_name == 'unmatched'
|
47
63
|
return nil
|
48
64
|
else
|
49
65
|
return (controller_name + "_controller").classify.constantize
|
data/lib/activeai/version.rb
CHANGED
data/lib/activeai.rb
CHANGED
@@ -16,5 +16,17 @@ module ActiveAI
|
|
16
16
|
}
|
17
17
|
end
|
18
18
|
|
19
|
+
def self.route_examples_to_function_call_examples(examples)
|
20
|
+
examples.map do |example|
|
21
|
+
function = example['Route'].gsub('/','.').gsub('#','.')
|
22
|
+
function = "unmatched" if function == "None"
|
23
|
+
|
24
|
+
{
|
25
|
+
description: example['Match'],
|
26
|
+
code: "#{function}(#{example['Params']&.strip})"
|
27
|
+
}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
19
31
|
end
|
20
32
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activeai
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- jeriko
|
@@ -64,6 +64,7 @@ files:
|
|
64
64
|
- lib/activeai/behavior/llm/conversation.rb
|
65
65
|
- lib/activeai/behavior/llm/follow_structured_examples.rb
|
66
66
|
- lib/activeai/behavior/llm/unstructured.rb
|
67
|
+
- lib/activeai/behavior/llm/write_function_call.rb
|
67
68
|
- lib/activeai/configuration.rb
|
68
69
|
- lib/activeai/controller.rb
|
69
70
|
- lib/activeai/neural_network.rb
|