agent_c 2.9
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 +7 -0
- data/.rubocop.yml +10 -0
- data/.ruby-version +1 -0
- data/CLAUDE.md +21 -0
- data/README.md +360 -0
- data/Rakefile +16 -0
- data/TODO.md +105 -0
- data/agent_c.gemspec +38 -0
- data/docs/batch.md +503 -0
- data/docs/chat-methods.md +156 -0
- data/docs/cost-reporting.md +86 -0
- data/docs/pipeline-tips-and-tricks.md +453 -0
- data/docs/session-configuration.md +274 -0
- data/docs/testing.md +747 -0
- data/docs/tools.md +103 -0
- data/docs/versioned-store.md +840 -0
- data/lib/agent_c/agent/chat.rb +211 -0
- data/lib/agent_c/agent/chat_response.rb +38 -0
- data/lib/agent_c/agent/chats/anthropic_bedrock.rb +48 -0
- data/lib/agent_c/batch.rb +102 -0
- data/lib/agent_c/configs/repo.rb +90 -0
- data/lib/agent_c/context.rb +56 -0
- data/lib/agent_c/costs/data.rb +39 -0
- data/lib/agent_c/costs/report.rb +219 -0
- data/lib/agent_c/db/store.rb +162 -0
- data/lib/agent_c/errors.rb +19 -0
- data/lib/agent_c/pipeline.rb +152 -0
- data/lib/agent_c/pipelines/agent.rb +219 -0
- data/lib/agent_c/processor.rb +98 -0
- data/lib/agent_c/prompts.yml +53 -0
- data/lib/agent_c/schema.rb +71 -0
- data/lib/agent_c/session.rb +206 -0
- data/lib/agent_c/store.rb +72 -0
- data/lib/agent_c/test_helpers.rb +173 -0
- data/lib/agent_c/tools/dir_glob.rb +46 -0
- data/lib/agent_c/tools/edit_file.rb +114 -0
- data/lib/agent_c/tools/file_metadata.rb +43 -0
- data/lib/agent_c/tools/git_status.rb +30 -0
- data/lib/agent_c/tools/grep.rb +119 -0
- data/lib/agent_c/tools/paths.rb +36 -0
- data/lib/agent_c/tools/read_file.rb +94 -0
- data/lib/agent_c/tools/run_rails_test.rb +87 -0
- data/lib/agent_c/tools.rb +61 -0
- data/lib/agent_c/utils/git.rb +87 -0
- data/lib/agent_c/utils/shell.rb +58 -0
- data/lib/agent_c/version.rb +5 -0
- data/lib/agent_c.rb +32 -0
- data/lib/versioned_store/base.rb +314 -0
- data/lib/versioned_store/config.rb +26 -0
- data/lib/versioned_store/stores/schema.rb +127 -0
- data/lib/versioned_store/version.rb +5 -0
- data/lib/versioned_store.rb +5 -0
- data/template/Gemfile +9 -0
- data/template/Gemfile.lock +152 -0
- data/template/README.md +61 -0
- data/template/Rakefile +50 -0
- data/template/bin/rake +27 -0
- data/template/lib/autoload.rb +10 -0
- data/template/lib/config.rb +59 -0
- data/template/lib/pipeline.rb +19 -0
- data/template/lib/prompts.yml +57 -0
- data/template/lib/store.rb +17 -0
- data/template/test/pipeline_test.rb +221 -0
- data/template/test/test_helper.rb +18 -0
- metadata +194 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "set"
|
|
4
|
+
module VersionedStore
|
|
5
|
+
module Stores
|
|
6
|
+
class Schema
|
|
7
|
+
Record = Data.define(:name, :table, :blocks)
|
|
8
|
+
Migration = Data.define(:version, :block)
|
|
9
|
+
|
|
10
|
+
class RecordContext
|
|
11
|
+
attr_reader :schema_instance, :table_name, :record_name
|
|
12
|
+
|
|
13
|
+
def initialize(schema_instance, record_name)
|
|
14
|
+
@schema_instance = schema_instance
|
|
15
|
+
@record_name = record_name
|
|
16
|
+
@table_name = nil
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def schema(table_name = nil, &block)
|
|
20
|
+
# If no table name provided, infer from record name
|
|
21
|
+
if table_name.nil?
|
|
22
|
+
name_str = record_name.to_s
|
|
23
|
+
table_name = (name_str.end_with?('s') ? name_str : "#{name_str}s").to_sym
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Store the table name for later use
|
|
27
|
+
@table_name = table_name
|
|
28
|
+
|
|
29
|
+
# Collect all schema blocks for a table
|
|
30
|
+
schema_instance.schema_blocks[table_name] ||= []
|
|
31
|
+
schema_instance.schema_blocks[table_name] << block if block
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def method_missing(...)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def respond_to_missing?(...)
|
|
38
|
+
true
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
attr_reader :migrations, :records, :migrated_tables, :schema_blocks, :post_init_hooks
|
|
43
|
+
def initialize
|
|
44
|
+
@migrations = []
|
|
45
|
+
@records = {}
|
|
46
|
+
@migration_counter = 1
|
|
47
|
+
@migrated_tables = Set.new
|
|
48
|
+
@schema_blocks = {}
|
|
49
|
+
@post_init_hooks = []
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def dup
|
|
53
|
+
new_schema = Schema.new
|
|
54
|
+
new_schema.instance_variable_set(:@migrations, @migrations.dup)
|
|
55
|
+
new_schema.instance_variable_set(:@records, @records.dup)
|
|
56
|
+
new_schema.instance_variable_set(:@migration_counter, @migration_counter)
|
|
57
|
+
new_schema.instance_variable_set(:@migrated_tables, @migrated_tables.dup)
|
|
58
|
+
new_schema.instance_variable_set(:@schema_blocks, @schema_blocks.dup)
|
|
59
|
+
new_schema.instance_variable_set(:@post_init_hooks, @post_init_hooks.dup)
|
|
60
|
+
new_schema.instance_variable_set(:@dir, @dir)
|
|
61
|
+
new_schema
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def dir(path = nil)
|
|
65
|
+
@dir = path if path
|
|
66
|
+
@dir
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def migrate(version = @migration_counter += 1, &block)
|
|
70
|
+
migrations << Migration.new(version: version, block: block)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def prepend_migration(version, &block)
|
|
74
|
+
migrations.unshift(Migration.new(version: version, block: block))
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def record(name, table: nil, &block)
|
|
78
|
+
# If block is given, execute it in RecordContext to extract schema calls
|
|
79
|
+
extracted_table = table
|
|
80
|
+
if block
|
|
81
|
+
context = RecordContext.new(self, name)
|
|
82
|
+
context.instance_exec(&block)
|
|
83
|
+
extracted_table ||= context.table_name
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
prev = records[name]
|
|
87
|
+
blocks = prev ? prev.blocks.dup : []
|
|
88
|
+
blocks << block if block
|
|
89
|
+
# Prefer the first non-nil table name, otherwise default to name + "s"
|
|
90
|
+
table_name = prev&.table || extracted_table
|
|
91
|
+
if table_name.nil?
|
|
92
|
+
name_str = name.to_s
|
|
93
|
+
table_name = (name_str.end_with?('s') ? name_str : "#{name_str}s").to_sym
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
records[name] = Record.new(
|
|
97
|
+
name: name,
|
|
98
|
+
table: table_name,
|
|
99
|
+
blocks: blocks
|
|
100
|
+
)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Add a migration for each table with collected schema blocks (called after all record blocks)
|
|
104
|
+
def add_table_migrations!
|
|
105
|
+
schema_blocks.each do |table_name, blocks|
|
|
106
|
+
next if migrated_tables.include?(table_name) || table_name.nil?
|
|
107
|
+
blocks_to_eval = blocks.dup
|
|
108
|
+
migration_block = Proc.new do
|
|
109
|
+
create_table(table_name) do |t|
|
|
110
|
+
blocks_to_eval.each { |blk| blk.call(t) }
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
version = "table_#{table_name}"
|
|
114
|
+
prepend_migration(version, &migration_block)
|
|
115
|
+
migrated_tables.add(table_name)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def self.call(&block)
|
|
120
|
+
schema = new
|
|
121
|
+
schema.instance_exec(&block) if block
|
|
122
|
+
schema.add_table_migrations!
|
|
123
|
+
schema
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
data/template/Gemfile
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: ..
|
|
3
|
+
specs:
|
|
4
|
+
agent_c (2.71828)
|
|
5
|
+
activerecord
|
|
6
|
+
async
|
|
7
|
+
json-schema
|
|
8
|
+
ruby_llm
|
|
9
|
+
sqlite3
|
|
10
|
+
zeitwerk
|
|
11
|
+
|
|
12
|
+
GEM
|
|
13
|
+
remote: https://rubygems.org/
|
|
14
|
+
specs:
|
|
15
|
+
activemodel (8.1.2)
|
|
16
|
+
activesupport (= 8.1.2)
|
|
17
|
+
activerecord (8.1.2)
|
|
18
|
+
activemodel (= 8.1.2)
|
|
19
|
+
activesupport (= 8.1.2)
|
|
20
|
+
timeout (>= 0.4.0)
|
|
21
|
+
activesupport (8.1.2)
|
|
22
|
+
base64
|
|
23
|
+
bigdecimal
|
|
24
|
+
concurrent-ruby (~> 1.0, >= 1.3.1)
|
|
25
|
+
connection_pool (>= 2.2.5)
|
|
26
|
+
drb
|
|
27
|
+
i18n (>= 1.6, < 2)
|
|
28
|
+
json
|
|
29
|
+
logger (>= 1.4.2)
|
|
30
|
+
minitest (>= 5.1)
|
|
31
|
+
securerandom (>= 0.3)
|
|
32
|
+
tzinfo (~> 2.0, >= 2.0.5)
|
|
33
|
+
uri (>= 0.13.1)
|
|
34
|
+
addressable (2.8.8)
|
|
35
|
+
public_suffix (>= 2.0.2, < 8.0)
|
|
36
|
+
async (2.36.0)
|
|
37
|
+
console (~> 1.29)
|
|
38
|
+
fiber-annotation
|
|
39
|
+
io-event (~> 1.11)
|
|
40
|
+
metrics (~> 0.12)
|
|
41
|
+
traces (~> 0.18)
|
|
42
|
+
base64 (0.3.0)
|
|
43
|
+
bigdecimal (4.0.1)
|
|
44
|
+
concurrent-ruby (1.3.6)
|
|
45
|
+
connection_pool (3.0.2)
|
|
46
|
+
console (1.34.2)
|
|
47
|
+
fiber-annotation
|
|
48
|
+
fiber-local (~> 1.1)
|
|
49
|
+
json
|
|
50
|
+
date (3.5.1)
|
|
51
|
+
debug (1.11.1)
|
|
52
|
+
irb (~> 1.10)
|
|
53
|
+
reline (>= 0.3.8)
|
|
54
|
+
drb (2.2.3)
|
|
55
|
+
erb (6.0.1)
|
|
56
|
+
event_stream_parser (1.0.0)
|
|
57
|
+
faraday (2.14.0)
|
|
58
|
+
faraday-net_http (>= 2.0, < 3.5)
|
|
59
|
+
json
|
|
60
|
+
logger
|
|
61
|
+
faraday-multipart (1.2.0)
|
|
62
|
+
multipart-post (~> 2.0)
|
|
63
|
+
faraday-net_http (3.4.2)
|
|
64
|
+
net-http (~> 0.5)
|
|
65
|
+
faraday-retry (2.4.0)
|
|
66
|
+
faraday (~> 2.0)
|
|
67
|
+
fiber-annotation (0.2.0)
|
|
68
|
+
fiber-local (1.1.0)
|
|
69
|
+
fiber-storage
|
|
70
|
+
fiber-storage (1.0.1)
|
|
71
|
+
i18n (1.14.8)
|
|
72
|
+
concurrent-ruby (~> 1.0)
|
|
73
|
+
io-console (0.8.2)
|
|
74
|
+
io-event (1.14.2)
|
|
75
|
+
irb (1.16.0)
|
|
76
|
+
pp (>= 0.6.0)
|
|
77
|
+
rdoc (>= 4.0.0)
|
|
78
|
+
reline (>= 0.4.2)
|
|
79
|
+
json (2.18.0)
|
|
80
|
+
json-schema (6.1.0)
|
|
81
|
+
addressable (~> 2.8)
|
|
82
|
+
bigdecimal (>= 3.1, < 5)
|
|
83
|
+
logger (1.7.0)
|
|
84
|
+
marcel (1.1.0)
|
|
85
|
+
metrics (0.15.0)
|
|
86
|
+
minitest (6.0.1)
|
|
87
|
+
prism (~> 1.5)
|
|
88
|
+
multipart-post (2.4.1)
|
|
89
|
+
net-http (0.9.1)
|
|
90
|
+
uri (>= 0.11.1)
|
|
91
|
+
pp (0.6.3)
|
|
92
|
+
prettyprint
|
|
93
|
+
prettyprint (0.2.0)
|
|
94
|
+
prism (1.8.0)
|
|
95
|
+
psych (5.3.1)
|
|
96
|
+
date
|
|
97
|
+
stringio
|
|
98
|
+
public_suffix (7.0.2)
|
|
99
|
+
rake (13.3.1)
|
|
100
|
+
rdoc (7.1.0)
|
|
101
|
+
erb
|
|
102
|
+
psych (>= 4.0.0)
|
|
103
|
+
tsort
|
|
104
|
+
reline (0.6.3)
|
|
105
|
+
io-console (~> 0.5)
|
|
106
|
+
ruby_llm (1.11.0)
|
|
107
|
+
base64
|
|
108
|
+
event_stream_parser (~> 1)
|
|
109
|
+
faraday (>= 1.10.0)
|
|
110
|
+
faraday-multipart (>= 1)
|
|
111
|
+
faraday-net_http (>= 1)
|
|
112
|
+
faraday-retry (>= 1)
|
|
113
|
+
marcel (~> 1.0)
|
|
114
|
+
ruby_llm-schema (~> 0.2.1)
|
|
115
|
+
zeitwerk (~> 2)
|
|
116
|
+
ruby_llm-schema (0.2.5)
|
|
117
|
+
securerandom (0.4.1)
|
|
118
|
+
sqlite3 (2.9.0-aarch64-linux-gnu)
|
|
119
|
+
sqlite3 (2.9.0-aarch64-linux-musl)
|
|
120
|
+
sqlite3 (2.9.0-arm-linux-gnu)
|
|
121
|
+
sqlite3 (2.9.0-arm-linux-musl)
|
|
122
|
+
sqlite3 (2.9.0-arm64-darwin)
|
|
123
|
+
sqlite3 (2.9.0-x86_64-darwin)
|
|
124
|
+
sqlite3 (2.9.0-x86_64-linux-gnu)
|
|
125
|
+
sqlite3 (2.9.0-x86_64-linux-musl)
|
|
126
|
+
stringio (3.2.0)
|
|
127
|
+
timeout (0.6.0)
|
|
128
|
+
traces (0.18.2)
|
|
129
|
+
tsort (0.2.0)
|
|
130
|
+
tzinfo (2.0.6)
|
|
131
|
+
concurrent-ruby (~> 1.0)
|
|
132
|
+
uri (1.1.1)
|
|
133
|
+
zeitwerk (2.7.4)
|
|
134
|
+
|
|
135
|
+
PLATFORMS
|
|
136
|
+
aarch64-linux-gnu
|
|
137
|
+
aarch64-linux-musl
|
|
138
|
+
arm-linux-gnu
|
|
139
|
+
arm-linux-musl
|
|
140
|
+
arm64-darwin
|
|
141
|
+
x86_64-darwin
|
|
142
|
+
x86_64-linux-gnu
|
|
143
|
+
x86_64-linux-musl
|
|
144
|
+
|
|
145
|
+
DEPENDENCIES
|
|
146
|
+
agent_c!
|
|
147
|
+
debug
|
|
148
|
+
minitest
|
|
149
|
+
rake
|
|
150
|
+
|
|
151
|
+
BUNDLED WITH
|
|
152
|
+
2.6.5
|
data/template/README.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Overview
|
|
2
|
+
|
|
3
|
+
This directory contains a small script demonstrating how to run a batch of pipelines.
|
|
4
|
+
|
|
5
|
+
For each `summary` record created, Claude will choose a random file, summarize it, and write the summary to disk. Then our pipeline commits the changes at the end.
|
|
6
|
+
|
|
7
|
+
It creates two records and runs them across two worktrees.
|
|
8
|
+
|
|
9
|
+
The main entrypoint is the Rakefile.
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
### Running the Batch
|
|
13
|
+
|
|
14
|
+
You'll need to set the relevant environment variables specified in the Config. (The environment variables necessary assume you're using Claude on Bedrock.)
|
|
15
|
+
|
|
16
|
+
Then run:
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
bin/rake run
|
|
20
|
+
# => Summary report:
|
|
21
|
+
# => Succeeded: 2
|
|
22
|
+
# => Pending: 0
|
|
23
|
+
# => Failed: 0
|
|
24
|
+
# => Run cost: $0.31
|
|
25
|
+
# => Project total cost: $1.67
|
|
26
|
+
# => ---
|
|
27
|
+
# => task: 1 - wrote summary to /tmp/example-worktrees/summary-examples-0/VERSIONED_STORE_BASE_SUMMARY.md
|
|
28
|
+
# => task: 2 - wrote summary to /tmp/example-worktrees/summary-examples-1/SUMMARY-es.md
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Watching progress
|
|
32
|
+
|
|
33
|
+
You can tail the logs with:
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
# See EVERYTHING
|
|
37
|
+
tail -f log/run.log
|
|
38
|
+
|
|
39
|
+
# See just progress
|
|
40
|
+
tail -f log/run.log | grep INFO
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Poking around the data
|
|
44
|
+
|
|
45
|
+
```sh
|
|
46
|
+
bin/rake console
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Resetting state
|
|
50
|
+
|
|
51
|
+
Delete the state stored in the `./tmp` directory to start all over:
|
|
52
|
+
|
|
53
|
+
```sh
|
|
54
|
+
rm -rf ./tmp
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Run the tests:
|
|
58
|
+
|
|
59
|
+
```sh
|
|
60
|
+
bin/rake test
|
|
61
|
+
```
|
data/template/Rakefile
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "bundler/setup"
|
|
4
|
+
require "rake/testtask"
|
|
5
|
+
|
|
6
|
+
require_relative "./lib/autoload"
|
|
7
|
+
|
|
8
|
+
Rake::TestTask.new(:test) do |t|
|
|
9
|
+
t.libs << "test"
|
|
10
|
+
t.libs << "lib"
|
|
11
|
+
t.test_files = FileList["test/**/*_test.rb"]
|
|
12
|
+
t.verbose = true
|
|
13
|
+
t.warning = false
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
desc "Run the pipeline"
|
|
17
|
+
task :run do
|
|
18
|
+
batch = AgentC::Batch.new(**Config::BATCH)
|
|
19
|
+
|
|
20
|
+
["english", "spanish"].map do |language|
|
|
21
|
+
record = batch.store.summary.find_or_create_by!(language:)
|
|
22
|
+
|
|
23
|
+
batch.add_task(record)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
batch.call
|
|
27
|
+
|
|
28
|
+
puts "Summary report:"
|
|
29
|
+
puts batch.report
|
|
30
|
+
puts "---\n"
|
|
31
|
+
|
|
32
|
+
batch.store.task.all.each do |task|
|
|
33
|
+
next unless task.done?
|
|
34
|
+
|
|
35
|
+
full_path = File.join(
|
|
36
|
+
task.workspace.dir,
|
|
37
|
+
task.record.summary_path
|
|
38
|
+
)
|
|
39
|
+
puts "task: #{task.id} - wrote summary to #{full_path}"
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
task :console do
|
|
44
|
+
batch = AgentC::Batch.new(**Config::BATCH)
|
|
45
|
+
|
|
46
|
+
# poke around the data here
|
|
47
|
+
binding.irb
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
task default: :test
|
data/template/bin/rake
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# This file was generated by Bundler.
|
|
6
|
+
#
|
|
7
|
+
# The application 'rake' is installed as part of a gem, and
|
|
8
|
+
# this file is here to facilitate running it.
|
|
9
|
+
#
|
|
10
|
+
|
|
11
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
|
12
|
+
|
|
13
|
+
bundle_binstub = File.expand_path("bundle", __dir__)
|
|
14
|
+
|
|
15
|
+
if File.file?(bundle_binstub)
|
|
16
|
+
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
|
|
17
|
+
load(bundle_binstub)
|
|
18
|
+
else
|
|
19
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
|
20
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
require "rubygems"
|
|
25
|
+
require "bundler/setup"
|
|
26
|
+
|
|
27
|
+
load Gem.bin_path("rake", "rake")
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "fileutils"
|
|
4
|
+
require "tmpdir"
|
|
5
|
+
|
|
6
|
+
module Config
|
|
7
|
+
LOG_PATH = "./log/run.log"
|
|
8
|
+
FileUtils.mkdir_p(File.dirname(LOG_PATH))
|
|
9
|
+
|
|
10
|
+
LOGGER = Logger.new(LOG_PATH)
|
|
11
|
+
|
|
12
|
+
PROJECT = "TemplateProject.v1"
|
|
13
|
+
|
|
14
|
+
BATCH = {
|
|
15
|
+
record_type: :summary,
|
|
16
|
+
pipeline: Pipeline,
|
|
17
|
+
|
|
18
|
+
store: {
|
|
19
|
+
class: Store,
|
|
20
|
+
config: {
|
|
21
|
+
logger: LOGGER,
|
|
22
|
+
dir: File.join(
|
|
23
|
+
File.expand_path("../tmp", __dir__),
|
|
24
|
+
PROJECT,
|
|
25
|
+
)
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
repo: {
|
|
30
|
+
dir: File.expand_path("../../", __dir__),
|
|
31
|
+
initial_revision: "main",
|
|
32
|
+
working_subdir: "", # use the root-level of the repo
|
|
33
|
+
worktrees_root_dir: "/tmp/example-worktrees",
|
|
34
|
+
worktree_branch_prefix: "summary-examples",
|
|
35
|
+
worktree_envs: [
|
|
36
|
+
{
|
|
37
|
+
SOME_ENV: "1",
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
SOME_ENV: "2",
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
session: {
|
|
46
|
+
agent_db_path: File.expand_path("../../tmp/claude.sqlite", __dir__),
|
|
47
|
+
logger: LOGGER,
|
|
48
|
+
i18n_path: File.expand_path("prompts.yml", __dir__),
|
|
49
|
+
project: PROJECT,
|
|
50
|
+
ruby_llm: {
|
|
51
|
+
bedrock_api_key: ENV.fetch("AWS_ACCESS_KEY_ID"),
|
|
52
|
+
bedrock_secret_key: ENV.fetch("AWS_SECRET_ACCESS_KEY"),
|
|
53
|
+
bedrock_session_token: ENV.fetch("AWS_SESSION_TOKEN"),
|
|
54
|
+
bedrock_region: ENV.fetch("AWS_REGION", "us-west-2"),
|
|
55
|
+
default_model: ENV.fetch("LLM_MODEL", "us.anthropic.claude-sonnet-4-5-20250929-v1:0")
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
}
|
|
59
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Pipeline < AgentC::Pipeline
|
|
4
|
+
agent_step(:pick_a_random_file)
|
|
5
|
+
agent_step(:summarize_the_file)
|
|
6
|
+
agent_step(:write_summary_to_disk)
|
|
7
|
+
|
|
8
|
+
step(:finalize) do
|
|
9
|
+
if repo.uncommitted_changes?
|
|
10
|
+
repo.commit_all(
|
|
11
|
+
<<~TXT
|
|
12
|
+
claude: added file: #{record.summary_path}
|
|
13
|
+
TXT
|
|
14
|
+
)
|
|
15
|
+
else
|
|
16
|
+
task.fail!("didn't create a file")
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
en:
|
|
2
|
+
# This prompt will be used by all steps, it will be cached
|
|
3
|
+
# to save $$$.
|
|
4
|
+
global_summary_cache: &global_summary_cache |
|
|
5
|
+
This project is a ruby gem. You will be summarizing a file using
|
|
6
|
+
the language specified.
|
|
7
|
+
pick_a_random_file:
|
|
8
|
+
tools: [read_file, grep, dir_glob]
|
|
9
|
+
cached_prompts:
|
|
10
|
+
- *global_summary_cache
|
|
11
|
+
prompt: |
|
|
12
|
+
# YOUR JOB
|
|
13
|
+
|
|
14
|
+
Find a random ruby file within the repository. Bonus points for picking
|
|
15
|
+
a file with many lines.
|
|
16
|
+
response_schema:
|
|
17
|
+
input_path:
|
|
18
|
+
description: |
|
|
19
|
+
The path to the file you have chosen
|
|
20
|
+
|
|
21
|
+
summarize_the_file:
|
|
22
|
+
tools: [read_file]
|
|
23
|
+
cached_prompts:
|
|
24
|
+
- *global_summary_cache
|
|
25
|
+
prompt: |
|
|
26
|
+
You will be given a file path. Your job is to summarize the file for a
|
|
27
|
+
developer to read and understand.
|
|
28
|
+
|
|
29
|
+
You must write your summary using the language provided.
|
|
30
|
+
|
|
31
|
+
language: %{language}
|
|
32
|
+
file path: %{input_path}
|
|
33
|
+
response_schema:
|
|
34
|
+
summary_body:
|
|
35
|
+
description: |
|
|
36
|
+
Your summary of the file
|
|
37
|
+
|
|
38
|
+
write_summary_to_disk:
|
|
39
|
+
tools: [edit_file]
|
|
40
|
+
cached_prompts:
|
|
41
|
+
- *global_summary_cache
|
|
42
|
+
prompt: |
|
|
43
|
+
You will be given a file path and some summary text. Write the text to the
|
|
44
|
+
a well-named file at the top-level of the repository. You will return the
|
|
45
|
+
path that you wrote.
|
|
46
|
+
|
|
47
|
+
IMPORTANT: you **must** invoke the edit_file tool to process this request.
|
|
48
|
+
|
|
49
|
+
summary:
|
|
50
|
+
---BEGIN-SUMMARY---
|
|
51
|
+
%{summary_body}
|
|
52
|
+
---END-SUMMARY---
|
|
53
|
+
|
|
54
|
+
response_schema:
|
|
55
|
+
summary_path:
|
|
56
|
+
description: |
|
|
57
|
+
The path to the file you wrote.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Store < VersionedStore::Base
|
|
4
|
+
include AgentC::Store
|
|
5
|
+
|
|
6
|
+
record(:summary) do
|
|
7
|
+
schema do |t|
|
|
8
|
+
# we'll input this data
|
|
9
|
+
t.string(:language)
|
|
10
|
+
|
|
11
|
+
# claude will generate this data
|
|
12
|
+
t.string(:input_path)
|
|
13
|
+
t.string(:summary_body)
|
|
14
|
+
t.string(:summary_path)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|