scout-ai 0.2.0 → 1.0.0

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 (80) hide show
  1. checksums.yaml +4 -4
  2. data/.vimproject +91 -10
  3. data/Rakefile +1 -0
  4. data/VERSION +1 -1
  5. data/bin/scout-ai +2 -0
  6. data/lib/scout/llm/agent/chat.rb +24 -0
  7. data/lib/scout/llm/agent.rb +13 -13
  8. data/lib/scout/llm/ask.rb +26 -16
  9. data/lib/scout/llm/backends/bedrock.rb +129 -0
  10. data/lib/scout/llm/backends/huggingface.rb +6 -21
  11. data/lib/scout/llm/backends/ollama.rb +69 -36
  12. data/lib/scout/llm/backends/openai.rb +85 -35
  13. data/lib/scout/llm/backends/openwebui.rb +1 -1
  14. data/lib/scout/llm/backends/relay.rb +3 -2
  15. data/lib/scout/llm/backends/responses.rb +272 -0
  16. data/lib/scout/llm/chat.rb +547 -0
  17. data/lib/scout/llm/parse.rb +70 -13
  18. data/lib/scout/llm/tools.rb +126 -5
  19. data/lib/scout/llm/utils.rb +17 -10
  20. data/lib/scout/model/base.rb +19 -0
  21. data/lib/scout/model/python/base.rb +25 -0
  22. data/lib/scout/model/python/huggingface/causal/next_token.rb +23 -0
  23. data/lib/scout/model/python/huggingface/causal.rb +29 -0
  24. data/lib/scout/model/python/huggingface/classification +0 -0
  25. data/lib/scout/model/python/huggingface/classification.rb +50 -0
  26. data/lib/scout/model/python/huggingface.rb +112 -0
  27. data/lib/scout/model/python/torch/dataloader.rb +57 -0
  28. data/lib/scout/model/python/torch/helpers.rb +84 -0
  29. data/lib/scout/model/python/torch/introspection.rb +34 -0
  30. data/lib/scout/model/python/torch/load_and_save.rb +47 -0
  31. data/lib/scout/model/python/torch.rb +94 -0
  32. data/lib/scout/model/util/run.rb +181 -0
  33. data/lib/scout/model/util/save.rb +81 -0
  34. data/lib/scout-ai.rb +3 -1
  35. data/python/scout_ai/__init__.py +35 -0
  36. data/python/scout_ai/__pycache__/__init__.cpython-310.pyc +0 -0
  37. data/python/scout_ai/__pycache__/__init__.cpython-311.pyc +0 -0
  38. data/python/scout_ai/__pycache__/huggingface.cpython-310.pyc +0 -0
  39. data/python/scout_ai/__pycache__/huggingface.cpython-311.pyc +0 -0
  40. data/python/scout_ai/__pycache__/util.cpython-310.pyc +0 -0
  41. data/python/scout_ai/__pycache__/util.cpython-311.pyc +0 -0
  42. data/python/scout_ai/atcold/__init__.py +0 -0
  43. data/python/scout_ai/atcold/plot_lib.py +141 -0
  44. data/python/scout_ai/atcold/spiral.py +27 -0
  45. data/python/scout_ai/huggingface/data.py +48 -0
  46. data/python/scout_ai/huggingface/eval.py +60 -0
  47. data/python/scout_ai/huggingface/model.py +29 -0
  48. data/python/scout_ai/huggingface/rlhf.py +83 -0
  49. data/python/scout_ai/huggingface/train/__init__.py +34 -0
  50. data/python/scout_ai/huggingface/train/__pycache__/__init__.cpython-310.pyc +0 -0
  51. data/python/scout_ai/huggingface/train/__pycache__/next_token.cpython-310.pyc +0 -0
  52. data/python/scout_ai/huggingface/train/next_token.py +315 -0
  53. data/python/scout_ai/language_model.py +70 -0
  54. data/python/scout_ai/util.py +32 -0
  55. data/scout-ai.gemspec +130 -0
  56. data/scout_commands/agent/ask +133 -15
  57. data/scout_commands/agent/kb +15 -0
  58. data/scout_commands/llm/ask +71 -12
  59. data/scout_commands/llm/process +4 -2
  60. data/test/data/cat.jpg +0 -0
  61. data/test/scout/llm/agent/test_chat.rb +14 -0
  62. data/test/scout/llm/backends/test_bedrock.rb +60 -0
  63. data/test/scout/llm/backends/test_huggingface.rb +3 -3
  64. data/test/scout/llm/backends/test_ollama.rb +48 -10
  65. data/test/scout/llm/backends/test_openai.rb +96 -11
  66. data/test/scout/llm/backends/test_responses.rb +115 -0
  67. data/test/scout/llm/test_ask.rb +1 -0
  68. data/test/scout/llm/test_chat.rb +214 -0
  69. data/test/scout/llm/test_parse.rb +81 -2
  70. data/test/scout/model/python/huggingface/causal/test_next_token.rb +59 -0
  71. data/test/scout/model/python/huggingface/test_causal.rb +33 -0
  72. data/test/scout/model/python/huggingface/test_classification.rb +30 -0
  73. data/test/scout/model/python/test_base.rb +44 -0
  74. data/test/scout/model/python/test_huggingface.rb +9 -0
  75. data/test/scout/model/python/test_torch.rb +71 -0
  76. data/test/scout/model/python/torch/test_helpers.rb +14 -0
  77. data/test/scout/model/test_base.rb +117 -0
  78. data/test/scout/model/util/test_save.rb +31 -0
  79. metadata +72 -5
  80. data/questions/coach +0 -2
@@ -0,0 +1,44 @@
1
+ require File.expand_path(__FILE__).sub(%r(/test/.*), '/test/test_helper.rb')
2
+ require File.expand_path(__FILE__).sub(%r(.*/test/), '').sub(/test_(.*)\.rb/,'\1')
3
+
4
+ class TestPythonModel < Test::Unit::TestCase
5
+ def test_linear
6
+ model = nil
7
+
8
+ TmpFile.with_path do |dir|
9
+
10
+ dir['model.py'].write <<-EOF
11
+ class TestModel:
12
+ def __init__(self, delta):
13
+ self.delta = delta
14
+
15
+ def eval(self, x):
16
+ return [e + self.delta for e in x]
17
+ EOF
18
+
19
+ model = PythonModel.new dir, 'TestModel', :model, delta: 1
20
+
21
+ model.eval do |sample,list=nil|
22
+ init unless state
23
+ if list
24
+ state.eval(list)
25
+ else
26
+ state.eval([sample])[0]
27
+ end
28
+ end
29
+
30
+ assert_equal 2, model.eval(1)
31
+ assert_equal [4, 6], model.eval_list([3, 5])
32
+
33
+ model.save
34
+
35
+ model = ScoutModel.new dir
36
+
37
+ assert_equal 2, model.eval(1)
38
+
39
+ model = ScoutModel.new dir, delta: 2
40
+
41
+ assert_equal 3, model.eval(1)
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,9 @@
1
+ require File.expand_path(__FILE__).sub(%r(/test/.*), '/test/test_helper.rb')
2
+ require File.expand_path(__FILE__).sub(%r(.*/test/), '').sub(/test_(.*)\.rb/,'\1')
3
+
4
+ class TestHuggingface < Test::Unit::TestCase
5
+ def test_true
6
+ assert true
7
+ end
8
+ end
9
+
@@ -0,0 +1,71 @@
1
+ require File.expand_path(__FILE__).sub(%r(/test/.*), '/test/test_helper.rb')
2
+ require File.expand_path(__FILE__).sub(%r(.*/test/), '').sub(/test_(.*)\.rb/,'\1')
3
+
4
+ class TestTorch < Test::Unit::TestCase
5
+ def test_linear
6
+ model = nil
7
+
8
+ TmpFile.with_dir do |dir|
9
+
10
+ # Create model
11
+
12
+ TorchModel.init_python
13
+
14
+ model = TorchModel.new dir
15
+ model.state = ScoutPython.torch.nn.Linear.new(1, 1)
16
+ model.criterion = ScoutPython.torch.nn.MSELoss.new()
17
+
18
+ model.extract_features do |f|
19
+ [f]
20
+ end
21
+
22
+ model.post_process do |v,list|
23
+ list ? list.collect{|vv| vv.first } : v.first
24
+ end
25
+
26
+ # Train model
27
+
28
+ model.add 5.0, [10.0]
29
+ model.add 10.0, [20.0]
30
+
31
+ model.options[:training_args][:epochs] = 1000
32
+ model.train
33
+
34
+ w = model.get_weights.to_ruby.first.first
35
+
36
+ assert w > 1.8
37
+ assert w < 2.2
38
+
39
+ # Load the model again
40
+
41
+ sss 0
42
+ model.save
43
+
44
+ model = ScoutModel.new dir
45
+
46
+ # Test model
47
+
48
+ y = model.eval_list([100.0, 200.0]).first
49
+
50
+ assert(y > 150.0)
51
+ assert(y < 250.0)
52
+
53
+ y = model.eval(100.0)
54
+
55
+ assert(y > 150.0)
56
+ assert(y < 250.0)
57
+
58
+ test = [1.0, 5.0, 10.0, 20.0]
59
+ input_sum = Misc.sum(test)
60
+ sum = Misc.sum(model.eval_list(test))
61
+ assert sum > 0.8 * input_sum * 2
62
+ assert sum < 1.2 * input_sum * 2
63
+
64
+ w = TorchModel.get_weights(model.state).to_ruby.first.first
65
+
66
+ assert w > 1.8
67
+ assert w < 2.2
68
+ end
69
+ end
70
+ end
71
+
@@ -0,0 +1,14 @@
1
+ require File.expand_path(__FILE__).sub(%r(/test/.*), '/test/test_helper.rb')
2
+ require File.expand_path(__FILE__).sub(%r(.*/test/), '').sub(/test_(.*)\.rb/,'\1')
3
+
4
+ require 'scout/model/python/base'
5
+ class TestTorchHelpers < Test::Unit::TestCase
6
+ def test_del
7
+ ScoutPython.init_scout
8
+ ScoutPython.pyimport :torch
9
+ batch = [[100.0]]
10
+ tensor = TorchModel.tensor(batch, 'cuda', @dtype)
11
+ tensor.del
12
+ end
13
+ end
14
+
@@ -0,0 +1,117 @@
1
+ require File.expand_path(__FILE__).sub(%r(/test/.*), '/test/test_helper.rb')
2
+ require File.expand_path(__FILE__).sub(%r(.*/test/), '').sub(/test_(.*)\.rb/,'\1')
3
+
4
+ class TestClass < Test::Unit::TestCase
5
+ def test_trivial_model
6
+ model = ScoutModel.new
7
+ model.eval do |sample,list=nil|
8
+ if list
9
+ list.collect{|sample|
10
+ sample * 2
11
+ }
12
+ else
13
+ sample * 2
14
+ end
15
+ end
16
+
17
+ assert_equal 2, model.eval(1)
18
+ assert_equal [2, 4], model.eval_list([1, 2])
19
+ end
20
+
21
+ def test_trivial_model_options
22
+ model = ScoutModel.new nil, factor: 4
23
+ model.eval do |sample,list=nil|
24
+ if list
25
+ list.collect{|sample|
26
+ sample * @options[:factor]
27
+ }
28
+ else
29
+ sample * @options[:factor]
30
+ end
31
+ end
32
+
33
+ assert_equal 4, model.eval(1)
34
+ assert_equal [4, 8], model.eval_list([1, 2])
35
+ end
36
+
37
+ def test_R_model
38
+ require 'rbbt-util'
39
+ require 'rbbt/util/R'
40
+
41
+ text =<<-EOF
42
+ 1 0;1;1
43
+ 1 1;0;1
44
+ 1 1;1;1
45
+ 1 0;1;1
46
+ 1 1;;1
47
+ 0 0;1;0
48
+ 0 1;0;0
49
+ 0 0;1;0
50
+ 0 1;0;0
51
+ EOF
52
+
53
+ TmpFile.with_file do |dir|
54
+ Open.mkdir dir
55
+ model = ScoutModel.new dir
56
+
57
+ model.extract_features do |sample|
58
+ sample.split(";")
59
+ end
60
+
61
+ model.train do |list,labels|
62
+ TmpFile.with_file do |feature_file|
63
+ Open.write(feature_file, list.collect{|feats| feats * "\t"} * "\n")
64
+ Open.write(feature_file + '.class', labels * "\n")
65
+ R.run <<-EOF
66
+ features = read.table("#{ feature_file }", sep ="\\t", stringsAsFactors=FALSE);
67
+ labels = scan("#{ feature_file }.class", what=numeric());
68
+ features = cbind(features, class = labels);
69
+ rbbt.require('e1071')
70
+ model = svm(class ~ ., data = features)
71
+ save(model, file="#{ state_file }");
72
+ EOF
73
+ end
74
+ end
75
+
76
+ model.eval do |features|
77
+ TmpFile.with_file do |feature_file|
78
+ TmpFile.with_file do |results|
79
+ Open.write(feature_file, features * "\t")
80
+ R.run <<-EOF
81
+ features = read.table("#{ feature_file }", sep ="\\t", stringsAsFactors=FALSE);
82
+ library(e1071)
83
+ load(file="#{ state_file }")
84
+ label = predict(model, features);
85
+ cat(label, file="#{results}");
86
+ EOF
87
+
88
+ Open.read(results)
89
+ end
90
+ end
91
+ end
92
+
93
+ text.split(/\n/).each do |line|
94
+ label, sample = line.split(" ")
95
+ model.add(sample, label)
96
+ end
97
+
98
+ model.train
99
+
100
+ assert model.eval("1;1;1").to_f > 0.5
101
+ assert model.eval("0;0;0").to_f < 0.5
102
+
103
+ model.save
104
+
105
+ model = ScoutModel.new dir
106
+ assert model.eval("1;1;1").to_f > 0.5
107
+ assert model.eval("0;0;0").to_f < 0.5
108
+
109
+ model.post_process do |result|
110
+ result.to_f < 0.5 ? :bad : :good
111
+ end
112
+
113
+ assert_equal :bad, model.eval("0;0;0")
114
+ end
115
+ end
116
+ end
117
+
@@ -0,0 +1,31 @@
1
+ require File.expand_path(__FILE__).sub(%r(/test/.*), '/test/test_helper.rb')
2
+ require File.expand_path(__FILE__).sub(%r(.*/test/), '').sub(/test_(.*)\.rb/,'\1')
3
+
4
+ require 'scout/model/base'
5
+
6
+ class TestClass < Test::Unit::TestCase
7
+ def test_trivial_model_save
8
+
9
+ TmpFile.with_file do |dir|
10
+ model = ScoutModel.new dir
11
+
12
+ model.eval do |sample,list=nil|
13
+ if list
14
+ list.collect{|sample|
15
+ sample * 2
16
+ }
17
+ else
18
+ sample * 2
19
+ end
20
+ end
21
+
22
+ model.save
23
+
24
+ model = ScoutModel.new dir
25
+
26
+ assert_equal 2, model.eval(1)
27
+ assert_equal [2, 4], model.eval_list([1, 2])
28
+ end
29
+ end
30
+ end
31
+
metadata CHANGED
@@ -1,14 +1,28 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scout-ai
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Miguel Vazquez
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-03-19 00:00:00.000000000 Z
11
- dependencies: []
10
+ date: 2025-06-05 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: scout-rig
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '0'
12
26
  description: assorted functionalities to help scouts use AI
13
27
  email: mikisvaz@gmail.com
14
28
  executables:
@@ -29,38 +43,91 @@ files:
29
43
  - bin/scout-ai
30
44
  - lib/scout-ai.rb
31
45
  - lib/scout/llm/agent.rb
46
+ - lib/scout/llm/agent/chat.rb
32
47
  - lib/scout/llm/ask.rb
48
+ - lib/scout/llm/backends/bedrock.rb
33
49
  - lib/scout/llm/backends/huggingface.rb
34
50
  - lib/scout/llm/backends/ollama.rb
35
51
  - lib/scout/llm/backends/openai.rb
36
52
  - lib/scout/llm/backends/openwebui.rb
37
53
  - lib/scout/llm/backends/relay.rb
54
+ - lib/scout/llm/backends/responses.rb
55
+ - lib/scout/llm/chat.rb
38
56
  - lib/scout/llm/embed.rb
39
57
  - lib/scout/llm/parse.rb
40
58
  - lib/scout/llm/rag.rb
41
59
  - lib/scout/llm/tools.rb
42
60
  - lib/scout/llm/utils.rb
43
- - questions/coach
61
+ - lib/scout/model/base.rb
62
+ - lib/scout/model/python/base.rb
63
+ - lib/scout/model/python/huggingface.rb
64
+ - lib/scout/model/python/huggingface/causal.rb
65
+ - lib/scout/model/python/huggingface/causal/next_token.rb
66
+ - lib/scout/model/python/huggingface/classification
67
+ - lib/scout/model/python/huggingface/classification.rb
68
+ - lib/scout/model/python/torch.rb
69
+ - lib/scout/model/python/torch/dataloader.rb
70
+ - lib/scout/model/python/torch/helpers.rb
71
+ - lib/scout/model/python/torch/introspection.rb
72
+ - lib/scout/model/python/torch/load_and_save.rb
73
+ - lib/scout/model/util/run.rb
74
+ - lib/scout/model/util/save.rb
75
+ - python/scout_ai/__init__.py
76
+ - python/scout_ai/__pycache__/__init__.cpython-310.pyc
77
+ - python/scout_ai/__pycache__/__init__.cpython-311.pyc
78
+ - python/scout_ai/__pycache__/huggingface.cpython-310.pyc
79
+ - python/scout_ai/__pycache__/huggingface.cpython-311.pyc
80
+ - python/scout_ai/__pycache__/util.cpython-310.pyc
81
+ - python/scout_ai/__pycache__/util.cpython-311.pyc
82
+ - python/scout_ai/atcold/__init__.py
83
+ - python/scout_ai/atcold/plot_lib.py
84
+ - python/scout_ai/atcold/spiral.py
85
+ - python/scout_ai/huggingface/data.py
86
+ - python/scout_ai/huggingface/eval.py
87
+ - python/scout_ai/huggingface/model.py
88
+ - python/scout_ai/huggingface/rlhf.py
89
+ - python/scout_ai/huggingface/train/__init__.py
90
+ - python/scout_ai/huggingface/train/__pycache__/__init__.cpython-310.pyc
91
+ - python/scout_ai/huggingface/train/__pycache__/next_token.cpython-310.pyc
92
+ - python/scout_ai/huggingface/train/next_token.py
93
+ - python/scout_ai/language_model.py
94
+ - python/scout_ai/util.py
95
+ - scout-ai.gemspec
44
96
  - scout_commands/agent/ask
97
+ - scout_commands/agent/kb
45
98
  - scout_commands/llm/ask
46
99
  - scout_commands/llm/process
47
100
  - scout_commands/llm/template
101
+ - test/data/cat.jpg
48
102
  - test/data/person/brothers
49
103
  - test/data/person/identifiers
50
104
  - test/data/person/marriages
51
105
  - test/data/person/parents
106
+ - test/scout/llm/agent/test_chat.rb
107
+ - test/scout/llm/backends/test_bedrock.rb
52
108
  - test/scout/llm/backends/test_huggingface.rb
53
109
  - test/scout/llm/backends/test_ollama.rb
54
110
  - test/scout/llm/backends/test_openai.rb
55
111
  - test/scout/llm/backends/test_openwebui.rb
56
112
  - test/scout/llm/backends/test_relay.rb
113
+ - test/scout/llm/backends/test_responses.rb
57
114
  - test/scout/llm/test_agent.rb
58
115
  - test/scout/llm/test_ask.rb
116
+ - test/scout/llm/test_chat.rb
59
117
  - test/scout/llm/test_embed.rb
60
118
  - test/scout/llm/test_parse.rb
61
119
  - test/scout/llm/test_rag.rb
62
120
  - test/scout/llm/test_tools.rb
63
121
  - test/scout/llm/test_utils.rb
122
+ - test/scout/model/python/huggingface/causal/test_next_token.rb
123
+ - test/scout/model/python/huggingface/test_causal.rb
124
+ - test/scout/model/python/huggingface/test_classification.rb
125
+ - test/scout/model/python/test_base.rb
126
+ - test/scout/model/python/test_huggingface.rb
127
+ - test/scout/model/python/test_torch.rb
128
+ - test/scout/model/python/torch/test_helpers.rb
129
+ - test/scout/model/test_base.rb
130
+ - test/scout/model/util/test_save.rb
64
131
  - test/test_helper.rb
65
132
  homepage: http://github.com/mikisvaz/scout-ai
66
133
  licenses:
@@ -80,7 +147,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
80
147
  - !ruby/object:Gem::Version
81
148
  version: '0'
82
149
  requirements: []
83
- rubygems_version: 3.6.5
150
+ rubygems_version: 3.6.6
84
151
  specification_version: 4
85
152
  summary: AI gear for scouts
86
153
  test_files: []
data/questions/coach DELETED
@@ -1,2 +0,0 @@
1
- system: You write prompts to give instructions to a coding LLM to perform certain task
2
- user: ???