summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoricebaker <icebaker@proton.me>2023-06-04 11:49:00 -0300
committericebaker <icebaker@proton.me>2023-06-04 11:49:00 -0300
commit1c497945d4bbfef5dd44a074800bec83057bcc0a (patch)
tree6154ff90cd8f92cdf3f4c4c246ae7161cc56196f
parent851397413a914e2caee3e05468495dac5076812f (diff)
new spec and end-user flow
-rw-r--r--README.md88
-rw-r--r--components/provider.rb6
-rw-r--r--components/providers/base.rb4
-rw-r--r--components/providers/openai.rb48
-rw-r--r--components/storage.rb44
-rw-r--r--controllers/security.rb4
-rw-r--r--docker-compose.example.yml10
-rw-r--r--static/cartridges/baseline.yml15
-rw-r--r--static/cartridges/default.yml1
9 files changed, 139 insertions, 81 deletions
diff --git a/README.md b/README.md
index d43d25e..ff600bc 100644
--- a/README.md
+++ b/README.md
@@ -44,10 +44,11 @@ bundle install
For credentials and configurations, relevant environment variables can be set in your `.bashrc`, `.zshrc`, or equivalent files, as well as in your Docker Container or System Environment. Example:
```sh
-export NANO_BOTS_ENCRYPTION_PASSWORD='UNSAFE'
export OPENAI_API_ADDRESS=https://api.openai.com
-export OPENAI_API_ACCESS_TOKEN=your-token
-export OPENAI_API_USER_IDENTIFIER=your-user
+export OPENAI_API_KEY=your-access-token
+
+export NANO_BOTS_ENCRYPTION_PASSWORD=UNSAFE
+export NANO_BOTS_END_USER=your-user
# export NANO_BOTS_STATE_DIRECTORY=/home/user/.local/state/nano-bots
# export NANO_BOTS_CARTRIDGES_DIRECTORY=/home/user/.local/share/nano-bots/cartridges
@@ -56,10 +57,11 @@ export OPENAI_API_USER_IDENTIFIER=your-user
Alternatively, if your current directory has a `.env` file with the environment variables, they will be automatically loaded:
```sh
-NANO_BOTS_ENCRYPTION_PASSWORD='UNSAFE'
OPENAI_API_ADDRESS=https://api.openai.com
-OPENAI_API_ACCESS_TOKEN=your-token
-OPENAI_API_USER_IDENTIFIER=your-user
+OPENAI_API_KEY=your-access-token
+
+NANO_BOTS_ENCRYPTION_PASSWORD=UNSAFE
+NANO_BOTS_END_USER=your-user
# NANO_BOTS_STATE_DIRECTORY=/home/user/.local/state/nano-bots
# NANO_BOTS_CARTRIDGES_DIRECTORY=/home/user/.local/share/nano-bots/cartridges
@@ -85,13 +87,13 @@ services:
image: ruby:3.2.2-slim-bullseye
command: sh -c "gem install nano-bots -v 0.0.10 && bash"
environment:
- NANO_BOTS_ENCRYPTION_PASSWORD: UNSAFE
OPENAI_API_ADDRESS: https://api.openai.com
- OPENAI_API_ACCESS_TOKEN: your-token
- OPENAI_API_USER_IDENTIFIER: your-user
+ OPENAI_API_KEY: your-access-token
+ NANO_BOTS_ENCRYPTION_PASSWORD: UNSAFE
+ NANO_BOTS_END_USER: your-user
volumes:
- - ./your-cartridges:/cartridges
- # - ./your-data:/data
+ - ./your-cartridges:/.local/share/nano-bots/cartridges
+ - ./your-state:/.local/state/nano-bots
```
Enter the container:
@@ -104,8 +106,8 @@ Start playing:
nb - - eval "hello"
nb - - repl
-nb cartridges/assistant.yml - eval "hello"
-nb cartridges/assistant.yml - repl
+nb assistant.yml - eval "hello"
+nb assistant.yml - repl
```
## Usage
@@ -256,13 +258,13 @@ behaviors:
directive: You are a helpful assistant.
provider:
- name: openai
+ id: openai
+ credentials:
+ address: ENV/OPENAI_API_ADDRESS
+ access-token: ENV/OPENAI_API_KEY
settings:
+ user: ENV/NANO_BOTS_END_USER
model: gpt-3.5-turbo
- credentials:
- address: ENV/OPENAI_API_ADDRESS
- access-token: ENV/OPENAI_API_ACCESS_TOKEN
- user-identifier: ENV/OPENAI_API_USER_IDENTIFIER
```
Check the Nano Bots specification to learn more about [how to build cartridges](https://spec.nbots.io/#/README?id=cartridges).
@@ -314,33 +316,48 @@ A common strategy for deploying Nano Bots to multiple users through APIs or auto
You can define custom end-user identifiers in the following way:
```ruby
-NanoBot.new(environment: { NANO_BOTS_USER_IDENTIFIER: 'user-a' })
-NanoBot.new(environment: { NANO_BOTS_USER_IDENTIFIER: 'user-b' })
+NanoBot.new(environment: { NANO_BOTS_END_USER: 'custom-user-a' })
+NanoBot.new(environment: { NANO_BOTS_END_USER: 'custom-user-b' })
```
-Consider that you have have the following OpenAI user identifier:
+Consider that you have the following end-user identifier in your environment:
```sh
-OPENAI_API_USER_IDENTIFIER=your-name
+NANO_BOTS_END_USER=your-name
+```
+
+Or a configuration in your Cartridge:
+```yml
+---
+provider:
+ id: openai
+ settings:
+ user: your-name
```
The requests will be performed as follows:
```ruby
-NanoBot.new(environment: {NANO_BOTS_USER_IDENTIFIER: 'user-a'})
-# { user: 'your-name/user-a' }
+NanoBot.new(cartridge: '-')
+# { user: 'your-name' }
-NanoBot.new(environment: {NANO_BOTS_USER_IDENTIFIER: 'user-b'})
-# { user: 'your-name/user-b' }
+NanoBot.new(cartridge: '-', environment: { NANO_BOTS_END_USER: 'custom-user-a' })
+# { user: 'custom-user-a' }
+
+NanoBot.new(cartridge: '-', environment: { NANO_BOTS_END_USER: 'custom-user-b' })
+# { user: 'custom-user-b' }
```
Actually, to enhance privacy, neither your user nor your users' identifiers will be shared in this way. Instead, they will be encrypted before being shared with the provider:
```ruby
-'your-name/user-a'
-# -onBK9GWafYz-JM8-cydhn4jd4Bkfkec5FtJ1ReCrtHCDPjkhCqUjRobG1zLnAz3BLo1kFhRW3w=
+'your-name'
+# _O7OjYUESagb46YSeUeSfSMzoO1Yg0BZqpsAkPg4j62SeNYlgwq3kn51Ob2wmIehoA==
+
+'custom-user-a'
+# _O7OjYUESagb46YSeUeSfSMzoO1Yg0BZJgIXHCBHyADW-rn4IQr-s2RvP7vym8u5tnzYMIs=
-'your-name/user-a'
-# RldW4_xxktCksEAR9G8aORuq3skPAc9ivWj3eye2ICCHQy8gG_R5qLMS3Fg-0lY6LwxKGQur5Ww=
+'custom-user-b'
+# _O7OjYUESagb46YSeUeSfSMzoO1Yg0BZkjUwCcsh9sVppKvYMhd2qGRvP7vym8u5tnzYMIg=
```
In this manner, you possess identifiers if required, however, their actual content can only be decrypted by you via your secure password (`NANO_BOTS_ENCRYPTION_PASSWORD`).
@@ -352,11 +369,14 @@ To decrypt your encrypted data, once you have properly configured your password,
```ruby
require 'nano-bots'
-NanoBot.security.decrypt('-onBK9GWafYz-JM8-cydhn4jd4Bkfkec5FtJ1ReCrtHCDPjkhCqUjRobG1zLnAz3BLo1kFhRW3w=')
-# your-name/user-b
+NanoBot.security.decrypt('_O7OjYUESagb46YSeUeSfSMzoO1Yg0BZqpsAkPg4j62SeNYlgwq3kn51Ob2wmIehoA==')
+# your-name
+
+NanoBot.security.decrypt('_O7OjYUESagb46YSeUeSfSMzoO1Yg0BZJgIXHCBHyADW-rn4IQr-s2RvP7vym8u5tnzYMIs=')
+# custom-user-a
-NanoBot.security.decrypt('RldW4_xxktCksEAR9G8aORuq3skPAc9ivWj3eye2ICCHQy8gG_R5qLMS3Fg-0lY6LwxKGQur5Ww=')
-# your-name/user-b
+NanoBot.security.decrypt('_O7OjYUESagb46YSeUeSfSMzoO1Yg0BZkjUwCcsh9sVppKvYMhd2qGRvP7vym8u5tnzYMIg=')
+# custom-user-b
```
If you lose your password, you lose your data. It is not possible to recover it at all. For real.
diff --git a/components/provider.rb b/components/provider.rb
index 3138cc4..163b099 100644
--- a/components/provider.rb
+++ b/components/provider.rb
@@ -8,11 +8,11 @@ module NanoBot
module Components
class Provider
def self.new(provider, environment: {})
- case provider[:name]
+ case provider[:id]
when 'openai'
- Providers::OpenAI.new(provider[:settings], environment:)
+ Providers::OpenAI.new(provider[:settings], provider[:credentials], environment:)
else
- raise "Unsupported provider #{provider[:name]}"
+ raise "Unsupported provider \"#{provider[:id]}\""
end
end
end
diff --git a/components/providers/base.rb b/components/providers/base.rb
index 011c5dd..7a99833 100644
--- a/components/providers/base.rb
+++ b/components/providers/base.rb
@@ -6,6 +6,10 @@ module NanoBot
module Components
module Providers
class Base
+ def initialize(_settings, _credentials, _environment: {})
+ raise NoMethodError, "The 'initialize' method is not implemented for the current provider."
+ end
+
def evaluate(_payload)
raise NoMethodError, "The 'evaluate' method is not implemented for the current provider."
end
diff --git a/components/providers/openai.rb b/components/providers/openai.rb
index c64a588..ce6fb33 100644
--- a/components/providers/openai.rb
+++ b/components/providers/openai.rb
@@ -9,6 +9,8 @@ module NanoBot
module Components
module Providers
class OpenAI < Base
+ DEFAULT_ADDRESS = 'https://api.openai.com'
+
CHAT_SETTINGS = %i[
model stream temperature top_p n stop max_tokens
presence_penalty frequency_penalty logit_bias
@@ -16,14 +18,18 @@ module NanoBot
attr_reader :settings
- def initialize(settings, environment: {})
+ def initialize(settings, credentials, environment: {})
@settings = settings
+ @credentials = credentials
@environment = environment
- @client = ::OpenAI::Client.new(
- uri_base: "#{@settings[:credentials][:address].sub(%r{/$}, '')}/",
- access_token: @settings[:credentials][:'access-token']
- )
+ uri_base = if @credentials[:address].nil? || @credentials[:address].to_s.strip.empty?
+ "#{DEFAULT_ADDRESS}/"
+ else
+ "#{@credentials[:address].to_s.sub(%r{/$}, '')}/"
+ end
+
+ @client = ::OpenAI::Client.new(uri_base:, access_token: @credentials[:'access-token'])
end
def stream(input)
@@ -48,16 +54,7 @@ module NanoBot
)
end
- user = @settings[:credentials][:'user-identifier']
-
- user_suffix = @environment && (
- @environment['NANO_BOTS_USER_IDENTIFIER'] ||
- @environment[:NANO_BOTS_USER_IDENTIFIER]
- )
-
- user = "#{user}/#{user_suffix}" if user_suffix && user_suffix != ''
-
- payload = { model: @settings[:model], user: Crypto.encrypt(user, soft: true), messages: }
+ payload = { user: OpenAI.end_user(@settings, @environment), messages: }
CHAT_SETTINGS.each do |key|
payload[key] = @settings[key] if @settings.key?(key)
@@ -87,6 +84,27 @@ module NanoBot
block.call({ who: 'AI', message: result.dig('choices', 0, 'message', 'content') }, true)
end
end
+
+ def self.end_user(settings, environment)
+ user = ENV.fetch('NANO_BOTS_END_USER', nil)
+
+ user = settings[:user] if !settings[:user].nil? && !settings[:user].to_s.strip.empty?
+
+ candidate = environment && (
+ environment['NANO_BOTS_END_USER'] ||
+ environment[:NANO_BOTS_END_USER]
+ )
+
+ user = candidate if !candidate.nil? && !candidate.to_s.strip.empty?
+
+ user = if user.nil? || user.to_s.strip.empty?
+ 'unknown'
+ else
+ user.to_s.strip
+ end
+
+ Crypto.encrypt(user, soft: true)
+ end
end
end
end
diff --git a/components/storage.rb b/components/storage.rb
index b6d8910..577ce67 100644
--- a/components/storage.rb
+++ b/components/storage.rb
@@ -8,6 +8,31 @@ require_relative './crypto'
module NanoBot
module Components
class Storage
+ def self.end_user(cartridge, environment)
+ user = ENV.fetch('NANO_BOTS_END_USER', nil)
+
+ if cartridge[:provider][:id] == 'openai' &&
+ !cartridge[:provider][:settings][:user].nil? &&
+ !cartridge[:provider][:settings][:user].to_s.strip.empty?
+ user = cartridge[:provider][:settings][:user]
+ end
+
+ candidate = environment && (
+ environment['NANO_BOTS_END_USER'] ||
+ environment[:NANO_BOTS_END_USER]
+ )
+
+ user = candidate if !candidate.nil? && !candidate.to_s.strip.empty?
+
+ user = if user.nil? || user.to_s.strip.empty?
+ 'unknown'
+ else
+ user.to_s.strip
+ end
+
+ Crypto.encrypt(user, soft: true)
+ end
+
def self.build_path_and_ensure_state_file!(key, cartridge, environment: {})
path = [
Logic::Helpers::Hash.fetch(cartridge, %i[state directory]),
@@ -18,27 +43,12 @@ module NanoBot
path = "#{user_home!.sub(%r{/$}, '')}/.local/state/nano-bots" if path.nil?
- prefix = environment && (
- environment['NANO_BOTS_USER_IDENTIFIER'] ||
- environment[:NANO_BOTS_USER_IDENTIFIER]
- )
-
- path = "#{path.sub(%r{/$}, '')}/ruby-nano-bots/vault"
-
- if prefix
- normalized = prefix.split('/').map do |part|
- Crypto.encrypt(
- part.to_s.gsub('.', '-').force_encoding('UTF-8').to_slug.normalize,
- soft: true
- )
- end.join('/')
-
- path = "#{path}/#{normalized}"
- end
+ path = "#{path.sub(%r{/$}, '')}/ruby-nano-bots"
path = "#{path}/#{cartridge[:meta][:author].to_slug.normalize}"
path = "#{path}/#{cartridge[:meta][:name].to_slug.normalize}"
path = "#{path}/#{cartridge[:meta][:version].to_s.gsub('.', '-').to_slug.normalize}"
+ path = "#{path}/#{end_user(cartridge, environment)}"
path = "#{path}/#{Crypto.encrypt(key, soft: true)}"
path = "#{path}/state.json"
diff --git a/controllers/security.rb b/controllers/security.rb
index 8f066a5..c1180f2 100644
--- a/controllers/security.rb
+++ b/controllers/security.rb
@@ -9,6 +9,10 @@ module NanoBot
Components::Crypto.decrypt(content)
end
+ def self.encrypt(content, soft: false)
+ Components::Crypto.encrypt(content, soft:)
+ end
+
def self.check
password = ENV.fetch('NANO_BOTS_ENCRYPTION_PASSWORD', nil)
password = 'UNSAFE' unless password && password != ''
diff --git a/docker-compose.example.yml b/docker-compose.example.yml
index 4b7b5ec..51b96aa 100644
--- a/docker-compose.example.yml
+++ b/docker-compose.example.yml
@@ -5,10 +5,10 @@ services:
image: ruby:3.2.2-slim-bullseye
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.0.10 && bash"
environment:
- NANO_BOTS_ENCRYPTION_PASSWORD: UNSAFE
OPENAI_API_ADDRESS: https://api.openai.com
- OPENAI_API_ACCESS_TOKEN: your-token
- OPENAI_API_USER_IDENTIFIER: your-user
+ OPENAI_API_KEY: your-access-token
+ NANO_BOTS_ENCRYPTION_PASSWORD: UNSAFE
+ NANO_BOTS_END_USER: your-user
volumes:
- - ./your-cartridges:/cartridges
- # - ./your-data:/data
+ - ./your-cartridges:/.local/share/nano-bots/cartridges
+ - ./your-state:/.local/state/nano-bots
diff --git a/static/cartridges/baseline.yml b/static/cartridges/baseline.yml
index b5eed62..50c4756 100644
--- a/static/cartridges/baseline.yml
+++ b/static/cartridges/baseline.yml
@@ -1,14 +1,17 @@
---
meta:
+ symbol: 🤖
name: Unknown
- author: Nobody
+ author: None
version: 0.0.0
+ license: CC0-1.0
+ description: Unknown
provider:
- name: openai
+ id: openai
+ credentials:
+ address: ENV/OPENAI_API_ADDRESS
+ access-token: ENV/OPENAI_API_KEY
settings:
+ user: ENV/NANO_BOTS_END_USER
model: gpt-3.5-turbo
- credentials:
- address: ENV/OPENAI_API_ADDRESS
- access-token: ENV/OPENAI_API_ACCESS_TOKEN
- user-identifier: ENV/OPENAI_API_USER_IDENTIFIER
diff --git a/static/cartridges/default.yml b/static/cartridges/default.yml
index 9a89a4b..2cadc8c 100644
--- a/static/cartridges/default.yml
+++ b/static/cartridges/default.yml
@@ -8,7 +8,6 @@ interfaces:
prompt:
- text: '🤖'
- text: '> '
- color: blue
eval:
output:
stream: true