nano-bots 2.5.1 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fcaf16c41f69802d1287b6ee3cebf9d66aede4da329aff6f195fb52234271b6b
4
- data.tar.gz: f3ee08d1382fb0f6a174fee054452acb58fd4b756bbbabef7e3107e43fc50069
3
+ metadata.gz: e8c2efff966a76151fb23a83f4c77bc5af780f31898194747c53d8ddd2ff2877
4
+ data.tar.gz: 94642cd59c39f0f9d308e97fe3736bb3d89f529928d3e3896f4c1351a2f10fed
5
5
  SHA512:
6
- metadata.gz: e301f25d8653f9127015ce5bc66d38aaa20b5f024b6d5cb0fb218f27898cc18147cb6f3d0b3f89d1b0a6bf9c55e62c46dc10ebb577dfe4e47daef1b3452dd401
7
- data.tar.gz: cec8dbcbc256d29aebe5ea35572bb6378fdb742c22f27ccc9e801817be3855f7c415d16353cb5fb187a3a09af8854e4e6915e6db37738fd8d97e9f992c50ea45
6
+ metadata.gz: ff0d2f67a1126a43443cd231184ad3dd02dea9c34178d6aa5da4c49cfdcceb137ab24af7bbaaad83d3e9c61d7019b2ba2950c15b7c1c7d072abc24de8eb8a5a7
7
+ data.tar.gz: 6850151d3af95c232c800e891e4c6ef8ee610030e6f9e45d24c623d497b1d61804f4b709e35b682ad89781fbb5b304d2e9b1048ae0150abaffdec9a0b2084f03
data/Gemfile CHANGED
@@ -8,5 +8,5 @@ group :test, :development do
8
8
  gem 'pry-byebug', '~> 3.10', '>= 3.10.1'
9
9
  gem 'rspec', '~> 3.12'
10
10
  gem 'rubocop', '~> 1.59'
11
- gem 'rubocop-rspec', '~> 2.25'
11
+ gem 'rubocop-rspec', '~> 2.26', '>= 2.26.1'
12
12
  end
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- nano-bots (2.5.1)
4
+ nano-bots (3.0.0)
5
5
  babosa (~> 2.0)
6
6
  cohere-ai (~> 1.0, >= 1.0.1)
7
7
  concurrent-ruby (~> 1.2, >= 1.2.2)
@@ -13,6 +13,7 @@ PATH
13
13
  pry (~> 0.14.2)
14
14
  rainbow (~> 3.1, >= 3.1.1)
15
15
  rbnacl (~> 7.1, >= 7.1.1)
16
+ redcarpet (~> 3.6)
16
17
  ruby-openai (~> 6.3, >= 6.3.1)
17
18
  sweet-moon (~> 0.0.7)
18
19
 
@@ -23,7 +24,6 @@ GEM
23
24
  public_suffix (>= 2.0.2, < 6.0)
24
25
  ast (2.4.2)
25
26
  babosa (2.0.0)
26
- base64 (0.2.0)
27
27
  byebug (11.1.3)
28
28
  coderay (1.1.3)
29
29
  cohere-ai (1.0.1)
@@ -32,13 +32,12 @@ GEM
32
32
  diff-lcs (1.5.0)
33
33
  dotenv (2.8.1)
34
34
  event_stream_parser (1.0.0)
35
- faraday (2.8.1)
36
- base64
37
- faraday-net_http (>= 2.0, < 3.1)
38
- ruby2_keywords (>= 0.0.4)
35
+ faraday (2.9.0)
36
+ faraday-net_http (>= 2.0, < 3.2)
39
37
  faraday-multipart (1.0.4)
40
38
  multipart-post (~> 2)
41
- faraday-net_http (3.0.2)
39
+ faraday-net_http (3.1.0)
40
+ net-http
42
41
  ffi (1.16.3)
43
42
  gemini-ai (3.1.2)
44
43
  event_stream_parser (~> 1.0)
@@ -64,11 +63,13 @@ GEM
64
63
  faraday (~> 2.8, >= 2.8.1)
65
64
  multi_json (1.15.0)
66
65
  multipart-post (2.3.0)
66
+ net-http (0.4.1)
67
+ uri
67
68
  ollama-ai (1.0.0)
68
69
  faraday (~> 2.8)
69
70
  os (1.1.4)
70
71
  parallel (1.24.0)
71
- parser (3.3.0.1)
72
+ parser (3.3.0.2)
72
73
  ast (~> 2.4.1)
73
74
  racc
74
75
  pry (0.14.2)
@@ -82,7 +83,8 @@ GEM
82
83
  rainbow (3.1.1)
83
84
  rbnacl (7.1.1)
84
85
  ffi
85
- regexp_parser (2.8.3)
86
+ redcarpet (3.6.0)
87
+ regexp_parser (2.9.0)
86
88
  rexml (3.2.6)
87
89
  rspec (3.12.0)
88
90
  rspec-core (~> 3.12.0)
@@ -112,8 +114,8 @@ GEM
112
114
  parser (>= 3.2.1.0)
113
115
  rubocop-capybara (2.20.0)
114
116
  rubocop (~> 1.41)
115
- rubocop-factory_bot (2.25.0)
116
- rubocop (~> 1.33)
117
+ rubocop-factory_bot (2.25.1)
118
+ rubocop (~> 1.41)
117
119
  rubocop-rspec (2.26.1)
118
120
  rubocop (~> 1.40)
119
121
  rubocop-capybara (~> 2.17)
@@ -123,7 +125,6 @@ GEM
123
125
  faraday (>= 1)
124
126
  faraday-multipart (>= 1)
125
127
  ruby-progressbar (1.13.0)
126
- ruby2_keywords (0.0.5)
127
128
  signet (0.18.0)
128
129
  addressable (~> 2.8)
129
130
  faraday (>= 0.17.5, < 3.a)
@@ -132,6 +133,7 @@ GEM
132
133
  sweet-moon (0.0.7)
133
134
  ffi (~> 1.15, >= 1.15.5)
134
135
  unicode-display_width (2.5.0)
136
+ uri (0.13.0)
135
137
 
136
138
  PLATFORMS
137
139
  x86_64-linux
@@ -141,7 +143,7 @@ DEPENDENCIES
141
143
  pry-byebug (~> 3.10, >= 3.10.1)
142
144
  rspec (~> 3.12)
143
145
  rubocop (~> 1.59)
144
- rubocop-rspec (~> 2.25)
146
+ rubocop-rspec (~> 2.26, >= 2.26.1)
145
147
 
146
148
  BUNDLED WITH
147
149
  2.4.22
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Nano Bots 💎 🤖
2
2
 
3
- An implementation of the [Nano Bots](https://spec.nbots.io) specification with support for [Cohere Command](https://cohere.com), [Google Gemini](https://deepmind.google/technologies/gemini), [Maritaca AI MariTalk](https://www.maritaca.ai), [Mistral AI](https://mistral.ai), [Ollama](https://ollama.ai), [OpenAI ChatGPT](https://openai.com/chatgpt), and others.
3
+ An implementation of the [Nano Bots](https://spec.nbots.io) specification with support for [Cohere Command](https://cohere.com), [Google Gemini](https://deepmind.google/technologies/gemini), [Maritaca AI MariTalk](https://www.maritaca.ai), [Mistral AI](https://mistral.ai), [Ollama](https://ollama.ai), [OpenAI ChatGPT](https://openai.com/chatgpt), and others, with support for calling tools (functions).
4
4
 
5
5
  ![Ruby Nano Bots](https://raw.githubusercontent.com/icebaker/assets/main/nano-bots/ruby-nano-bots-canvas.png)
6
6
 
@@ -9,7 +9,7 @@ https://user-images.githubusercontent.com/113217272/238141567-c58a240c-7b67-4b3b
9
9
  ## TL;DR and Quick Start
10
10
 
11
11
  ```sh
12
- gem install nano-bots -v 2.5.1
12
+ gem install nano-bots -v 3.0.0
13
13
  ```
14
14
 
15
15
  ```bash
@@ -34,13 +34,22 @@ well. How can I assist you?
34
34
  ---
35
35
  meta:
36
36
  symbol: 🤖
37
- name: ChatGPT
37
+ name: Nano Bot Name
38
+ author: Your Name
39
+ version: 1.0.0
40
+ license: CC0-1.0
41
+ description: A helpful assistant.
42
+
43
+ behaviors:
44
+ interaction:
45
+ directive: You are a helpful assistant.
38
46
 
39
47
  provider:
40
48
  id: openai
41
49
  credentials:
42
50
  access-token: ENV/OPENAI_API_KEY
43
51
  settings:
52
+ user: ENV/NANO_BOTS_END_USER
44
53
  model: gpt-4-1106-preview
45
54
  ```
46
55
 
@@ -50,7 +59,7 @@ nb gpt.yml - eval "hi"
50
59
  ```
51
60
 
52
61
  ```ruby
53
- gem 'nano-bots', '~> 2.5.1'
62
+ gem 'nano-bots', '~> 3.0.0'
54
63
  ```
55
64
 
56
65
  ```ruby
@@ -241,13 +250,13 @@ end
241
250
  To install the CLI on your system:
242
251
 
243
252
  ```sh
244
- gem install nano-bots -v 2.5.1
253
+ gem install nano-bots -v 3.0.0
245
254
  ```
246
255
 
247
256
  To use it in a Ruby project as a library, add to your `Gemfile`:
248
257
 
249
258
  ```ruby
250
- gem 'nano-bots', '~> 2.5.1'
259
+ gem 'nano-bots', '~> 3.0.0'
251
260
  ```
252
261
 
253
262
  ```sh
@@ -260,8 +269,8 @@ For credentials and configurations, relevant environment variables can be set in
260
269
  export NANO_BOTS_ENCRYPTION_PASSWORD=UNSAFE
261
270
  export NANO_BOTS_END_USER=your-user
262
271
 
263
- # export NANO_BOTS_STATE_DIRECTORY=/home/user/.local/state/nano-bots
264
- # export NANO_BOTS_CARTRIDGES_DIRECTORY=/home/user/.local/share/nano-bots/cartridges
272
+ # export NANO_BOTS_STATE_PATH=/home/user/.local/state/nano-bots
273
+ # export NANO_BOTS_CARTRIDGES_PATH=/home/user/.local/share/nano-bots/cartridges
265
274
  ```
266
275
 
267
276
  Alternatively, if your current directory has a `.env` file with the environment variables, they will be automatically loaded:
@@ -270,8 +279,8 @@ Alternatively, if your current directory has a `.env` file with the environment
270
279
  NANO_BOTS_ENCRYPTION_PASSWORD=UNSAFE
271
280
  NANO_BOTS_END_USER=your-user
272
281
 
273
- # NANO_BOTS_STATE_DIRECTORY=/home/user/.local/state/nano-bots
274
- # NANO_BOTS_CARTRIDGES_DIRECTORY=/home/user/.local/share/nano-bots/cartridges
282
+ # NANO_BOTS_STATE_PATH=/home/user/.local/state/nano-bots
283
+ # NANO_BOTS_CARTRIDGES_PATH=/home/user/.local/share/nano-bots/cartridges
275
284
  ```
276
285
 
277
286
  ### Cohere Command
@@ -954,7 +963,7 @@ cd ruby-nano-bots
954
963
  cp docker-compose.example.yml docker-compose.yml
955
964
  ```
956
965
 
957
- Set your provider credentials and choose your desired directory for the cartridges files:
966
+ Set your provider credentials and choose your desired path for the cartridges files:
958
967
 
959
968
  ### Cohere Command Container
960
969
 
@@ -963,7 +972,7 @@ Set your provider credentials and choose your desired directory for the cartridg
963
972
  services:
964
973
  nano-bots:
965
974
  image: ruby:3.2.2-slim-bookworm
966
- command: sh -c "apt-get update && apt-get install -y --no-install-recommends build-essential libffi-dev libsodium-dev lua5.4-dev curl && curl -s https://raw.githubusercontent.com/babashka/babashka/master/install | bash && gem install nano-bots -v 2.5.1 && bash"
975
+ command: sh -c "apt-get update && apt-get install -y --no-install-recommends build-essential libffi-dev libsodium-dev lua5.4-dev curl && curl -s https://raw.githubusercontent.com/babashka/babashka/master/install | bash && gem install nano-bots -v 3.0.0 && bash"
967
976
  environment:
968
977
  COHERE_API_KEY: your-api-key
969
978
  NANO_BOTS_ENCRYPTION_PASSWORD: UNSAFE
@@ -980,7 +989,7 @@ services:
980
989
  services:
981
990
  nano-bots:
982
991
  image: ruby:3.2.2-slim-bookworm
983
- command: sh -c "apt-get update && apt-get install -y --no-install-recommends build-essential libffi-dev libsodium-dev lua5.4-dev curl && curl -s https://raw.githubusercontent.com/babashka/babashka/master/install | bash && gem install nano-bots -v 2.5.1 && bash"
992
+ command: sh -c "apt-get update && apt-get install -y --no-install-recommends build-essential libffi-dev libsodium-dev lua5.4-dev curl && curl -s https://raw.githubusercontent.com/babashka/babashka/master/install | bash && gem install nano-bots -v 3.0.0 && bash"
984
993
  environment:
985
994
  MARITACA_API_KEY: your-api-key
986
995
  NANO_BOTS_ENCRYPTION_PASSWORD: UNSAFE
@@ -997,7 +1006,7 @@ services:
997
1006
  services:
998
1007
  nano-bots:
999
1008
  image: ruby:3.2.2-slim-bookworm
1000
- command: sh -c "apt-get update && apt-get install -y --no-install-recommends build-essential libffi-dev libsodium-dev lua5.4-dev curl && curl -s https://raw.githubusercontent.com/babashka/babashka/master/install | bash && gem install nano-bots -v 2.5.1 && bash"
1009
+ command: sh -c "apt-get update && apt-get install -y --no-install-recommends build-essential libffi-dev libsodium-dev lua5.4-dev curl && curl -s https://raw.githubusercontent.com/babashka/babashka/master/install | bash && gem install nano-bots -v 3.0.0 && bash"
1001
1010
  environment:
1002
1011
  MISTRAL_API_KEY: your-api-key
1003
1012
  NANO_BOTS_ENCRYPTION_PASSWORD: UNSAFE
@@ -1016,7 +1025,7 @@ Remember that your `localhost` is by default inaccessible from inside Docker. Yo
1016
1025
  services:
1017
1026
  nano-bots:
1018
1027
  image: ruby:3.2.2-slim-bookworm
1019
- command: sh -c "apt-get update && apt-get install -y --no-install-recommends build-essential libffi-dev libsodium-dev lua5.4-dev curl && curl -s https://raw.githubusercontent.com/babashka/babashka/master/install | bash && gem install nano-bots -v 2.5.1 && bash"
1028
+ command: sh -c "apt-get update && apt-get install -y --no-install-recommends build-essential libffi-dev libsodium-dev lua5.4-dev curl && curl -s https://raw.githubusercontent.com/babashka/babashka/master/install | bash && gem install nano-bots -v 3.0.0 && bash"
1020
1029
  environment:
1021
1030
  OLLAMA_API_ADDRESS: http://localhost:11434
1022
1031
  NANO_BOTS_ENCRYPTION_PASSWORD: UNSAFE
@@ -1035,7 +1044,7 @@ services:
1035
1044
  services:
1036
1045
  nano-bots:
1037
1046
  image: ruby:3.2.2-slim-bookworm
1038
- command: sh -c "apt-get update && apt-get install -y --no-install-recommends build-essential libffi-dev libsodium-dev lua5.4-dev curl && curl -s https://raw.githubusercontent.com/babashka/babashka/master/install | bash && gem install nano-bots -v 2.5.1 && bash"
1047
+ command: sh -c "apt-get update && apt-get install -y --no-install-recommends build-essential libffi-dev libsodium-dev lua5.4-dev curl && curl -s https://raw.githubusercontent.com/babashka/babashka/master/install | bash && gem install nano-bots -v 3.0.0 && bash"
1039
1048
  environment:
1040
1049
  OPENAI_API_KEY: your-access-token
1041
1050
  NANO_BOTS_ENCRYPTION_PASSWORD: UNSAFE
@@ -1054,7 +1063,7 @@ services:
1054
1063
  services:
1055
1064
  nano-bots:
1056
1065
  image: ruby:3.2.2-slim-bookworm
1057
- command: sh -c "apt-get update && apt-get install -y --no-install-recommends build-essential libffi-dev libsodium-dev lua5.4-dev curl && curl -s https://raw.githubusercontent.com/babashka/babashka/master/install | bash && gem install nano-bots -v 2.5.1 && bash"
1066
+ command: sh -c "apt-get update && apt-get install -y --no-install-recommends build-essential libffi-dev libsodium-dev lua5.4-dev curl && curl -s https://raw.githubusercontent.com/babashka/babashka/master/install | bash && gem install nano-bots -v 3.0.0 && bash"
1058
1067
  environment:
1059
1068
  GOOGLE_API_KEY: your-api-key
1060
1069
  NANO_BOTS_ENCRYPTION_PASSWORD: UNSAFE
@@ -1071,7 +1080,7 @@ services:
1071
1080
  services:
1072
1081
  nano-bots:
1073
1082
  image: ruby:3.2.2-slim-bookworm
1074
- command: sh -c "apt-get update && apt-get install -y --no-install-recommends build-essential libffi-dev libsodium-dev lua5.4-dev curl && curl -s https://raw.githubusercontent.com/babashka/babashka/master/install | bash && gem install nano-bots -v 2.5.1 && bash"
1083
+ command: sh -c "apt-get update && apt-get install -y --no-install-recommends build-essential libffi-dev libsodium-dev lua5.4-dev curl && curl -s https://raw.githubusercontent.com/babashka/babashka/master/install | bash && gem install nano-bots -v 3.0.0 && bash"
1075
1084
  environment:
1076
1085
  GOOGLE_CREDENTIALS_FILE_PATH: /root/.config/google-credentials.json
1077
1086
  GOOGLE_REGION: us-east4
@@ -1090,7 +1099,7 @@ services:
1090
1099
  services:
1091
1100
  nano-bots:
1092
1101
  image: ruby:3.2.2-slim-bookworm
1093
- command: sh -c "apt-get update && apt-get install -y --no-install-recommends build-essential libffi-dev libsodium-dev lua5.4-dev curl && curl -s https://raw.githubusercontent.com/babashka/babashka/master/install | bash && gem install nano-bots -v 2.5.1 && bash"
1102
+ command: sh -c "apt-get update && apt-get install -y --no-install-recommends build-essential libffi-dev libsodium-dev lua5.4-dev curl && curl -s https://raw.githubusercontent.com/babashka/babashka/master/install | bash && gem install nano-bots -v 3.0.0 && bash"
1094
1103
  environment:
1095
1104
  GOOGLE_REGION: us-east4
1096
1105
  NANO_BOTS_ENCRYPTION_PASSWORD: UNSAFE
@@ -1139,6 +1148,12 @@ bundle exec ruby spec/tasks/run-model.rb spec/data/cartridges/models/openai/gpt-
1139
1148
  bundle exec ruby spec/tasks/run-model.rb spec/data/cartridges/models/openai/gpt-4-turbo.yml stream
1140
1149
  ```
1141
1150
 
1151
+ If you face issues upgrading gem versions:
1152
+
1153
+ ```sh
1154
+ bundle install --full-index
1155
+ ```
1156
+
1142
1157
  ### Publish to RubyGems
1143
1158
 
1144
1159
  ```bash
@@ -1146,5 +1161,5 @@ gem build nano-bots.gemspec
1146
1161
 
1147
1162
  gem signin
1148
1163
 
1149
- gem push nano-bots-2.5.1.gem
1164
+ gem push nano-bots-3.0.0.gem
1150
1165
  ```
@@ -45,7 +45,7 @@ module NanoBot
45
45
  def self.clojure(source:, parameters:, values:, safety:)
46
46
  ensure_safety!(safety)
47
47
 
48
- raise 'TODO: sandboxed Clojure through Babashka not implemented' if safety[:sandboxed]
48
+ raise 'Sandboxed Clojure not supported.' if safety[:sandboxed]
49
49
 
50
50
  raise 'invalid Clojure parameter name' if parameters.include?('injected-parameters')
51
51
 
@@ -140,7 +140,7 @@ module NanoBot
140
140
  begin
141
141
  @client.chat(parameters: Logic::OpenAI::Tokens.apply_policies!(cartridge, payload))
142
142
  rescue StandardError => e
143
- raise e.class, e.response[:body] if e.response && e.response[:body]
143
+ raise e.class, e.response[:body] if e.respond_to?(:response) && e.response && e.response[:body]
144
144
 
145
145
  raise e
146
146
  end
@@ -148,7 +148,7 @@ module NanoBot
148
148
  begin
149
149
  result = @client.chat(parameters: Logic::OpenAI::Tokens.apply_policies!(cartridge, payload))
150
150
  rescue StandardError => e
151
- raise e.class, e.response[:body] if e.response && e.response[:body]
151
+ raise e.class, e.response[:body] if e.respond_to?(:response) && e.response && e.response[:body]
152
152
 
153
153
  raise e
154
154
  end
@@ -8,6 +8,8 @@ require_relative 'crypto'
8
8
  module NanoBot
9
9
  module Components
10
10
  class Storage
11
+ EXTENSIONS = %w[yml yaml markdown mdown mkdn md].freeze
12
+
11
13
  def self.end_user(cartridge, environment)
12
14
  user = ENV.fetch('NANO_BOTS_END_USER', nil)
13
15
 
@@ -35,7 +37,9 @@ module NanoBot
35
37
 
36
38
  def self.build_path_and_ensure_state_file!(key, cartridge, environment: {})
37
39
  path = [
40
+ Logic::Helpers::Hash.fetch(cartridge, %i[state path]),
38
41
  Logic::Helpers::Hash.fetch(cartridge, %i[state directory]),
42
+ ENV.fetch('NANO_BOTS_STATE_PATH', nil),
39
43
  ENV.fetch('NANO_BOTS_STATE_DIRECTORY', nil)
40
44
  ].find do |candidate|
41
45
  !candidate.nil? && !candidate.empty?
@@ -64,32 +68,59 @@ module NanoBot
64
68
  path
65
69
  end
66
70
 
67
- def self.cartridges_path
68
- [
69
- ENV.fetch('NANO_BOTS_CARTRIDGES_DIRECTORY', nil),
70
- "#{user_home!.sub(%r{/$}, '')}/.local/share/nano-bots/cartridges"
71
- ].compact.uniq.filter { |path| File.directory?(path) }.compact.first
71
+ def self.cartridges_path(components: {})
72
+ components[:directory?] = ->(path) { File.directory?(path) } unless components.key?(:directory?)
73
+ components[:ENV] = ENV unless components.key?(:ENV)
74
+
75
+ default = "#{user_home!(components:).sub(%r{/$}, '')}/.local/share/nano-bots/cartridges"
76
+
77
+ from_environment = [
78
+ components[:ENV].fetch('NANO_BOTS_CARTRIDGES_PATH', nil),
79
+ components[:ENV].fetch('NANO_BOTS_CARTRIDGES_DIRECTORY', nil)
80
+ ].compact
81
+
82
+ elected = [
83
+ from_environment.empty? ? nil : from_environment.join(':'),
84
+ default
85
+ ].compact.uniq.filter do |path|
86
+ path.split(':').any? { |candidate| components[:directory?].call(candidate) }
87
+ end.compact.first
88
+
89
+ return default unless elected
90
+
91
+ elected = elected.split(':').filter do |path|
92
+ components[:directory?].call(path)
93
+ end.compact
94
+
95
+ elected.size.positive? ? elected.join(':') : default
72
96
  end
73
97
 
74
98
  def self.cartridge_path(path)
75
99
  partial = File.join(File.dirname(path), File.basename(path, File.extname(path)))
76
100
 
77
- candidates = [
78
- path,
79
- "#{partial}.yml",
80
- "#{partial}.yaml"
81
- ]
101
+ candidates = [path]
82
102
 
83
- unless ENV.fetch('NANO_BOTS_CARTRIDGES_DIRECTORY', nil).nil?
84
- directory = ENV.fetch('NANO_BOTS_CARTRIDGES_DIRECTORY').sub(%r{/$}, '')
103
+ EXTENSIONS.each do |extension|
104
+ candidates << "#{partial}.#{extension}"
105
+ end
106
+
107
+ directories = [
108
+ ENV.fetch('NANO_BOTS_CARTRIDGES_PATH', nil),
109
+ ENV.fetch('NANO_BOTS_CARTRIDGES_DIRECTORY', nil)
110
+ ].compact.map do |directory|
111
+ directory.split(':')
112
+ end.flatten.map { |directory| directory.sub(%r{/$}, '') }
85
113
 
114
+ directories.each do |directory|
86
115
  partial = File.join(File.dirname(partial), File.basename(partial, File.extname(partial)))
87
116
 
88
117
  partial = partial.sub(%r{^\.?/}, '')
89
118
 
90
119
  candidates << "#{directory}/#{partial}"
91
- candidates << "#{directory}/#{partial}.yml"
92
- candidates << "#{directory}/#{partial}.yaml"
120
+
121
+ EXTENSIONS.each do |extension|
122
+ candidates << "#{directory}/#{partial}.#{extension}"
123
+ end
93
124
  end
94
125
 
95
126
  directory = "#{user_home!.sub(%r{/$}, '')}/.local/share/nano-bots/cartridges"
@@ -99,8 +130,10 @@ module NanoBot
99
130
  partial = partial.sub(%r{^\.?/}, '')
100
131
 
101
132
  candidates << "#{directory}/#{partial}"
102
- candidates << "#{directory}/#{partial}.yml"
103
- candidates << "#{directory}/#{partial}.yaml"
133
+
134
+ EXTENSIONS.each do |extension|
135
+ candidates << "#{directory}/#{partial}.#{extension}"
136
+ end
104
137
 
105
138
  candidates = candidates.uniq
106
139
 
@@ -109,7 +142,9 @@ module NanoBot
109
142
  end
110
143
  end
111
144
 
112
- def self.user_home!
145
+ def self.user_home!(components: {})
146
+ return components[:home] if components[:home]
147
+
113
148
  [Dir.home, `echo ~`.strip, '~'].find do |candidate|
114
149
  !candidate.nil? && !candidate.empty?
115
150
  end
@@ -3,35 +3,43 @@
3
3
  require_relative '../components/storage'
4
4
  require_relative '../logic/helpers/hash'
5
5
  require_relative '../logic/cartridge/default'
6
+ require_relative '../logic/cartridge/parser'
6
7
 
7
8
  module NanoBot
8
9
  module Controllers
9
10
  class Cartridges
10
- def self.all
11
+ def self.load(path)
12
+ Logic::Cartridge::Parser.parse(File.read(path), format: File.extname(path))
13
+ end
14
+
15
+ def self.all(components: {})
11
16
  files = {}
12
17
 
13
- path = Components::Storage.cartridges_path
18
+ paths = Components::Storage.cartridges_path(components:)
14
19
 
15
- Dir.glob("#{path}/**/*.{yml,yaml}").each do |file|
16
- files[Pathname.new(file).realpath] = {
17
- base: path,
18
- path: Pathname.new(file).realpath
19
- }
20
+ paths.split(':').each do |path|
21
+ Dir.glob("#{path}/**/*.{yml,yaml,markdown,mdown,mkdn,md}").each do |file|
22
+ files[Pathname.new(file).realpath] = {
23
+ base: path,
24
+ path: Pathname.new(file).realpath
25
+ }
26
+ end
20
27
  end
21
28
 
22
29
  cartridges = []
23
30
 
24
31
  files.values.uniq.map do |file|
25
- cartridge = Logic::Helpers::Hash.symbolize_keys(
26
- YAML.safe_load_file(file[:path], permitted_classes: [Symbol])
27
- ).merge({
28
- system: {
29
- id: file[:path].to_s.sub(/^#{Regexp.escape(file[:base])}/, '').sub(%r{^/}, '').sub(/\.[^.]+\z/,
30
- ''),
31
- path: file[:path],
32
- base: file[:base]
33
- }
34
- })
32
+ cartridge = load(file[:path]).merge(
33
+ {
34
+ system: {
35
+ id: file[:path].to_s.sub(
36
+ /^#{Regexp.escape(file[:base])}/, ''
37
+ ).sub(%r{^/}, '').sub(/\.[^.]+\z/, ''),
38
+ path: file[:path],
39
+ base: file[:base]
40
+ }
41
+ }
42
+ )
35
43
 
36
44
  next if cartridge[:meta][:name].nil?
37
45
 
@@ -1,11 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'yaml'
4
-
5
3
  require_relative '../logic/helpers/hash'
6
4
  require_relative '../components/provider'
7
5
  require_relative '../components/storage'
8
6
  require_relative '../components/stream'
7
+ require_relative 'cartridges'
9
8
  require_relative 'interfaces/repl'
10
9
  require_relative 'interfaces/eval'
11
10
  require_relative 'session'
@@ -83,13 +82,11 @@ module NanoBot
83
82
  raise StandardError, "Cartridge file not found: \"#{path}\""
84
83
  end
85
84
 
86
- @cartridge = YAML.safe_load_file(elected_path, permitted_classes: [Symbol])
85
+ @cartridge = Cartridges.load(elected_path)
87
86
  end
88
87
 
89
88
  @safe_cartridge = Marshal.load(Marshal.dump(@cartridge))
90
89
 
91
- @cartridge = Logic::Helpers::Hash.symbolize_keys(@cartridge)
92
-
93
90
  inject_environment_variables!(@cartridge)
94
91
  end
95
92
 
@@ -2,7 +2,7 @@
2
2
  services:
3
3
  nano-bots:
4
4
  image: ruby:3.2.2-slim-bookworm
5
- command: sh -c "apt-get update && apt-get install -y --no-install-recommends build-essential libffi-dev libsodium-dev lua5.4-dev curl && curl -s https://raw.githubusercontent.com/babashka/babashka/master/install | bash && gem install nano-bots -v 2.5.1 && bash"
5
+ command: sh -c "apt-get update && apt-get install -y --no-install-recommends build-essential libffi-dev libsodium-dev lua5.4-dev curl && curl -s https://raw.githubusercontent.com/babashka/babashka/master/install | bash && gem install nano-bots -v 3.0.0 && bash"
6
6
  environment:
7
7
  COHERE_API_KEY: your-api-key
8
8
 
@@ -0,0 +1,134 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'singleton'
4
+
5
+ require 'redcarpet'
6
+ require 'redcarpet/render_strip'
7
+
8
+ module NanoBot
9
+ module Logic
10
+ module Cartridge
11
+ module Parser
12
+ def self.parse(raw, format:)
13
+ normalized = format.to_s.downcase.gsub('.', '').strip
14
+
15
+ if %w[yml yaml].include?(normalized)
16
+ yaml(raw)
17
+ elsif %w[markdown mdown mkdn md].include?(normalized)
18
+ markdown(raw)
19
+ else
20
+ raise "Unknown cartridge format: '#{format}'"
21
+ end
22
+ end
23
+
24
+ def self.markdown(raw)
25
+ yaml_source = []
26
+
27
+ tools = []
28
+
29
+ blocks = Markdown.new.render(raw).blocks
30
+
31
+ previous_block_is_tool = false
32
+
33
+ blocks.each do |block|
34
+ if block[:language] == 'yaml'
35
+ parsed = Logic::Helpers::Hash.symbolize_keys(
36
+ YAML.safe_load(block[:source], permitted_classes: [Symbol])
37
+ )
38
+
39
+ if parsed.key?(:tools) && parsed[:tools].is_a?(Array) && !parsed[:tools].empty?
40
+ previous_block_is_tool = true
41
+
42
+ tools.concat(parsed[:tools])
43
+
44
+ parsed.delete(:tools)
45
+
46
+ unless parsed.empty?
47
+ yaml_source << YAML.dump(
48
+ Logic::Helpers::Hash.stringify_keys(parsed)
49
+ ).gsub(/^---/, '') # TODO: Is this safe enough?
50
+ end
51
+ else
52
+ yaml_source << block[:source]
53
+ previous_block_is_tool = false
54
+ nil
55
+ end
56
+ elsif previous_block_is_tool
57
+ tools.last[block[:language].to_sym] = block[:source]
58
+ previous_block_is_tool = false
59
+ end
60
+ end
61
+
62
+ unless tools.empty?
63
+ yaml_source << YAML.dump(
64
+ Logic::Helpers::Hash.stringify_keys({ tools: })
65
+ ).gsub(/^---/, '') # TODO: Is this safe enough?
66
+ end
67
+
68
+ cartridge = {}
69
+
70
+ yaml_source.each do |source|
71
+ cartridge = Logic::Helpers::Hash.deep_merge(cartridge, yaml(source))
72
+ end
73
+
74
+ cartridge
75
+ end
76
+
77
+ def self.yaml(raw)
78
+ Logic::Helpers::Hash.symbolize_keys(
79
+ YAML.safe_load(raw, permitted_classes: [Symbol])
80
+ )
81
+ end
82
+
83
+ class Renderer < Redcarpet::Render::Base
84
+ LANGUAGES_MAP = {
85
+ 'yml' => 'yaml',
86
+ 'yaml' => 'yaml',
87
+ 'lua' => 'lua',
88
+ 'fnl' => 'fennel',
89
+ 'fennel' => 'fennel',
90
+ 'clj' => 'clojure',
91
+ 'clojure' => 'clojure'
92
+ }.freeze
93
+
94
+ LANGUAGES = LANGUAGES_MAP.keys.freeze
95
+
96
+ def initialize(...)
97
+ super(...)
98
+ @_nano_bots_blocks = []
99
+ end
100
+
101
+ attr_reader :_nano_bots_blocks
102
+
103
+ def block_code(code, language)
104
+ key = language.to_s.downcase.strip
105
+
106
+ return nil unless LANGUAGES.include?(key)
107
+
108
+ @_nano_bots_blocks << { language: LANGUAGES_MAP[key], source: code }
109
+
110
+ nil
111
+ end
112
+ end
113
+
114
+ class Markdown
115
+ attr_reader :markdown
116
+
117
+ def initialize
118
+ @renderer = Renderer.new
119
+ @markdown = Redcarpet::Markdown.new(@renderer, fenced_code_blocks: true)
120
+ end
121
+
122
+ def blocks
123
+ @renderer._nano_bots_blocks
124
+ end
125
+
126
+ def render(raw)
127
+ @markdown.render(raw.gsub(/```\w/, "\n\n\\0"))
128
+ self
129
+ end
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
@@ -4,6 +4,16 @@ module NanoBot
4
4
  module Logic
5
5
  module Helpers
6
6
  module Hash
7
+ def self.deep_merge(hash1, hash2)
8
+ hash1.merge(hash2) do |_key, old_val, new_val|
9
+ if old_val.is_a?(::Hash) && new_val.is_a?(::Hash)
10
+ deep_merge(old_val, new_val)
11
+ else
12
+ new_val
13
+ end
14
+ end
15
+ end
16
+
7
17
  def self.symbolize_keys(object)
8
18
  case object
9
19
  when ::Hash
@@ -17,6 +27,19 @@ module NanoBot
17
27
  end
18
28
  end
19
29
 
30
+ def self.stringify_keys(object)
31
+ case object
32
+ when ::Hash
33
+ object.each_with_object({}) do |(key, value), result|
34
+ result[key.to_s] = stringify_keys(value)
35
+ end
36
+ when Array
37
+ object.map { |e| stringify_keys(e) }
38
+ else
39
+ object
40
+ end
41
+ end
42
+
20
43
  def self.fetch(object, path)
21
44
  node = object
22
45
 
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 'rbnacl', '~> 7.1', '>= 7.1.1'
40
+ spec.add_dependency 'redcarpet', '~> 3.6'
40
41
  spec.add_dependency 'sweet-moon', '~> 0.0.7'
41
42
 
42
43
  spec.add_dependency 'cohere-ai', '~> 1.0', '>= 1.0.1'
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../../controllers/cartridges'
4
+
5
+ module NanoBot
6
+ module Cartridges
7
+ def self.all(components: {})
8
+ Controllers::Cartridges.all(components:)
9
+ end
10
+
11
+ def self.load(path)
12
+ Controllers::Cartridges.load(path)
13
+ end
14
+ end
15
+ end
@@ -8,6 +8,7 @@ require_relative '../../controllers/instance'
8
8
  require_relative '../../controllers/security'
9
9
  require_relative '../../controllers/interfaces/cli'
10
10
  require_relative '../../components/stream'
11
+ require_relative 'nano-bots/cartridges'
11
12
 
12
13
  module NanoBot
13
14
  def self.new(cartridge: '-', state: '-', environment: {})
@@ -24,7 +25,7 @@ module NanoBot
24
25
  end
25
26
 
26
27
  def self.cartridges
27
- Controllers::Cartridges.all
28
+ Cartridges
28
29
  end
29
30
 
30
31
  def self.cli
data/static/gem.rb CHANGED
@@ -3,8 +3,8 @@
3
3
  module NanoBot
4
4
  GEM = {
5
5
  name: 'nano-bots',
6
- version: '2.5.1',
7
- specification: '2.3.0',
6
+ version: '3.0.0',
7
+ specification: '3.0.0',
8
8
  author: 'icebaker',
9
9
  summary: 'Ruby Implementation of Nano Bots: small, AI-powered bots for OpenAI ChatGPT, Ollama, Mistral AI, Cohere Command, Maritaca AI MariTalk, and Google Gemini.',
10
10
  description: 'Ruby Implementation of Nano Bots: small, AI-powered bots that can be easily shared as a single file, designed to support multiple providers such as OpenAI ChatGPT, Ollama, Mistral AI, Cohere Command, Maritaca AI MariTalk, and Google Gemini, with support for calling Tools (Functions).',
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nano-bots
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.5.1
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - icebaker
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-01-07 00:00:00.000000000 Z
11
+ date: 2024-01-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: babosa
@@ -118,6 +118,20 @@ dependencies:
118
118
  - - ">="
119
119
  - !ruby/object:Gem::Version
120
120
  version: 7.1.1
121
+ - !ruby/object:Gem::Dependency
122
+ name: redcarpet
123
+ requirement: !ruby/object:Gem::Requirement
124
+ requirements:
125
+ - - "~>"
126
+ - !ruby/object:Gem::Version
127
+ version: '3.6'
128
+ type: :runtime
129
+ prerelease: false
130
+ version_requirements: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - "~>"
133
+ - !ruby/object:Gem::Version
134
+ version: '3.6'
121
135
  - !ruby/object:Gem::Dependency
122
136
  name: sweet-moon
123
137
  requirement: !ruby/object:Gem::Requirement
@@ -287,6 +301,7 @@ files:
287
301
  - logic/cartridge/default.rb
288
302
  - logic/cartridge/fetch.rb
289
303
  - logic/cartridge/interaction.rb
304
+ - logic/cartridge/parser.rb
290
305
  - logic/cartridge/safety.rb
291
306
  - logic/cartridge/streaming.rb
292
307
  - logic/cartridge/tools.rb
@@ -302,6 +317,7 @@ files:
302
317
  - logic/providers/openai/tools.rb
303
318
  - nano-bots.gemspec
304
319
  - ports/dsl/nano-bots.rb
320
+ - ports/dsl/nano-bots/cartridges.rb
305
321
  - ports/dsl/nano-bots/cli.rb
306
322
  - static/cartridges/baseline.yml
307
323
  - static/cartridges/default.yml