feat: Implement learn command for agent tool with knowledge management features
- Introduced the `agent learn` command to manage learned knowledge, including user preferences, ROM patterns, project context, and conversation memory. - Added functionality for setting, getting, listing preferences, and managing project contexts. - Implemented memory storage and retrieval, allowing the agent to remember past conversations and key facts. - Enhanced CLI output with usage instructions and error handling for the learn command. - Created a new `LearnedKnowledgeService` to handle persistent data storage and retrieval.
This commit is contained in:
@@ -134,6 +134,7 @@ The `z3ed` CLI is the foundation for an AI-driven Model-Code-Program (MCP) loop,
|
||||
- `agent chat`: Opens an interactive terminal chat (TUI) with the AI agent.
|
||||
- `agent simple-chat`: A lightweight, non-TUI chat mode for scripting and automation.
|
||||
- `agent test ...`: Commands for running and managing automated GUI tests.
|
||||
- `agent learn ...`: **NEW**: Manage learned knowledge (preferences, ROM patterns, project context, conversation memory).
|
||||
|
||||
### Resource Commands
|
||||
|
||||
@@ -163,11 +164,82 @@ Accessible from **Debug → Agent Chat** inside YAZE. Provides the same conversa
|
||||
Z3ED supports multiple AI providers. Configuration is resolved with command-line flags taking precedence over environment variables.
|
||||
|
||||
- `--ai_provider=<provider>`: Selects the AI provider (`mock`, `ollama`, `gemini`).
|
||||
- `--ai_model=<model>`: Specifies the model name (e.g., `qwen2.5-coder:7b`, `gemini-1.5-flash`).
|
||||
- `--ai_model=<model>`: Specifies the model name (e.g., `qwen2.5-coder:7b`, `gemini-2.5-flash`).
|
||||
- `--gemini_api_key=<key>`: Your Gemini API key.
|
||||
- `--ollama_host=<url>`: The URL for your Ollama server (default: `http://localhost:11434`).
|
||||
|
||||
## 8. CLI Output & Help System
|
||||
### System Prompt Versions
|
||||
|
||||
Z3ED includes multiple system prompt versions for different use cases:
|
||||
|
||||
- **v1 (default)**: Original reactive prompt with basic tool calling
|
||||
- **v2**: Enhanced with better JSON formatting and error handling
|
||||
- **v3 (latest)**: Proactive prompt with intelligent tool chaining and implicit iteration - **RECOMMENDED**
|
||||
|
||||
To use v3 prompt: Set environment variable `Z3ED_PROMPT_VERSION=v3` or it will be auto-selected for Gemini 2.0+ models.
|
||||
|
||||
## 8. Learn Command - Knowledge Management
|
||||
|
||||
The learn command enables the AI agent to remember preferences, patterns, and context across sessions.
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```bash
|
||||
# Store a preference
|
||||
z3ed agent learn --preference "default_palette=2"
|
||||
|
||||
# Get a preference
|
||||
z3ed agent learn --get-preference default_palette
|
||||
|
||||
# List all preferences
|
||||
z3ed agent learn --list-preferences
|
||||
|
||||
# View statistics
|
||||
z3ed agent learn --stats
|
||||
|
||||
# Export all learned data
|
||||
z3ed agent learn --export my_learned_data.json
|
||||
|
||||
# Import learned data
|
||||
z3ed agent learn --import my_learned_data.json
|
||||
```
|
||||
|
||||
### Project Context
|
||||
|
||||
Store project-specific information that the agent can reference:
|
||||
|
||||
```bash
|
||||
# Save project context
|
||||
z3ed agent learn --project "myrom" --context "Vanilla+ difficulty hack, focus on dungeon redesign"
|
||||
|
||||
# List projects
|
||||
z3ed agent learn --list-projects
|
||||
|
||||
# Get project details
|
||||
z3ed agent learn --get-project "myrom"
|
||||
```
|
||||
|
||||
### Conversation Memory
|
||||
|
||||
The agent automatically stores summaries of conversations for future reference:
|
||||
|
||||
```bash
|
||||
# View recent memories
|
||||
z3ed agent learn --recent-memories 10
|
||||
|
||||
# Search memories by topic
|
||||
z3ed agent learn --search-memories "room 5"
|
||||
```
|
||||
|
||||
### Storage Location
|
||||
|
||||
All learned data is stored in `~/.yaze/agent/`:
|
||||
- `preferences.json`: User preferences
|
||||
- `patterns.json`: Learned ROM patterns
|
||||
- `projects.json`: Project contexts
|
||||
- `memories.json`: Conversation summaries
|
||||
|
||||
## 9. CLI Output & Help System
|
||||
|
||||
The `z3ed` CLI features a modernized output system designed to be clean for users and informative for developers.
|
||||
|
||||
@@ -205,7 +277,7 @@ The help system is organized by category for easy navigation.
|
||||
- **Main Help**: `z3ed --help` or `z3ed -h` shows a high-level overview of command categories.
|
||||
- **Category Help**: `z3ed help <category>` provides detailed information for a specific group of commands (e.g., `agent`, `patch`, `rom`).
|
||||
|
||||
## 9. Collaborative Sessions & Multimodal Vision
|
||||
## 10. Collaborative Sessions & Multimodal Vision
|
||||
|
||||
### Overview
|
||||
|
||||
@@ -784,7 +856,7 @@ The AI response appears in your chat history and can reference specific details
|
||||
- **Agent Editor Docs**: `src/app/editor/agent/README.md`
|
||||
- **Integration Guide**: `docs/z3ed/YAZE_SERVER_V2_INTEGRATION.md`
|
||||
|
||||
## 10. Roadmap & Implementation Status
|
||||
## 11. Roadmap & Implementation Status
|
||||
|
||||
**Last Updated**: October 4, 2025
|
||||
|
||||
@@ -815,7 +887,13 @@ The AI response appears in your chat history and can reference specific details
|
||||
4. **Collaboration UI Enhancements (1 day)**: Add UI elements for ROM sync, snapshot sharing, and proposal management in the Agent Chat widget.
|
||||
5. **Windows Cross-Platform Testing (8-10h)**: Validate `z3ed` and the test harness on Windows.
|
||||
|
||||
## 11. Troubleshooting
|
||||
### ✅ Recently Completed (v0.2.0-alpha)
|
||||
|
||||
- **Enhanced System Prompt (v3)**: Proactive tool chaining with implicit iteration to minimize back-and-forth
|
||||
- **Learn Command**: Full implementation with preferences, ROM patterns, project context, and conversation memory
|
||||
- **gRPC Windows Build Optimization**: Documented vcpkg approach and optimization strategies
|
||||
|
||||
## 12. Troubleshooting
|
||||
|
||||
- **"Build with -DZ3ED_AI=ON" warning**: AI features are disabled. Rebuild with the flag to enable them.
|
||||
- **"gRPC not available" error**: GUI testing is disabled. Rebuild with `-DYAZE_WITH_GRPC=ON`.
|
||||
|
||||
@@ -110,7 +110,7 @@ absl::Status Agent::Run(const std::vector<std::string>& arg_vec) {
|
||||
return agent::HandleGuiCommand(subcommand_args);
|
||||
}
|
||||
if (subcommand == "learn") {
|
||||
return agent::HandleLearnCommand();
|
||||
return agent::HandleLearnCommand(subcommand_args);
|
||||
}
|
||||
if (subcommand == "list") {
|
||||
return agent::HandleListCommand();
|
||||
|
||||
@@ -20,7 +20,7 @@ absl::Status HandleDiffCommand(Rom& rom,
|
||||
absl::Status HandleAcceptCommand(const std::vector<std::string>& args, Rom& rom);
|
||||
absl::Status HandleTestCommand(const std::vector<std::string>& args);
|
||||
absl::Status HandleGuiCommand(const std::vector<std::string>& args);
|
||||
absl::Status HandleLearnCommand();
|
||||
absl::Status HandleLearnCommand(const std::vector<std::string>& args = {});
|
||||
absl::Status HandleListCommand();
|
||||
absl::Status HandleCommitCommand(Rom& rom);
|
||||
absl::Status HandleRevertCommand(Rom& rom);
|
||||
|
||||
@@ -385,9 +385,170 @@ absl::Status HandleDiffCommand(Rom& rom, const std::vector<std::string>& args) {
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status HandleLearnCommand() {
|
||||
std::cout << "Agent learn not yet implemented." << std::endl;
|
||||
return absl::OkStatus();
|
||||
absl::Status HandleLearnCommand(const std::vector<std::string>& args) {
|
||||
using namespace yaze::cli::agent;
|
||||
|
||||
static LearnedKnowledgeService learn_service;
|
||||
static bool initialized = false;
|
||||
|
||||
if (!initialized) {
|
||||
auto status = learn_service.Initialize();
|
||||
if (!status.ok()) {
|
||||
std::cerr << "Failed to initialize learned knowledge service: "
|
||||
<< status.message() << std::endl;
|
||||
return status;
|
||||
}
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
if (args.empty()) {
|
||||
// Show usage
|
||||
std::cout << "\nUsage: z3ed agent learn [options]\n\n";
|
||||
std::cout << "Options:\n";
|
||||
std::cout << " --preference <key>=<value> Set a preference\n";
|
||||
std::cout << " --get-preference <key> Get a preference value\n";
|
||||
std::cout << " --list-preferences List all preferences\n";
|
||||
std::cout << " --pattern <type> --data <json> Learn a ROM pattern\n";
|
||||
std::cout << " --query-patterns <type> Query learned patterns\n";
|
||||
std::cout << " --project <name> --context <text> Save project context\n";
|
||||
std::cout << " --get-project <name> Get project context\n";
|
||||
std::cout << " --list-projects List all projects\n";
|
||||
std::cout << " --memory <topic> --summary <text> Store conversation memory\n";
|
||||
std::cout << " --search-memories <query> Search memories\n";
|
||||
std::cout << " --recent-memories [limit] Show recent memories\n";
|
||||
std::cout << " --export <file> Export all data to JSON\n";
|
||||
std::cout << " --import <file> Import data from JSON\n";
|
||||
std::cout << " --stats Show statistics\n";
|
||||
std::cout << " --clear Clear all learned data\n";
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// Parse arguments
|
||||
std::string command = args[0];
|
||||
|
||||
if (command == "--preference" && args.size() >= 2) {
|
||||
std::string pref = args[1];
|
||||
size_t eq_pos = pref.find('=');
|
||||
if (eq_pos == std::string::npos) {
|
||||
return absl::InvalidArgumentError("Preference must be in format key=value");
|
||||
}
|
||||
std::string key = pref.substr(0, eq_pos);
|
||||
std::string value = pref.substr(eq_pos + 1);
|
||||
auto status = learn_service.SetPreference(key, value);
|
||||
if (status.ok()) {
|
||||
std::cout << "✓ Preference '" << key << "' set to '" << value << "'\n";
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
if (command == "--get-preference" && args.size() >= 2) {
|
||||
auto value = learn_service.GetPreference(args[1]);
|
||||
if (value) {
|
||||
std::cout << args[1] << " = " << *value << "\n";
|
||||
} else {
|
||||
std::cout << "Preference '" << args[1] << "' not found\n";
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
if (command == "--list-preferences") {
|
||||
auto prefs = learn_service.GetAllPreferences();
|
||||
if (prefs.empty()) {
|
||||
std::cout << "No preferences stored.\n";
|
||||
} else {
|
||||
std::cout << "\n=== Stored Preferences ===\n";
|
||||
for (const auto& [key, value] : prefs) {
|
||||
std::cout << " " << key << " = " << value << "\n";
|
||||
}
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
if (command == "--stats") {
|
||||
auto stats = learn_service.GetStats();
|
||||
std::cout << "\n=== Learned Knowledge Statistics ===\n";
|
||||
std::cout << " Preferences: " << stats.preference_count << "\n";
|
||||
std::cout << " ROM Patterns: " << stats.pattern_count << "\n";
|
||||
std::cout << " Projects: " << stats.project_count << "\n";
|
||||
std::cout << " Memories: " << stats.memory_count << "\n";
|
||||
std::cout << " First learned: " << absl::FormatTime(absl::FromUnixMillis(stats.first_learned_at)) << "\n";
|
||||
std::cout << " Last updated: " << absl::FormatTime(absl::FromUnixMillis(stats.last_updated_at)) << "\n";
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
if (command == "--export" && args.size() >= 2) {
|
||||
auto json = learn_service.ExportToJSON();
|
||||
if (!json.ok()) {
|
||||
return json.status();
|
||||
}
|
||||
std::ofstream file(args[1]);
|
||||
if (!file.is_open()) {
|
||||
return absl::InternalError("Failed to open file for writing");
|
||||
}
|
||||
file << *json;
|
||||
std::cout << "✓ Exported learned data to " << args[1] << "\n";
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
if (command == "--import" && args.size() >= 2) {
|
||||
std::ifstream file(args[1]);
|
||||
if (!file.is_open()) {
|
||||
return absl::NotFoundError("File not found: " + args[1]);
|
||||
}
|
||||
std::stringstream buffer;
|
||||
buffer << file.rdbuf();
|
||||
auto status = learn_service.ImportFromJSON(buffer.str());
|
||||
if (status.ok()) {
|
||||
std::cout << "✓ Imported learned data from " << args[1] << "\n";
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
if (command == "--clear") {
|
||||
auto status = learn_service.ClearAll();
|
||||
if (status.ok()) {
|
||||
std::cout << "✓ All learned data cleared\n";
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
if (command == "--list-projects") {
|
||||
auto projects = learn_service.GetAllProjects();
|
||||
if (projects.empty()) {
|
||||
std::cout << "No projects stored.\n";
|
||||
} else {
|
||||
std::cout << "\n=== Stored Projects ===\n";
|
||||
for (const auto& proj : projects) {
|
||||
std::cout << " " << proj.project_name << "\n";
|
||||
std::cout << " ROM Hash: " << proj.rom_hash.substr(0, 16) << "...\n";
|
||||
std::cout << " Last Accessed: " << absl::FormatTime(absl::FromUnixMillis(proj.last_accessed)) << "\n";
|
||||
}
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
if (command == "--recent-memories") {
|
||||
int limit = 10;
|
||||
if (args.size() >= 2) {
|
||||
limit = std::stoi(args[1]);
|
||||
}
|
||||
auto memories = learn_service.GetRecentMemories(limit);
|
||||
if (memories.empty()) {
|
||||
std::cout << "No memories stored.\n";
|
||||
} else {
|
||||
std::cout << "\n=== Recent Memories ===\n";
|
||||
for (const auto& mem : memories) {
|
||||
std::cout << " Topic: " << mem.topic << "\n";
|
||||
std::cout << " Summary: " << mem.summary << "\n";
|
||||
std::cout << " Facts: " << mem.key_facts.size() << " key facts\n";
|
||||
std::cout << " Created: " << absl::FormatTime(absl::FromUnixMillis(mem.created_at)) << "\n";
|
||||
std::cout << "\n";
|
||||
}
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
return absl::InvalidArgumentError("Unknown learn command. Use 'z3ed agent learn' for usage.");
|
||||
}
|
||||
|
||||
absl::Status HandleListCommand() {
|
||||
|
||||
673
src/cli/service/agent/learned_knowledge_service.cc
Normal file
673
src/cli/service/agent/learned_knowledge_service.cc
Normal file
@@ -0,0 +1,673 @@
|
||||
#include "cli/service/agent/learned_knowledge_service.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "absl/time/clock.h"
|
||||
#include "absl/time/time.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <direct.h>
|
||||
#define mkdir(path, mode) _mkdir(path)
|
||||
#else
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
namespace yaze {
|
||||
namespace cli {
|
||||
namespace agent {
|
||||
|
||||
namespace {
|
||||
|
||||
int64_t CurrentTimestamp() {
|
||||
return absl::ToUnixMillis(absl::Now());
|
||||
}
|
||||
|
||||
std::string GenerateRandomID() {
|
||||
static int counter = 0;
|
||||
auto now = std::chrono::system_clock::now().time_since_epoch().count();
|
||||
return absl::StrFormat("%lld_%d", now, counter++);
|
||||
}
|
||||
|
||||
bool FileExists(const std::filesystem::path& path) {
|
||||
return std::filesystem::exists(path);
|
||||
}
|
||||
|
||||
absl::Status EnsureDirectoryExists(const std::filesystem::path& path) {
|
||||
if (!std::filesystem::exists(path)) {
|
||||
std::error_code ec;
|
||||
if (!std::filesystem::create_directories(path, ec)) {
|
||||
return absl::InternalError(
|
||||
absl::StrCat("Failed to create directory: ", path.string(),
|
||||
" - ", ec.message()));
|
||||
}
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
LearnedKnowledgeService::LearnedKnowledgeService()
|
||||
: LearnedKnowledgeService(std::filesystem::path(getenv("HOME") ? getenv("HOME") : ".") / ".yaze" / "agent") {}
|
||||
|
||||
LearnedKnowledgeService::LearnedKnowledgeService(
|
||||
const std::filesystem::path& data_dir)
|
||||
: data_dir_(data_dir),
|
||||
prefs_file_(data_dir / "preferences.json"),
|
||||
patterns_file_(data_dir / "patterns.json"),
|
||||
projects_file_(data_dir / "projects.json"),
|
||||
memories_file_(data_dir / "memories.json") {}
|
||||
|
||||
absl::Status LearnedKnowledgeService::Initialize() {
|
||||
if (initialized_) {
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// Ensure data directory exists
|
||||
auto status = EnsureDirectoryExists(data_dir_);
|
||||
if (!status.ok()) {
|
||||
return status;
|
||||
}
|
||||
|
||||
// Load existing data
|
||||
LoadPreferences(); // Ignore errors for empty files
|
||||
LoadPatterns();
|
||||
LoadProjects();
|
||||
LoadMemories();
|
||||
|
||||
initialized_ = true;
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status LearnedKnowledgeService::SaveAll() {
|
||||
auto status = SavePreferences();
|
||||
if (!status.ok()) return status;
|
||||
|
||||
status = SavePatterns();
|
||||
if (!status.ok()) return status;
|
||||
|
||||
status = SaveProjects();
|
||||
if (!status.ok()) return status;
|
||||
|
||||
status = SaveMemories();
|
||||
if (!status.ok()) return status;
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// === Preference Management ===
|
||||
|
||||
absl::Status LearnedKnowledgeService::SetPreference(const std::string& key,
|
||||
const std::string& value) {
|
||||
if (!initialized_) {
|
||||
return absl::FailedPreconditionError("Service not initialized");
|
||||
}
|
||||
|
||||
preferences_[key] = value;
|
||||
return SavePreferences();
|
||||
}
|
||||
|
||||
std::optional<std::string> LearnedKnowledgeService::GetPreference(
|
||||
const std::string& key) const {
|
||||
auto it = preferences_.find(key);
|
||||
if (it != preferences_.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> LearnedKnowledgeService::GetAllPreferences() const {
|
||||
return preferences_;
|
||||
}
|
||||
|
||||
absl::Status LearnedKnowledgeService::RemovePreference(const std::string& key) {
|
||||
if (!initialized_) {
|
||||
return absl::FailedPreconditionError("Service not initialized");
|
||||
}
|
||||
|
||||
preferences_.erase(key);
|
||||
return SavePreferences();
|
||||
}
|
||||
|
||||
// === ROM Pattern Learning ===
|
||||
|
||||
absl::Status LearnedKnowledgeService::LearnPattern(const std::string& type,
|
||||
const std::string& rom_hash,
|
||||
const std::string& data,
|
||||
float confidence) {
|
||||
if (!initialized_) {
|
||||
return absl::FailedPreconditionError("Service not initialized");
|
||||
}
|
||||
|
||||
ROMPattern pattern;
|
||||
pattern.pattern_type = type;
|
||||
pattern.rom_hash = rom_hash;
|
||||
pattern.pattern_data = data;
|
||||
pattern.confidence = confidence;
|
||||
pattern.learned_at = CurrentTimestamp();
|
||||
pattern.access_count = 1;
|
||||
|
||||
patterns_.push_back(pattern);
|
||||
return SavePatterns();
|
||||
}
|
||||
|
||||
std::vector<LearnedKnowledgeService::ROMPattern>
|
||||
LearnedKnowledgeService::QueryPatterns(const std::string& type,
|
||||
const std::string& rom_hash) const {
|
||||
std::vector<ROMPattern> results;
|
||||
|
||||
for (const auto& pattern : patterns_) {
|
||||
bool type_match = type.empty() || pattern.pattern_type == type;
|
||||
bool hash_match = rom_hash.empty() || pattern.rom_hash == rom_hash;
|
||||
|
||||
if (type_match && hash_match) {
|
||||
results.push_back(pattern);
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
absl::Status LearnedKnowledgeService::UpdatePatternConfidence(
|
||||
const std::string& type,
|
||||
const std::string& rom_hash,
|
||||
float new_confidence) {
|
||||
bool found = false;
|
||||
|
||||
for (auto& pattern : patterns_) {
|
||||
if (pattern.pattern_type == type && pattern.rom_hash == rom_hash) {
|
||||
pattern.confidence = new_confidence;
|
||||
pattern.access_count++;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
return absl::NotFoundError("Pattern not found");
|
||||
}
|
||||
|
||||
return SavePatterns();
|
||||
}
|
||||
|
||||
// === Project Context ===
|
||||
|
||||
absl::Status LearnedKnowledgeService::SaveProjectContext(
|
||||
const std::string& project_name,
|
||||
const std::string& rom_hash,
|
||||
const std::string& context) {
|
||||
if (!initialized_) {
|
||||
return absl::FailedPreconditionError("Service not initialized");
|
||||
}
|
||||
|
||||
// Update existing or create new
|
||||
bool found = false;
|
||||
for (auto& project : projects_) {
|
||||
if (project.project_name == project_name) {
|
||||
project.rom_hash = rom_hash;
|
||||
project.context_data = context;
|
||||
project.last_accessed = CurrentTimestamp();
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
ProjectContext project;
|
||||
project.project_name = project_name;
|
||||
project.rom_hash = rom_hash;
|
||||
project.context_data = context;
|
||||
project.last_accessed = CurrentTimestamp();
|
||||
projects_.push_back(project);
|
||||
}
|
||||
|
||||
return SaveProjects();
|
||||
}
|
||||
|
||||
std::optional<LearnedKnowledgeService::ProjectContext>
|
||||
LearnedKnowledgeService::GetProjectContext(const std::string& project_name) const {
|
||||
for (const auto& project : projects_) {
|
||||
if (project.project_name == project_name) {
|
||||
return project;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::vector<LearnedKnowledgeService::ProjectContext>
|
||||
LearnedKnowledgeService::GetAllProjects() const {
|
||||
return projects_;
|
||||
}
|
||||
|
||||
// === Conversation Memory ===
|
||||
|
||||
absl::Status LearnedKnowledgeService::StoreConversationSummary(
|
||||
const std::string& topic,
|
||||
const std::string& summary,
|
||||
const std::vector<std::string>& key_facts) {
|
||||
if (!initialized_) {
|
||||
return absl::FailedPreconditionError("Service not initialized");
|
||||
}
|
||||
|
||||
ConversationMemory memory;
|
||||
memory.id = GenerateRandomID();
|
||||
memory.topic = topic;
|
||||
memory.summary = summary;
|
||||
memory.key_facts = key_facts;
|
||||
memory.created_at = CurrentTimestamp();
|
||||
memory.access_count = 1;
|
||||
|
||||
memories_.push_back(memory);
|
||||
|
||||
// Keep only last 100 memories
|
||||
if (memories_.size() > 100) {
|
||||
memories_.erase(memories_.begin());
|
||||
}
|
||||
|
||||
return SaveMemories();
|
||||
}
|
||||
|
||||
std::vector<LearnedKnowledgeService::ConversationMemory>
|
||||
LearnedKnowledgeService::SearchMemories(const std::string& query) const {
|
||||
std::vector<ConversationMemory> results;
|
||||
|
||||
std::string query_lower = query;
|
||||
std::transform(query_lower.begin(), query_lower.end(), query_lower.begin(), ::tolower);
|
||||
|
||||
for (const auto& memory : memories_) {
|
||||
std::string topic_lower = memory.topic;
|
||||
std::string summary_lower = memory.summary;
|
||||
std::transform(topic_lower.begin(), topic_lower.end(), topic_lower.begin(), ::tolower);
|
||||
std::transform(summary_lower.begin(), summary_lower.end(), summary_lower.begin(), ::tolower);
|
||||
|
||||
if (topic_lower.find(query_lower) != std::string::npos ||
|
||||
summary_lower.find(query_lower) != std::string::npos) {
|
||||
results.push_back(memory);
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
std::vector<LearnedKnowledgeService::ConversationMemory>
|
||||
LearnedKnowledgeService::GetRecentMemories(int limit) const {
|
||||
std::vector<ConversationMemory> recent = memories_;
|
||||
|
||||
// Sort by created_at descending
|
||||
std::sort(recent.begin(), recent.end(),
|
||||
[](const ConversationMemory& a, const ConversationMemory& b) {
|
||||
return a.created_at > b.created_at;
|
||||
});
|
||||
|
||||
if (recent.size() > static_cast<size_t>(limit)) {
|
||||
recent.resize(limit);
|
||||
}
|
||||
|
||||
return recent;
|
||||
}
|
||||
|
||||
// === Import/Export ===
|
||||
|
||||
#ifdef YAZE_WITH_JSON
|
||||
absl::StatusOr<std::string> LearnedKnowledgeService::ExportToJSON() const {
|
||||
nlohmann::json export_data;
|
||||
|
||||
// Export preferences
|
||||
export_data["preferences"] = preferences_;
|
||||
|
||||
// Export patterns
|
||||
export_data["patterns"] = nlohmann::json::array();
|
||||
for (const auto& pattern : patterns_) {
|
||||
nlohmann::json p;
|
||||
p["type"] = pattern.pattern_type;
|
||||
p["rom_hash"] = pattern.rom_hash;
|
||||
p["data"] = pattern.pattern_data;
|
||||
p["confidence"] = pattern.confidence;
|
||||
p["learned_at"] = pattern.learned_at;
|
||||
p["access_count"] = pattern.access_count;
|
||||
export_data["patterns"].push_back(p);
|
||||
}
|
||||
|
||||
// Export projects
|
||||
export_data["projects"] = nlohmann::json::array();
|
||||
for (const auto& project : projects_) {
|
||||
nlohmann::json p;
|
||||
p["name"] = project.project_name;
|
||||
p["rom_hash"] = project.rom_hash;
|
||||
p["context"] = project.context_data;
|
||||
p["last_accessed"] = project.last_accessed;
|
||||
export_data["projects"].push_back(p);
|
||||
}
|
||||
|
||||
// Export memories
|
||||
export_data["memories"] = nlohmann::json::array();
|
||||
for (const auto& memory : memories_) {
|
||||
nlohmann::json m;
|
||||
m["id"] = memory.id;
|
||||
m["topic"] = memory.topic;
|
||||
m["summary"] = memory.summary;
|
||||
m["key_facts"] = memory.key_facts;
|
||||
m["created_at"] = memory.created_at;
|
||||
m["access_count"] = memory.access_count;
|
||||
export_data["memories"].push_back(m);
|
||||
}
|
||||
|
||||
return export_data.dump(2);
|
||||
}
|
||||
|
||||
absl::Status LearnedKnowledgeService::ImportFromJSON(const std::string& json_data) {
|
||||
try {
|
||||
auto data = nlohmann::json::parse(json_data);
|
||||
|
||||
// Import preferences
|
||||
if (data.contains("preferences")) {
|
||||
for (const auto& [key, value] : data["preferences"].items()) {
|
||||
preferences_[key] = value.get<std::string>();
|
||||
}
|
||||
}
|
||||
|
||||
// Import patterns
|
||||
if (data.contains("patterns")) {
|
||||
for (const auto& p : data["patterns"]) {
|
||||
ROMPattern pattern;
|
||||
pattern.pattern_type = p["type"];
|
||||
pattern.rom_hash = p["rom_hash"];
|
||||
pattern.pattern_data = p["data"];
|
||||
pattern.confidence = p["confidence"];
|
||||
pattern.learned_at = p["learned_at"];
|
||||
pattern.access_count = p["access_count"];
|
||||
patterns_.push_back(pattern);
|
||||
}
|
||||
}
|
||||
|
||||
// Import projects
|
||||
if (data.contains("projects")) {
|
||||
for (const auto& p : data["projects"]) {
|
||||
ProjectContext project;
|
||||
project.project_name = p["name"];
|
||||
project.rom_hash = p["rom_hash"];
|
||||
project.context_data = p["context"];
|
||||
project.last_accessed = p["last_accessed"];
|
||||
projects_.push_back(project);
|
||||
}
|
||||
}
|
||||
|
||||
// Import memories
|
||||
if (data.contains("memories")) {
|
||||
for (const auto& m : data["memories"]) {
|
||||
ConversationMemory memory;
|
||||
memory.id = m["id"];
|
||||
memory.topic = m["topic"];
|
||||
memory.summary = m["summary"];
|
||||
memory.key_facts = m["key_facts"].get<std::vector<std::string>>();
|
||||
memory.created_at = m["created_at"];
|
||||
memory.access_count = m["access_count"];
|
||||
memories_.push_back(memory);
|
||||
}
|
||||
}
|
||||
|
||||
return SaveAll();
|
||||
} catch (const std::exception& e) {
|
||||
return absl::InternalError(absl::StrCat("JSON parse error: ", e.what()));
|
||||
}
|
||||
}
|
||||
#else
|
||||
absl::StatusOr<std::string> LearnedKnowledgeService::ExportToJSON() const {
|
||||
return absl::UnimplementedError("JSON support not enabled. Build with -DYAZE_WITH_JSON=ON");
|
||||
}
|
||||
|
||||
absl::Status LearnedKnowledgeService::ImportFromJSON(const std::string&) {
|
||||
return absl::UnimplementedError("JSON support not enabled. Build with -DYAZE_WITH_JSON=ON");
|
||||
}
|
||||
#endif
|
||||
|
||||
absl::Status LearnedKnowledgeService::ClearAll() {
|
||||
preferences_.clear();
|
||||
patterns_.clear();
|
||||
projects_.clear();
|
||||
memories_.clear();
|
||||
return SaveAll();
|
||||
}
|
||||
|
||||
// === Statistics ===
|
||||
|
||||
LearnedKnowledgeService::Stats LearnedKnowledgeService::GetStats() const {
|
||||
Stats stats;
|
||||
stats.preference_count = preferences_.size();
|
||||
stats.pattern_count = patterns_.size();
|
||||
stats.project_count = projects_.size();
|
||||
stats.memory_count = memories_.size();
|
||||
|
||||
// Find earliest learned_at
|
||||
int64_t earliest = CurrentTimestamp();
|
||||
for (const auto& pattern : patterns_) {
|
||||
if (pattern.learned_at < earliest) {
|
||||
earliest = pattern.learned_at;
|
||||
}
|
||||
}
|
||||
for (const auto& memory : memories_) {
|
||||
if (memory.created_at < earliest) {
|
||||
earliest = memory.created_at;
|
||||
}
|
||||
}
|
||||
stats.first_learned_at = earliest;
|
||||
|
||||
// Last updated is now
|
||||
stats.last_updated_at = CurrentTimestamp();
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
// === Internal Helpers ===
|
||||
|
||||
#ifdef YAZE_WITH_JSON
|
||||
absl::Status LearnedKnowledgeService::LoadPreferences() {
|
||||
if (!FileExists(prefs_file_)) {
|
||||
return absl::OkStatus(); // No file yet, empty preferences
|
||||
}
|
||||
|
||||
try {
|
||||
std::ifstream file(prefs_file_);
|
||||
if (!file.is_open()) {
|
||||
return absl::InternalError("Failed to open preferences file");
|
||||
}
|
||||
|
||||
nlohmann::json data;
|
||||
file >> data;
|
||||
|
||||
for (const auto& [key, value] : data.items()) {
|
||||
preferences_[key] = value.get<std::string>();
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
} catch (const std::exception& e) {
|
||||
return absl::InternalError(absl::StrCat("Failed to load preferences: ", e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
absl::Status LearnedKnowledgeService::SavePreferences() {
|
||||
try {
|
||||
nlohmann::json data = preferences_;
|
||||
|
||||
std::ofstream file(prefs_file_);
|
||||
if (!file.is_open()) {
|
||||
return absl::InternalError("Failed to open preferences file for writing");
|
||||
}
|
||||
|
||||
file << data.dump(2);
|
||||
return absl::OkStatus();
|
||||
} catch (const std::exception& e) {
|
||||
return absl::InternalError(absl::StrCat("Failed to save preferences: ", e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
absl::Status LearnedKnowledgeService::LoadPatterns() {
|
||||
if (!FileExists(patterns_file_)) {
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
try {
|
||||
std::ifstream file(patterns_file_);
|
||||
nlohmann::json data;
|
||||
file >> data;
|
||||
|
||||
for (const auto& p : data) {
|
||||
ROMPattern pattern;
|
||||
pattern.pattern_type = p["type"];
|
||||
pattern.rom_hash = p["rom_hash"];
|
||||
pattern.pattern_data = p["data"];
|
||||
pattern.confidence = p["confidence"];
|
||||
pattern.learned_at = p["learned_at"];
|
||||
pattern.access_count = p.value("access_count", 0);
|
||||
patterns_.push_back(pattern);
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
} catch (const std::exception& e) {
|
||||
return absl::InternalError(absl::StrCat("Failed to load patterns: ", e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
absl::Status LearnedKnowledgeService::SavePatterns() {
|
||||
try {
|
||||
nlohmann::json data = nlohmann::json::array();
|
||||
|
||||
for (const auto& pattern : patterns_) {
|
||||
nlohmann::json p;
|
||||
p["type"] = pattern.pattern_type;
|
||||
p["rom_hash"] = pattern.rom_hash;
|
||||
p["data"] = pattern.pattern_data;
|
||||
p["confidence"] = pattern.confidence;
|
||||
p["learned_at"] = pattern.learned_at;
|
||||
p["access_count"] = pattern.access_count;
|
||||
data.push_back(p);
|
||||
}
|
||||
|
||||
std::ofstream file(patterns_file_);
|
||||
file << data.dump(2);
|
||||
return absl::OkStatus();
|
||||
} catch (const std::exception& e) {
|
||||
return absl::InternalError(absl::StrCat("Failed to save patterns: ", e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
absl::Status LearnedKnowledgeService::LoadProjects() {
|
||||
if (!FileExists(projects_file_)) {
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
try {
|
||||
std::ifstream file(projects_file_);
|
||||
nlohmann::json data;
|
||||
file >> data;
|
||||
|
||||
for (const auto& p : data) {
|
||||
ProjectContext project;
|
||||
project.project_name = p["name"];
|
||||
project.rom_hash = p["rom_hash"];
|
||||
project.context_data = p["context"];
|
||||
project.last_accessed = p["last_accessed"];
|
||||
projects_.push_back(project);
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
} catch (const std::exception& e) {
|
||||
return absl::InternalError(absl::StrCat("Failed to load projects: ", e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
absl::Status LearnedKnowledgeService::SaveProjects() {
|
||||
try {
|
||||
nlohmann::json data = nlohmann::json::array();
|
||||
|
||||
for (const auto& project : projects_) {
|
||||
nlohmann::json p;
|
||||
p["name"] = project.project_name;
|
||||
p["rom_hash"] = project.rom_hash;
|
||||
p["context"] = project.context_data;
|
||||
p["last_accessed"] = project.last_accessed;
|
||||
data.push_back(p);
|
||||
}
|
||||
|
||||
std::ofstream file(projects_file_);
|
||||
file << data.dump(2);
|
||||
return absl::OkStatus();
|
||||
} catch (const std::exception& e) {
|
||||
return absl::InternalError(absl::StrCat("Failed to save projects: ", e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
absl::Status LearnedKnowledgeService::SaveMemories() {
|
||||
try {
|
||||
nlohmann::json data = nlohmann::json::array();
|
||||
|
||||
for (const auto& memory : memories_) {
|
||||
nlohmann::json m;
|
||||
m["id"] = memory.id;
|
||||
m["topic"] = memory.topic;
|
||||
m["summary"] = memory.summary;
|
||||
m["key_facts"] = memory.key_facts;
|
||||
m["created_at"] = memory.created_at;
|
||||
m["access_count"] = memory.access_count;
|
||||
data.push_back(m);
|
||||
}
|
||||
|
||||
std::ofstream file(memories_file_);
|
||||
file << data.dump(2);
|
||||
return absl::OkStatus();
|
||||
} catch (const std::exception& e) {
|
||||
return absl::InternalError(absl::StrCat("Failed to save memories: ", e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
absl::Status LearnedKnowledgeService::LoadMemories() {
|
||||
if (!FileExists(memories_file_)) {
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
try {
|
||||
std::ifstream file(memories_file_);
|
||||
nlohmann::json data;
|
||||
file >> data;
|
||||
|
||||
for (const auto& m : data) {
|
||||
ConversationMemory memory;
|
||||
memory.id = m["id"];
|
||||
memory.topic = m["topic"];
|
||||
memory.summary = m["summary"];
|
||||
memory.key_facts = m["key_facts"].get<std::vector<std::string>>();
|
||||
memory.created_at = m["created_at"];
|
||||
memory.access_count = m.value("access_count", 0);
|
||||
memories_.push_back(memory);
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
} catch (const std::exception& e) {
|
||||
return absl::InternalError(absl::StrCat("Failed to load memories: ", e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
// Stub implementations when JSON is not available
|
||||
absl::Status LearnedKnowledgeService::LoadPreferences() { return absl::OkStatus(); }
|
||||
absl::Status LearnedKnowledgeService::SavePreferences() { return absl::UnimplementedError("JSON support required"); }
|
||||
absl::Status LearnedKnowledgeService::LoadPatterns() { return absl::OkStatus(); }
|
||||
absl::Status LearnedKnowledgeService::SavePatterns() { return absl::UnimplementedError("JSON support required"); }
|
||||
absl::Status LearnedKnowledgeService::LoadProjects() { return absl::OkStatus(); }
|
||||
absl::Status LearnedKnowledgeService::SaveProjects() { return absl::UnimplementedError("JSON support required"); }
|
||||
absl::Status LearnedKnowledgeService::LoadMemories() { return absl::OkStatus(); }
|
||||
absl::Status LearnedKnowledgeService::SaveMemories() { return absl::UnimplementedError("JSON support required"); }
|
||||
#endif
|
||||
|
||||
std::string LearnedKnowledgeService::GenerateID() const {
|
||||
return GenerateRandomID();
|
||||
}
|
||||
|
||||
} // namespace agent
|
||||
} // namespace cli
|
||||
} // namespace yaze
|
||||
225
src/cli/service/agent/learned_knowledge_service.h
Normal file
225
src/cli/service/agent/learned_knowledge_service.h
Normal file
@@ -0,0 +1,225 @@
|
||||
#ifndef YAZE_CLI_SERVICE_AGENT_LEARNED_KNOWLEDGE_SERVICE_H_
|
||||
#define YAZE_CLI_SERVICE_AGENT_LEARNED_KNOWLEDGE_SERVICE_H_
|
||||
|
||||
#include <filesystem>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
|
||||
#ifdef YAZE_WITH_JSON
|
||||
#include "nlohmann/json.hpp"
|
||||
#endif
|
||||
|
||||
namespace yaze {
|
||||
namespace cli {
|
||||
namespace agent {
|
||||
|
||||
/**
|
||||
* @class LearnedKnowledgeService
|
||||
* @brief Manages persistent learned information across agent sessions
|
||||
*
|
||||
* Stores:
|
||||
* - User preferences (default palettes, favorite tools, etc.)
|
||||
* - ROM patterns (frequently accessed rooms, sprite placements, etc.)
|
||||
* - Project context (ROM-specific notes, goals, custom names)
|
||||
* - Conversation memory (summaries of past discussions)
|
||||
*/
|
||||
class LearnedKnowledgeService {
|
||||
public:
|
||||
LearnedKnowledgeService();
|
||||
explicit LearnedKnowledgeService(const std::filesystem::path& data_dir);
|
||||
|
||||
// Initialize the service and load existing data
|
||||
absl::Status Initialize();
|
||||
|
||||
// Save all data to disk
|
||||
absl::Status SaveAll();
|
||||
|
||||
// === Preference Management ===
|
||||
|
||||
/**
|
||||
* Set a user preference
|
||||
* @param key Preference key (e.g., "default_palette", "preferred_tool")
|
||||
* @param value Preference value
|
||||
*/
|
||||
absl::Status SetPreference(const std::string& key, const std::string& value);
|
||||
|
||||
/**
|
||||
* Get a user preference
|
||||
* @param key Preference key
|
||||
* @return Value if exists, nullopt otherwise
|
||||
*/
|
||||
std::optional<std::string> GetPreference(const std::string& key) const;
|
||||
|
||||
/**
|
||||
* List all preferences
|
||||
*/
|
||||
std::map<std::string, std::string> GetAllPreferences() const;
|
||||
|
||||
/**
|
||||
* Remove a preference
|
||||
*/
|
||||
absl::Status RemovePreference(const std::string& key);
|
||||
|
||||
// === ROM Pattern Learning ===
|
||||
|
||||
struct ROMPattern {
|
||||
std::string pattern_type; // e.g., "sprite_location", "tile_usage"
|
||||
std::string rom_hash;
|
||||
std::string pattern_data; // JSON encoded
|
||||
float confidence = 1.0f; // 0.0 to 1.0
|
||||
int64_t learned_at = 0;
|
||||
int access_count = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Learn a pattern from the current ROM
|
||||
* @param type Pattern type (e.g., "sprite_distribution", "room_access_frequency")
|
||||
* @param rom_hash SHA256 hash of the ROM
|
||||
* @param data Pattern-specific data (JSON)
|
||||
*/
|
||||
absl::Status LearnPattern(const std::string& type,
|
||||
const std::string& rom_hash,
|
||||
const std::string& data,
|
||||
float confidence = 1.0f);
|
||||
|
||||
/**
|
||||
* Query patterns for a specific ROM
|
||||
* @param type Pattern type to query
|
||||
* @param rom_hash ROM hash to filter by (empty = all ROMs)
|
||||
* @return Vector of matching patterns
|
||||
*/
|
||||
std::vector<ROMPattern> QueryPatterns(const std::string& type,
|
||||
const std::string& rom_hash = "") const;
|
||||
|
||||
/**
|
||||
* Update pattern confidence/access count
|
||||
*/
|
||||
absl::Status UpdatePatternConfidence(const std::string& type,
|
||||
const std::string& rom_hash,
|
||||
float new_confidence);
|
||||
|
||||
// === Project Context ===
|
||||
|
||||
struct ProjectContext {
|
||||
std::string project_name;
|
||||
std::string rom_hash;
|
||||
std::string context_data; // JSON encoded: description, goals, custom labels
|
||||
int64_t last_accessed = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Save context for a project/ROM
|
||||
*/
|
||||
absl::Status SaveProjectContext(const std::string& project_name,
|
||||
const std::string& rom_hash,
|
||||
const std::string& context);
|
||||
|
||||
/**
|
||||
* Get project context
|
||||
*/
|
||||
std::optional<ProjectContext> GetProjectContext(const std::string& project_name) const;
|
||||
|
||||
/**
|
||||
* List all projects
|
||||
*/
|
||||
std::vector<ProjectContext> GetAllProjects() const;
|
||||
|
||||
// === Conversation Memory ===
|
||||
|
||||
struct ConversationMemory {
|
||||
std::string id;
|
||||
std::string topic;
|
||||
std::string summary;
|
||||
std::vector<std::string> key_facts;
|
||||
int64_t created_at = 0;
|
||||
int access_count = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Store a conversation summary
|
||||
* @param topic Topic/theme of the conversation
|
||||
* @param summary Brief summary
|
||||
* @param key_facts Important facts extracted
|
||||
*/
|
||||
absl::Status StoreConversationSummary(const std::string& topic,
|
||||
const std::string& summary,
|
||||
const std::vector<std::string>& key_facts);
|
||||
|
||||
/**
|
||||
* Search conversation memories by topic/keyword
|
||||
*/
|
||||
std::vector<ConversationMemory> SearchMemories(const std::string& query) const;
|
||||
|
||||
/**
|
||||
* Get most recent conversation memories
|
||||
*/
|
||||
std::vector<ConversationMemory> GetRecentMemories(int limit = 10) const;
|
||||
|
||||
// === Import/Export ===
|
||||
|
||||
/**
|
||||
* Export all learned data to JSON
|
||||
*/
|
||||
absl::StatusOr<std::string> ExportToJSON() const;
|
||||
|
||||
/**
|
||||
* Import learned data from JSON
|
||||
*/
|
||||
absl::Status ImportFromJSON(const std::string& json_data);
|
||||
|
||||
/**
|
||||
* Clear all learned data
|
||||
*/
|
||||
absl::Status ClearAll();
|
||||
|
||||
// === Statistics ===
|
||||
|
||||
struct Stats {
|
||||
int preference_count = 0;
|
||||
int pattern_count = 0;
|
||||
int project_count = 0;
|
||||
int memory_count = 0;
|
||||
int64_t first_learned_at = 0;
|
||||
int64_t last_updated_at = 0;
|
||||
};
|
||||
|
||||
Stats GetStats() const;
|
||||
|
||||
private:
|
||||
std::filesystem::path data_dir_;
|
||||
std::filesystem::path prefs_file_;
|
||||
std::filesystem::path patterns_file_;
|
||||
std::filesystem::path projects_file_;
|
||||
std::filesystem::path memories_file_;
|
||||
|
||||
std::map<std::string, std::string> preferences_;
|
||||
std::vector<ROMPattern> patterns_;
|
||||
std::vector<ProjectContext> projects_;
|
||||
std::vector<ConversationMemory> memories_;
|
||||
|
||||
bool initialized_ = false;
|
||||
|
||||
// Internal helpers
|
||||
absl::Status LoadPreferences();
|
||||
absl::Status LoadPatterns();
|
||||
absl::Status LoadProjects();
|
||||
absl::Status LoadMemories();
|
||||
|
||||
absl::Status SavePreferences();
|
||||
absl::Status SavePatterns();
|
||||
absl::Status SaveProjects();
|
||||
absl:Status SaveMemories();
|
||||
|
||||
std::string GenerateID() const;
|
||||
};
|
||||
|
||||
} // namespace agent
|
||||
} // namespace cli
|
||||
} // namespace yaze
|
||||
|
||||
#endif // YAZE_CLI_SERVICE_AGENT_LEARNED_KNOWLEDGE_SERVICE_H_
|
||||
Reference in New Issue
Block a user