brute 0.1.6 → 0.1.7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 48b59415efb00c3e5da0f9264aa04291f477b4255fb35407a2ed0e68fec69fc2
4
- data.tar.gz: 668d46ac81b5ff1f8dfd3f832f08736aa38820fda44c4432940b7f82e1261079
3
+ metadata.gz: 4f0f32487b029541fdb462f5f4958a95e4727150911b51f6d8ab457b875187d8
4
+ data.tar.gz: f162d75e227b4270e4a56dba42fe3cdddd23f9492adeff5cd1f345cbbb811961
5
5
  SHA512:
6
- metadata.gz: c9f9b4f883b6b77a7e81980528e9ed0c703280114ff8b7ee26409b69c8127ec699740c43deea027394045c33a7b18a0a59dd72d7ccdf0694eaa62754b75ed2d9
7
- data.tar.gz: 1ee08e461182f1065e9fe01313a823fa8af31f820341d680d4b43619016745db28876c061352eab33f25049cd6a87d9c44b039f87eae5c837101cc8cd07bd159
6
+ metadata.gz: 9aa172f042960dc5c9ec3250cf27781614077be7db114edc65d4ce72e178dfcab9ed9a9918d6583ed190d36cc54e865d8118bea9ac9814064a12a3f2b7ac8627
7
+ data.tar.gz: c0cc5addf257b161cc06385417a24833bf9f99a73038040abc67c3caef75ab0a0b9e3d357364b0fa0d194ca3b259555b80f09bf805fc12d17be1e4386d8b061b
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brute
4
+ module Middleware
5
+ # Guards against tool-only LLM responses where the assistant message
6
+ # is dropped from the context buffer.
7
+ #
8
+ # When the LLM responds with only tool_use blocks (no text), llm.rb's
9
+ # response adapter produces empty choices. Context#talk appends nil,
10
+ # BufferNilGuard strips it, and the assistant message carrying tool_use
11
+ # blocks is lost. This causes "unexpected tool_use_id" on the next call
12
+ # because tool_result references a tool_use that's missing from the buffer.
13
+ #
14
+ # This middleware runs post-call and injects a synthetic assistant message
15
+ # when tool calls exist but no assistant message was recorded.
16
+ class ToolUseGuard
17
+ def initialize(app)
18
+ @app = app
19
+ end
20
+
21
+ def call(env)
22
+ response = @app.call(env)
23
+
24
+ ctx = env[:context]
25
+ functions = ctx.functions
26
+
27
+ # If there are pending tool calls, ensure the buffer has an assistant
28
+ # message with tool_use blocks.
29
+ if functions && !functions.empty?
30
+ messages = ctx.messages.to_a
31
+ last_assistant = messages.reverse.find { |m| m.role.to_s == "assistant" }
32
+
33
+ unless last_assistant&.tool_call?
34
+ # Build a synthetic assistant message with the tool_use data
35
+ tool_calls = functions.map do |fn|
36
+ LLM::Object.from(id: fn.id, name: fn.name, arguments: fn.arguments)
37
+ end
38
+ original_tool_calls = functions.map do |fn|
39
+ { "type" => "tool_use", "id" => fn.id, "name" => fn.name, "input" => fn.arguments || {} }
40
+ end
41
+
42
+ synthetic = LLM::Message.new(:assistant, "", {
43
+ tool_calls: tool_calls,
44
+ original_tool_calls: original_tool_calls,
45
+ })
46
+ ctx.messages.concat([synthetic])
47
+ end
48
+ end
49
+
50
+ response
51
+ end
52
+ end
53
+ end
54
+ end
@@ -181,6 +181,9 @@ module Brute
181
181
  # Handle reasoning params and model-switch normalization (pre-call)
182
182
  use Middleware::ReasoningNormalizer, **reasoning unless reasoning.empty?
183
183
 
184
+ # Guard against tool-only responses dropping the assistant message
185
+ use Middleware::ToolUseGuard
186
+
184
187
  # Innermost: the actual LLM call
185
188
  run Middleware::LLMCall.new
186
189
  end
data/lib/brute/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Brute
4
- VERSION = "0.1.6"
4
+ VERSION = "0.1.7"
5
5
  end
data/lib/brute.rb CHANGED
@@ -47,6 +47,7 @@ require_relative 'brute/middleware/session_persistence'
47
47
  require_relative 'brute/middleware/tracing'
48
48
  require_relative 'brute/middleware/tool_error_tracking'
49
49
  require_relative 'brute/middleware/reasoning_normalizer'
50
+ require_relative "brute/middleware/tool_use_guard"
50
51
 
51
52
  # Tools
52
53
  require_relative 'brute/tools/fs_read'
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: 0.1.6
4
+ version: 0.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brute Contributors
@@ -27,16 +27,16 @@ dependencies:
27
27
  name: diff-lcs
28
28
  requirement: !ruby/object:Gem::Requirement
29
29
  requirements:
30
- - - "~>"
30
+ - - ">="
31
31
  - !ruby/object:Gem::Version
32
- version: '2.0'
32
+ version: '1.5'
33
33
  type: :runtime
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
- - - "~>"
37
+ - - ">="
38
38
  - !ruby/object:Gem::Version
39
- version: '2.0'
39
+ version: '1.5'
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: llm.rb
42
42
  requirement: !ruby/object:Gem::Requirement
@@ -52,33 +52,33 @@ dependencies:
52
52
  - !ruby/object:Gem::Version
53
53
  version: '4.11'
54
54
  - !ruby/object:Gem::Dependency
55
- name: minitest
55
+ name: rake
56
56
  requirement: !ruby/object:Gem::Requirement
57
57
  requirements:
58
58
  - - "~>"
59
59
  - !ruby/object:Gem::Version
60
- version: '5.0'
60
+ version: '13.0'
61
61
  type: :development
62
62
  prerelease: false
63
63
  version_requirements: !ruby/object:Gem::Requirement
64
64
  requirements:
65
65
  - - "~>"
66
66
  - !ruby/object:Gem::Version
67
- version: '5.0'
67
+ version: '13.0'
68
68
  - !ruby/object:Gem::Dependency
69
- name: rake
69
+ name: rspec
70
70
  requirement: !ruby/object:Gem::Requirement
71
71
  requirements:
72
72
  - - "~>"
73
73
  - !ruby/object:Gem::Version
74
- version: '13.0'
74
+ version: '3.13'
75
75
  type: :development
76
76
  prerelease: false
77
77
  version_requirements: !ruby/object:Gem::Requirement
78
78
  requirements:
79
79
  - - "~>"
80
80
  - !ruby/object:Gem::Version
81
- version: '13.0'
81
+ version: '3.13'
82
82
  description: Production-grade coding agent with tool execution, middleware pipeline,
83
83
  context compaction, session persistence, and multi-provider LLM support.
84
84
  executables: []
@@ -101,6 +101,7 @@ files:
101
101
  - lib/brute/middleware/session_persistence.rb
102
102
  - lib/brute/middleware/token_tracking.rb
103
103
  - lib/brute/middleware/tool_error_tracking.rb
104
+ - lib/brute/middleware/tool_use_guard.rb
104
105
  - lib/brute/middleware/tracing.rb
105
106
  - lib/brute/orchestrator.rb
106
107
  - lib/brute/patches/anthropic_tool_role.rb