Skip to content

Commit fb7d810

Browse files
authored
Consolidate VersionedKvStore commits to eliminate duplicate metadata commits (#68)
This PR addresses the issue where VersionedKvStore::commit() was creating two separate git commits: one for the main data changes and another for prolly metadata files (prolly_config_tree_config and prolly_hash_mappings). The changes consolidate these into a single atomic commit. Changes Made Core Changes - Modified VersionedKvStore::commit() (src/git/versioned_store.rs:257-291) - Updated create_git_tree() to stage prolly metadata files before creating the git tree using git add and git write-tree - Removed the separate commit_prolly_metadata() call that was creating the second commit - Maintains the same functionality while reducing commit count from 2 to 1 - Updated VersionedKvStore::init() (src/git/versioned_store.rs:104-114) - Removed the extra metadata commit after initialization - Now creates only the initial commit which includes metadata files - Removed unused function (src/git/versioned_store.rs) - Deleted commit_prolly_metadata() function as it's no longer needed - Function was only used for creating separate metadata commits
1 parent 250bb96 commit fb7d810

6 files changed

Lines changed: 1369 additions & 322 deletions

File tree

Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
# Financial Advisory AI with Versioned Memory
2+
3+
A demonstration of an AI-powered financial advisory system using ProllyTree for versioned memory management. This example showcases how to build a secure, auditable AI agent that maintains consistent memory across time and can handle complex financial recommendations with full traceability.
4+
5+
## Features
6+
7+
- 🤖 **AI-Powered Recommendations**: Uses OpenAI's API to generate intelligent investment advice
8+
- 📊 **Multi-Source Data Validation**: Cross-validates market data from multiple sources
9+
- 🔒 **Security Monitoring**: Detects and prevents injection attacks and anomalies
10+
- 📚 **Versioned Memory**: Uses ProllyTree to maintain git-like versioned storage of all data
11+
- 🕐 **Temporal Queries**: Query recommendations and data as they existed at any point in time
12+
- 🌿 **Branch Management**: Create memory branches for different scenarios or clients
13+
- 📝 **Audit Trail**: Complete audit logs for compliance and debugging
14+
- 🎯 **Risk-Aware**: Adapts recommendations based on client risk tolerance
15+
16+
## Prerequisites
17+
18+
- Rust (latest stable version)
19+
- Git (for memory versioning)
20+
- OpenAI API key (optional, for AI-enhanced reasoning)
21+
22+
## Quick Start
23+
24+
### 1. Initialize Storage Directory
25+
26+
First, create a directory with git repository for the advisor's memory:
27+
28+
```bash
29+
# Create a directory for the advisor's memory
30+
mkdir -p /tmp/advisor
31+
cd /tmp/advisor
32+
33+
# Initialize git repository (required for versioned memory)
34+
git init
35+
36+
# Return to the project directory
37+
cd /path/to/prollytree
38+
```
39+
40+
### 2. Set Environment Variables (Optional)
41+
42+
For AI-enhanced recommendations, set your OpenAI API key:
43+
44+
```bash
45+
export OPENAI_API_KEY="your-api-key-here"
46+
```
47+
48+
### 3. Run the Financial Advisor
49+
50+
```bash
51+
# Basic usage with temporary storage
52+
cargo run --example financial_advisor -- --storage /tmp/advisor/data advise
53+
54+
# Or use the shorter form
55+
cargo run -- --storage /tmp/advisor/data advise
56+
```
57+
58+
## Usage
59+
60+
### Interactive Commands
61+
62+
Once the advisor is running, you can use these commands:
63+
64+
#### Core Operations
65+
- `recommend <SYMBOL>` - Get AI-powered recommendation for a stock symbol (e.g., `recommend AAPL`)
66+
- `profile` - Show current client profile
67+
- `risk <LEVEL>` - Set risk tolerance (`conservative`, `moderate`, or `aggressive`)
68+
69+
#### History and Analysis
70+
- `history` - Show recent recommendations
71+
- `history <commit>` - Show recommendations at a specific git commit
72+
- `history --branch <name>` - Show recommendations from a specific branch
73+
- `memory` - Show memory system status and statistics
74+
- `audit` - Show complete audit trail
75+
76+
#### Advanced Features
77+
- `branch <NAME>` - Create a new memory branch
78+
- `visualize` - Show memory tree visualization
79+
- `test-inject <TEXT>` - Test security monitoring (try malicious inputs)
80+
81+
#### Other Commands
82+
- `help` - Show all available commands
83+
- `exit` or `quit` - Exit the advisor
84+
85+
### Example Session
86+
87+
```bash
88+
🏦> recommend AAPL
89+
📊 Recommendation Generated
90+
Symbol: AAPL
91+
Action: BUY
92+
Confidence: 52.0%
93+
Reasoning: Analysis of AAPL at $177.89 with P/E ratio 28.4...
94+
95+
🏦> risk aggressive
96+
✅ Risk tolerance set to: Aggressive
97+
98+
🏦> recommend AAPL
99+
📊 Recommendation Generated
100+
Symbol: AAPL
101+
Action: BUY
102+
Confidence: 60.0%
103+
(Notice higher confidence for aggressive risk tolerance)
104+
105+
🏦> history
106+
📜 Recent Recommendations
107+
📊 Recommendation #1
108+
Symbol: AAPL
109+
Action: BUY
110+
Confidence: 60.0%
111+
...
112+
📊 Recommendation #2
113+
Symbol: AAPL
114+
Action: BUY
115+
Confidence: 52.0%
116+
...
117+
118+
🏦> memory
119+
🧠 Memory Status
120+
✅ Memory validation: ACTIVE
121+
🛡️ Security monitoring: ENABLED
122+
📝 Audit trail: ENABLED
123+
🌿 Current branch: main
124+
📊 Total commits: 15
125+
💡 Recommendations: 2
126+
```
127+
128+
## Command Line Options
129+
130+
```bash
131+
cargo run -- [OPTIONS] <COMMAND>
132+
133+
Commands:
134+
advise Start interactive advisory session
135+
visualize Visualize memory evolution
136+
attack Run attack simulations
137+
benchmark Run performance benchmarks
138+
memory Git memory operations
139+
examples Show integration examples
140+
audit Audit memory for compliance
141+
142+
Options:
143+
-s, --storage <PATH> Path to store agent memory [default: ./advisor_memory/data]
144+
-h, --help Print help
145+
```
146+
147+
## Architecture
148+
149+
### Memory System
150+
- **ProllyTree Storage**: Git-like versioned storage for all data
151+
- **Multi-table Schema**: Separate tables for recommendations, market data, client profiles
152+
- **Cross-validation**: Data integrity through hash validation and cross-references
153+
- **Temporal Queries**: Query data as it existed at any commit or branch
154+
155+
### Security Features
156+
- **Input Sanitization**: Prevents SQL injection and other attacks
157+
- **Anomaly Detection**: Monitors for suspicious patterns in data
158+
- **Attack Simulation**: Built-in testing for security vulnerabilities
159+
- **Audit Logging**: Complete trail of all operations
160+
161+
### AI Integration
162+
- **Market Analysis**: Real-time analysis of market conditions
163+
- **Risk Assessment**: Adapts to client risk tolerance
164+
- **Reasoning Generation**: Explains the logic behind recommendations
165+
- **Multi-source Validation**: Cross-checks data from multiple financial sources
166+
167+
## Advanced Usage
168+
169+
### Branch Management
170+
171+
Create branches for different scenarios:
172+
173+
```bash
174+
🏦> branch conservative-strategy
175+
✅ Created branch: conservative-strategy
176+
177+
🏦> risk conservative
178+
🏦> recommend MSFT
179+
# Generate recommendations for conservative strategy
180+
181+
🏦> history --branch main
182+
# Compare with main branch recommendations
183+
```
184+
185+
### Temporal Analysis
186+
187+
Analyze how recommendations changed over time:
188+
189+
```bash
190+
# Get commit history
191+
🏦> memory
192+
193+
# Query specific time points
194+
🏦> history abc1234 # Recommendations at specific commit
195+
🏦> history def5678 # Compare with different commit
196+
```
197+
198+
### Security Testing
199+
200+
Test the system's security:
201+
202+
```bash
203+
🏦> test-inject "'; DROP TABLE recommendations; --"
204+
🛡️ Security Alert: Potential SQL injection detected and blocked
205+
206+
🏦> test-inject "unusual market manipulation data"
207+
🚨 Anomaly detected in data pattern
208+
```
209+
210+
## Troubleshooting## License
211+
212+
This example is part of the ProllyTree project and follows the same license terms.
213+
214+
## Contributing
215+
216+
Contributions are welcome! Please see the main project's contributing guidelines.
217+
218+
## Disclaimer
219+
220+
This is a demonstration system for educational purposes. Do not use for actual financial decisions without proper validation and compliance review.

examples/financial_advisor/src/advisor/interactive.rs

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -176,9 +176,9 @@ impl<'a> InteractiveSession<'a> {
176176
if parts.len() >= 2 {
177177
// history <commit_hash> or history --branch <branch_name>
178178
if parts[1] == "--branch" && parts.len() >= 3 {
179-
self.show_history_at_branch(&parts[2]).await?;
179+
self.show_history_at_branch(parts[2]).await?;
180180
} else {
181-
self.show_history_at_commit(&parts[1]).await?;
181+
self.show_history_at_commit(parts[1]).await?;
182182
}
183183
} else {
184184
self.show_history().await?;
@@ -453,12 +453,27 @@ impl<'a> InteractiveSession<'a> {
453453
);
454454
println!("{}", "━".repeat(50).dimmed());
455455

456-
// For now, show current branch recommendations (could be extended to support branch switching)
457-
println!(
458-
"{} Branch-specific history not yet implemented, showing current branch",
459-
"ℹ️".yellow()
460-
);
461-
self.show_history().await?;
456+
match self.advisor.get_recommendations_at_branch(branch, 10).await {
457+
Ok(recommendations) => {
458+
if recommendations.is_empty() {
459+
println!(
460+
"{} No recommendations found on branch {}",
461+
"ℹ️".blue(),
462+
branch
463+
);
464+
} else {
465+
self.display_recommendations(&recommendations).await?;
466+
}
467+
}
468+
Err(e) => {
469+
println!(
470+
"{} Failed to retrieve history on branch {}: {}",
471+
"❌".red(),
472+
branch,
473+
e
474+
);
475+
}
476+
}
462477

463478
Ok(())
464479
}
@@ -608,7 +623,7 @@ impl<'a> InteractiveSession<'a> {
608623
};
609624

610625
let response_info = if let Some(ms) = source.response_time_ms {
611-
format!(" ({}ms)", ms)
626+
format!(" ({ms}ms)")
612627
} else {
613628
String::new()
614629
};

0 commit comments

Comments
 (0)