simple_acp 0.0.1

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 +7 -0
  2. data/.envrc +1 -0
  3. data/CHANGELOG.md +5 -0
  4. data/COMMITS.md +196 -0
  5. data/LICENSE.txt +21 -0
  6. data/README.md +385 -0
  7. data/Rakefile +13 -0
  8. data/docs/api/client-base.md +383 -0
  9. data/docs/api/index.md +159 -0
  10. data/docs/api/models.md +286 -0
  11. data/docs/api/server-base.md +379 -0
  12. data/docs/api/storage.md +347 -0
  13. data/docs/assets/images/simple_acp.jpg +0 -0
  14. data/docs/client/index.md +279 -0
  15. data/docs/client/sessions.md +324 -0
  16. data/docs/client/streaming.md +345 -0
  17. data/docs/client/sync-async.md +308 -0
  18. data/docs/core-concepts/agents.md +253 -0
  19. data/docs/core-concepts/events.md +337 -0
  20. data/docs/core-concepts/index.md +147 -0
  21. data/docs/core-concepts/messages.md +211 -0
  22. data/docs/core-concepts/runs.md +278 -0
  23. data/docs/core-concepts/sessions.md +281 -0
  24. data/docs/examples.md +659 -0
  25. data/docs/getting-started/configuration.md +166 -0
  26. data/docs/getting-started/index.md +62 -0
  27. data/docs/getting-started/installation.md +95 -0
  28. data/docs/getting-started/quick-start.md +189 -0
  29. data/docs/index.md +119 -0
  30. data/docs/server/creating-agents.md +360 -0
  31. data/docs/server/http-endpoints.md +411 -0
  32. data/docs/server/index.md +218 -0
  33. data/docs/server/multi-turn.md +329 -0
  34. data/docs/server/streaming.md +315 -0
  35. data/docs/storage/custom.md +414 -0
  36. data/docs/storage/index.md +176 -0
  37. data/docs/storage/memory.md +198 -0
  38. data/docs/storage/postgresql.md +350 -0
  39. data/docs/storage/redis.md +287 -0
  40. data/examples/01_basic/client.rb +88 -0
  41. data/examples/01_basic/server.rb +100 -0
  42. data/examples/02_async_execution/client.rb +107 -0
  43. data/examples/02_async_execution/server.rb +56 -0
  44. data/examples/03_run_management/client.rb +115 -0
  45. data/examples/03_run_management/server.rb +84 -0
  46. data/examples/04_rich_messages/client.rb +160 -0
  47. data/examples/04_rich_messages/server.rb +180 -0
  48. data/examples/05_await_resume/client.rb +164 -0
  49. data/examples/05_await_resume/server.rb +114 -0
  50. data/examples/06_agent_metadata/client.rb +188 -0
  51. data/examples/06_agent_metadata/server.rb +192 -0
  52. data/examples/README.md +252 -0
  53. data/examples/run_demo.sh +137 -0
  54. data/lib/simple_acp/client/base.rb +448 -0
  55. data/lib/simple_acp/client/sse.rb +141 -0
  56. data/lib/simple_acp/models/agent_manifest.rb +129 -0
  57. data/lib/simple_acp/models/await.rb +123 -0
  58. data/lib/simple_acp/models/base.rb +147 -0
  59. data/lib/simple_acp/models/errors.rb +102 -0
  60. data/lib/simple_acp/models/events.rb +256 -0
  61. data/lib/simple_acp/models/message.rb +235 -0
  62. data/lib/simple_acp/models/message_part.rb +225 -0
  63. data/lib/simple_acp/models/metadata.rb +161 -0
  64. data/lib/simple_acp/models/run.rb +298 -0
  65. data/lib/simple_acp/models/session.rb +137 -0
  66. data/lib/simple_acp/models/types.rb +210 -0
  67. data/lib/simple_acp/server/agent.rb +116 -0
  68. data/lib/simple_acp/server/app.rb +264 -0
  69. data/lib/simple_acp/server/base.rb +510 -0
  70. data/lib/simple_acp/server/context.rb +210 -0
  71. data/lib/simple_acp/server/falcon_runner.rb +61 -0
  72. data/lib/simple_acp/storage/base.rb +129 -0
  73. data/lib/simple_acp/storage/memory.rb +108 -0
  74. data/lib/simple_acp/storage/postgresql.rb +233 -0
  75. data/lib/simple_acp/storage/redis.rb +178 -0
  76. data/lib/simple_acp/version.rb +5 -0
  77. data/lib/simple_acp.rb +91 -0
  78. data/mkdocs.yml +152 -0
  79. data/sig/simple_acp.rbs +4 -0
  80. metadata +418 -0
@@ -0,0 +1,198 @@
1
+ # Memory Storage
2
+
3
+ The Memory storage backend stores all data in-process using thread-safe data structures. It's the default backend and ideal for development and testing.
4
+
5
+ ## Features
6
+
7
+ - **Zero dependencies** - No external services required
8
+ - **Thread-safe** - Uses `concurrent-ruby` for safe concurrent access
9
+ - **Fast** - All operations are in-memory
10
+ - **Simple** - No configuration needed
11
+
12
+ ## Limitations
13
+
14
+ - **Not persistent** - Data is lost when the process exits
15
+ - **Single process** - Cannot share data between processes
16
+ - **Memory bound** - Limited by available RAM
17
+
18
+ ## Usage
19
+
20
+ ### Basic Setup
21
+
22
+ ```ruby
23
+ require 'simple_acp'
24
+
25
+ # Memory is the default
26
+ server = SimpleAcp::Server::Base.new
27
+
28
+ # Or explicitly
29
+ storage = SimpleAcp::Storage::Memory.new
30
+ server = SimpleAcp::Server::Base.new(storage: storage)
31
+ ```
32
+
33
+ ### With Options
34
+
35
+ ```ruby
36
+ storage = SimpleAcp::Storage::Memory.new(
37
+ # Currently no specific options
38
+ )
39
+ ```
40
+
41
+ ## Operations
42
+
43
+ ### Runs
44
+
45
+ ```ruby
46
+ # Save a run
47
+ storage.save_run(run)
48
+
49
+ # Get a run
50
+ run = storage.get_run("run-id")
51
+
52
+ # Delete a run
53
+ storage.delete_run("run-id")
54
+
55
+ # List runs
56
+ result = storage.list_runs(
57
+ agent_name: "echo", # Optional filter
58
+ session_id: "sess-1", # Optional filter
59
+ limit: 10,
60
+ offset: 0
61
+ )
62
+ puts result[:runs] # Array of runs
63
+ puts result[:total] # Total count
64
+ ```
65
+
66
+ ### Sessions
67
+
68
+ ```ruby
69
+ # Save a session
70
+ storage.save_session(session)
71
+
72
+ # Get a session
73
+ session = storage.get_session("session-id")
74
+
75
+ # Delete a session
76
+ storage.delete_session("session-id")
77
+ ```
78
+
79
+ ### Events
80
+
81
+ ```ruby
82
+ # Add an event
83
+ storage.add_event("run-id", event)
84
+
85
+ # Get events
86
+ events = storage.get_events("run-id", limit: 100, offset: 0)
87
+ ```
88
+
89
+ ## Utility Methods
90
+
91
+ ### Clear All Data
92
+
93
+ ```ruby
94
+ storage.clear!
95
+ ```
96
+
97
+ ### Get Statistics
98
+
99
+ ```ruby
100
+ stats = storage.stats
101
+
102
+ puts "Runs: #{stats[:runs]}"
103
+ puts "Sessions: #{stats[:sessions]}"
104
+ puts "Events: #{stats[:events]}"
105
+ ```
106
+
107
+ ### Health Check
108
+
109
+ ```ruby
110
+ if storage.ping
111
+ puts "Storage is healthy"
112
+ end
113
+ ```
114
+
115
+ ## Thread Safety
116
+
117
+ Memory storage uses `Concurrent::Map` from concurrent-ruby:
118
+
119
+ ```ruby
120
+ # Safe for concurrent access
121
+ threads = 10.times.map do |i|
122
+ Thread.new do
123
+ run = create_run(i)
124
+ storage.save_run(run)
125
+ end
126
+ end
127
+
128
+ threads.each(&:join)
129
+ ```
130
+
131
+ ## Testing
132
+
133
+ Memory storage is ideal for tests:
134
+
135
+ ```ruby
136
+ class MyAgentTest < Minitest::Test
137
+ def setup
138
+ @storage = SimpleAcp::Storage::Memory.new
139
+ @server = SimpleAcp::Server::Base.new(storage: @storage)
140
+ register_agents(@server)
141
+ end
142
+
143
+ def teardown
144
+ @storage.clear!
145
+ end
146
+
147
+ def test_agent_behavior
148
+ run = @server.run_sync(
149
+ agent_name: "echo",
150
+ input: [SimpleAcp::Models::Message.user("test")]
151
+ )
152
+
153
+ assert_equal "completed", run.status
154
+ end
155
+ end
156
+ ```
157
+
158
+ ## Migration to Production
159
+
160
+ When moving to production, switch to Redis or PostgreSQL:
161
+
162
+ ```ruby
163
+ # Development
164
+ if ENV['RACK_ENV'] == 'development'
165
+ storage = SimpleAcp::Storage::Memory.new
166
+ else
167
+ # Production
168
+ storage = SimpleAcp::Storage::Redis.new(url: ENV['REDIS_URL'])
169
+ # or
170
+ storage = SimpleAcp::Storage::PostgreSQL.new(url: ENV['DATABASE_URL'])
171
+ end
172
+
173
+ server = SimpleAcp::Server::Base.new(storage: storage)
174
+ ```
175
+
176
+ ## Best Practices
177
+
178
+ 1. **Use for development** - Quick iteration without setup
179
+ 2. **Use for tests** - Isolated, fast test runs
180
+ 3. **Clear between tests** - Use `clear!` in teardown
181
+ 4. **Monitor memory** - Watch for growing data in long runs
182
+ 5. **Don't use in production** - Data loss on restart
183
+
184
+ ## Implementation Details
185
+
186
+ The Memory backend uses these data structures:
187
+
188
+ | Data | Structure | Thread Safety |
189
+ |------|-----------|---------------|
190
+ | Runs | `Concurrent::Map` | Yes |
191
+ | Sessions | `Concurrent::Map` | Yes |
192
+ | Events | `Concurrent::Map` with `Mutex` | Yes |
193
+
194
+ ## Next Steps
195
+
196
+ - Learn about [Redis](redis.md) for distributed deployments
197
+ - Explore [PostgreSQL](postgresql.md) for persistent storage
198
+ - Build a [Custom Backend](custom.md) for special needs
@@ -0,0 +1,350 @@
1
+ # PostgreSQL Storage
2
+
3
+ PostgreSQL storage provides permanent, relational storage ideal for production deployments requiring audit trails and complex queries.
4
+
5
+ ## Features
6
+
7
+ - **Persistent** - Data survives restarts
8
+ - **ACID compliant** - Reliable transactions
9
+ - **Queryable** - Full SQL capabilities
10
+ - **Scalable** - Supports read replicas
11
+
12
+ ## Requirements
13
+
14
+ Add the Sequel and pg gems to your Gemfile:
15
+
16
+ ```ruby
17
+ gem 'sequel', '~> 5.0'
18
+ gem 'pg', '~> 1.5'
19
+ ```
20
+
21
+ ## Usage
22
+
23
+ ### Basic Setup
24
+
25
+ ```ruby
26
+ require 'simple_acp'
27
+ require 'simple_acp/storage/postgresql'
28
+
29
+ storage = SimpleAcp::Storage::PostgreSQL.new(
30
+ url: "postgres://localhost/simple_acp"
31
+ )
32
+
33
+ server = SimpleAcp::Server::Base.new(storage: storage)
34
+ ```
35
+
36
+ ### Configuration Options
37
+
38
+ ```ruby
39
+ storage = SimpleAcp::Storage::PostgreSQL.new(
40
+ # Connection URL
41
+ url: "postgres://user:pass@host:5432/database",
42
+
43
+ # Or specify individually
44
+ host: "localhost",
45
+ port: 5432,
46
+ database: "simple_acp",
47
+ user: "postgres",
48
+ password: "secret",
49
+
50
+ # Or use existing Sequel connection
51
+ db: existing_sequel_db,
52
+
53
+ # Behavior
54
+ skip_setup: false # Skip automatic table creation
55
+ )
56
+ ```
57
+
58
+ ### Environment Variables
59
+
60
+ ```ruby
61
+ # Uses DATABASE_URL if not specified
62
+ storage = SimpleAcp::Storage::PostgreSQL.new
63
+
64
+ # Reads from:
65
+ # ENV['DATABASE_URL'] || "postgres://localhost/acp"
66
+ ```
67
+
68
+ ## Database Schema
69
+
70
+ Tables are automatically created on first use:
71
+
72
+ ### acp_runs
73
+
74
+ ```sql
75
+ CREATE TABLE acp_runs (
76
+ run_id VARCHAR PRIMARY KEY,
77
+ agent_name VARCHAR NOT NULL,
78
+ session_id VARCHAR,
79
+ status VARCHAR NOT NULL,
80
+ output TEXT, -- JSON
81
+ error TEXT, -- JSON
82
+ await_request TEXT, -- JSON
83
+ created_at TIMESTAMP,
84
+ finished_at TIMESTAMP,
85
+ updated_at TIMESTAMP
86
+ );
87
+
88
+ CREATE INDEX idx_runs_agent ON acp_runs(agent_name);
89
+ CREATE INDEX idx_runs_session ON acp_runs(session_id);
90
+ ```
91
+
92
+ ### acp_sessions
93
+
94
+ ```sql
95
+ CREATE TABLE acp_sessions (
96
+ id VARCHAR PRIMARY KEY,
97
+ history TEXT, -- JSON
98
+ state TEXT, -- JSON
99
+ created_at TIMESTAMP,
100
+ updated_at TIMESTAMP
101
+ );
102
+ ```
103
+
104
+ ### acp_events
105
+
106
+ ```sql
107
+ CREATE TABLE acp_events (
108
+ id SERIAL PRIMARY KEY,
109
+ run_id VARCHAR NOT NULL,
110
+ event_type VARCHAR NOT NULL,
111
+ data TEXT, -- JSON
112
+ created_at TIMESTAMP
113
+ );
114
+
115
+ CREATE INDEX idx_events_run ON acp_events(run_id);
116
+ ```
117
+
118
+ ## Operations
119
+
120
+ ### Runs
121
+
122
+ ```ruby
123
+ # Save
124
+ storage.save_run(run)
125
+
126
+ # Get
127
+ run = storage.get_run("run-id")
128
+
129
+ # Delete (also deletes events)
130
+ storage.delete_run("run-id")
131
+
132
+ # List with filters
133
+ result = storage.list_runs(
134
+ agent_name: "echo",
135
+ session_id: "session-123",
136
+ limit: 10,
137
+ offset: 0
138
+ )
139
+ ```
140
+
141
+ ### Sessions
142
+
143
+ ```ruby
144
+ # Save (insert or update)
145
+ storage.save_session(session)
146
+
147
+ # Get
148
+ session = storage.get_session("session-id")
149
+
150
+ # Delete
151
+ storage.delete_session("session-id")
152
+ ```
153
+
154
+ ### Events
155
+
156
+ ```ruby
157
+ # Add
158
+ storage.add_event("run-id", event)
159
+
160
+ # Get with pagination
161
+ events = storage.get_events("run-id", limit: 100, offset: 0)
162
+ ```
163
+
164
+ ## Connection Management
165
+
166
+ ### Connection Pool
167
+
168
+ Sequel automatically manages connection pooling:
169
+
170
+ ```ruby
171
+ storage = SimpleAcp::Storage::PostgreSQL.new(
172
+ url: ENV['DATABASE_URL']
173
+ )
174
+
175
+ # Pool is managed automatically
176
+ ```
177
+
178
+ ### Close Connection
179
+
180
+ ```ruby
181
+ storage.close # Disconnects from database
182
+ ```
183
+
184
+ ### Health Check
185
+
186
+ ```ruby
187
+ if storage.ping
188
+ puts "PostgreSQL is healthy"
189
+ else
190
+ puts "PostgreSQL connection failed"
191
+ end
192
+ ```
193
+
194
+ ## Production Configuration
195
+
196
+ ### Recommended Setup
197
+
198
+ ```ruby
199
+ storage = SimpleAcp::Storage::PostgreSQL.new(
200
+ url: ENV['DATABASE_URL'],
201
+ skip_setup: true # Manage schema via migrations
202
+ )
203
+ ```
204
+
205
+ ### With Connection Options
206
+
207
+ ```ruby
208
+ require 'sequel'
209
+
210
+ db = Sequel.connect(
211
+ ENV['DATABASE_URL'],
212
+ max_connections: 10,
213
+ pool_timeout: 10,
214
+ connect_timeout: 5
215
+ )
216
+
217
+ storage = SimpleAcp::Storage::PostgreSQL.new(db: db)
218
+ ```
219
+
220
+ ## Custom Queries
221
+
222
+ Access the underlying Sequel database:
223
+
224
+ ```ruby
225
+ # Get the Sequel database object
226
+ db = storage.instance_variable_get(:@db)
227
+
228
+ # Custom queries
229
+ recent_runs = db[:acp_runs]
230
+ .where(agent_name: "chat")
231
+ .where { created_at > Time.now - 3600 }
232
+ .order(Sequel.desc(:created_at))
233
+ .limit(10)
234
+ .all
235
+
236
+ # Aggregate queries
237
+ stats = db[:acp_runs]
238
+ .group(:agent_name)
239
+ .select { [agent_name, count(*).as(total)] }
240
+ .all
241
+ ```
242
+
243
+ ## Maintenance
244
+
245
+ ### Clear All Data
246
+
247
+ ```ruby
248
+ storage.clear! # Truncates all tables
249
+ ```
250
+
251
+ ### Manual Schema Setup
252
+
253
+ ```ruby
254
+ # Skip auto-setup
255
+ storage = SimpleAcp::Storage::PostgreSQL.new(
256
+ url: ENV['DATABASE_URL'],
257
+ skip_setup: true
258
+ )
259
+
260
+ # Run migrations manually in your deployment
261
+ ```
262
+
263
+ ### Vacuum and Analyze
264
+
265
+ ```sql
266
+ -- Periodic maintenance
267
+ VACUUM ANALYZE acp_runs;
268
+ VACUUM ANALYZE acp_sessions;
269
+ VACUUM ANALYZE acp_events;
270
+ ```
271
+
272
+ ### Archive Old Data
273
+
274
+ ```sql
275
+ -- Move old runs to archive
276
+ INSERT INTO acp_runs_archive
277
+ SELECT * FROM acp_runs
278
+ WHERE created_at < NOW() - INTERVAL '90 days';
279
+
280
+ DELETE FROM acp_runs
281
+ WHERE created_at < NOW() - INTERVAL '90 days';
282
+ ```
283
+
284
+ ## Error Handling
285
+
286
+ ```ruby
287
+ begin
288
+ run = storage.get_run("run-id")
289
+ rescue Sequel::DatabaseConnectionError
290
+ puts "Database connection failed"
291
+ rescue Sequel::DatabaseError => e
292
+ puts "Database error: #{e.message}"
293
+ end
294
+ ```
295
+
296
+ ## Performance Tips
297
+
298
+ ### Indexes
299
+
300
+ The default schema includes indexes on common query patterns. Add more as needed:
301
+
302
+ ```sql
303
+ -- For time-range queries
304
+ CREATE INDEX idx_runs_created ON acp_runs(created_at);
305
+
306
+ -- For status queries
307
+ CREATE INDEX idx_runs_status ON acp_runs(status);
308
+ ```
309
+
310
+ ### Partitioning
311
+
312
+ For high-volume deployments, consider partitioning:
313
+
314
+ ```sql
315
+ -- Partition events by month
316
+ CREATE TABLE acp_events (
317
+ id SERIAL,
318
+ run_id VARCHAR NOT NULL,
319
+ event_type VARCHAR NOT NULL,
320
+ data TEXT,
321
+ created_at TIMESTAMP
322
+ ) PARTITION BY RANGE (created_at);
323
+
324
+ CREATE TABLE acp_events_2025_01 PARTITION OF acp_events
325
+ FOR VALUES FROM ('2025-01-01') TO ('2025-02-01');
326
+ ```
327
+
328
+ ## Best Practices
329
+
330
+ 1. **Use connection pooling** - Let Sequel manage connections
331
+ 2. **Skip auto-setup in production** - Use migrations instead
332
+ 3. **Index appropriately** - Based on your query patterns
333
+ 4. **Archive old data** - Keep tables manageable
334
+ 5. **Monitor query performance** - Watch for slow queries
335
+
336
+ ## Comparison with Other Backends
337
+
338
+ | Feature | PostgreSQL | Redis | Memory |
339
+ |---------|------------|-------|--------|
340
+ | Persistence | Permanent | TTL | None |
341
+ | Multi-process | Yes | Yes | No |
342
+ | Speed | Moderate | Fast | Fastest |
343
+ | Query flexibility | Full SQL | Limited | None |
344
+ | Audit trail | Yes | Limited | No |
345
+
346
+ ## Next Steps
347
+
348
+ - Learn about [Redis](redis.md) for caching layer
349
+ - Build a [Custom Backend](custom.md) for special needs
350
+ - Review [Memory](memory.md) for development