forked from mofa-org/mofa
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path.cursorrules
More file actions
383 lines (279 loc) · 13.2 KB
/
.cursorrules
File metadata and controls
383 lines (279 loc) · 13.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
# Cursor AI Development Guidelines for MoFA Project
This file provides guidance to Cursor AI when working with code in this repository.
---
## Rust Project Development Standards
Based on issues discovered during code reviews, the following general development standards have been compiled:
---
## I. Error Handling Standards
### 1. Unified Error System
- **MUST** define a unified error type in the crate root (e.g., `KernelError`)
- **MUST** establish a clear error hierarchy where module errors can be unified through the `From` trait
- **MUST NOT** use `anyhow::Result` as a public API return type in library code; use `thiserror` to define typed errors
- **MUST NOT** implement blanket `From<anyhow::Error>` for error types, as this erases structured error information
### 2. Error Type Design
```rust
// Recommended: Use thiserror to define clear error enums
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum KernelError {
#[error("Agent error: {0}")]
Agent(#[from] AgentError),
#[error("Config error: {0}")]
Config(#[from] ConfigError),
// ...
}
```
---
## II. Type Design and API Stability
### 1. Enum Extensibility
- **MUST** add the `#[non_exhaustive]` attribute to public enums to ensure backward compatibility
```rust
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum AgentState {
Idle,
Running,
// New variants can be safely added in the future
}
```
### 2. Derive Trait Standards
- Comparable/testable types **MUST** derive `PartialEq`, `Eq`
- Debug output types **MUST** derive `Debug`; for fields that cannot be auto-derived, implement manually
- Serializable types **MUST** derive `Clone` (unless there's a special reason not to)
---
## III. Naming and Module Design
### 1. Naming Uniqueness
- **MUST NOT** define types with the same name representing different concepts within the same crate
- Checklist: `AgentConfig`, `AgentEvent`, `TaskPriority`, and other core type names
### 2. Module Export Control
- **MUST** use `pub(crate)` to limit internal module visibility
- **MUST** carefully design the public API surface through `lib.rs` or `prelude`
- **MUST NOT** directly `pub mod` export all modules
```rust
// Recommended lib.rs structure
pub mod error;
pub mod agent;
pub use error::KernelError;
pub use agent::{Agent, AgentContext};
mod internal; // Internal implementation
```
### 3. Prelude Design
- **SHOULD** provide a crate-level prelude module that aggregates commonly used types
```rust
// src/prelude.rs
pub use crate::error::KernelError;
pub use crate::agent::{Agent, AgentContext, AgentState};
// ...
```
---
## IV. Performance and Dependencies Management
### 1. Async Features
- In Rust 1.75+ environments, **SHOULD** use native `async fn in trait` instead of `#[async_trait]`
- Only use `async` on methods that genuinely require async; synchronous operations should not be marked as async
### 2. Avoid Repeated Computation
- Objects with high compilation costs like regular expressions **MUST** be cached using `LazyLock` or `OnceLock`
```rust
use std::sync::LazyLock;
static ENV_VAR_REGEX: LazyLock<Regex> = LazyLock::new(|| {
Regex::new(r"\$\{([^}]+)\}").unwrap()
});
```
### 3. Timestamp Handling
- Timestamp generation logic **MUST** be abstracted into a single utility function
- **SHOULD** provide an injectable clock abstraction for testing
```rust
pub trait Clock: Send + Sync {
fn now_millis(&self) -> u64;
}
pub struct SystemClock;
impl Clock for SystemClock {
fn now_millis(&self) -> u64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_millis() as u64
}
}
```
### 4. Avoid Reinventing the Wheel
- **MUST NOT** hand-write logic for Base64, encryption algorithms, etc. that have mature implementations
- Prioritize using widely validated community crates
---
## V. Type Safety
### 1. Reduce Dynamic Type Usage
- **MUST NOT** abuse `serde_json::Value` in scenarios where generic constraints can be used
- **AVOID** using `Box<dyn Any + Send + Sync>` as generic storage; prefer generics or trait objects with specific traits
### 2. Mutability and Interface Consistency
- The choice between `&self` and `&mut self` in trait method signatures **MUST** be consistent
- If internal state modification through `&self` is needed (e.g., `Arc<RwLock<_>>`), document side effects clearly
---
## VI. Interface Consistency
### 1. Parameter Type Conventions
- Constructor parameter types **SHOULD** be unified: prefer `impl Into<String>` or `&str`
```rust
// Recommended
pub fn new(id: impl Into<String>) -> Self { ... }
// Avoid
pub fn new(id: String) -> Self { ... }
```
### 2. Builder Pattern Validation
- Builder methods **MUST** validate invalid input or return `Result`
```rust
pub fn with_weight(mut self, weight: f64) -> Result<Self, &'static str> {
if weight < 0.0 {
return Err("Weight must be non-negative");
}
self.weight = Some(weight);
Ok(self)
}
```
### 3. Naming Conventions
- **MUST NOT** create custom method names that conflict with standard trait method names (e.g., `to_string_output` vs `to_string`)
---
## VII. Code Correctness
### 1. Manual Ord/Eq Implementation
- **MUST** write complete tests covering all branches for manually implemented `Ord` trait
- Recommend using `derive` or simplified implementations based on discriminants
### 2. Type Conversion Safety
- Numeric type conversions **MUST** explicitly handle potential overflow
```rust
// Avoid
let ts = as_millis() as u64;
// Recommended
let ts = u64::try_from(as_millis()).unwrap_or(u64::MAX);
```
---
## VIII. Serialization and Compatibility
### 1. Message Protocol Versioning
- Binary serialization **MUST** include version identifiers
```rust
#[derive(Serialize, Deserialize)]
struct MessageEnvelope {
version: u8,
payload: Vec<u8>,
}
```
### 2. Serialization Abstraction
- Message buses **SHOULD** support pluggable serialization backends
```rust
pub trait Serializer: Send + Sync {
fn serialize<T: Serialize>(&self, value: &T) -> Result<Vec<u8>>;
fn deserialize<T: DeserializeOwned>(&self, data: &[u8]) -> Result<T>;
}
```
---
## IX. Testing Standards
### 1. Test Coverage
- **MUST** include: boundary values, null values, invalid input, concurrent scenarios
- **MUST NOT** only test the happy path
### 2. Unit Tests and Integration Tests
- **MUST** write unit tests for core logic
- **SHOULD** write integration tests for inter-module interactions
### 3. Testability Design
- External dependencies (clock, random numbers, network) **MUST** be injectable through traits for mock implementations
---
## X. Feature Isolation
### 1. Feature Flag Standards
- Dependencies behind feature gates **MUST** be marked with `optional = true` in `Cargo.toml`
- **MUST NOT** feature gate partial code while the dependency is still compiled unconditionally
```toml
[dependencies]
config = { version = "0.14", optional = true }
[features]
default = []
config-loader = ["dep:config"]
```
---
## Checklist Template
| Check Item | Requirement | Status |
|------------|-------------|--------|
| Public enums have `#[non_exhaustive]` | Must | ☐ |
| Public error types are unified | Must | ☐ |
| No types with same name but different meanings | Forbidden | ☐ |
| Traits have unnecessary async usage | Check | ☐ |
| Numeric conversions have overflow risk | Check | ☐ |
| Time-related code is testable | Must | ☐ |
| Builders have input validation | Must | ☐ |
| Regex etc. use caching | Must | ☐ |
| Integration tests exist | Should | ☐ |
| Error path test coverage | Must | ☐ |
---
## MoFA Microkernel Architecture Standards
### Architecture Layering
MoFA follows a strict microkernel architecture with clear separation of concerns:
```
┌─────────────────────────────────────────────────────────────┐
│ mofa-sdk (Standard API) │
│ - External standard interface │
│ - Re-exports core types from kernel and foundation │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ mofa-runtime (Execution Lifecycle) │
│ - AgentRegistry, EventLoop, PluginManager │
│ - Dynamic loading and plugin management │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ mofa-foundation (Business Logic) │
│ - ✅ Concrete implementations (InMemoryStorage, SimpleToolRegistry) |
│ - ✅ Extended types (RichAgentContext, business-specific data) |
│ - ❌ FORBIDDEN: Re-defining kernel traits │
│ - ✅ ALLOWED: Importing and extending kernel traits │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ mofa-kernel (Microkernel Core) │
│ - ✅ Trait definitions (Tool, Memory, Reasoner, etc.) │
│ - ✅ Core data types (AgentInput, AgentOutput, AgentState) │
│ - ✅ Base abstractions (MoFAAgent, AgentPlugin) │
│ - ❌ FORBIDDEN: Concrete implementations (except test code) │
│ - ❌ FORBIDDEN: Business logic │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ mofa-plugins (Plugin Layer) │
│ - Plugin adapters (ToolPluginAdapter) │
│ - Concrete plugin implementations │
└─────────────────────────────────────────────────────────────┘
```
### Core Rules
#### Rule 1: Trait Definition Location
- ✅ **Kernel Layer**: Define ALL core trait interfaces
- ❌ **Foundation Layer**: NEVER re-define the same trait from kernel
- ✅ **Foundation Layer**: CAN import traits from kernel and add extension methods
#### Rule 2: Implementation Location
- ✅ **Foundation Layer**: Provide ALL concrete implementations
- ❌ **Kernel Layer**: NO concrete implementations (test code excepted)
- ✅ **Plugins Layer**: Provide optional advanced implementations
#### Rule 3: Type Exports
- ✅ **Kernel**: Export only types it defines
- ✅ **Foundation**: Export only types it implements, NOT re-export kernel traits
- ✅ **SDK**: Standard re-export of user-facing APIs
#### Rule 4: Data Types
- ✅ **Kernel Layer**: Base data types (AgentInput, AgentOutput, AgentState, ToolInput, ToolResult)
- ✅ **Foundation Layer**: Business-specific data types (Session, PromptContext, ComponentOutput)
- ⚠️ **Boundary**: If a type is part of a trait definition, put it in kernel; if business-specific, put it in foundation
#### Rule 5: Dependency Direction
```
Foundation → Kernel (ALLOWED)
Plugins → Kernel (ALLOWED)
Plugins → Foundation (ALLOWED)
Kernel → Foundation (FORBIDDEN! Creates circular dependency)
```
### Quick Reference
| What | Where | Example |
|-------|-------|---------|
| **Trait definitions** | `mofa-kernel` | `Tool`, `Memory`, `Reasoner`, `Coordinator` |
| **Core data types** | `mofa-kernel` | `AgentInput`, `AgentOutput`, `AgentState` |
| **Base abstractions** | `mofa-kernel` | `MoFAAgent`, `AgentPlugin` |
| **Concrete implementations** | `mofa-foundation` | `SimpleToolRegistry`, `InMemoryStorage` |
| **Business types** | `mofa-foundation` | `Session`, `PromptContext`, `RichAgentContext` |
| **Plugin implementations** | `mofa-plugins` | `ToolPluginAdapter`, `LLMPlugin` |
---
## Code and Documentation Language
**English is the primary language for all code comments and documentation.**
- Use English for inline comments, doc comments (`///`, `//!`), and README files
- Variable, function, and type names should be in English
- Commit messages should be written in English
- This ensures consistency and accessibility for international contributors