nano-bots 0.1.1 → 1.0.0
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/.ruby-version +1 -0
- data/Gemfile +3 -2
- data/Gemfile.lock +37 -22
- data/README.md +6 -6
- data/components/adapter.rb +16 -30
- data/components/embedding.rb +89 -0
- data/components/provider.rb +1 -1
- data/components/providers/openai/tools.rb +101 -0
- data/components/providers/openai.rb +103 -20
- data/components/storage.rb +1 -1
- data/components/stream.rb +6 -1
- data/controllers/cartridges.rb +1 -1
- data/controllers/instance.rb +4 -4
- data/controllers/interfaces/cli.rb +1 -1
- data/controllers/interfaces/tools.rb +104 -0
- data/controllers/session.rb +80 -26
- data/docker-compose.example.yml +1 -1
- data/logic/cartridge/adapters.rb +1 -1
- data/logic/cartridge/affixes.rb +1 -1
- data/logic/cartridge/default.rb +2 -2
- data/logic/cartridge/fetch.rb +24 -0
- data/logic/cartridge/interaction.rb +7 -7
- data/logic/cartridge/safety.rb +39 -0
- data/logic/cartridge/tools.rb +53 -0
- data/logic/providers/openai/tools.rb +58 -0
- data/logic/providers/openai.rb +57 -0
- data/nano-bots.gemspec +3 -2
- data/static/cartridges/baseline.yml +1 -1
- data/static/cartridges/default.yml +16 -0
- data/static/fennel/fennel.lua +1538 -1734
- data/static/gem.rb +1 -1
- metadata +36 -7
data/controllers/instance.rb
CHANGED
@@ -6,9 +6,9 @@ require_relative '../logic/helpers/hash'
|
|
6
6
|
require_relative '../components/provider'
|
7
7
|
require_relative '../components/storage'
|
8
8
|
require_relative '../components/stream'
|
9
|
-
require_relative '
|
10
|
-
require_relative '
|
11
|
-
require_relative '
|
9
|
+
require_relative 'interfaces/repl'
|
10
|
+
require_relative 'interfaces/eval'
|
11
|
+
require_relative 'session'
|
12
12
|
|
13
13
|
module NanoBot
|
14
14
|
module Controllers
|
@@ -83,7 +83,7 @@ module NanoBot
|
|
83
83
|
raise StandardError, "Cartridge file not found: \"#{path}\""
|
84
84
|
end
|
85
85
|
|
86
|
-
@cartridge = YAML.
|
86
|
+
@cartridge = YAML.safe_load_file(elected_path, permitted_classes: [Symbol])
|
87
87
|
end
|
88
88
|
|
89
89
|
@safe_cartridge = Marshal.load(Marshal.dump(@cartridge))
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rainbow'
|
4
|
+
|
5
|
+
require_relative '../../logic/cartridge/tools'
|
6
|
+
require_relative '../../logic/cartridge/safety'
|
7
|
+
require_relative '../../components/embedding'
|
8
|
+
|
9
|
+
module NanoBot
|
10
|
+
module Controllers
|
11
|
+
module Interfaces
|
12
|
+
module Tool
|
13
|
+
def self.confirming(session, cartridge, mode, feedback)
|
14
|
+
yeses = Logic::Cartridge::Safety.yeses(cartridge)
|
15
|
+
default_answer = Logic::Cartridge::Safety.default_answer(cartridge)
|
16
|
+
dispatch_feedback(session, cartridge, mode, feedback)
|
17
|
+
session.flush
|
18
|
+
answer = $stdin.gets.chomp.to_s.downcase.strip
|
19
|
+
answer = default_answer if answer == ''
|
20
|
+
session.print("\n")
|
21
|
+
yeses.include?(answer)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.adapt(feedback, adapter, cartridge)
|
25
|
+
call = {
|
26
|
+
parameters: %w[id name parameters parameters-as-json output],
|
27
|
+
values: [
|
28
|
+
feedback[:id], feedback[:name], feedback[:parameters],
|
29
|
+
feedback[:parameters].to_json,
|
30
|
+
feedback[:output]
|
31
|
+
],
|
32
|
+
safety: { sandboxed: Logic::Cartridge::Safety.sandboxed?(cartridge) }
|
33
|
+
}
|
34
|
+
|
35
|
+
raise StandardError, 'conflicting adapters' if %i[fennel lua clojure].count { |key| !adapter[key].nil? } > 1
|
36
|
+
|
37
|
+
if adapter[:fennel]
|
38
|
+
call[:source] = adapter[:fennel]
|
39
|
+
Components::Embedding.fennel(**call)
|
40
|
+
elsif adapter[:clojure]
|
41
|
+
call[:source] = adapter[:clojure]
|
42
|
+
Components::Embedding.clojure(**call)
|
43
|
+
elsif adapter[:lua]
|
44
|
+
call[:parameters] = %w[id name parameters parameters_as_json output]
|
45
|
+
call[:source] = adapter[:lua]
|
46
|
+
Components::Embedding.lua(**call)
|
47
|
+
else
|
48
|
+
raise 'missing handler for adapter'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.dispatch_feedback(session, cartridge, mode, feedback)
|
53
|
+
enabled = Logic::Cartridge::Tools.feedback?(cartridge, mode.to_sym, feedback[:action].to_sym)
|
54
|
+
|
55
|
+
enabled = true if feedback[:action].to_sym == :confirming
|
56
|
+
|
57
|
+
return unless enabled
|
58
|
+
|
59
|
+
color = Logic::Cartridge::Tools.fetch_from_interface(
|
60
|
+
cartridge, mode.to_sym, feedback[:action].to_sym, [:color]
|
61
|
+
)
|
62
|
+
|
63
|
+
adapter = Tool.adapter(cartridge, mode, feedback)
|
64
|
+
|
65
|
+
if %i[fennel lua clojure].any? { |key| !adapter[key].nil? }
|
66
|
+
message = adapt(feedback, adapter, cartridge)
|
67
|
+
else
|
68
|
+
message = "#{feedback[:name]} #{feedback[:parameters].to_json}"
|
69
|
+
|
70
|
+
message += "\n#{feedback[:output]}" if feedback[:action].to_sym == :responding
|
71
|
+
end
|
72
|
+
|
73
|
+
message = "#{adapter[:prefix]}#{message}#{adapter[:suffix]}"
|
74
|
+
|
75
|
+
session.print(color.nil? ? message : Rainbow(message).send(color))
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.adapter(cartridge, mode, feedback)
|
79
|
+
prefix = Logic::Cartridge::Tools.fetch_from_interface(
|
80
|
+
cartridge, mode.to_sym, feedback[:action].to_sym, [:prefix]
|
81
|
+
)
|
82
|
+
|
83
|
+
suffix = Logic::Cartridge::Tools.fetch_from_interface(
|
84
|
+
cartridge, mode.to_sym, feedback[:action].to_sym, [:suffix]
|
85
|
+
)
|
86
|
+
|
87
|
+
fennel = Logic::Cartridge::Tools.fetch_from_interface(
|
88
|
+
cartridge, mode.to_sym, feedback[:action].to_sym, %i[adapter fennel]
|
89
|
+
)
|
90
|
+
|
91
|
+
lua = Logic::Cartridge::Tools.fetch_from_interface(
|
92
|
+
cartridge, mode.to_sym, feedback[:action].to_sym, %i[adapter lua]
|
93
|
+
)
|
94
|
+
|
95
|
+
clojure = Logic::Cartridge::Tools.fetch_from_interface(
|
96
|
+
cartridge, mode.to_sym, feedback[:action].to_sym, %i[adapter clojure]
|
97
|
+
)
|
98
|
+
|
99
|
+
{ prefix:, suffix:, fennel:, lua:, clojure: }
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
data/controllers/session.rb
CHANGED
@@ -3,10 +3,14 @@
|
|
3
3
|
require 'babosa'
|
4
4
|
|
5
5
|
require 'fileutils'
|
6
|
+
require 'rainbow'
|
6
7
|
|
7
8
|
require_relative '../logic/helpers/hash'
|
9
|
+
require_relative '../logic/cartridge/safety'
|
8
10
|
require_relative '../logic/cartridge/streaming'
|
9
11
|
require_relative '../logic/cartridge/interaction'
|
12
|
+
require_relative '../logic/cartridge/fetch'
|
13
|
+
require_relative 'interfaces/tools'
|
10
14
|
require_relative '../components/storage'
|
11
15
|
require_relative '../components/adapter'
|
12
16
|
require_relative '../components/crypto'
|
@@ -14,6 +18,7 @@ require_relative '../components/crypto'
|
|
14
18
|
module NanoBot
|
15
19
|
module Controllers
|
16
20
|
STREAM_TIMEOUT_IN_SECONDS = 5
|
21
|
+
INFINITE_LOOP_PREVENTION = 10
|
17
22
|
|
18
23
|
class Session
|
19
24
|
attr_accessor :stream
|
@@ -41,9 +46,9 @@ module NanoBot
|
|
41
46
|
end
|
42
47
|
|
43
48
|
def load_state
|
44
|
-
@state = Logic::Helpers::Hash.symbolize_keys(
|
45
|
-
|
46
|
-
|
49
|
+
@state = Logic::Helpers::Hash.symbolize_keys(
|
50
|
+
JSON.parse(Components::Crypto.decrypt(File.read(@state_path)))
|
51
|
+
)
|
47
52
|
end
|
48
53
|
|
49
54
|
def store_state!
|
@@ -68,7 +73,7 @@ module NanoBot
|
|
68
73
|
mode: mode.to_s,
|
69
74
|
input: message,
|
70
75
|
message: Components::Adapter.apply(
|
71
|
-
|
76
|
+
Logic::Cartridge::Interaction.input(@cartridge, mode.to_sym, message), @cartridge
|
72
77
|
)
|
73
78
|
}
|
74
79
|
|
@@ -78,41 +83,88 @@ module NanoBot
|
|
78
83
|
end
|
79
84
|
|
80
85
|
def process(input, mode:)
|
86
|
+
interface = Logic::Helpers::Hash.fetch(@cartridge, [:interfaces, mode.to_sym]) || {}
|
87
|
+
|
88
|
+
input[:interface] = interface
|
89
|
+
input[:tools] = @cartridge[:tools]
|
90
|
+
|
91
|
+
needs_another_round = true
|
92
|
+
|
93
|
+
rounds = 0
|
94
|
+
|
95
|
+
while needs_another_round
|
96
|
+
needs_another_round = process_interaction(input, mode:)
|
97
|
+
rounds += 1
|
98
|
+
raise StandardError, 'infinite loop prevention' if rounds > INFINITE_LOOP_PREVENTION
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def process_interaction(input, mode:)
|
81
103
|
prefix = Logic::Cartridge::Affixes.get(@cartridge, mode.to_sym, :output, :prefix)
|
82
104
|
suffix = Logic::Cartridge::Affixes.get(@cartridge, mode.to_sym, :output, :suffix)
|
83
105
|
|
84
|
-
|
106
|
+
color = Logic::Cartridge::Fetch.cascate(
|
107
|
+
@cartridge, [[:interfaces, mode.to_sym, :output, :color], %i[interfaces output color]]
|
108
|
+
)
|
85
109
|
|
86
|
-
|
110
|
+
color = color.to_sym if color
|
87
111
|
|
88
|
-
|
112
|
+
streaming = Logic::Cartridge::Streaming.enabled?(@cartridge, mode.to_sym)
|
89
113
|
|
90
114
|
updated_at = Time.now
|
91
115
|
|
92
116
|
ready = false
|
93
|
-
@provider.evaluate(input) do |output, finished|
|
94
|
-
updated_at = Time.now
|
95
|
-
|
96
|
-
if finished
|
97
|
-
event = Marshal.load(Marshal.dump(output))
|
98
117
|
|
99
|
-
|
100
|
-
@cartridge, mode.to_sym, output, streaming, finished
|
101
|
-
)
|
118
|
+
needs_another_round = false
|
102
119
|
|
103
|
-
|
120
|
+
@provider.evaluate(input, streaming, @cartridge) do |feedback|
|
121
|
+
needs_another_round = true if feedback[:needs_another_round]
|
104
122
|
|
105
|
-
|
106
|
-
event[:output] = "#{prefix}#{output[:message]}#{suffix}"
|
107
|
-
|
108
|
-
@state[:history] << event
|
109
|
-
|
110
|
-
self.print(output[:message]) unless streaming
|
123
|
+
updated_at = Time.now
|
111
124
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
125
|
+
if feedback[:interaction] &&
|
126
|
+
feedback.dig(:interaction, :meta, :tool, :action) &&
|
127
|
+
feedback[:interaction][:meta][:tool][:action] == 'confirming'
|
128
|
+
Interfaces::Tool.confirming(self, @cartridge, mode, feedback[:interaction][:meta][:tool])
|
129
|
+
else
|
130
|
+
|
131
|
+
if feedback[:interaction] && feedback.dig(:interaction, :meta, :tool, :action)
|
132
|
+
Interfaces::Tool.dispatch_feedback(
|
133
|
+
self, @cartridge, mode, feedback[:interaction][:meta][:tool]
|
134
|
+
)
|
135
|
+
end
|
136
|
+
|
137
|
+
if feedback[:interaction]
|
138
|
+
event = Marshal.load(Marshal.dump(feedback[:interaction]))
|
139
|
+
event[:mode] = mode.to_s
|
140
|
+
event[:output] = nil
|
141
|
+
|
142
|
+
if feedback[:interaction][:who] == 'AI' && feedback[:interaction][:message]
|
143
|
+
event[:output] = feedback[:interaction][:message]
|
144
|
+
unless streaming
|
145
|
+
output = Logic::Cartridge::Interaction.output(
|
146
|
+
@cartridge, mode.to_sym, feedback[:interaction], streaming, feedback[:finished]
|
147
|
+
)
|
148
|
+
output[:message] = Components::Adapter.apply(output[:message], @cartridge)
|
149
|
+
event[:output] = (output[:message]).to_s
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
@state[:history] << event if feedback[:should_be_stored]
|
154
|
+
|
155
|
+
if event[:output] && ((!feedback[:finished] && streaming) || (!streaming && feedback[:finished]))
|
156
|
+
self.print(color ? Rainbow(event[:output]).send(color) : event[:output])
|
157
|
+
end
|
158
|
+
|
159
|
+
# The `print` function already outputs a prefix and a suffix, so
|
160
|
+
# we should add them afterwards to avoid printing them twice.
|
161
|
+
event[:output] = "#{prefix}#{event[:output]}#{suffix}"
|
162
|
+
end
|
163
|
+
|
164
|
+
if feedback[:finished]
|
165
|
+
flush
|
166
|
+
ready = true
|
167
|
+
end
|
116
168
|
end
|
117
169
|
end
|
118
170
|
|
@@ -122,6 +174,8 @@ module NanoBot
|
|
122
174
|
end
|
123
175
|
|
124
176
|
store_state! unless @stateless
|
177
|
+
|
178
|
+
needs_another_round
|
125
179
|
end
|
126
180
|
|
127
181
|
def flush
|
data/docker-compose.example.yml
CHANGED
@@ -3,7 +3,7 @@ version: '3.7'
|
|
3
3
|
services:
|
4
4
|
nano-bots:
|
5
5
|
image: ruby:3.2.2-slim-bullseye
|
6
|
-
command: sh -c "apt-get update && apt-get install -y --no-install-recommends build-essential libffi-dev libsodium-dev lua5.4-dev && gem install nano-bots -v 0.
|
6
|
+
command: sh -c "apt-get update && apt-get install -y --no-install-recommends build-essential libffi-dev libsodium-dev lua5.4-dev && gem install nano-bots -v 1.0.0 && bash"
|
7
7
|
environment:
|
8
8
|
OPENAI_API_ADDRESS: https://api.openai.com
|
9
9
|
OPENAI_API_KEY: your-access-token
|
data/logic/cartridge/adapters.rb
CHANGED
data/logic/cartridge/affixes.rb
CHANGED
data/logic/cartridge/default.rb
CHANGED
@@ -15,7 +15,7 @@ module NanoBot
|
|
15
15
|
return @values if @values
|
16
16
|
|
17
17
|
path = File.expand_path('../../static/cartridges/default.yml', __dir__)
|
18
|
-
cartridge = YAML.
|
18
|
+
cartridge = YAML.safe_load_file(path, permitted_classes: [Symbol])
|
19
19
|
@values = Logic::Helpers::Hash.symbolize_keys(cartridge)
|
20
20
|
@values
|
21
21
|
end
|
@@ -24,7 +24,7 @@ module NanoBot
|
|
24
24
|
return @baseline if @baseline
|
25
25
|
|
26
26
|
path = File.expand_path('../../static/cartridges/baseline.yml', __dir__)
|
27
|
-
cartridge = YAML.
|
27
|
+
cartridge = YAML.safe_load_file(path, permitted_classes: [Symbol])
|
28
28
|
@baseline = Logic::Helpers::Hash.symbolize_keys(cartridge)
|
29
29
|
@baseline
|
30
30
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'default'
|
4
|
+
require_relative '../helpers/hash'
|
5
|
+
|
6
|
+
module NanoBot
|
7
|
+
module Logic
|
8
|
+
module Cartridge
|
9
|
+
module Fetch
|
10
|
+
def self.cascate(cartridge, paths)
|
11
|
+
results = paths.map { |path| Helpers::Hash.fetch(cartridge, path) }
|
12
|
+
result = results.find { |candidate| !candidate.nil? }
|
13
|
+
return result unless result.nil?
|
14
|
+
|
15
|
+
results = paths.map { |path| Helpers::Hash.fetch(Default.instance.values, path) }
|
16
|
+
result = results.find { |candidate| !candidate.nil? }
|
17
|
+
return result unless result.nil?
|
18
|
+
|
19
|
+
nil
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -1,9 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
require_relative './affixes'
|
6
|
-
require_relative './adapters'
|
3
|
+
require_relative 'affixes'
|
4
|
+
require_relative 'adapters'
|
7
5
|
|
8
6
|
module NanoBot
|
9
7
|
module Logic
|
@@ -12,23 +10,25 @@ module NanoBot
|
|
12
10
|
def self.input(cartridge, interface, content)
|
13
11
|
lua = Adapter.expression(cartridge, interface, :input, :lua)
|
14
12
|
fennel = Adapter.expression(cartridge, interface, :input, :fennel)
|
13
|
+
clojure = Adapter.expression(cartridge, interface, :input, :clojure)
|
15
14
|
|
16
15
|
prefix = Affixes.get(cartridge, interface, :input, :prefix)
|
17
16
|
suffix = Affixes.get(cartridge, interface, :input, :suffix)
|
18
17
|
|
19
|
-
{ content:, prefix:, suffix:, lua:, fennel: }
|
18
|
+
{ content:, prefix:, suffix:, lua:, fennel:, clojure: }
|
20
19
|
end
|
21
20
|
|
22
21
|
def self.output(cartridge, interface, result, streaming, _finished)
|
23
22
|
if streaming
|
24
|
-
result[:message] = { content: result[:message], lua: nil, fennel: nil }
|
23
|
+
result[:message] = { content: result[:message], lua: nil, fennel: nil, clojure: nil }
|
25
24
|
return result
|
26
25
|
end
|
27
26
|
|
28
27
|
lua = Adapter.expression(cartridge, interface, :output, :lua)
|
29
28
|
fennel = Adapter.expression(cartridge, interface, :output, :fennel)
|
29
|
+
clojure = Adapter.expression(cartridge, interface, :output, :clojure)
|
30
30
|
|
31
|
-
result[:message] = { content: result[:message], lua:, fennel: }
|
31
|
+
result[:message] = { content: result[:message], lua:, fennel:, clojure: }
|
32
32
|
|
33
33
|
result
|
34
34
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'fetch'
|
4
|
+
|
5
|
+
module NanoBot
|
6
|
+
module Logic
|
7
|
+
module Cartridge
|
8
|
+
module Safety
|
9
|
+
def self.default_answer(cartridge)
|
10
|
+
default = Fetch.cascate(cartridge, [%i[interfaces tools confirming default]])
|
11
|
+
return [] if default.nil?
|
12
|
+
|
13
|
+
default
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.yeses(cartridge)
|
17
|
+
yeses_values = Fetch.cascate(cartridge, [%i[interfaces tools confirming yeses]])
|
18
|
+
return [] if yeses_values.nil?
|
19
|
+
|
20
|
+
yeses_values
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.confirmable?(cartridge)
|
24
|
+
confirmable = Fetch.cascate(cartridge, [%i[safety tools confirmable]])
|
25
|
+
return true if confirmable.nil?
|
26
|
+
|
27
|
+
confirmable
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.sandboxed?(cartridge)
|
31
|
+
sandboxed = Fetch.cascate(cartridge, [%i[safety functions sandboxed]])
|
32
|
+
return true if sandboxed.nil?
|
33
|
+
|
34
|
+
sandboxed
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'fetch'
|
4
|
+
require_relative 'affixes'
|
5
|
+
require_relative 'adapters'
|
6
|
+
|
7
|
+
module NanoBot
|
8
|
+
module Logic
|
9
|
+
module Cartridge
|
10
|
+
module Tools
|
11
|
+
def self.fetch_from_interface(cartridge, interface, action, path)
|
12
|
+
Fetch.cascate(cartridge, [
|
13
|
+
[:interfaces, interface, :tools, action].concat(path),
|
14
|
+
[:interfaces, :tools, action].concat(path),
|
15
|
+
%i[interfaces tools].concat(path)
|
16
|
+
])
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.feedback?(cartridge, interface, action)
|
20
|
+
Fetch.cascate(cartridge, [
|
21
|
+
[:interfaces, interface, :tools, action, :feedback],
|
22
|
+
[:interfaces, :tools, action, :feedback],
|
23
|
+
%i[interfaces tools feedback]
|
24
|
+
])
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.input(cartridge, interface, content)
|
28
|
+
lua = Adapter.expression(cartridge, interface, :input, :lua)
|
29
|
+
fennel = Adapter.expression(cartridge, interface, :input, :fennel)
|
30
|
+
|
31
|
+
prefix = Affixes.get(cartridge, interface, :input, :prefix)
|
32
|
+
suffix = Affixes.get(cartridge, interface, :input, :suffix)
|
33
|
+
|
34
|
+
{ content:, prefix:, suffix:, lua:, fennel: }
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.output(cartridge, interface, result, streaming, _finished)
|
38
|
+
if streaming
|
39
|
+
result[:message] = { content: result[:message], lua: nil, fennel: nil }
|
40
|
+
return result
|
41
|
+
end
|
42
|
+
|
43
|
+
lua = Adapter.expression(cartridge, interface, :output, :lua)
|
44
|
+
fennel = Adapter.expression(cartridge, interface, :output, :fennel)
|
45
|
+
|
46
|
+
result[:message] = { content: result[:message], lua:, fennel: }
|
47
|
+
|
48
|
+
result
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
require_relative '../../helpers/hash'
|
6
|
+
|
7
|
+
module NanoBot
|
8
|
+
module Logic
|
9
|
+
module OpenAI
|
10
|
+
module Tools
|
11
|
+
def self.prepare(cartridge, tools)
|
12
|
+
applies = []
|
13
|
+
|
14
|
+
tools = Marshal.load(Marshal.dump(tools))
|
15
|
+
|
16
|
+
tools.each do |tool|
|
17
|
+
tool = Helpers::Hash.symbolize_keys(tool)
|
18
|
+
|
19
|
+
cartridge.each do |candidate|
|
20
|
+
next unless tool[:function][:name] == candidate[:name]
|
21
|
+
|
22
|
+
source = {}
|
23
|
+
|
24
|
+
source[:clojure] = candidate[:clojure] if candidate[:clojure]
|
25
|
+
source[:fennel] = candidate[:fennel] if candidate[:fennel]
|
26
|
+
source[:lua] = candidate[:lua] if candidate[:lua]
|
27
|
+
|
28
|
+
applies << {
|
29
|
+
id: tool[:id],
|
30
|
+
name: tool[:function][:name],
|
31
|
+
type: 'function',
|
32
|
+
parameters: JSON.parse(tool[:function][:arguments]),
|
33
|
+
source:
|
34
|
+
}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
raise 'missing tool' if applies.size != tools.size
|
39
|
+
|
40
|
+
applies
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.adapt(cartridge)
|
44
|
+
output = {
|
45
|
+
type: 'function',
|
46
|
+
function: {
|
47
|
+
name: cartridge[:name], description: cartridge[:description]
|
48
|
+
}
|
49
|
+
}
|
50
|
+
|
51
|
+
output[:function][:parameters] = (cartridge[:parameters] || { type: 'object', properties: {} })
|
52
|
+
|
53
|
+
output
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module NanoBot
|
6
|
+
module Logic
|
7
|
+
module OpenAI
|
8
|
+
def self.prepare_tools(cartridge, tools)
|
9
|
+
applies = []
|
10
|
+
tools.each do |tool|
|
11
|
+
cartridge.each do |candidate|
|
12
|
+
next unless candidate[:type] == 'function' &&
|
13
|
+
tool[:type] == candidate[:type] &&
|
14
|
+
tool[:function][:name] == candidate[:name]
|
15
|
+
|
16
|
+
source = {}
|
17
|
+
|
18
|
+
source[:fennel] = candidate[:fennel] if candidate[:fennel]
|
19
|
+
source[:lua] = candidate[:lua] if candidate[:lua]
|
20
|
+
|
21
|
+
applies << {
|
22
|
+
name: tool[:function][:name],
|
23
|
+
type: candidate[:type],
|
24
|
+
parameters: JSON.parse(tool[:function][:arguments]),
|
25
|
+
source:
|
26
|
+
}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
applies
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.adapt_tool(cartridge)
|
34
|
+
raise 'unsupported tool' if cartridge[:type] != 'function'
|
35
|
+
|
36
|
+
adapted = {
|
37
|
+
type: 'function',
|
38
|
+
function: {
|
39
|
+
name: cartridge[:name], description: cartridge[:description],
|
40
|
+
parameters: { type: 'object', properties: {} }
|
41
|
+
}
|
42
|
+
}
|
43
|
+
|
44
|
+
properties = adapted[:function][:parameters][:properties]
|
45
|
+
|
46
|
+
cartridge[:parameters].each do |parameter|
|
47
|
+
key = parameter[:name].to_sym
|
48
|
+
properties[key] = {}
|
49
|
+
properties[key][:type] = parameter[:type] || 'string'
|
50
|
+
properties[key][:description] = parameter[:description] if parameter[:description]
|
51
|
+
end
|
52
|
+
|
53
|
+
adapted
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
data/nano-bots.gemspec
CHANGED
@@ -32,12 +32,13 @@ Gem::Specification.new do |spec|
|
|
32
32
|
spec.executables = ['nb']
|
33
33
|
|
34
34
|
spec.add_dependency 'babosa', '~> 2.0'
|
35
|
+
spec.add_dependency 'concurrent-ruby', '~> 1.2', '>= 1.2.2'
|
35
36
|
spec.add_dependency 'dotenv', '~> 2.8', '>= 2.8.1'
|
36
|
-
spec.add_dependency 'faraday', '~> 2.7', '>= 2.7.
|
37
|
+
spec.add_dependency 'faraday', '~> 2.7', '>= 2.7.12'
|
37
38
|
spec.add_dependency 'pry', '~> 0.14.2'
|
38
39
|
spec.add_dependency 'rainbow', '~> 3.1', '>= 3.1.1'
|
39
40
|
spec.add_dependency 'rbnacl', '~> 7.1', '>= 7.1.1'
|
40
|
-
spec.add_dependency 'ruby-openai', '~>
|
41
|
+
spec.add_dependency 'ruby-openai', '~> 6.3'
|
41
42
|
spec.add_dependency 'sweet-moon', '~> 0.0.7'
|
42
43
|
|
43
44
|
spec.metadata['rubygems_mfa_required'] = 'true'
|
@@ -1,4 +1,10 @@
|
|
1
1
|
---
|
2
|
+
safety:
|
3
|
+
functions:
|
4
|
+
sandboxed: true
|
5
|
+
tools:
|
6
|
+
confirmable: true
|
7
|
+
|
2
8
|
interfaces:
|
3
9
|
repl:
|
4
10
|
output:
|
@@ -12,6 +18,16 @@ interfaces:
|
|
12
18
|
output:
|
13
19
|
stream: true
|
14
20
|
suffix: "\n"
|
21
|
+
tools:
|
22
|
+
confirming:
|
23
|
+
suffix: ' [yN] '
|
24
|
+
default: 'n'
|
25
|
+
yeses: ['y', 'yes']
|
26
|
+
executing:
|
27
|
+
feedback: false
|
28
|
+
responding:
|
29
|
+
suffix: "\n\n"
|
30
|
+
feedback: true
|
15
31
|
|
16
32
|
provider:
|
17
33
|
settings:
|