summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
Diffstat (limited to 'spec')
-rw-r--r--spec/components/storage_spec.rb53
-rw-r--r--spec/data/cartridges/block.md7
-rw-r--r--spec/data/cartridges/markdown.md37
-rw-r--r--spec/data/cartridges/meta.md25
-rw-r--r--spec/data/cartridges/models/ollama/phi-2.yml (renamed from spec/data/cartridges/models/ollama/llama2.yml)4
-rw-r--r--spec/data/cartridges/tools.md76
-rw-r--r--spec/logic/cartridge/parser_spec.rb119
-rw-r--r--spec/logic/helpers/hash_spec.rb17
8 files changed, 336 insertions, 2 deletions
diff --git a/spec/components/storage_spec.rb b/spec/components/storage_spec.rb
new file mode 100644
index 0000000..99131dd
--- /dev/null
+++ b/spec/components/storage_spec.rb
@@ -0,0 +1,53 @@
+# frozen_string_literal: true
+
+require_relative '../../components/storage'
+
+RSpec.describe NanoBot::Components::Storage do
+ it 'symbolizes keys' do
+ expect(
+ described_class.cartridges_path(
+ components: { home: '/home/aqua', ENV: {}, directory?: ->(_) { true } }
+ )
+ ).to eq('/home/aqua/.local/share/nano-bots/cartridges')
+
+ expect(
+ described_class.cartridges_path(
+ components: {
+ home: '/home/aqua',
+ ENV: { 'NANO_BOTS_CARTRIDGES_DIRECTORY' => '/home/aqua/my-cartridges' },
+ directory?: ->(_) { true }
+ }
+ )
+ ).to eq('/home/aqua/my-cartridges')
+
+ expect(
+ described_class.cartridges_path(
+ components: {
+ home: '/home/aqua',
+ ENV: {
+ 'NANO_BOTS_CARTRIDGES_DIRECTORY' => '/home/aqua/my-cartridges',
+ 'NANO_BOTS_CARTRIDGES_PATH' => '/home/aqua/lime/my-cartridges'
+ },
+ directory?: ->(_) { true }
+ }
+ )
+ ).to eq('/home/aqua/lime/my-cartridges:/home/aqua/my-cartridges')
+
+ expect(
+ described_class.cartridges_path(
+ components: {
+ home: '/home/aqua',
+ ENV: {
+ 'NANO_BOTS_CARTRIDGES_DIRECTORY' => '/home/aqua/my-cartridges',
+ 'NANO_BOTS_CARTRIDGES_PATH' => '/home/aqua/lime/my-cartridges:/home/aqua/ivory/my-cartridges'
+ },
+ directory?: lambda do |path|
+ { '/home/aqua/my-cartridges' => true,
+ '/home/aqua/lime/my-cartridge' => false,
+ '/home/aqua/ivory/my-cartridges' => true }[path]
+ end
+ }
+ )
+ ).to eq('/home/aqua/ivory/my-cartridges:/home/aqua/my-cartridges')
+ end
+end
diff --git a/spec/data/cartridges/block.md b/spec/data/cartridges/block.md
new file mode 100644
index 0000000..ef8588d
--- /dev/null
+++ b/spec/data/cartridges/block.md
@@ -0,0 +1,7 @@
+First, we need to add some important details:
+```yaml
+safety:
+ functions:
+ sandboxed: false
+```
+Hi!
diff --git a/spec/data/cartridges/markdown.md b/spec/data/cartridges/markdown.md
new file mode 100644
index 0000000..cd50b7b
--- /dev/null
+++ b/spec/data/cartridges/markdown.md
@@ -0,0 +1,37 @@
+A cartridge is a YAML file with human-readable data that outlines the bot's goals, expected behaviors, and settings for authentication and provider utilization.
+
+We begin with the meta section, which provides information about what this cartridge is designed for:
+
+```yaml
+meta:
+ symbol: 🤖
+ name: ChatGPT 4 Turbo
+ author: icebaker
+ version: 0.0.1
+ license: CC0-1.0
+ description: A helpful assistant.
+```
+
+It includes details like versioning and license.
+
+Next, we add a behavior section that will provide the bot with a directive on how it should behave:
+
+```yaml
+behaviors:
+ interaction:
+ directive: You are a helpful assistant.
+```
+
+Now, we need to provide instructions on how this Nano Bot should connect with a provider, which credentials to use, and what specific configurations for the LLM are required:
+
+```yaml
+provider:
+ id: openai
+ credentials:
+ access-token: ENV/OPENAI_API_KEY
+ settings:
+ user: ENV/NANO_BOTS_END_USER
+ model: gpt-4-1106-preview
+```
+
+In my API, I have set the environment variables `OPENAI_API_KEY` and `NANO_BOTS_END_USER`, which is where the values for these will come from.
diff --git a/spec/data/cartridges/meta.md b/spec/data/cartridges/meta.md
new file mode 100644
index 0000000..68a0cbd
--- /dev/null
+++ b/spec/data/cartridges/meta.md
@@ -0,0 +1,25 @@
+Start by defining a meta section:
+
+```yaml
+meta:
+ symbol: 🤖
+ name: Nano Bot Name
+ author: Your Name
+ description: A helpful assistant.
+```
+
+You can also add version and license information:
+
+```yaml
+meta:
+ version: 1.0.0
+ license: CC0-1.0
+```
+
+Then, add a behavior section:
+
+```yaml
+behaviors:
+ interaction:
+ directive: You are a helpful assistant.
+```
diff --git a/spec/data/cartridges/models/ollama/llama2.yml b/spec/data/cartridges/models/ollama/phi-2.yml
index 7f20753..5c8e131 100644
--- a/spec/data/cartridges/models/ollama/llama2.yml
+++ b/spec/data/cartridges/models/ollama/phi-2.yml
@@ -1,10 +1,10 @@
---
meta:
symbol: 🦙
- name: Llama 2 through Ollama
+ name: Phi-2 through Ollama
license: CC0-1.0
provider:
id: ollama
settings:
- model: llama2
+ model: phi
diff --git a/spec/data/cartridges/tools.md b/spec/data/cartridges/tools.md
new file mode 100644
index 0000000..5d2da5a
--- /dev/null
+++ b/spec/data/cartridges/tools.md
@@ -0,0 +1,76 @@
+A cartridge is a YAML file with human-readable data that outlines the bot's goals, expected behaviors, and settings for authentication and provider utilization.
+
+We begin with the meta section, which provides information about what this cartridge is designed for:
+
+```yaml
+meta:
+ symbol: 🕛
+ name: Date and Time
+ author: icebaker
+ version: 0.0.1
+ license: CC0-1.0
+ description: A helpful assistant.
+```
+
+It includes details like versioning and license.
+
+Next, we add a behavior section that will provide the bot with a directive on how it should behave:
+
+```yaml
+behaviors:
+ interaction:
+ directive: You are a helpful assistant.
+```
+
+Now, we need to provide instructions on how this Nano Bot should connect with a provider, which credentials to use, and what specific configurations for the LLM are required:
+
+```yaml
+provider:
+ id: openai
+ credentials:
+ access-token: ENV/OPENAI_API_KEY
+ settings:
+ user: ENV/NANO_BOTS_END_USER
+ model: gpt-4-1106-preview
+```
+
+In my API, I have set the environment variables `OPENAI_API_KEY` and `NANO_BOTS_END_USER`, which is where the values for these will come from.
+
+Nano Bot ready; let's start adding some extra power to it.
+
+## Random Numbers
+
+```yml
+tools:
+- name: random-number
+ description: Generates a random number within a given range.
+ parameters:
+ type: object
+ properties:
+ from:
+ type: integer
+ description: The minimum expected number for random generation.
+ to:
+ type: integer
+ description: The maximum expected number for random generation.
+ required:
+ - from
+ - to
+```
+
+```clj
+(let [{:strs [from to]} parameters]
+ (+ from (rand-int (+ 1 (- to from)))))
+```
+
+## Date and Time
+
+```yaml
+tools:
+- name: date-and-time
+ description: Returns the current date and time.
+```
+
+```fnl
+(os.date)
+```
diff --git a/spec/logic/cartridge/parser_spec.rb b/spec/logic/cartridge/parser_spec.rb
new file mode 100644
index 0000000..8297baa
--- /dev/null
+++ b/spec/logic/cartridge/parser_spec.rb
@@ -0,0 +1,119 @@
+# frozen_string_literal: true
+
+require_relative '../../../logic/cartridge/parser'
+
+RSpec.describe NanoBot::Logic::Cartridge::Parser do
+ context 'markdown' do
+ context 'default' do
+ let(:raw) { File.read('spec/data/cartridges/markdown.md') }
+
+ it 'parses markdown cartridge' do
+ expect(described_class.parse(raw, format: 'md')).to eq(
+ { meta: {
+ symbol: '🤖',
+ name: 'ChatGPT 4 Turbo',
+ author: 'icebaker',
+ version: '0.0.1',
+ license: 'CC0-1.0',
+ description: 'A helpful assistant.'
+ },
+ behaviors: { interaction: { directive: 'You are a helpful assistant.' } },
+ provider: {
+ id: 'openai',
+ credentials: { 'access-token': 'ENV/OPENAI_API_KEY' },
+ settings: {
+ user: 'ENV/NANO_BOTS_END_USER',
+ model: 'gpt-4-1106-preview'
+ }
+ } }
+ )
+ end
+ end
+
+ context 'meta' do
+ let(:raw) { File.read('spec/data/cartridges/meta.md') }
+
+ it 'parses markdown cartridge' do
+ expect(described_class.parse(raw, format: 'md')).to eq(
+ {
+ meta: {
+ symbol: '🤖',
+ name: 'Nano Bot Name',
+ author: 'Your Name',
+ description: 'A helpful assistant.',
+ version: '1.0.0',
+ license: 'CC0-1.0'
+ },
+ behaviors: {
+ interaction: {
+ directive: 'You are a helpful assistant.'
+ }
+ }
+ }
+ )
+ end
+ end
+
+ context 'tools' do
+ let(:raw) { File.read('spec/data/cartridges/tools.md') }
+
+ it 'parses markdown cartridge' do
+ expect(described_class.parse(raw, format: 'md')).to eq(
+ { meta: {
+ symbol: '🕛',
+ name: 'Date and Time',
+ author: 'icebaker',
+ version: '0.0.1',
+ license: 'CC0-1.0',
+ description: 'A helpful assistant.'
+ },
+ behaviors: {
+ interaction: {
+ directive: 'You are a helpful assistant.'
+ }
+ },
+ provider: {
+ id: 'openai',
+ credentials: { 'access-token': 'ENV/OPENAI_API_KEY' },
+ settings: {
+ user: 'ENV/NANO_BOTS_END_USER',
+ model: 'gpt-4-1106-preview'
+ }
+ },
+ tools: [
+ { name: 'random-number',
+ description: 'Generates a random number within a given range.',
+ parameters: {
+ type: 'object',
+ properties: {
+ from: {
+ type: 'integer',
+ description: 'The minimum expected number for random generation.'
+ },
+ to: {
+ type: 'integer',
+ description: 'The maximum expected number for random generation.'
+ }
+ },
+ required: %w[from to]
+ },
+ clojure: "(let [{:strs [from to]} parameters]\n (+ from (rand-int (+ 1 (- to from)))))\n" },
+ { name: 'date-and-time',
+ description: 'Returns the current date and time.',
+ fennel: "(os.date)\n" }
+ ] }
+ )
+ end
+ end
+
+ context 'block' do
+ let(:raw) { File.read('spec/data/cartridges/block.md') }
+
+ it 'parses markdown cartridge' do
+ expect(described_class.parse(raw, format: 'md')).to eq(
+ { safety: { functions: { sandboxed: false } } }
+ )
+ end
+ end
+ end
+end
diff --git a/spec/logic/helpers/hash_spec.rb b/spec/logic/helpers/hash_spec.rb
index 09012c8..0da92fb 100644
--- a/spec/logic/helpers/hash_spec.rb
+++ b/spec/logic/helpers/hash_spec.rb
@@ -7,7 +7,24 @@ RSpec.describe NanoBot::Logic::Helpers::Hash do
expect(described_class.symbolize_keys({ 'a' => 'b', 'c' => { 'd' => ['e'] } })).to eq(
{ a: 'b', c: { d: ['e'] } }
)
+ end
+
+ it 'deep merges' do
+ expect(described_class.deep_merge(
+ { a: { x: 1, y: 2 }, b: 3 },
+ { a: { y: 99, z: 4 }, c: 5 }
+ )).to eq(
+ { a: { x: 1, y: 99, z: 4 }, b: 3, c: 5 }
+ )
+ end
+
+ it 'stringify keys' do
+ expect(described_class.stringify_keys({ a: 'b', c: { d: [:e] } })).to eq(
+ { 'a' => 'b', 'c' => { 'd' => [:e] } }
+ )
+ end
+ it 'fetch a path of keys' do
expect(described_class.fetch({ a: 'b', c: { d: ['e'] } }, %i[c d])).to eq(
['e']
)