pedicab 0.3.1 → 0.3.3

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.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/API.md +401 -0
  3. data/EXAMPLES.md +884 -0
  4. data/Gemfile.lock +10 -24
  5. data/INSTALLATION.md +652 -0
  6. data/README.md +329 -10
  7. data/lib/pedicab/#city.rb# +27 -0
  8. data/lib/pedicab/ride.rb +60 -81
  9. data/lib/pedicab/version.rb +1 -1
  10. data/lib/pedicab.py +3 -8
  11. data/lib/pedicab.rb +141 -133
  12. metadata +6 -89
  13. data/#README.md# +0 -51
  14. data/books/Arnold_Bennett-How_to_Live_on_24_Hours_a_Day.txt +0 -1247
  15. data/books/Edward_L_Bernays-crystallizing_public_opinion.txt +0 -4422
  16. data/books/Emma_Goldman-Anarchism_and_Other_Essays.txt +0 -7654
  17. data/books/Office_of_Strategic_Services-Simple_Sabotage_Field_Manual.txt +0 -1057
  18. data/books/Sigmund_Freud-Group_Psychology_and_The_Analysis_of_The_Ego.txt +0 -2360
  19. data/books/Steve_Hassan-The_Bite_Model.txt +0 -130
  20. data/books/Steve_Hassan-The_Bite_Model.txt~ +0 -132
  21. data/books/Sun_Tzu-Art_of_War.txt +0 -159
  22. data/books/Sun_Tzu-Art_of_War.txt~ +0 -166
  23. data/books/US-Constitution.txt +0 -502
  24. data/books/US-Constitution.txt~ +0 -502
  25. data/books/cia-kubark.txt +0 -4637
  26. data/books/machiavelli-the_prince.txt +0 -4599
  27. data/books/sun_tzu-art_of_war.txt +0 -1017
  28. data/books/us_army-bayonette.txt +0 -843
  29. data/lib/pedicab/calc.rb~ +0 -8
  30. data/lib/pedicab/link.rb +0 -38
  31. data/lib/pedicab/link.rb~ +0 -14
  32. data/lib/pedicab/mark.rb +0 -9
  33. data/lib/pedicab/mark.rb~ +0 -5
  34. data/lib/pedicab/on.rb +0 -6
  35. data/lib/pedicab/on.rb~ +0 -6
  36. data/lib/pedicab/poke.rb +0 -14
  37. data/lib/pedicab/poke.rb~ +0 -15
  38. data/lib/pedicab/query.rb +0 -92
  39. data/lib/pedicab/query.rb~ +0 -93
  40. data/lib/pedicab/rank.rb +0 -92
  41. data/lib/pedicab/rank.rb~ +0 -89
  42. data/lib/pedicab/ride.rb~ +0 -101
  43. data/lib/pedicab.sh~ +0 -3
data/lib/pedicab.rb CHANGED
@@ -3,174 +3,182 @@
3
3
  require "benchmark"
4
4
  require "open3"
5
5
  require "json"
6
- require "eqn"
7
- require "httparty"
8
- require "redcarpet"
9
- require "nokogiri"
10
- #require "knn"
6
+ require "erb"
7
+
11
8
  require_relative "pedicab/version"
12
- require_relative "pedicab/on"
13
- require_relative "pedicab/mark"
14
- require_relative "pedicab/rank"
15
- require_relative "pedicab/poke"
16
- require_relative "pedicab/query"
17
- require_relative "pedicab/link"
18
9
  require_relative "pedicab/ride"
19
10
 
20
11
  module Pedicab
12
+ # Base exception class for Pedicab-specific errors
21
13
  class Error < StandardError; end
14
+
15
+ @@MEMORY= 5
16
+ def self.memory
17
+ @@MEMORY
18
+ end
19
+
20
+ def self.memory= size
21
+ @@MEMORY = size
22
+ end
23
+ # Lists all available GGUF models in the /models directory
24
+ #
25
+ # @return [Array<String>] Array of model names (without .gguf extension)
26
+ # @example
27
+ # puts Pedicab.models
28
+ # => ["qwen", "llama2", "mistral"]
22
29
  def self.models
23
30
  Dir['/models/*'].map { |e| e.gsub('.gguf', '').gsub('/models/','') }
24
31
  end
25
- class P
26
32
 
27
- LIST = {
28
- questions: "all unique questions necessary to respond to the following",
29
- facts: "unique pieces of information within the following",
30
- entities: "unique named entities within the following"
31
- }
33
+ # Main conversation interface for AI interactions
34
+ # Provides context management, state tracking, and elegant operator syntax
35
+ class P
36
+ # @return [Float] Time taken for the last request in seconds
37
+ # @return [Array<Float>] Array of processing times for all requests
38
+ # @return [Array<String>] Array of LLM thinking processes
39
+ # @return [String] The last prompt sent to the model
40
+ # @return [Array<String>] Array of all responses received
41
+ # @return [String] The last response content
42
+ # @return [Pedicab::Ride] The associated ride instance for direct model access
43
+ # @return [Array<String>] Array of previous prompts
44
+ attr_reader :took, :time, :thoughts, :prompt, :response, :out, :ride, :last
32
45
 
33
- attr_reader :took, :response, :rank
34
- attr_accessor :out
46
+ # @return [Proc] Response handler lambda
47
+ # @return [Hash] Current conversation context
48
+ attr_accessor :handler, :context
35
49
 
36
- def initialize k
50
+ # Initialize a new conversation instance
51
+ #
52
+ # @param id [String] Unique identifier for the conversation
53
+ # @example
54
+ # ai = Pedicab::P.new('my_bot')
55
+ # response = ai["Hello, world!"]
56
+ def initialize(k)
37
57
  @id = k
38
- @ride = Pedicab.ride[k]
58
+ @handler = lambda { |s| s.out }
59
+ @ride = Pedicab.ride(k)
60
+ @context = {}
39
61
  reset!
40
62
  end
41
-
42
- ##
43
- # extract intent.
44
- def intent i
45
- @intent = @ride.go(%[Respond with only the single word describing the type of the response necessary for the following:\n#{i}])
46
- end
47
63
 
48
- ##
49
- # reset context.
64
+ # Reset all conversation state, context, and history
65
+ # Clears prompts, responses, timing data, and ride state
66
+ #
67
+ # @return [void]
68
+ # @example
69
+ # ai.reset! # Start fresh conversation
50
70
  def reset!
51
71
  @ride.reset!
72
+ @exe = ""
73
+ @time = []
74
+ @last = []
52
75
  @response = []
53
- @rank = RANK[@id]
54
- @intent = ""
55
- @prompt = ""
56
- @out = ""
57
- @took = 0
76
+ @thoughts = []
77
+ @prompt = nil
78
+ @out = nil
79
+ @took = 0
58
80
  end
59
81
 
60
- def dispatch i
61
- @ride.go(i)
62
- end
63
-
64
- ##
65
- # if x, continue...
66
- def gate x, &b
67
- if @ride.go? ERB.new(x).result(binding)
68
- if block_given?
69
- b.call(self)
70
- else
71
- return true
72
- end
73
- else
74
- if !block_given?
75
- return false
76
- end
82
+ # Set or execute the response handler
83
+ #
84
+ # @param block [Proc, nil] Optional handler that receives the response object
85
+ # @return [Proc] The handler when setting, or handler result when executing
86
+ # @example
87
+ # # Set custom handler
88
+ # ai.handle { |response| puts response.out }
89
+ #
90
+ # # Execute handler
91
+ # result = ai.handle
92
+ def handle(&block)
93
+ @handler = block
94
+ if @response.length > Pedicab.memory
95
+ @response.shift
96
+ @last.shift
97
+ @thoughts.shift
77
98
  end
78
99
  end
79
100
 
80
- ##
81
- # process prompt into context.
82
- def prompt i
83
- @prompt = i
84
- @took = Benchmark.realtime { @out = dispatch([@response[-1], @prompt].flatten.compact.uniq.join("\n")) }
85
- @response << @out
86
- return @out
87
- end
88
-
89
- ##
90
- # distill input
91
- def extract i
92
- @ride.go(%[Distill and outline the following without repeating yourself in the simplest possible terms:\n#{i}])
93
- end
94
- ##
95
- # compile output
96
- def compile i
97
- @ride.go("Expand on the following and outline in plaintext without repeating yourself:\n#{i}").gsub("Outline:\n","").gsub(/\n\n+/, "\n")
98
- end
99
- ##
100
- # integrate
101
- def outline i
102
- @ride.go("#{@respond.join("\n")}\nDistill the following into the above outline without repeating yourself:\n#{i}")
103
- end
104
- ##
105
- # chain links
106
- def chain i
107
- a = []
108
- LINK.each_pair { |k,v| if @ride.go?(%[A response to the following requires #{k}:\n#{i}]); a << k; end }
109
- aa = a.compact.shuffle
110
- puts %[#---[CHAIN]---> #{aa}]
111
- [ aa.map { |e| LINK.on[e].call(self, i) }, i ].flatten
101
+ # Start a fresh conversation with the given prompt
102
+ # Clears previous context and begins a new conversation
103
+ #
104
+ # @param input [String] The prompt to send to the LLM
105
+ # @return [Object] Result of the handler (typically the response object)
106
+ # @example
107
+ # response = ai["What is the meaning of life?"]
108
+ # puts response.out
109
+ def [] input
110
+ reset!
111
+ @prompt = input
112
+ think(input)
113
+ @handler.call(self)
112
114
  end
113
115
 
114
- ##
115
- # Is response complete?
116
- def done?
117
- @ride.go?(%["#{@out}" truthfully answers the following:\n#{@prompt}])
118
- end
119
-
120
- ##
121
- # Is intent met by current output?
122
- def ready?
123
- @ride.go?(%[The following satisfies #{@intent}:\n#{@out}])
124
- end
125
-
126
- ##
127
- # extract elements from prompt.
128
- def each i, p, &b
129
- @took = Benchmark.realtime { @ride.go!(i, p) { |e| b.call(e) } }
130
- end
131
-
132
- ##
133
- # extract questions and expand into context.
134
- def more q
135
- each(LIST[:questions], POKE[q]) { |e| dispatch(%[#{e}\n#{@ride.go(e)}]); }
116
+ # Continue an existing conversation with context
117
+ # Maintains previous exchanges and builds upon them
118
+ #
119
+ # @param input [String] The prompt to send to the LLM
120
+ # @return [Object] Result of the handler (typically the response object)
121
+ # @example
122
+ # ai["What is Ruby?"] # First question
123
+ # ai << "What about Python?" # Continues with context
124
+ def << input
125
+ @last << @prompt if @prompt
126
+ @prompt = input
127
+ think(input)
128
+ @handler.call(self)
136
129
  end
137
-
138
- ##
139
- # process inputs into context.
140
130
 
141
- def [] i
142
- reset!
143
- prompt(POKE[i])
131
+ # Calculate total processing time for all requests in the conversation
132
+ #
133
+ # @return [Float] Total time in seconds
134
+ # @example
135
+ # ai["Question 1"]
136
+ # ai["Question 2"]
137
+ # puts "Total time: #{ai.life}s"
138
+ def life
139
+ a = 0
140
+ @time.map { |e| a += e }
141
+ return a
144
142
  end
145
143
 
146
- def << i
147
- dispatch(POKE[i])
148
- end
149
- end
144
+ private
150
145
 
151
- def self.chunk text, size=1024, &b
152
- chunks = []
153
- paragraphs = text.split(/\n\n+/)
154
-
155
- current_chunk = ""
156
- paragraphs.each do |para|
157
- # If adding this paragraph would exceed chunk size
158
- if current_chunk.length + para.length > size && !current_chunk.empty?
159
- chunks << current_chunk
160
- current_chunk = para
161
- else
162
- current_chunk += (current_chunk.empty? ? "" : "\n\n") + para
146
+ # Process a prompt through the LLM with conversation context
147
+ # Builds context from previous exchanges and sends to the ride
148
+ #
149
+ # @param input [String] The prompt to process
150
+ # @return [String] The response content
151
+ def think(input)
152
+ # Build conversation context from previous exchanges
153
+ @context = @last.zip(@response).map { |k, v| "#{k}\n#{v}" }.join("\n\n")
154
+ full_prompt = [@context, @prompt].compact.join("\n\n")
155
+
156
+ # Process through the ride with timing
157
+ @took = Benchmark.realtime { @out = @ride.go(full_prompt) }
158
+
159
+ # Extract executable code if present in response
160
+ if m = /```(.*)```/.match(@out)
161
+ @exe = m[1]
163
162
  end
164
- end
165
- chunks << current_chunk unless current_chunk.empty?
166
- if block_given?
167
- return chunks.map { |e| b.call(self, e) }
168
- else
169
- return chunks
163
+
164
+ # Record timing and response data
165
+ @time << @took
166
+ @thoughts << @ride[:thought]
167
+ @response << @out
168
+ @out
170
169
  end
171
170
  end
172
171
 
172
+ # Create a new conversation instance (convenience method)
173
+ #
174
+ # @param k [String] Unique identifier for the conversation
175
+ # @return [Pedicab::P] New conversation instance
176
+ # @example
177
+ # ai = Pedicab['my_assistant']
178
+ # response = ai["Hello, world!"]
173
179
  def self.[] k
174
180
  P.new(k)
175
181
  end
176
182
  end
183
+
184
+
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pedicab
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Erik Olson
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-11-21 00:00:00.000000000 Z
11
+ date: 2026-01-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: benchmark
@@ -52,62 +52,6 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
- - !ruby/object:Gem::Dependency
56
- name: eqn
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :runtime
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '0'
69
- - !ruby/object:Gem::Dependency
70
- name: httparty
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- type: :runtime
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
- - !ruby/object:Gem::Dependency
84
- name: redcarpet
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- type: :runtime
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '0'
97
- - !ruby/object:Gem::Dependency
98
- name: nokogiri
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: '0'
104
- type: :runtime
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - ">="
109
- - !ruby/object:Gem::Version
110
- version: '0'
111
55
  description:
112
56
  email:
113
57
  - xorgnak@xorgnak.com
@@ -115,48 +59,21 @@ executables: []
115
59
  extensions: []
116
60
  extra_rdoc_files: []
117
61
  files:
118
- - "#README.md#"
62
+ - API.md
119
63
  - CHANGELOG.md
120
64
  - CODE_OF_CONDUCT.md
65
+ - EXAMPLES.md
121
66
  - Gemfile
122
67
  - Gemfile.lock
68
+ - INSTALLATION.md
123
69
  - LICENSE.txt
124
70
  - README.md
125
71
  - Rakefile
126
- - books/Arnold_Bennett-How_to_Live_on_24_Hours_a_Day.txt
127
- - books/Edward_L_Bernays-crystallizing_public_opinion.txt
128
- - books/Emma_Goldman-Anarchism_and_Other_Essays.txt
129
- - books/Office_of_Strategic_Services-Simple_Sabotage_Field_Manual.txt
130
- - books/Sigmund_Freud-Group_Psychology_and_The_Analysis_of_The_Ego.txt
131
- - books/Steve_Hassan-The_Bite_Model.txt
132
- - books/Steve_Hassan-The_Bite_Model.txt~
133
- - books/Sun_Tzu-Art_of_War.txt
134
- - books/Sun_Tzu-Art_of_War.txt~
135
- - books/US-Constitution.txt
136
- - books/US-Constitution.txt~
137
- - books/cia-kubark.txt
138
- - books/machiavelli-the_prince.txt
139
- - books/sun_tzu-art_of_war.txt
140
- - books/us_army-bayonette.txt
141
72
  - lib/pedicab.py
142
73
  - lib/pedicab.rb
143
74
  - lib/pedicab.sh
144
- - lib/pedicab.sh~
145
- - lib/pedicab/calc.rb~
146
- - lib/pedicab/link.rb
147
- - lib/pedicab/link.rb~
148
- - lib/pedicab/mark.rb
149
- - lib/pedicab/mark.rb~
150
- - lib/pedicab/on.rb
151
- - lib/pedicab/on.rb~
152
- - lib/pedicab/poke.rb
153
- - lib/pedicab/poke.rb~
154
- - lib/pedicab/query.rb
155
- - lib/pedicab/query.rb~
156
- - lib/pedicab/rank.rb
157
- - lib/pedicab/rank.rb~
75
+ - lib/pedicab/#city.rb#
158
76
  - lib/pedicab/ride.rb
159
- - lib/pedicab/ride.rb~
160
77
  - lib/pedicab/version.rb
161
78
  - sig/pedicab.rbs
162
79
  homepage: https://github.com/xorgnak/pedicab
data/#README.md# DELETED
@@ -1,51 +0,0 @@
1
- # Pedicab
2
- Install: bundle add pedicab
3
- bundler managed?: gem install pedicab
4
-
5
- ## Usage
6
-
7
- What you going?
8
- 0h!
9
-
10
- the gem!?
11
-
12
- okay.
13
-
14
- "AI" has been around since before buddy holly. Not citiong sources, but generic gguf files are the newest and asap pending *. Short-fast-n-lould is their're a tech you should "understand"; no judgment.
15
-
16
- 1. LLM's are a giant pattern response engines without souls.
17
-
18
- 2. do the pre-req'. (curl a .gguf into /models/model.gguf)
19
- 2.a. **Seriously!?**: Yes, that's it. no details. dealer's choice. figure it out.
20
-
21
- 2. You cab fix that with:
22
-
23
- a. your favorite author.
24
- b. your corpo gibberish.
25
- c. you'll figure it out.
26
-
27
- Either way, use the `books/` to seed your distills. Do it, and enjoy the product o' their results.
28
-
29
- usage:
30
-
31
- ```
32
- @me = Pedicab['me']
33
-
34
- # to seed the model context.
35
- my = @me << "What is the meaning of life>?"
36
-
37
- # ... ( to expound... )
38
- # @me["But what if I'm a piece o'poop?"]
39
- # => try it, it works,
40
-
41
- # question: could I give you more guildance?
42
- # answert: yes.
43
-
44
- # question: would it matter?
45
- # answer: no. figure it out.
46
-
47
- # summary:
48
- #
49
-
50
-
51
- ```