Skip to content

Commit aac7a1b

Browse files
committed
docs: add improvement plan — Memory, Session Persistence, Streaming, Error Recovery, Sandbox, Multi-Modal
1 parent d26d8e2 commit aac7a1b

1 file changed

Lines changed: 266 additions & 0 deletions

File tree

docs/improvement-plan.md

Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,266 @@
1+
# A3S Code Improvement Plan
2+
3+
## Current State Summary
4+
5+
- 5 core components, 14 extension points, 11 built-in tools
6+
- 1133 tests passing, 3 SDKs (Rust/Python/Node.js)
7+
- Lane-based priority queue with external task distribution
8+
- Security, skills, planning, hooks all implemented and tested
9+
10+
---
11+
12+
## Phase 1: Memory System — File-Based Default Backend
13+
14+
**Priority: High | Effort: Medium | Impact: High**
15+
16+
### Problem
17+
18+
`MemoryStore` trait is defined with 9 methods (store, retrieve, search, search_by_tags, get_recent, get_important, delete, clear, count), but:
19+
20+
1. No production-ready default implementation — only `TestMemoryStore` in test code (in-memory `Mutex<Vec<MemoryItem>>`)
21+
2. `AgentMemory` is not wired into `AgentSession` or `SessionOptions` — no `with_memory()` builder
22+
3. `MemoryContextProvider` exists but can't be used without a real store
23+
4. Memory is lost on process restart
24+
25+
### Solution
26+
27+
#### 1.1 Implement `FileMemoryStore`
28+
29+
Follow the `FileSessionStore` pattern in `store.rs`:
30+
31+
```
32+
memory/
33+
{session_id}/
34+
{memory_id}.json # Individual memory items
35+
index.json # Lightweight index for fast search (tags, timestamps, importance)
36+
```
37+
38+
Key design decisions:
39+
- One JSON file per memory item (atomic writes, easy cleanup)
40+
- `index.json` holds a compact index: `{ id, content_preview, tags, importance, timestamp, memory_type }` for each item
41+
- Index loaded into memory on init for fast `search()` and `search_by_tags()`
42+
- Full content loaded on-demand from individual files
43+
- Atomic writes via temp file + rename (same as `FileSessionStore`)
44+
- Path traversal prevention on memory IDs
45+
46+
```rust
47+
pub struct FileMemoryStore {
48+
dir: PathBuf,
49+
index: RwLock<MemoryIndex>,
50+
}
51+
52+
struct MemoryIndex {
53+
items: Vec<MemoryIndexEntry>,
54+
}
55+
56+
struct MemoryIndexEntry {
57+
id: String,
58+
content_lower: String, // For substring search
59+
tags: Vec<String>,
60+
importance: f32,
61+
timestamp: DateTime<Utc>,
62+
memory_type: MemoryType,
63+
}
64+
```
65+
66+
#### 1.2 Wire `AgentMemory` into `SessionOptions` and `AgentSession`
67+
68+
```rust
69+
// SessionOptions builder
70+
impl SessionOptions {
71+
pub fn with_memory(mut self, store: Arc<dyn MemoryStore>) -> Self { ... }
72+
pub fn with_file_memory(mut self, dir: impl Into<PathBuf>) -> Self { ... }
73+
}
74+
75+
// AgentSession gains memory field
76+
pub struct AgentSession {
77+
memory: Option<AgentMemory>,
78+
// ...
79+
}
80+
```
81+
82+
#### 1.3 Auto-remember in AgentLoop
83+
84+
After each successful tool execution turn:
85+
- `remember_success()` for successful patterns
86+
- `remember_failure()` for errors
87+
- Inject relevant memories via `MemoryContextProvider` into system prompt
88+
89+
#### 1.4 SDK Bindings
90+
91+
Expose in Python and Node.js SDKs:
92+
- `SessionOptions.memory_dir` / `memoryDir` — path to file-based memory store
93+
- `session.remember(content, tags, importance)` — manual memory storage
94+
- `session.recall(query, limit)` — manual memory recall
95+
96+
#### 1.5 Tests
97+
98+
- `FileMemoryStore` unit tests (store, retrieve, search, delete, clear, index rebuild)
99+
- Integration test: memory persists across session restarts
100+
- Concurrent access test (multiple readers/writers)
101+
- Index corruption recovery test
102+
103+
---
104+
105+
## Phase 2: Session Persistence Integration
106+
107+
**Priority: High | Effort: Low | Impact: High**
108+
109+
### Problem
110+
111+
`FileSessionStore` and `SessionStore` trait exist and work, but `AgentSession` doesn't expose save/load/resume APIs. Sessions are always created fresh.
112+
113+
### Solution
114+
115+
#### 2.1 Session Resume API
116+
117+
```rust
118+
impl Agent {
119+
pub fn resume_session(&self, session_id: &str, opts: Option<SessionOptions>) -> Result<AgentSession>;
120+
}
121+
122+
impl AgentSession {
123+
pub async fn save(&self) -> Result<()>;
124+
pub fn session_id(&self) -> &str;
125+
}
126+
```
127+
128+
#### 2.2 Auto-Save
129+
130+
Optional auto-save after each turn:
131+
```rust
132+
SessionOptions::new().with_auto_save(true)
133+
```
134+
135+
#### 2.3 SDK Bindings
136+
137+
- `agent.resume_session(id)` in all 3 SDKs
138+
- `session.save()` in all 3 SDKs
139+
140+
---
141+
142+
## Phase 3: Streaming SDK Experience
143+
144+
**Priority: Medium | Effort: Medium | Impact: Medium**
145+
146+
### Problem
147+
148+
- Node.js `stream()` collects all events then returns array — not truly streaming
149+
- Python `stream()` uses synchronous iterator + thread — not async native
150+
151+
### Solution
152+
153+
#### 3.1 Node.js: True Async Iterator
154+
155+
```typescript
156+
const stream = session.stream("prompt");
157+
for await (const event of stream) {
158+
if (event.type === "text_delta") process.stdout.write(event.text);
159+
}
160+
```
161+
162+
Implement via napi-rs `AsyncIterator` or `ReadableStream`.
163+
164+
#### 3.2 Python: Async Generator
165+
166+
```python
167+
async for event in session.stream("prompt"):
168+
if event.type == "text_delta":
169+
print(event.text, end="")
170+
```
171+
172+
Implement via PyO3 `__aiter__` / `__anext__` protocol.
173+
174+
---
175+
176+
## Phase 4: Error Recovery & Resilience
177+
178+
**Priority: Medium | Effort: Medium | Impact: Medium**
179+
180+
### Problem
181+
182+
- LLM returns invalid JSON → agent loop fails
183+
- Tool execution timeout → no automatic retry/degradation
184+
- No circuit breaker for repeated LLM failures
185+
186+
### Solution
187+
188+
#### 4.1 LLM Response Recovery
189+
190+
- Parse error → retry with "Your previous response was malformed, please try again"
191+
- Max 2 retries before surfacing error
192+
193+
#### 4.2 Tool Execution Timeout
194+
195+
- Per-tool timeout configuration
196+
- Timeout → return error result to LLM (not crash)
197+
- LLM can decide to retry or use alternative approach
198+
199+
#### 4.3 Circuit Breaker
200+
201+
- Track consecutive LLM failures per session
202+
- After N failures, pause and surface error to caller
203+
- Configurable via `SessionOptions`
204+
205+
---
206+
207+
## Phase 5: A3S Box Sandbox Integration
208+
209+
**Priority: Low | Effort: High | Impact: High**
210+
211+
### Problem
212+
213+
`bash` tool executes commands directly on host. No isolation for untrusted code.
214+
215+
### Solution
216+
217+
#### 5.1 Sandboxed Bash Tool
218+
219+
```rust
220+
SessionOptions::new()
221+
.with_sandbox(SandboxConfig {
222+
backend: SandboxBackend::Box, // Use A3S Box
223+
image: "ubuntu:22.04",
224+
memory_limit: "512m",
225+
network: false,
226+
})
227+
```
228+
229+
When sandbox is enabled, `bash` tool routes commands through A3S Box instead of `std::process::Command`.
230+
231+
#### 5.2 File System Isolation
232+
233+
Sandboxed sessions mount workspace as read-write volume. All file operations go through the sandbox.
234+
235+
---
236+
237+
## Phase 6: Multi-Modal Support
238+
239+
**Priority: Low | Effort: High | Impact: Medium**
240+
241+
### Problem
242+
243+
Only text input/output. No image/file attachment support.
244+
245+
### Solution
246+
247+
- Support image attachments in `send()` / `stream()`
248+
- Support image output from tools (screenshots, diagrams)
249+
- Requires LLM provider support (Claude vision, GPT-4V)
250+
251+
---
252+
253+
## Priority Matrix
254+
255+
| Phase | Priority | Effort | Impact | Dependencies |
256+
|-------|----------|--------|--------|-------------|
257+
| 1. Memory (File-Based) | 🔴 High | Medium | High | None |
258+
| 2. Session Persistence | 🔴 High | Low | High | None |
259+
| 3. Streaming SDK | 🟡 Medium | Medium | Medium | None |
260+
| 4. Error Recovery | 🟡 Medium | Medium | Medium | None |
261+
| 5. Sandbox Integration | 🟢 Low | High | High | A3S Box |
262+
| 6. Multi-Modal | 🟢 Low | High | Medium | LLM providers |
263+
264+
**Recommended execution order:** Phase 1 → Phase 2 → Phase 4 → Phase 3 → Phase 5 → Phase 6
265+
266+
Phase 1 and 2 can be done in parallel. Phase 4 is independent. Phase 3 requires SDK build toolchain changes. Phase 5 and 6 are longer-term.

0 commit comments

Comments
 (0)