nano-bots 0.0.3 → 0.0.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ed836839edfabe16e119f3f7e52ad82fbef851885d5adbb5b3097620d0491bfb
4
- data.tar.gz: a4f909df92cb62b9d5882ad3c9419e0c4560a15f251fa37aae92814b0e586143
3
+ metadata.gz: 1ef7d964a5303c4cf07054210b720b5e57eede718ce549cb697331911577e884
4
+ data.tar.gz: bcfad5aec3b82903fc144d58d37640458bb97e957bddd5deabf46bc890d3a1e7
5
5
  SHA512:
6
- metadata.gz: 2c8f39d6d1b0362fb936b0ee0d3df73a6efb77ee3cb86c17c754f1a129d38c01034c2deff7f37f16143a17c28446fc4ebd868e047aaf616ab298b61d0310fa4e
7
- data.tar.gz: 61ec7033e15173f2c74aeb830b48dcfaac676f7be282f3ebede3c198e710c7b92caad92649ddc84b7e3e665de2a74b4417c260aebb63caa0e0d0a3b7cdfb6fa6
6
+ metadata.gz: 816c65f1d09e912d76dfd5e651e9ae17fa9e0bb4fcbfd0932ef6498922c2c4d20422c329dfd239af90ccdd00dc8d1eb03a15ac723f0907e19fbecc79b4fcb2ad
7
+ data.tar.gz: b3254fb89ddfc4d69139130388150e986b2f750a3f56e6a068d211bff6db7413ed47b536dcbc84b04fde1c1679ea5968c7cf63e4ba62d72f07c436d64d21b611
data/Gemfile.lock CHANGED
@@ -1,13 +1,14 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- nano-bots (0.0.3)
4
+ nano-bots (0.0.5)
5
5
  babosa (~> 2.0)
6
6
  dotenv (~> 2.8, >= 2.8.1)
7
7
  faraday (~> 2.7, >= 2.7.4)
8
8
  pry (~> 0.14.2)
9
9
  rainbow (~> 3.1, >= 3.1.1)
10
10
  ruby-openai (~> 4.0)
11
+ sweet-moon (~> 0.0.7)
11
12
 
12
13
  GEM
13
14
  remote: https://rubygems.org/
@@ -23,6 +24,7 @@ GEM
23
24
  faraday-multipart (1.0.4)
24
25
  multipart-post (~> 2)
25
26
  faraday-net_http (3.0.2)
27
+ ffi (1.15.5)
26
28
  json (2.6.3)
27
29
  method_source (1.0.0)
28
30
  multipart-post (2.3.0)
@@ -73,6 +75,8 @@ GEM
73
75
  faraday-multipart (>= 1)
74
76
  ruby-progressbar (1.13.0)
75
77
  ruby2_keywords (0.0.5)
78
+ sweet-moon (0.0.7)
79
+ ffi (~> 1.15, >= 1.15.5)
76
80
  unicode-display_width (2.4.2)
77
81
 
78
82
  PLATFORMS
data/README.md CHANGED
@@ -5,7 +5,7 @@ A Ruby implementation of the [Nano Bots](https://github.com/icebaker/nano-bots)
5
5
  ![Ruby Nano Bots](https://user-images.githubusercontent.com/113217272/237839690-7880915a-b287-4484-a75e-0b96284b8a32.png)
6
6
  _Image artificially created by Midjourney through a prompt generated by a Nano Bot specialized in Midjourney._
7
7
 
8
- https://user-images.githubusercontent.com/113217272/237840989-1e29a5cc-6644-48d0-87b4-62798dc6ebd3.mp4
8
+ https://user-images.githubusercontent.com/113217272/238141567-c58a240c-7b67-4b3b-864a-0f49bbf6e22f.mp4
9
9
 
10
10
  - [Setup](#setup)
11
11
  - [Docker](#docker)
@@ -23,13 +23,13 @@ https://user-images.githubusercontent.com/113217272/237840989-1e29a5cc-6644-48d0
23
23
  For a system usage:
24
24
 
25
25
  ```sh
26
- gem install nano-bots -v 0.0.3
26
+ gem install nano-bots -v 0.0.5
27
27
  ```
28
28
 
29
29
  To use it in a project, add it to your `Gemfile`:
30
30
 
31
31
  ```ruby
32
- gem 'nano-bots', '~> 0.0.3'
32
+ gem 'nano-bots', '~> 0.0.5'
33
33
  ```
34
34
 
35
35
  ```sh
@@ -76,7 +76,7 @@ version: '3.7'
76
76
  services:
77
77
  nano-bots:
78
78
  image: ruby:3.2.2-slim-bullseye
79
- command: sh -c "gem install nano-bots -v 0.0.3 && bash"
79
+ command: sh -c "gem install nano-bots -v 0.0.5 && bash"
80
80
  environment:
81
81
  OPENAI_API_ADDRESS: https://api.openai.com
82
82
  OPENAI_API_ACCESS_TOKEN: your-token
@@ -254,5 +254,5 @@ gem build nano-bots.gemspec
254
254
 
255
255
  gem signin
256
256
 
257
- gem push nano-bots-0.0.3.gem
257
+ gem push nano-bots-0.0.5.gem
258
258
  ```
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'sweet-moon'
4
+
5
+ module NanoBot
6
+ module Components
7
+ class Adapter
8
+ def self.apply(_direction, params)
9
+ content = params[:content]
10
+
11
+ if params[:fennel] && params[:lua]
12
+ raise StandardError, 'Adapter conflict: You can only use either Lua or Fennel, not both.'
13
+ end
14
+
15
+ if params[:fennel]
16
+ content = fennel(content, params[:fennel])
17
+ elsif params[:lua]
18
+ content = lua(content, params[:lua])
19
+ end
20
+
21
+ "#{params[:prefix]}#{content}#{params[:suffix]}"
22
+ end
23
+
24
+ def self.fennel(content, expression)
25
+ path = "#{File.expand_path('../static/fennel', __dir__)}/?.lua"
26
+ state = SweetMoon::State.new(package_path: path).fennel
27
+ state.fennel.eval("(set _G.adapter (fn [content] #{expression}))")
28
+ adapter = state.get(:adapter)
29
+ adapter.call([content])
30
+ end
31
+
32
+ def self.lua(content, expression)
33
+ state = SweetMoon::State.new
34
+ state.eval("adapter = function(content) return #{expression}; end")
35
+ adapter = state.get(:adapter)
36
+ adapter.call([content])
37
+ end
38
+ end
39
+ end
40
+ end
@@ -43,7 +43,7 @@ module NanoBot
43
43
 
44
44
  partial = File.join(File.dirname(partial), File.basename(partial, File.extname(partial)))
45
45
 
46
- partial = path.sub(%r{^\.?/}, '')
46
+ partial = partial.sub(%r{^\.?/}, '')
47
47
 
48
48
  candidates << "#{directory}/#{partial}"
49
49
  candidates << "#{directory}/#{partial}.yml"
@@ -54,7 +54,7 @@ module NanoBot
54
54
 
55
55
  partial = File.join(File.dirname(partial), File.basename(partial, File.extname(partial)))
56
56
 
57
- partial = path.sub(%r{^\.?/}, '')
57
+ partial = partial.sub(%r{^\.?/}, '')
58
58
 
59
59
  candidates << "#{directory}/#{partial}"
60
60
  candidates << "#{directory}/#{partial}.yml"
@@ -23,7 +23,7 @@ module NanoBot
23
23
  end
24
24
 
25
25
  def cartridge
26
- puts YAML.dump(@safe_cartridge)
26
+ @safe_cartridge
27
27
  end
28
28
 
29
29
  def state
@@ -55,7 +55,7 @@ module NanoBot
55
55
 
56
56
  def load_cartridge!(path)
57
57
  elected_path = if path.strip == '-'
58
- File.expand_path('../static/cartridges/default.yml', __dir__)
58
+ File.expand_path('../static/cartridges/baseline.yml', __dir__)
59
59
  else
60
60
  Components::Storage.cartridge_path(path)
61
61
  end
@@ -54,9 +54,9 @@ module NanoBot
54
54
  when 'repl'
55
55
  bot.repl
56
56
  when 'state'
57
- bot.state
57
+ pp bot.state
58
58
  when 'cartridge'
59
- bot.cartridge
59
+ puts YAML.dump(bot.cartridge)
60
60
  else
61
61
  raise "TODO: [#{params[:command]}]"
62
62
  end
@@ -4,34 +4,21 @@ require 'pry'
4
4
  require 'rainbow'
5
5
 
6
6
  require_relative '../../logic/helpers/hash'
7
+ require_relative '../../logic/cartridge/affixes'
7
8
 
8
9
  module NanoBot
9
10
  module Controllers
10
11
  module Interfaces
11
12
  module Eval
12
13
  def self.evaluate(input, cartridge, session)
13
- prefix = build_prefix(cartridge)
14
- postfix = build_postfix(cartridge)
14
+ prefix = Logic::Cartridge::Affixes.get(cartridge, :eval, :output, :prefix)
15
+ suffix = Logic::Cartridge::Affixes.get(cartridge, :eval, :output, :suffix)
15
16
 
16
17
  session.print(prefix) unless prefix.nil?
17
18
 
18
19
  session.evaluate_and_print(input, mode: 'eval')
19
20
 
20
- session.print(postfix) unless postfix.nil?
21
- end
22
-
23
- def self.build_prefix(cartridge)
24
- eval_interface = Logic::Helpers::Hash.fetch(cartridge, %i[interfaces eval])
25
- return nil if eval_interface.nil?
26
-
27
- eval_interface[:prefix]
28
- end
29
-
30
- def self.build_postfix(cartridge)
31
- eval_interface = Logic::Helpers::Hash.fetch(cartridge, %i[interfaces eval])
32
- return "\n" if eval_interface.nil? || !eval_interface.key?(:postfix) # default
33
-
34
- eval_interface[:postfix]
21
+ session.print(suffix) unless suffix.nil?
35
22
  end
36
23
  end
37
24
  end
@@ -4,19 +4,20 @@ require 'pry'
4
4
  require 'rainbow'
5
5
 
6
6
  require_relative '../../logic/helpers/hash'
7
+ require_relative '../../logic/cartridge/affixes'
7
8
 
8
9
  module NanoBot
9
10
  module Controllers
10
11
  module Interfaces
11
12
  module REPL
12
13
  def self.start(cartridge, session)
13
- prefix = build_prefix(cartridge)
14
- postfix = build_postfix(cartridge)
14
+ prefix = Logic::Cartridge::Affixes.get(cartridge, :repl, :output, :prefix)
15
+ suffix = Logic::Cartridge::Affixes.get(cartridge, :repl, :output, :suffix)
15
16
 
16
17
  if Logic::Helpers::Hash.fetch(cartridge, %i[behaviors boot instruction])
17
18
  session.print(prefix) unless prefix.nil?
18
19
  session.boot(mode: 'repl')
19
- session.print(postfix) unless postfix.nil?
20
+ session.print(suffix) unless suffix.nil?
20
21
  session.print("\n")
21
22
  end
22
23
 
@@ -29,9 +30,9 @@ module NanoBot
29
30
  )
30
31
 
31
32
  Pry.commands.block_command(/(.*)/, 'handler') do |line|
32
- session.print(postfix) unless postfix.nil?
33
+ session.print(prefix) unless prefix.nil?
33
34
  session.evaluate_and_print(line, mode: 'repl')
34
- session.print(postfix) unless postfix.nil?
35
+ session.print(suffix) unless suffix.nil?
35
36
  session.print("\n")
36
37
  session.flush
37
38
  end
@@ -39,20 +40,6 @@ module NanoBot
39
40
  Pry.start
40
41
  end
41
42
 
42
- def self.build_prefix(cartridge)
43
- repl = Logic::Helpers::Hash.fetch(cartridge, %i[interfaces repl])
44
- return "\n" if repl.nil? || !repl.key?(:prefix) # default
45
-
46
- repl[:prefix]
47
- end
48
-
49
- def self.build_postfix(cartridge)
50
- repl = Logic::Helpers::Hash.fetch(cartridge, %i[interfaces repl])
51
- return "\n" if repl.nil? || !repl.key?(:postfix) # default
52
-
53
- repl[:postfix]
54
- end
55
-
56
43
  def self.build_prompt(prompt)
57
44
  result = ''
58
45
 
@@ -5,7 +5,10 @@ require 'babosa'
5
5
  require 'fileutils'
6
6
 
7
7
  require_relative '../logic/helpers/hash'
8
+ require_relative '../logic/cartridge/streaming'
9
+ require_relative '../logic/cartridge/interaction'
8
10
  require_relative '../components/storage'
11
+ require_relative '../components/adapter'
9
12
 
10
13
  module NanoBot
11
14
  module Controllers
@@ -32,12 +35,7 @@ module NanoBot
32
35
  end
33
36
 
34
37
  def state
35
- pp({
36
- state: {
37
- path: @state_path,
38
- content: @state
39
- }
40
- })
38
+ { state: { path: @state_path, content: @state } }
41
39
  end
42
40
 
43
41
  def load_state
@@ -61,24 +59,22 @@ module NanoBot
61
59
  def evaluate_and_print(message, mode:)
62
60
  behavior = Logic::Helpers::Hash.fetch(@cartridge, %i[behaviors interaction]) || {}
63
61
 
64
- @state[:history] << ({ who: 'user', message: })
62
+ @state[:history] << {
63
+ who: 'user',
64
+ message: Components::Adapter.apply(
65
+ :input, Logic::Cartridge::Interaction.input(@cartridge, mode.to_sym, message)
66
+ )
67
+ }
65
68
 
66
69
  input = { behavior:, history: @state[:history] }
67
70
 
68
71
  process(input, mode:)
69
72
  end
70
73
 
71
- def streaming(interface)
72
- provider = @provider.settings.key?(:stream) ? @provider.settings[:stream] : true
73
- interface = interface.key?(:stream) ? interface[:stream] : true
74
-
75
- provider && interface
76
- end
77
-
78
74
  def process(input, mode:)
79
75
  interface = Logic::Helpers::Hash.fetch(@cartridge, [:interfaces, mode.to_sym]) || {}
80
76
 
81
- streaming = streaming(interface)
77
+ streaming = Logic::Cartridge::Streaming.enabled?(@cartridge, mode.to_sym)
82
78
 
83
79
  input[:interface] = interface
84
80
 
@@ -87,9 +83,18 @@ module NanoBot
87
83
  ready = false
88
84
  @provider.evaluate(input) do |output, finished|
89
85
  updated_at = Time.now
86
+
90
87
  if finished
91
- @state[:history] << output
88
+ @state[:history] << Marshal.load(Marshal.dump(output))
89
+
90
+ output = Logic::Cartridge::Interaction.output(
91
+ @cartridge, mode.to_sym, output, streaming, finished
92
+ )
93
+
94
+ output[:message] = Components::Adapter.apply(:output, output[:message])
95
+
92
96
  self.print(output[:message]) unless streaming
97
+
93
98
  ready = true
94
99
  flush
95
100
  elsif streaming
@@ -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 "gem install nano-bots -v 0.0.3 && bash"
6
+ command: sh -c "apt-get update && apt-get install -y --no-install-recommends build-essential libffi-dev lua5.4-dev && gem install nano-bots -v 0.0.5 && bash"
7
7
  environment:
8
8
  OPENAI_API_ADDRESS: https://api.openai.com
9
9
  OPENAI_API_ACCESS_TOKEN: your-token
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../helpers/hash'
4
+ require_relative './default'
5
+
6
+ module NanoBot
7
+ module Logic
8
+ module Cartridge
9
+ module Adapter
10
+ def self.expression(cartridge, interface, direction, language)
11
+ adapter = [
12
+ {
13
+ exists: (Helpers::Hash.fetch(cartridge, [:interfaces, direction, :adapter]) || {}).key?(language),
14
+ value: Helpers::Hash.fetch(cartridge, [:interfaces, direction, :adapter, language])
15
+ },
16
+ {
17
+ exists: (Helpers::Hash.fetch(cartridge,
18
+ [:interfaces, interface, direction, :adapter]) || {}).key?(language),
19
+ value: Helpers::Hash.fetch(cartridge, [:interfaces, interface, direction, :adapter, language])
20
+ }
21
+ ].filter { |candidate| candidate[:exists] }.last
22
+
23
+ return nil if adapter.nil?
24
+
25
+ adapter[:value]
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../helpers/hash'
4
+ require_relative './default'
5
+
6
+ module NanoBot
7
+ module Logic
8
+ module Cartridge
9
+ module Affixes
10
+ def self.get(cartridge, interface, direction, kind)
11
+ affix = [
12
+ {
13
+ exists: (Helpers::Hash.fetch(cartridge, [:interfaces, direction]) || {}).key?(kind),
14
+ value: Helpers::Hash.fetch(cartridge, [:interfaces, direction, kind])
15
+ },
16
+ {
17
+ exists: (Helpers::Hash.fetch(cartridge, [:interfaces, interface, direction]) || {}).key?(kind),
18
+ value: Helpers::Hash.fetch(cartridge, [:interfaces, interface, direction, kind])
19
+ }
20
+ ].filter { |candidate| candidate[:exists] }.last
21
+
22
+ if affix.nil?
23
+ return Helpers::Hash.fetch(
24
+ Default.instance.values, [:interfaces, interface, direction, kind]
25
+ )
26
+ end
27
+
28
+ affix[:value]
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yaml'
4
+ require 'singleton'
5
+
6
+ require_relative '../helpers/hash'
7
+
8
+ module NanoBot
9
+ module Logic
10
+ module Cartridge
11
+ class Default
12
+ include Singleton
13
+
14
+ def values
15
+ return @values if @values
16
+
17
+ path = File.expand_path('../../static/cartridges/default.yml', __dir__)
18
+ cartridge = YAML.safe_load(File.read(path), permitted_classes: [Symbol])
19
+ @values = Logic::Helpers::Hash.symbolize_keys(cartridge)
20
+ @values
21
+ end
22
+
23
+ def baseline
24
+ return @baseline if @baseline
25
+
26
+ path = File.expand_path('../../static/cartridges/baseline.yml', __dir__)
27
+ cartridge = YAML.safe_load(File.read(path), permitted_classes: [Symbol])
28
+ @baseline = Logic::Helpers::Hash.symbolize_keys(cartridge)
29
+ @baseline
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'sweet-moon'
4
+
5
+ require_relative './affixes'
6
+ require_relative './adapters'
7
+
8
+ module NanoBot
9
+ module Logic
10
+ module Cartridge
11
+ module Interaction
12
+ def self.input(cartridge, interface, content)
13
+ lua = Adapter.expression(cartridge, interface, :input, :lua)
14
+ fennel = Adapter.expression(cartridge, interface, :input, :fennel)
15
+
16
+ prefix = Affixes.get(cartridge, interface, :input, :prefix)
17
+ suffix = Affixes.get(cartridge, interface, :input, :suffix)
18
+
19
+ { content:, prefix:, suffix:, lua:, fennel: }
20
+ end
21
+
22
+ def self.output(cartridge, interface, result, streaming, _finished)
23
+ if streaming
24
+ result[:message] = { content: result[:message], lua: nil, fennel: nil }
25
+ return result
26
+ end
27
+
28
+ lua = Adapter.expression(cartridge, interface, :output, :lua)
29
+ fennel = Adapter.expression(cartridge, interface, :output, :fennel)
30
+
31
+ result[:message] = { content: result[:message], lua:, fennel: }
32
+
33
+ result
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../helpers/hash'
4
+
5
+ module NanoBot
6
+ module Logic
7
+ module Cartridge
8
+ module Streaming
9
+ def self.enabled?(cartridge, interface)
10
+ return false if Helpers::Hash.fetch(cartridge, %i[provider settings stream]) == false
11
+
12
+ specific_interface = Helpers::Hash.fetch(cartridge, [:interfaces, interface, :output, :stream])
13
+
14
+ return specific_interface unless specific_interface.nil?
15
+
16
+ interface = Helpers::Hash.fetch(cartridge, %i[interfaces output stream])
17
+
18
+ return interface unless interface.nil?
19
+
20
+ true
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -23,6 +23,10 @@ module NanoBot
23
23
  return nil unless node
24
24
 
25
25
  path.each do |key|
26
+ unless node.is_a?(::Hash)
27
+ node = nil
28
+ break
29
+ end
26
30
  node = node[key]
27
31
  break if node.nil?
28
32
  end
data/nano-bots.gemspec CHANGED
@@ -37,6 +37,7 @@ Gem::Specification.new do |spec|
37
37
  spec.add_dependency 'pry', '~> 0.14.2'
38
38
  spec.add_dependency 'rainbow', '~> 3.1', '>= 3.1.1'
39
39
  spec.add_dependency 'ruby-openai', '~> 4.0'
40
+ spec.add_dependency 'sweet-moon', '~> 0.0.7'
40
41
 
41
42
  spec.metadata['rubygems_mfa_required'] = 'true'
42
43
  end
@@ -0,0 +1,14 @@
1
+ ---
2
+ meta:
3
+ name: Unknown
4
+ author: Nobody
5
+ version: 0.0.0
6
+
7
+ provider:
8
+ name: openai
9
+ settings:
10
+ model: gpt-3.5-turbo
11
+ credentials:
12
+ address: ENV/OPENAI_API_ADDRESS
13
+ access-token: ENV/OPENAI_API_ACCESS_TOKEN
14
+ user-identifier: ENV/OPENAI_API_USER_IDENTIFIER
@@ -1,14 +1,19 @@
1
1
  ---
2
- meta:
3
- name: Unknown
4
- author: Nobody
5
- version: 0.0.0
2
+ interfaces:
3
+ repl:
4
+ output:
5
+ stream: true
6
+ suffix: "\n"
7
+ prefix: "\n"
8
+ prompt:
9
+ - text: '🤖'
10
+ - text: '> '
11
+ color: blue
12
+ eval:
13
+ output:
14
+ stream: true
15
+ suffix: "\n"
6
16
 
7
17
  provider:
8
- name: openai
9
18
  settings:
10
- model: gpt-3.5-turbo
11
- credentials:
12
- address: ENV/OPENAI_API_ADDRESS
13
- access-token: ENV/OPENAI_API_ACCESS_TOKEN
14
- user-identifier: ENV/OPENAI_API_USER_IDENTIFIER
19
+ stream: true