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,411 @@
1
+ # HTTP Endpoints
2
+
3
+ The SimpleAcp server exposes HTTP endpoints for agent discovery, run management, and session handling.
4
+
5
+ ## Endpoint Overview
6
+
7
+ | Method | Path | Description |
8
+ |--------|------|-------------|
9
+ | `GET` | `/ping` | Health check |
10
+ | `GET` | `/agents` | List all agents |
11
+ | `GET` | `/agents/:name` | Get agent manifest |
12
+ | `POST` | `/runs` | Create a run |
13
+ | `GET` | `/runs/:id` | Get run status |
14
+ | `POST` | `/runs/:id` | Resume awaited run |
15
+ | `POST` | `/runs/:id/cancel` | Cancel a run |
16
+ | `GET` | `/runs/:id/events` | Get run events |
17
+ | `GET` | `/session/:id` | Get session info |
18
+
19
+ ## Health Check
20
+
21
+ ### GET /ping
22
+
23
+ Check server health.
24
+
25
+ **Request:**
26
+ ```bash
27
+ curl http://localhost:8000/ping
28
+ ```
29
+
30
+ **Response:**
31
+ ```json
32
+ {
33
+ "status": "ok"
34
+ }
35
+ ```
36
+
37
+ ## Agent Discovery
38
+
39
+ ### GET /agents
40
+
41
+ List all registered agents.
42
+
43
+ **Request:**
44
+ ```bash
45
+ curl http://localhost:8000/agents
46
+ ```
47
+
48
+ **Response:**
49
+ ```json
50
+ {
51
+ "agents": [
52
+ {
53
+ "name": "echo",
54
+ "description": "Echoes input back",
55
+ "input_content_types": ["text/plain"],
56
+ "output_content_types": ["text/plain"],
57
+ "metadata": {}
58
+ },
59
+ {
60
+ "name": "analyzer",
61
+ "description": "Analyzes JSON data",
62
+ "input_content_types": ["application/json"],
63
+ "output_content_types": ["application/json"],
64
+ "metadata": {"version": "1.0"}
65
+ }
66
+ ]
67
+ }
68
+ ```
69
+
70
+ ### GET /agents/:name
71
+
72
+ Get a specific agent's manifest.
73
+
74
+ **Request:**
75
+ ```bash
76
+ curl http://localhost:8000/agents/echo
77
+ ```
78
+
79
+ **Response:**
80
+ ```json
81
+ {
82
+ "name": "echo",
83
+ "description": "Echoes input back",
84
+ "input_content_types": ["text/plain"],
85
+ "output_content_types": ["text/plain"],
86
+ "metadata": {}
87
+ }
88
+ ```
89
+
90
+ **Error (404):**
91
+ ```json
92
+ {
93
+ "error": {
94
+ "code": "agent_not_found",
95
+ "message": "Agent 'unknown' not found"
96
+ }
97
+ }
98
+ ```
99
+
100
+ ## Run Management
101
+
102
+ ### POST /runs
103
+
104
+ Create and execute a run.
105
+
106
+ **Request (Synchronous):**
107
+ ```bash
108
+ curl -X POST http://localhost:8000/runs \
109
+ -H "Content-Type: application/json" \
110
+ -d '{
111
+ "agent_name": "echo",
112
+ "input": [
113
+ {
114
+ "role": "user",
115
+ "parts": [
116
+ {"content_type": "text/plain", "content": "Hello!"}
117
+ ]
118
+ }
119
+ ]
120
+ }'
121
+ ```
122
+
123
+ **Response:**
124
+ ```json
125
+ {
126
+ "run_id": "550e8400-e29b-41d4-a716-446655440000",
127
+ "agent_name": "echo",
128
+ "status": "completed",
129
+ "output": [
130
+ {
131
+ "role": "agent",
132
+ "parts": [
133
+ {"content_type": "text/plain", "content": "Echo: Hello!"}
134
+ ]
135
+ }
136
+ ],
137
+ "created_at": "2025-01-21T10:30:00Z",
138
+ "finished_at": "2025-01-21T10:30:01Z"
139
+ }
140
+ ```
141
+
142
+ **Request (Streaming):**
143
+ ```bash
144
+ curl -X POST http://localhost:8000/runs \
145
+ -H "Content-Type: application/json" \
146
+ -H "Accept: text/event-stream" \
147
+ -d '{"agent_name": "chat", "input": [...]}'
148
+ ```
149
+
150
+ **Response (SSE Stream):**
151
+ ```
152
+ event: run_started
153
+ data: {"run_id":"550e8400-..."}
154
+
155
+ event: message_created
156
+ data: {"message":{"role":"agent","parts":[]}}
157
+
158
+ event: message_part
159
+ data: {"part":{"content_type":"text/plain","content":"Hello"}}
160
+
161
+ event: message_completed
162
+ data: {"message":{"role":"agent","parts":[...]}}
163
+
164
+ event: run_completed
165
+ data: {"run":{...}}
166
+ ```
167
+
168
+ **Request with Session:**
169
+ ```bash
170
+ curl -X POST http://localhost:8000/runs \
171
+ -H "Content-Type: application/json" \
172
+ -d '{
173
+ "agent_name": "chat",
174
+ "session_id": "conversation-123",
175
+ "input": [...]
176
+ }'
177
+ ```
178
+
179
+ ### GET /runs/:id
180
+
181
+ Get run status.
182
+
183
+ **Request:**
184
+ ```bash
185
+ curl http://localhost:8000/runs/550e8400-e29b-41d4-a716-446655440000
186
+ ```
187
+
188
+ **Response:**
189
+ ```json
190
+ {
191
+ "run_id": "550e8400-e29b-41d4-a716-446655440000",
192
+ "agent_name": "processor",
193
+ "status": "in_progress",
194
+ "output": [],
195
+ "created_at": "2025-01-21T10:30:00Z"
196
+ }
197
+ ```
198
+
199
+ **Status Values:**
200
+ - `created` - Run created, not started
201
+ - `in_progress` - Currently executing
202
+ - `completed` - Finished successfully
203
+ - `failed` - Encountered error
204
+ - `awaiting` - Waiting for input
205
+ - `cancelled` - Cancelled by request
206
+
207
+ ### POST /runs/:id
208
+
209
+ Resume an awaited run.
210
+
211
+ **Request:**
212
+ ```bash
213
+ curl -X POST http://localhost:8000/runs/550e8400-... \
214
+ -H "Content-Type: application/json" \
215
+ -d '{
216
+ "await_resume": {
217
+ "type": "message",
218
+ "message": {
219
+ "role": "user",
220
+ "parts": [
221
+ {"content_type": "text/plain", "content": "My response"}
222
+ ]
223
+ }
224
+ }
225
+ }'
226
+ ```
227
+
228
+ **Response:**
229
+ ```json
230
+ {
231
+ "run_id": "550e8400-...",
232
+ "status": "completed",
233
+ "output": [...]
234
+ }
235
+ ```
236
+
237
+ ### POST /runs/:id/cancel
238
+
239
+ Cancel a running execution.
240
+
241
+ **Request:**
242
+ ```bash
243
+ curl -X POST http://localhost:8000/runs/550e8400-.../cancel
244
+ ```
245
+
246
+ **Response:**
247
+ ```json
248
+ {
249
+ "run_id": "550e8400-...",
250
+ "status": "cancelled"
251
+ }
252
+ ```
253
+
254
+ ### GET /runs/:id/events
255
+
256
+ Get events for a run.
257
+
258
+ **Request:**
259
+ ```bash
260
+ curl "http://localhost:8000/runs/550e8400-.../events?limit=100&offset=0"
261
+ ```
262
+
263
+ **Response:**
264
+ ```json
265
+ {
266
+ "events": [
267
+ {
268
+ "type": "run_started",
269
+ "run_id": "550e8400-..."
270
+ },
271
+ {
272
+ "type": "message_part",
273
+ "part": {"content_type": "text/plain", "content": "Hello"}
274
+ },
275
+ {
276
+ "type": "run_completed",
277
+ "run": {...}
278
+ }
279
+ ]
280
+ }
281
+ ```
282
+
283
+ ## Session Management
284
+
285
+ ### GET /session/:id
286
+
287
+ Get session information.
288
+
289
+ **Request:**
290
+ ```bash
291
+ curl http://localhost:8000/session/conversation-123
292
+ ```
293
+
294
+ **Response:**
295
+ ```json
296
+ {
297
+ "id": "conversation-123",
298
+ "history": [
299
+ {"role": "user", "parts": [...]},
300
+ {"role": "agent", "parts": [...]}
301
+ ],
302
+ "state": {"step": 2, "data": {"name": "Alice"}}
303
+ }
304
+ ```
305
+
306
+ ## Error Responses
307
+
308
+ All errors follow a consistent format:
309
+
310
+ ```json
311
+ {
312
+ "error": {
313
+ "code": "error_code",
314
+ "message": "Human-readable message"
315
+ }
316
+ }
317
+ ```
318
+
319
+ ### Error Codes
320
+
321
+ | Code | HTTP Status | Description |
322
+ |------|-------------|-------------|
323
+ | `agent_not_found` | 404 | Agent doesn't exist |
324
+ | `run_not_found` | 404 | Run doesn't exist |
325
+ | `session_not_found` | 404 | Session doesn't exist |
326
+ | `invalid_input` | 400 | Malformed request |
327
+ | `run_not_awaiting` | 400 | Resume on non-awaiting run |
328
+ | `internal_error` | 500 | Server error |
329
+
330
+ ## Request Headers
331
+
332
+ | Header | Purpose |
333
+ |--------|---------|
334
+ | `Content-Type: application/json` | Required for POST requests |
335
+ | `Accept: text/event-stream` | Request SSE streaming |
336
+
337
+ ## Query Parameters
338
+
339
+ ### /runs/:id/events
340
+
341
+ | Parameter | Type | Default | Description |
342
+ |-----------|------|---------|-------------|
343
+ | `limit` | integer | 100 | Max events to return |
344
+ | `offset` | integer | 0 | Events to skip |
345
+
346
+ ## Authentication
347
+
348
+ SimpleAcp doesn't include built-in authentication. Add it via middleware:
349
+
350
+ ```ruby
351
+ # config.ru
352
+ require 'simple_acp'
353
+
354
+ server = SimpleAcp::Server::Base.new
355
+ # ... register agents
356
+
357
+ # Add auth middleware
358
+ use Rack::Auth::Basic do |username, password|
359
+ username == ENV['API_USER'] && password == ENV['API_PASS']
360
+ end
361
+
362
+ run server.to_app
363
+ ```
364
+
365
+ ## CORS
366
+
367
+ For browser access, add CORS headers:
368
+
369
+ ```ruby
370
+ # config.ru
371
+ require 'rack/cors'
372
+
373
+ use Rack::Cors do
374
+ allow do
375
+ origins '*'
376
+ resource '*',
377
+ headers: :any,
378
+ methods: [:get, :post, :options],
379
+ expose: ['Content-Type']
380
+ end
381
+ end
382
+
383
+ run server.to_app
384
+ ```
385
+
386
+ ## Testing Endpoints
387
+
388
+ ```bash
389
+ # Health check
390
+ curl http://localhost:8000/ping | jq
391
+
392
+ # List agents
393
+ curl http://localhost:8000/agents | jq
394
+
395
+ # Run agent
396
+ curl -X POST http://localhost:8000/runs \
397
+ -H "Content-Type: application/json" \
398
+ -d '{"agent_name":"echo","input":[{"role":"user","parts":[{"content_type":"text/plain","content":"test"}]}]}' | jq
399
+
400
+ # Stream run
401
+ curl -X POST http://localhost:8000/runs \
402
+ -H "Content-Type: application/json" \
403
+ -H "Accept: text/event-stream" \
404
+ -d '{"agent_name":"chat","input":[...]}'
405
+ ```
406
+
407
+ ## Next Steps
408
+
409
+ - See [Client Guide](../client/index.md) for using these endpoints
410
+ - Review [API Reference](../api/server-base.md) for programmatic usage
411
+ - Explore [Storage](../storage/index.md) for data persistence
@@ -0,0 +1,218 @@
1
+ # Server Guide
2
+
3
+ The SimpleAcp server hosts agents and handles HTTP requests from clients. This guide covers everything you need to build robust agent servers.
4
+
5
+ ## Overview
6
+
7
+ ```mermaid
8
+ graph TB
9
+ subgraph Server
10
+ S[Server::Base]
11
+ A[App - Roda]
12
+ AG1[Agent 1]
13
+ AG2[Agent 2]
14
+ ST[(Storage)]
15
+ end
16
+
17
+ C1[Client 1] -->|HTTP| A
18
+ C2[Client 2] -->|HTTP| A
19
+ A --> S
20
+ S --> AG1
21
+ S --> AG2
22
+ S --> ST
23
+ ```
24
+
25
+ ## Quick Start
26
+
27
+ ```ruby
28
+ require 'simple_acp'
29
+
30
+ server = SimpleAcp::Server::Base.new
31
+
32
+ server.agent("hello") do |context|
33
+ SimpleAcp::Models::Message.agent("Hello from SimpleAcp!")
34
+ end
35
+
36
+ server.run(port: 8000)
37
+ ```
38
+
39
+ ## In This Section
40
+
41
+ <div class="grid cards" markdown>
42
+
43
+ - :material-robot:{ .lg .middle } **Creating Agents**
44
+
45
+ ---
46
+
47
+ Learn patterns for building effective agents
48
+
49
+ [:octicons-arrow-right-24: Creating Agents](creating-agents.md)
50
+
51
+ - :material-play-speed:{ .lg .middle } **Streaming Responses**
52
+
53
+ ---
54
+
55
+ Implement real-time streaming with SSE
56
+
57
+ [:octicons-arrow-right-24: Streaming](streaming.md)
58
+
59
+ - :material-chat-processing:{ .lg .middle } **Multi-Turn Conversations**
60
+
61
+ ---
62
+
63
+ Build stateful, context-aware agents
64
+
65
+ [:octicons-arrow-right-24: Multi-Turn](multi-turn.md)
66
+
67
+ - :material-api:{ .lg .middle } **HTTP Endpoints**
68
+
69
+ ---
70
+
71
+ Reference for all server endpoints
72
+
73
+ [:octicons-arrow-right-24: HTTP Endpoints](http-endpoints.md)
74
+
75
+ </div>
76
+
77
+ ## Server Architecture
78
+
79
+ ### Components
80
+
81
+ | Component | Purpose |
82
+ |-----------|---------|
83
+ | `Server::Base` | Core server managing agents and runs |
84
+ | `Server::App` | Roda HTTP application |
85
+ | `Server::Context` | Execution context passed to agents |
86
+ | `Server::Agent` | Agent wrapper with metadata |
87
+
88
+ ### Server Lifecycle
89
+
90
+ ```ruby
91
+ # 1. Create server with optional storage
92
+ server = SimpleAcp::Server::Base.new(
93
+ storage: SimpleAcp::Storage::Memory.new
94
+ )
95
+
96
+ # 2. Register agents
97
+ server.agent("name", description: "...") do |context|
98
+ # Handler logic
99
+ end
100
+
101
+ # 3. Start HTTP server (uses Falcon)
102
+ server.run(port: 8000)
103
+ ```
104
+
105
+ ### Programmatic Usage
106
+
107
+ Use the server without HTTP:
108
+
109
+ ```ruby
110
+ # Create runs directly
111
+ run = server.run_sync(
112
+ agent_name: "processor",
113
+ input: [SimpleAcp::Models::Message.user("Data")]
114
+ )
115
+
116
+ # Stream events
117
+ server.run_stream(agent_name: "streamer", input: messages) do |event|
118
+ # Handle events
119
+ end
120
+ ```
121
+
122
+ ## Configuration
123
+
124
+ ### Storage
125
+
126
+ ```ruby
127
+ # Memory (default)
128
+ server = SimpleAcp::Server::Base.new
129
+
130
+ # Redis
131
+ server = SimpleAcp::Server::Base.new(
132
+ storage: SimpleAcp::Storage::Redis.new(url: ENV['REDIS_URL'])
133
+ )
134
+
135
+ # PostgreSQL
136
+ server = SimpleAcp::Server::Base.new(
137
+ storage: SimpleAcp::Storage::PostgreSQL.new(url: ENV['DATABASE_URL'])
138
+ )
139
+ ```
140
+
141
+ ### HTTP Server Options
142
+
143
+ ```ruby
144
+ server.run(
145
+ port: 8000,
146
+ host: '0.0.0.0'
147
+ )
148
+ ```
149
+
150
+ Falcon uses fiber-based concurrency, efficiently handling thousands of concurrent connections without the need for thread pool configuration.
151
+
152
+ ## Best Practices
153
+
154
+ ### Agent Organization
155
+
156
+ ```ruby
157
+ # Group related agents
158
+ class MyServer
159
+ def initialize
160
+ @server = SimpleAcp::Server::Base.new
161
+ register_chat_agents
162
+ register_utility_agents
163
+ end
164
+
165
+ private
166
+
167
+ def register_chat_agents
168
+ @server.agent("chat") { |ctx| ... }
169
+ @server.agent("summarize") { |ctx| ... }
170
+ end
171
+
172
+ def register_utility_agents
173
+ @server.agent("ping") { |ctx| ... }
174
+ @server.agent("echo") { |ctx| ... }
175
+ end
176
+ end
177
+ ```
178
+
179
+ ### Error Handling
180
+
181
+ ```ruby
182
+ server.agent("safe") do |context|
183
+ begin
184
+ risky_operation(context.input)
185
+ rescue ValidationError => e
186
+ SimpleAcp::Models::Message.agent("Invalid input: #{e.message}")
187
+ rescue ExternalServiceError => e
188
+ # Log and return friendly error
189
+ logger.error("External service failed: #{e}")
190
+ SimpleAcp::Models::Message.agent("Service temporarily unavailable")
191
+ end
192
+ end
193
+ ```
194
+
195
+ ### Logging
196
+
197
+ ```ruby
198
+ server.agent("logged") do |context|
199
+ logger.info("Processing request", {
200
+ run_id: context.run_id,
201
+ agent: context.agent_name,
202
+ input_count: context.input.length
203
+ })
204
+
205
+ result = process(context.input)
206
+
207
+ logger.info("Request completed", {
208
+ run_id: context.run_id,
209
+ output_count: result.length
210
+ })
211
+
212
+ result
213
+ end
214
+ ```
215
+
216
+ ## Next Steps
217
+
218
+ Start with [Creating Agents](creating-agents.md) to learn agent development patterns.