brute 5.0.4 → 5.1.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.
- checksums.yaml +4 -4
- data/lib/brute/compaction/middleware/sliding_window.rb +170 -0
- data/lib/brute/compaction/middleware/strategy.rb +139 -0
- data/lib/brute/compaction/middleware/tool_results.rb +146 -0
- data/lib/brute/compaction/summarize.rb +340 -0
- data/lib/brute/compaction/transcript.rb +166 -0
- data/lib/brute/compaction.rb +57 -0
- data/lib/brute/contrib/otel.rb +2 -2
- data/lib/brute/env.rb +54 -0
- data/lib/brute/eval/case.rb +249 -0
- data/lib/brute/eval/suite.rb +176 -0
- data/lib/brute/eval/transcript.rb +147 -0
- data/lib/brute/eval/world.rb +106 -0
- data/lib/brute/eval.rb +48 -0
- data/lib/brute/hooks.rb +11 -0
- data/lib/brute/middleware/000_base.rb +1 -1
- data/lib/brute/middleware/001_slash_commands.rb +88 -0
- data/lib/brute/middleware/008_checkpoint.rb +1 -1
- data/lib/brute/middleware/040_compaction_check.rb +51 -135
- data/lib/brute/middleware/040_default_compaction_pipeline.rb +352 -0
- data/lib/brute/middleware/070_default_tool_pipeline.rb +327 -0
- data/lib/brute/middleware/070_tool_pipeline.rb +39 -305
- data/lib/brute/token_counter/approximate.rb +54 -0
- data/lib/brute/token_counter/tiktoken.rb +80 -0
- data/lib/brute/token_counter.rb +148 -0
- data/lib/brute/tools/adapter.rb +4 -4
- data/lib/brute/tools/skill_load.rb +2 -2
- data/lib/brute/tools/sub_agent.rb +2 -2
- data/lib/brute/turn/agent_pipeline.rb +117 -38
- data/lib/brute/turn/compaction_pipeline.rb +122 -0
- data/lib/brute/version.rb +1 -1
- data/lib/brute.rb +16 -1
- metadata +20 -1
|
@@ -21,7 +21,7 @@ module Brute
|
|
|
21
21
|
# use Brute::Middleware::SystemPrompt
|
|
22
22
|
# use Brute::Middleware::Loop::ToolResult
|
|
23
23
|
# use Brute::Middleware::MaxIterations, max_iterations: 10
|
|
24
|
-
# use Brute::Middleware::
|
|
24
|
+
# use Brute::Middleware::DefaultToolPipeline, tools: [Brute::Tools::FSRead, Brute::Tools::FSSearch]
|
|
25
25
|
# run ->(env) do
|
|
26
26
|
# # The LLM call, written with your library of choice. Convert
|
|
27
27
|
# # env[:messages] to its format, call it, and append the response
|
|
@@ -32,7 +32,7 @@ module Brute
|
|
|
32
32
|
#
|
|
33
33
|
# # The SubAgent IS a tool — hand it to a parent agent's ToolPipeline:
|
|
34
34
|
# main_agent = Brute.agent do
|
|
35
|
-
# use Brute::Middleware::
|
|
35
|
+
# use Brute::Middleware::DefaultToolPipeline, tools: [Brute::Tools::FSRead, researcher]
|
|
36
36
|
# run ->(env) { ... }
|
|
37
37
|
# end
|
|
38
38
|
# main_agent.start("delegate some research")
|
|
@@ -18,26 +18,37 @@ module Brute
|
|
|
18
18
|
|
|
19
19
|
# Register a slash command:
|
|
20
20
|
#
|
|
21
|
-
# map
|
|
22
|
-
# map(
|
|
21
|
+
# map("/compact") { |env| ... }
|
|
22
|
+
# map(/\Aplease compact/i) { |env| ... }
|
|
23
|
+
# map(->(said) { said.length > 10_000 }) { |env| ... }
|
|
23
24
|
#
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
# Whatever is given becomes a check: a function of what was said that
|
|
26
|
+
# answers true or false. A String is a slash command -- "/compact"
|
|
27
|
+
# becomes ^\/compact.*, the command and whatever rides after it -- and
|
|
28
|
+
# a Regexp is wrapped in a function that evaluates it, so by the time
|
|
29
|
+
# a command is registered there are only functions. Anything that
|
|
30
|
+
# already answers to #call is taken as the check itself.
|
|
31
|
+
#
|
|
32
|
+
# This is Rack::Builder's `map` overridden: an agent routes on what was
|
|
33
|
+
# said, not on a path, so there are no sub-builders and no URLMap.
|
|
34
|
+
#
|
|
35
|
+
# The block is a middleware. `start` puts the registry into the turn as
|
|
36
|
+
# env[:commands], and SlashCommands -- which the builder puts at the
|
|
37
|
+
# head of every chain -- runs the first command whose check passes on
|
|
38
|
+
# the newest message, only when it is a user message, before the rest
|
|
39
|
+
# of the stack.
|
|
40
|
+
def map(matcher, &block)
|
|
41
|
+
(@commands ||= []) << [check(matcher), block]
|
|
29
42
|
self
|
|
30
43
|
end
|
|
31
44
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
default_app.call(prompt)
|
|
38
|
-
end
|
|
39
|
-
end
|
|
45
|
+
# Every chain starts with the commands, registry or no registry: the
|
|
46
|
+
# builder puts SlashCommands at its head rather than leaving it to a
|
|
47
|
+
# `use` someone has to remember.
|
|
48
|
+
def to_app
|
|
49
|
+
Brute::Middleware::SlashCommands.new(super)
|
|
40
50
|
end
|
|
51
|
+
alias_method :build, :to_app
|
|
41
52
|
|
|
42
53
|
def start(input = nil, events: NullSink.new)
|
|
43
54
|
env = {
|
|
@@ -45,6 +56,7 @@ module Brute
|
|
|
45
56
|
events: events,
|
|
46
57
|
metadata: {},
|
|
47
58
|
current_iteration: 1,
|
|
59
|
+
commands: @commands || [],
|
|
48
60
|
}
|
|
49
61
|
hooks.emit(TURN_START_EVENT, env)
|
|
50
62
|
begin
|
|
@@ -57,6 +69,28 @@ module Brute
|
|
|
57
69
|
|
|
58
70
|
private
|
|
59
71
|
|
|
72
|
+
# A matcher becomes a function of what was said. A Regexp is
|
|
73
|
+
# evaluated; a String is a slash command first -- given without its
|
|
74
|
+
# slash, it grows one -- and then evaluated the same way.
|
|
75
|
+
def check(matcher)
|
|
76
|
+
if matcher.respond_to?(:call)
|
|
77
|
+
matcher
|
|
78
|
+
else
|
|
79
|
+
pattern = pattern_for(matcher)
|
|
80
|
+
->(said) { pattern.match?(said) }
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def pattern_for(matcher)
|
|
85
|
+
if matcher.is_a?(::Regexp)
|
|
86
|
+
matcher
|
|
87
|
+
else
|
|
88
|
+
name = matcher.to_s
|
|
89
|
+
name = name.start_with?("/") ? name : "/#{name}"
|
|
90
|
+
/^#{::Regexp.escape(name)}.*/
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
60
94
|
def coerce_messages(input)
|
|
61
95
|
case input
|
|
62
96
|
when nil then Brute.log
|
|
@@ -176,35 +210,80 @@ describe "brute/turn/agent_pipeline" do
|
|
|
176
210
|
agent.start("go")[:messages].last.content.should == "done"
|
|
177
211
|
end
|
|
178
212
|
|
|
179
|
-
it "
|
|
213
|
+
it "runs a command's block as a middleware, before the rest of the stack" do
|
|
214
|
+
order = []
|
|
180
215
|
agent = Brute.agent
|
|
181
|
-
.
|
|
182
|
-
.
|
|
216
|
+
.use(AgentStubMW)
|
|
217
|
+
.map("/compact") { |env| order << [:compact, env[:messages].last.content] }
|
|
218
|
+
.map("deploy") { |_env| order << :deploy } # grows its slash
|
|
219
|
+
.map(/\Aplease compact\b/i) { |_env| order << :asked } # a Regexp is evaluated
|
|
220
|
+
.map(->(said) { said.length > 20 }) { |_env| order << :long } # so is a function
|
|
221
|
+
.run(->(env) { order << :app; env[:messages].assistant("done") })
|
|
222
|
+
|
|
223
|
+
# The command runs first; the stack below it still runs.
|
|
224
|
+
agent.start("/compact notes")
|
|
225
|
+
order.should == [[:compact, "/compact notes"], :app]
|
|
226
|
+
|
|
227
|
+
# A String matches the command and whatever rides after it.
|
|
228
|
+
order.clear
|
|
229
|
+
agent.start("/deploy now")
|
|
230
|
+
order.should == [:deploy, :app]
|
|
231
|
+
|
|
232
|
+
# Checks are tried in the order they were registered, and the first to
|
|
233
|
+
# pass is the one that runs.
|
|
234
|
+
order.clear
|
|
235
|
+
agent.start("Please compact this, it has gone on long enough")
|
|
236
|
+
order.should == [:asked, :app]
|
|
237
|
+
|
|
238
|
+
order.clear
|
|
239
|
+
agent.start("something else entirely, at some length")
|
|
240
|
+
order.should == [:long, :app]
|
|
241
|
+
|
|
242
|
+
# Conversation and unregistered commands reach the stack untouched.
|
|
243
|
+
order.clear
|
|
244
|
+
agent.start("just a question")
|
|
245
|
+
agent.start("/unregistered")
|
|
246
|
+
order.should == [:app, :app]
|
|
247
|
+
|
|
248
|
+
# Only a user message says anything a command answers to.
|
|
249
|
+
order.clear
|
|
250
|
+
agent.start(Brute::Message.new(role: :assistant, content: "/compact"))
|
|
251
|
+
order.should == [:app]
|
|
252
|
+
|
|
253
|
+
# The registry rides in env, so anything below can see what was mapped.
|
|
254
|
+
agent.start("hello")[:commands].size.should == 4
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
it "turns a matcher into a check that answers true or false" do
|
|
258
|
+
checks = Brute.agent
|
|
259
|
+
.map("/compact") { |_env| }
|
|
260
|
+
.map("deploy") { |_env| }
|
|
261
|
+
.map(/\Ahello/) { |_env| }
|
|
262
|
+
.instance_variable_get(:@commands)
|
|
263
|
+
.map(&:first)
|
|
183
264
|
|
|
184
|
-
|
|
185
|
-
|
|
265
|
+
checks.each { |check| check.should.respond_to?(:call) }
|
|
266
|
+
|
|
267
|
+
checks[0].call("/compact keep the notes").should.be.true
|
|
268
|
+
checks[0].call("/compactor").should.be.true # ^\/compact.* and no more
|
|
269
|
+
checks[0].call("nope").should.be.false
|
|
270
|
+
|
|
271
|
+
checks[1].call("/deploy now").should.be.true # registered without the slash
|
|
272
|
+
checks[1].call("deploy now").should.be.false
|
|
273
|
+
|
|
274
|
+
checks[2].call("hello there").should.be.true
|
|
275
|
+
checks[2].call("well hello").should.be.false
|
|
186
276
|
end
|
|
187
277
|
|
|
188
|
-
it "
|
|
189
|
-
got = nil
|
|
278
|
+
it "map chains, and every chain is built with the commands at its head" do
|
|
190
279
|
agent = Brute.agent
|
|
191
|
-
.map("/
|
|
192
|
-
.
|
|
193
|
-
.run(->(prompt) { got = prompt })
|
|
194
|
-
|
|
195
|
-
agent.call("/weather London")
|
|
196
|
-
got.should == "Get the weather in the following location London"
|
|
197
|
-
agent.call("/echo hi there")
|
|
198
|
-
got.should == "you said: hi there"
|
|
199
|
-
end
|
|
280
|
+
.map("/compact") { |_env| }
|
|
281
|
+
.run(->(env) { env })
|
|
200
282
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
agent = Brute.agent.map("weather", "W $ARGUMENTS").run(->(prompt) { got = prompt })
|
|
283
|
+
agent.should.be.kind_of?(Brute::Turn::AgentPipeline) # map returns self
|
|
284
|
+
agent.build.should.be.kind_of?(Brute::Middleware::SlashCommands) # and the head is the commands
|
|
204
285
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
agent.call("/weather NYC") # registered as "weather", normalized to "/weather"
|
|
208
|
-
got.should == "W NYC"
|
|
286
|
+
# No commands, same head.
|
|
287
|
+
Brute.agent.run(->(env) { env }).build.should.be.kind_of?(Brute::Middleware::SlashCommands)
|
|
209
288
|
end
|
|
210
289
|
end
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "bundler/setup"
|
|
4
|
+
require "brute"
|
|
5
|
+
require "brute/turn/pipeline"
|
|
6
|
+
|
|
7
|
+
module Brute
|
|
8
|
+
module Turn
|
|
9
|
+
# A compactor built out of middleware.
|
|
10
|
+
#
|
|
11
|
+
# Like ToolPipeline it *composes* a Pipeline rather than inheriting: the
|
|
12
|
+
# definition block is instance_eval'd into the internal Pipeline, so `use`
|
|
13
|
+
# / `run` inside it are the builder's methods.
|
|
14
|
+
#
|
|
15
|
+
# The stack order is the policy. A layer that got the conversation under
|
|
16
|
+
# target does not call the next one, so the strategies that cost nothing
|
|
17
|
+
# sit at the top and the terminal app -- the summariser, the only thing
|
|
18
|
+
# here that spends money -- is reached only when they could not get there.
|
|
19
|
+
# That is `run` meaning what it means everywhere else in Brute: the model
|
|
20
|
+
# call, at the bottom, with the layers deciding what reaches it.
|
|
21
|
+
#
|
|
22
|
+
# Brute::Turn::CompactionPipeline.new do
|
|
23
|
+
# use Brute::Compaction::Middleware::ToolResults, keep_steps: 1
|
|
24
|
+
# use Brute::Compaction::Middleware::SlidingWindow, keep_steps: 2
|
|
25
|
+
#
|
|
26
|
+
# run Brute::Compaction::Summarize.new(
|
|
27
|
+
# Brute::Completion::OpenRouter.new(config: { access_token: key }),
|
|
28
|
+
# )
|
|
29
|
+
# end
|
|
30
|
+
#
|
|
31
|
+
# A pipeline that must never spend a call is the first two layers and
|
|
32
|
+
# `run ->(env) { env }` -- a policy said out loud rather than configured.
|
|
33
|
+
#
|
|
34
|
+
# The conversation being compacted rides on `env[:conversation]`, leaving
|
|
35
|
+
# `env[:messages]` to mean what it means to every other terminal app in
|
|
36
|
+
# Brute: the prompt going down, the reply coming back.
|
|
37
|
+
#
|
|
38
|
+
# It answers #compact, so what comes out drops into
|
|
39
|
+
# Brute::Middleware::DefaultCompactionPipeline as that turn's compactor.
|
|
40
|
+
class CompactionPipeline
|
|
41
|
+
def initialize(&block)
|
|
42
|
+
@pipeline = Pipeline.new
|
|
43
|
+
@pipeline.instance_eval(&block) if block
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Answer a smaller conversation, or nil when nothing was given up.
|
|
47
|
+
def compact(messages, target:, events: Pipeline::NullSink.new, token_counter: nil)
|
|
48
|
+
env = {
|
|
49
|
+
conversation: messages,
|
|
50
|
+
target: target,
|
|
51
|
+
token_counter: token_counter,
|
|
52
|
+
applied: [],
|
|
53
|
+
messages: Brute.log,
|
|
54
|
+
events: events,
|
|
55
|
+
metadata: {},
|
|
56
|
+
}
|
|
57
|
+
@pipeline.call(env)
|
|
58
|
+
|
|
59
|
+
unless env[:applied].empty?
|
|
60
|
+
env[:conversation]
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
__END__
|
|
68
|
+
|
|
69
|
+
describe "brute/turn/compaction_pipeline" do
|
|
70
|
+
def said(content) = Brute::Message.new(role: :user, content: content)
|
|
71
|
+
|
|
72
|
+
def layer(name, &block)
|
|
73
|
+
Class.new(Brute::Compaction::Middleware::Strategy) do
|
|
74
|
+
define_method(:strategy) { name }
|
|
75
|
+
define_method(:rewrite) { |conversation, target:| block.call(conversation, target) }
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it "composes strategies into one compactor, and only reaches run when they could not" do
|
|
80
|
+
reached = []
|
|
81
|
+
halves = layer("halves") { |c, _t| reached << "halves"; c.first(c.length / 2) }
|
|
82
|
+
never = layer("never") { |_c, _t| reached << "never"; nil }
|
|
83
|
+
# A terminal belongs to one pipeline: the builder binds an emit onto it
|
|
84
|
+
# and refuses to bind a second, so each pipeline gets its own.
|
|
85
|
+
terminal = lambda do
|
|
86
|
+
Object.new.tap { |it| it.define_singleton_method(:call) { |env| reached << "run"; env } }
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
four = [said("a" * 4_000), said("b" * 4_000), said("c" * 4_000), said("d" * 4_000)]
|
|
90
|
+
|
|
91
|
+
# Halving is enough, so the terminal -- the one that costs money -- is
|
|
92
|
+
# never reached. The stack order is the policy.
|
|
93
|
+
pipeline = Brute::Turn::CompactionPipeline.new do
|
|
94
|
+
use halves
|
|
95
|
+
run terminal.call
|
|
96
|
+
end
|
|
97
|
+
pipeline.compact(four, target: 3_000).map { |m| m.content[0, 1] }.should == ["a", "b"]
|
|
98
|
+
reached.should == ["halves"]
|
|
99
|
+
|
|
100
|
+
# A strategy that declines lets the turn fall through to it.
|
|
101
|
+
reached.clear
|
|
102
|
+
Brute::Turn::CompactionPipeline.new do
|
|
103
|
+
use never
|
|
104
|
+
run terminal.call
|
|
105
|
+
end.compact(four, target: 3_000).should.be.nil
|
|
106
|
+
reached.should == ["never", "run"]
|
|
107
|
+
|
|
108
|
+
# Nothing given up at all is nil, not the conversation it was handed --
|
|
109
|
+
# the caller applies whatever else comes back.
|
|
110
|
+
reached.clear
|
|
111
|
+
pipeline.compact(four, target: 500_000).should.be.nil
|
|
112
|
+
reached.should == []
|
|
113
|
+
|
|
114
|
+
# The conversation rides on :conversation, leaving :messages to mean what
|
|
115
|
+
# it means to every other terminal app -- the prompt down, the reply back.
|
|
116
|
+
seen = nil
|
|
117
|
+
Brute::Turn::CompactionPipeline.new do
|
|
118
|
+
run ->(env) { seen = [env[:conversation].length, env[:messages], env[:target]] }
|
|
119
|
+
end.compact(four, target: 10)
|
|
120
|
+
seen.should == [4, [], 10]
|
|
121
|
+
end
|
|
122
|
+
end
|
data/lib/brute/version.rb
CHANGED
data/lib/brute.rb
CHANGED
|
@@ -42,7 +42,7 @@ module Brute
|
|
|
42
42
|
#
|
|
43
43
|
# agent = Brute.agent
|
|
44
44
|
# .use(Brute::Middleware::SystemPrompt)
|
|
45
|
-
# .use(Brute::Middleware::
|
|
45
|
+
# .use(Brute::Middleware::DefaultToolPipeline, tools: Brute::Tools::ALL)
|
|
46
46
|
# .run ->(env) { ... } # the LLM-call proc (provider/model/creds here)
|
|
47
47
|
#
|
|
48
48
|
# agent.start("what changed?")
|
|
@@ -93,7 +93,14 @@ end
|
|
|
93
93
|
require_relative "brute/version"
|
|
94
94
|
require_relative "brute/hooks"
|
|
95
95
|
require_relative "brute/messages"
|
|
96
|
+
require_relative "brute/env"
|
|
96
97
|
require_relative "brute/middleware/000_base"
|
|
98
|
+
require_relative "brute/compaction"
|
|
99
|
+
require_relative "brute/compaction/transcript"
|
|
100
|
+
require_relative "brute/compaction/middleware/strategy"
|
|
101
|
+
require_relative "brute/compaction/middleware/tool_results"
|
|
102
|
+
require_relative "brute/compaction/middleware/sliding_window"
|
|
103
|
+
require_relative "brute/compaction/summarize"
|
|
97
104
|
require_relative "brute/completion/open_router"
|
|
98
105
|
require_relative "brute/completion/lang_chain"
|
|
99
106
|
require_relative "brute/completion/llmrb"
|
|
@@ -116,6 +123,7 @@ require_relative "brute/message_transport/openai"
|
|
|
116
123
|
require_relative "brute/message_transport/ruby_llm"
|
|
117
124
|
require_relative "brute/message_transport/ruby_open_ai"
|
|
118
125
|
require_relative "brute/message_transport/lang_chain"
|
|
126
|
+
require_relative "brute/middleware/001_slash_commands"
|
|
119
127
|
require_relative "brute/middleware/002_session_log"
|
|
120
128
|
require_relative "brute/middleware/004_summarize"
|
|
121
129
|
require_relative "brute/middleware/006_loop"
|
|
@@ -123,8 +131,10 @@ require_relative "brute/middleware/008_checkpoint"
|
|
|
123
131
|
require_relative "brute/middleware/010_max_iterations"
|
|
124
132
|
require_relative "brute/middleware/020_system_prompt"
|
|
125
133
|
require_relative "brute/middleware/025_skills"
|
|
134
|
+
require_relative "brute/middleware/040_default_compaction_pipeline"
|
|
126
135
|
require_relative "brute/middleware/040_compaction_check"
|
|
127
136
|
require_relative "brute/middleware/060_questions"
|
|
137
|
+
require_relative "brute/middleware/070_default_tool_pipeline"
|
|
128
138
|
require_relative "brute/middleware/070_tool_pipeline"
|
|
129
139
|
require_relative "brute/middleware/event_handler"
|
|
130
140
|
require_relative "brute/middleware/user_queue"
|
|
@@ -156,6 +166,9 @@ require_relative "brute/prompts/tool_usage"
|
|
|
156
166
|
require_relative "brute/rack/adapter"
|
|
157
167
|
require_relative "brute/skill"
|
|
158
168
|
require_relative "brute/system_prompt"
|
|
169
|
+
require_relative "brute/token_counter"
|
|
170
|
+
require_relative "brute/token_counter/approximate"
|
|
171
|
+
require_relative "brute/token_counter/tiktoken"
|
|
159
172
|
require_relative "brute/tool"
|
|
160
173
|
require_relative "brute/tools"
|
|
161
174
|
require_relative "brute/tools/adapter"
|
|
@@ -178,7 +191,9 @@ require_relative "brute/tools/todo_write"
|
|
|
178
191
|
require_relative "brute/truncation"
|
|
179
192
|
require_relative "brute/turn/agent_pipeline"
|
|
180
193
|
require_relative "brute/turn/pipeline"
|
|
194
|
+
require_relative "brute/turn/compaction_pipeline"
|
|
181
195
|
require_relative "brute/turn/tool_pipeline"
|
|
196
|
+
require_relative "brute/eval"
|
|
182
197
|
require_relative "brute/utils/diff"
|
|
183
198
|
|
|
184
199
|
# gangsta g-dogg bruh...
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: brute
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 5.0
|
|
4
|
+
version: 5.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Brute Contributors
|
|
@@ -282,12 +282,24 @@ extensions: []
|
|
|
282
282
|
extra_rdoc_files: []
|
|
283
283
|
files:
|
|
284
284
|
- lib/brute.rb
|
|
285
|
+
- lib/brute/compaction.rb
|
|
286
|
+
- lib/brute/compaction/middleware/sliding_window.rb
|
|
287
|
+
- lib/brute/compaction/middleware/strategy.rb
|
|
288
|
+
- lib/brute/compaction/middleware/tool_results.rb
|
|
289
|
+
- lib/brute/compaction/summarize.rb
|
|
290
|
+
- lib/brute/compaction/transcript.rb
|
|
285
291
|
- lib/brute/completion/lang_chain.rb
|
|
286
292
|
- lib/brute/completion/llmrb.rb
|
|
287
293
|
- lib/brute/completion/open_router.rb
|
|
288
294
|
- lib/brute/completion/ruby_llm.rb
|
|
289
295
|
- lib/brute/contrib/log_file.rb
|
|
290
296
|
- lib/brute/contrib/otel.rb
|
|
297
|
+
- lib/brute/env.rb
|
|
298
|
+
- lib/brute/eval.rb
|
|
299
|
+
- lib/brute/eval/case.rb
|
|
300
|
+
- lib/brute/eval/suite.rb
|
|
301
|
+
- lib/brute/eval/transcript.rb
|
|
302
|
+
- lib/brute/eval/world.rb
|
|
291
303
|
- lib/brute/events/handler.rb
|
|
292
304
|
- lib/brute/events/prefixed_terminal_output.rb
|
|
293
305
|
- lib/brute/events/terminal_output_handler.rb
|
|
@@ -302,6 +314,7 @@ files:
|
|
|
302
314
|
- lib/brute/message_transport/ruby_open_ai.rb
|
|
303
315
|
- lib/brute/messages.rb
|
|
304
316
|
- lib/brute/middleware/000_base.rb
|
|
317
|
+
- lib/brute/middleware/001_slash_commands.rb
|
|
305
318
|
- lib/brute/middleware/002_session_log.rb
|
|
306
319
|
- lib/brute/middleware/004_summarize.rb
|
|
307
320
|
- lib/brute/middleware/006_loop.rb
|
|
@@ -310,7 +323,9 @@ files:
|
|
|
310
323
|
- lib/brute/middleware/020_system_prompt.rb
|
|
311
324
|
- lib/brute/middleware/025_skills.rb
|
|
312
325
|
- lib/brute/middleware/040_compaction_check.rb
|
|
326
|
+
- lib/brute/middleware/040_default_compaction_pipeline.rb
|
|
313
327
|
- lib/brute/middleware/060_questions.rb
|
|
328
|
+
- lib/brute/middleware/070_default_tool_pipeline.rb
|
|
314
329
|
- lib/brute/middleware/070_tool_pipeline.rb
|
|
315
330
|
- lib/brute/middleware/event_handler.rb
|
|
316
331
|
- lib/brute/middleware/user_queue.rb
|
|
@@ -361,6 +376,9 @@ files:
|
|
|
361
376
|
- lib/brute/rack/adapter.rb
|
|
362
377
|
- lib/brute/skill.rb
|
|
363
378
|
- lib/brute/system_prompt.rb
|
|
379
|
+
- lib/brute/token_counter.rb
|
|
380
|
+
- lib/brute/token_counter/approximate.rb
|
|
381
|
+
- lib/brute/token_counter/tiktoken.rb
|
|
364
382
|
- lib/brute/tool.rb
|
|
365
383
|
- lib/brute/tools.rb
|
|
366
384
|
- lib/brute/tools/adapter.rb
|
|
@@ -382,6 +400,7 @@ files:
|
|
|
382
400
|
- lib/brute/tools/todo_write.rb
|
|
383
401
|
- lib/brute/truncation.rb
|
|
384
402
|
- lib/brute/turn/agent_pipeline.rb
|
|
403
|
+
- lib/brute/turn/compaction_pipeline.rb
|
|
385
404
|
- lib/brute/turn/pipeline.rb
|
|
386
405
|
- lib/brute/turn/tool_pipeline.rb
|
|
387
406
|
- lib/brute/usage_detection/lang_chain.rb
|