brute 1.0.0 → 2.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 (85) hide show
  1. checksums.yaml +4 -4
  2. data/lib/brute/agent.rb +72 -6
  3. data/lib/brute/events/handler.rb +69 -0
  4. data/lib/brute/events/prefixed_terminal_output.rb +72 -0
  5. data/lib/brute/events/terminal_output_handler.rb +68 -0
  6. data/lib/brute/middleware/001_otel_span.rb +77 -0
  7. data/lib/brute/middleware/003_tool_result_loop.rb +103 -0
  8. data/lib/brute/middleware/004_summarize.rb +139 -0
  9. data/lib/brute/middleware/005_tracing.rb +86 -0
  10. data/lib/brute/middleware/010_max_iterations.rb +73 -0
  11. data/lib/brute/middleware/015_otel_token_usage.rb +42 -0
  12. data/lib/brute/middleware/020_system_prompt.rb +128 -0
  13. data/lib/brute/middleware/040_compaction_check.rb +155 -0
  14. data/lib/brute/middleware/060_questions.rb +41 -0
  15. data/lib/brute/middleware/070_tool_call.rb +247 -0
  16. data/lib/brute/middleware/073_otel_tool_call.rb +49 -0
  17. data/lib/brute/middleware/075_otel_tool_results.rb +46 -0
  18. data/lib/brute/middleware/100_llm_call.rb +62 -0
  19. data/lib/brute/middleware/event_handler.rb +25 -0
  20. data/lib/brute/middleware/user_queue.rb +35 -0
  21. data/lib/brute/pipeline.rb +44 -107
  22. data/lib/brute/prompts/skills.rb +2 -2
  23. data/lib/brute/prompts.rb +23 -23
  24. data/lib/brute/providers/shell.rb +6 -19
  25. data/lib/brute/providers/shell_response.rb +22 -30
  26. data/lib/brute/session.rb +52 -0
  27. data/lib/brute/store/snapshot_store.rb +21 -37
  28. data/lib/brute/sub_agent.rb +106 -0
  29. data/lib/brute/system_prompt.rb +1 -83
  30. data/lib/brute/tool.rb +107 -0
  31. data/lib/brute/tools/delegate.rb +61 -70
  32. data/lib/brute/tools/fs_patch.rb +9 -7
  33. data/lib/brute/tools/fs_read.rb +233 -20
  34. data/lib/brute/tools/fs_remove.rb +8 -9
  35. data/lib/brute/tools/fs_search.rb +98 -16
  36. data/lib/brute/tools/fs_undo.rb +8 -8
  37. data/lib/brute/tools/fs_write.rb +7 -5
  38. data/lib/brute/tools/net_fetch.rb +8 -8
  39. data/lib/brute/tools/question.rb +36 -24
  40. data/lib/brute/tools/shell.rb +74 -16
  41. data/lib/brute/tools/todo_read.rb +8 -8
  42. data/lib/brute/tools/todo_write.rb +25 -18
  43. data/lib/brute/tools.rb +8 -12
  44. data/lib/brute/truncation.rb +219 -0
  45. data/lib/brute/version.rb +1 -1
  46. data/lib/brute.rb +82 -45
  47. metadata +59 -46
  48. data/lib/brute/loop/agent_stream.rb +0 -118
  49. data/lib/brute/loop/agent_turn.rb +0 -520
  50. data/lib/brute/loop/compactor.rb +0 -107
  51. data/lib/brute/loop/doom_loop.rb +0 -86
  52. data/lib/brute/loop/step.rb +0 -332
  53. data/lib/brute/loop/tool_call_step.rb +0 -90
  54. data/lib/brute/middleware/base.rb +0 -27
  55. data/lib/brute/middleware/compaction_check.rb +0 -106
  56. data/lib/brute/middleware/doom_loop_detection.rb +0 -136
  57. data/lib/brute/middleware/llm_call.rb +0 -128
  58. data/lib/brute/middleware/message_tracking.rb +0 -339
  59. data/lib/brute/middleware/otel/span.rb +0 -105
  60. data/lib/brute/middleware/otel/token_usage.rb +0 -68
  61. data/lib/brute/middleware/otel/tool_calls.rb +0 -68
  62. data/lib/brute/middleware/otel/tool_results.rb +0 -65
  63. data/lib/brute/middleware/otel.rb +0 -34
  64. data/lib/brute/middleware/reasoning_normalizer.rb +0 -192
  65. data/lib/brute/middleware/retry.rb +0 -157
  66. data/lib/brute/middleware/session_persistence.rb +0 -72
  67. data/lib/brute/middleware/token_tracking.rb +0 -124
  68. data/lib/brute/middleware/tool_error_tracking.rb +0 -179
  69. data/lib/brute/middleware/tool_use_guard.rb +0 -133
  70. data/lib/brute/middleware/tracing.rb +0 -124
  71. data/lib/brute/middleware.rb +0 -18
  72. data/lib/brute/orchestrator/turn.rb +0 -105
  73. data/lib/brute/patches/anthropic_tool_role.rb +0 -35
  74. data/lib/brute/patches/buffer_nil_guard.rb +0 -26
  75. data/lib/brute/providers/models_dev.rb +0 -111
  76. data/lib/brute/providers/ollama.rb +0 -135
  77. data/lib/brute/providers/opencode_go.rb +0 -43
  78. data/lib/brute/providers/opencode_zen.rb +0 -87
  79. data/lib/brute/providers.rb +0 -62
  80. data/lib/brute/queue/base_queue.rb +0 -222
  81. data/lib/brute/queue/parallel_queue.rb +0 -66
  82. data/lib/brute/queue/sequential_queue.rb +0 -63
  83. data/lib/brute/store/message_store.rb +0 -362
  84. data/lib/brute/store/session.rb +0 -106
  85. /data/lib/brute/{diff.rb → utils/diff.rb} +0 -0
@@ -1,106 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "json"
4
- require "fileutils"
5
- require "securerandom"
6
-
7
- module Brute
8
- module Store
9
- # Manages session persistence. Each session is a conversation that can be
10
- # saved to disk and resumed later.
11
- #
12
- # Storage layout (per-session directory):
13
- #
14
- # ~/.brute/sessions/{session-id}/
15
- # session.meta.json # session metadata
16
- # context.json # serialized conversation history
17
- # msg_0001.json # structured messages (OpenCode format)
18
- # msg_0002.json
19
- # ...
20
- #
21
- class Session
22
- attr_reader :id, :title, :path
23
-
24
- def initialize(id: nil, dir: nil)
25
- @id = id || SecureRandom.uuid
26
- @base_dir = dir || File.join(Dir.home, ".brute", "sessions")
27
- @session_dir = File.join(@base_dir, @id)
28
- @path = File.join(@session_dir, "context.json")
29
- @title = nil
30
- @metadata = {}
31
- FileUtils.mkdir_p(@session_dir)
32
- end
33
-
34
- def message_store
35
- @message_store ||= MessageStore.new(session_id: @id, dir: @session_dir)
36
- end
37
-
38
- # Serialize an array of LLM::Message objects to disk as JSON.
39
- def save_messages(messages, title: nil, metadata: {})
40
- @title = title if title
41
- @metadata.merge!(metadata)
42
-
43
- data = {
44
- schema_version: 1,
45
- messages: messages.map { |m| { role: m.role.to_s, content: m.content.to_s } },
46
- }
47
- FileUtils.mkdir_p(File.dirname(@path))
48
- File.write(@path, JSON.pretty_generate(data))
49
-
50
- save_meta
51
- end
52
-
53
- # List all saved sessions, newest first.
54
- def self.list(dir: nil)
55
- dir ||= File.join(Dir.home, ".brute", "sessions")
56
-
57
- if File.directory?(dir)
58
- sessions = Dir.glob(File.join(dir, "*", "session.meta.json")).filter_map do |meta_path|
59
- data = JSON.parse(File.read(meta_path), symbolize_names: true)
60
- id = data[:id]
61
- next unless id
62
- {
63
- id: id,
64
- title: data[:title],
65
- saved_at: data[:saved_at],
66
- path: File.join(File.dirname(meta_path), "context.json"),
67
- }
68
- end
69
-
70
- sessions.sort_by { |s| s[:saved_at] || "" }.reverse
71
- else
72
- []
73
- end
74
- end
75
-
76
- def delete
77
- FileUtils.rm_rf(@session_dir) if File.directory?(@session_dir)
78
- end
79
-
80
- private
81
-
82
- def meta_path
83
- File.join(@session_dir, "session.meta.json")
84
- end
85
-
86
- def save_meta
87
- data = {
88
- id: @id,
89
- title: @title,
90
- saved_at: Time.now.iso8601,
91
- metadata: @metadata,
92
- }
93
- FileUtils.mkdir_p(@session_dir)
94
- File.write(meta_path, JSON.pretty_generate(data))
95
- end
96
-
97
- def load_meta
98
- return unless File.exist?(meta_path)
99
-
100
- data = JSON.parse(File.read(meta_path), symbolize_names: true)
101
- @title = data[:title]
102
- @metadata = data[:metadata] || {}
103
- end
104
- end
105
- end
106
- end
File without changes