Riy777 commited on
Commit
11e97ef
·
1 Parent(s): 60efff2

Update learning_hub/memory_store.py

Browse files
Files changed (1) hide show
  1. learning_hub/memory_store.py +37 -41
learning_hub/memory_store.py CHANGED
@@ -2,7 +2,9 @@
2
  import json
3
  import asyncio
4
  from datetime import datetime
5
- from typing import List, Dict, Optional
 
 
6
  from .schemas import Delta, ReflectorOutput
7
  from .policy_engine import PolicyEngine
8
 
@@ -10,6 +12,7 @@ from .policy_engine import PolicyEngine
10
  # (لا يمكننا استيراده مباشرة لتجنب التبعيات الدائرية)
11
 
12
  class MemoryStore:
 
13
  def __init__(self, r2_service: Any, policy_engine: PolicyEngine, llm_service: Any):
14
  self.r2_service = r2_service
15
  self.policy_engine = policy_engine
@@ -24,7 +27,7 @@ class MemoryStore:
24
  }
25
 
26
  self.distill_threshold = 50 # (من النقطة 6)
27
- print("✅ Learning Hub Module: Memory Store loaded")
28
 
29
  async def _load_deltas_from_r2(self, domain: str) -> List[Dict]:
30
  """تحميل ملف الدلتا المحدد من R2"""
@@ -42,35 +45,36 @@ class MemoryStore:
42
  """حفظ ملف الدلتا المحدث إلى R2"""
43
  key = self.domain_files.get(domain, self.domain_files["general"])
44
  try:
45
- data_json = json.dumps(deltas_list, indent=2, ensure_ascii=False).encode('utf-8')
 
 
46
  self.r2_service.s3_client.put_object(
47
  Bucket="trading", Key=key, Body=data_json, ContentType="application/json"
48
  )
49
  except Exception as e:
50
  print(f"❌ [MemoryStore] فشل حفظ الدلتا إلى R2: {e}")
51
 
52
- async def save_new_delta(self,
53
- reflector_output: ReflectorOutput,
54
- trade_object: Dict[str, Any],
55
  domain: str = "strategy"):
56
  """
57
  حفظ "دلتا" جديدة بناءً على مخرجات المنعكس وسياسة القبول.
58
- (تنفيذ النقطة 5)
59
  """
60
  try:
61
  trade_pnl_percent = trade_object.get('pnl_percent', 0)
62
 
63
- # 1. التحقق من سياسة القبول (النقطة 5 و 7)
64
  is_approved, approval_reason = self.policy_engine.get_delta_acceptance(
65
- reflector_output,
66
  trade_pnl_percent
67
  )
68
 
69
- # 2. إنشاء كائن الدلتا (النقطة 3)
70
  new_delta = Delta(
71
  text=reflector_output.suggested_rule,
72
  domain=domain,
73
- score=reflector_output.confidence, # (سنستخدم الثقة كدرجة أولية)
74
  evidence_refs=[trade_object.get('id', 'unknown_trade_id')],
75
  approved=is_approved,
76
  trade_strategy=trade_object.get('strategy', 'unknown'),
@@ -79,26 +83,24 @@ class MemoryStore:
79
 
80
  # 3. تحميل، إضافة، وحفظ الدلتا
81
  deltas_list = await self._load_deltas_from_r2(domain)
82
- deltas_list.append(new_delta.model_dump())
83
  await self._save_deltas_to_r2(domain, deltas_list)
84
 
85
  print(f"✅ [MemoryStore] تم حفظ دلتا جديدة لـ {domain}. الحالة: {approval_reason}")
86
 
87
- # 4. تفعيل عملية "التقطير" (Distillation) إذا تم تجاوز الحد (النقطة 6)
88
- if len(deltas_list) % self.distill_threshold == 0 and is_approved:
89
- print(f"ℹ️ [MemoryStore] تم الوصول إلى حد {self.distill_threshold} دلتا. بدء عملية التقطير...")
90
- # (سنقوم باستدعاء عملية التقطير في الخلفية)
91
- # asyncio.create_task(self.distill_domain(domain))
92
- # (ملاحظة: التقطير سيتم تنفيذه في ملف curator.py لاحقاً)
93
- pass
94
 
95
  except Exception as e:
96
  print(f"❌ [MemoryStore] فشل فادح في حفظ الدلتا: {e}")
 
 
97
 
98
  async def get_active_context(self, domain: str, query: str, top_k: int = 3) -> str:
99
  """
100
  جلب "السياق النشط" (Active Context) لإرساله إلى النموذج.
101
- (تنفيذ النقطة 2 و 5 - خوارزمية الاسترجاع)
102
  """
103
  try:
104
  all_deltas_dicts = await self._load_deltas_from_r2(domain)
@@ -107,55 +109,49 @@ class MemoryStore:
107
  approved_deltas = [Delta(**d) for d in all_deltas_dicts if d.get('approved', False)]
108
 
109
  if not approved_deltas:
110
- return "No approved deltas (rules) found for this domain."
111
-
112
- # 2. خوارزمية الاسترجاع (تنفيذ النقطة 5)
113
- # (نسخة مبسطة تعتمد على الثقة والأولوية والكلمات المفتاحية)
114
- # (لا يمكننا استخدام semantic_sim بدون نموذج تضمين، لذا سنستخدم مطابقة الكلمات)
115
-
116
  scored_deltas = []
117
  for delta in approved_deltas:
118
- # أ. حساب الأولوية (priority_score)
119
  priority_map = {"high": 1.0, "medium": 0.6, "low": 0.2}
120
  priority_score = priority_map.get(delta.priority, 0.6)
121
 
122
- # ب. حساب الحداثة (freshness_score)
123
  try:
124
  age_days = (datetime.now() - datetime.fromisoformat(delta.created_at)).days
125
- freshness_score = max(0, 1.0 - (age_days / 90.0)) # (تتلاشى بعد 90 يوم)
126
  except Exception:
127
  freshness_score = 0.5
128
 
129
- # ج. حساب "الملاءمة" (relevance_score) - بديل مبسط لـ semantic_sim
130
- relevance_score = 0.5 # افتراضي
131
  query_words = set(query.lower().split())
132
  delta_words = set(delta.text.lower().split())
133
  if query_words.intersection(delta_words):
134
- relevance_score = 1.0 # (مطابقة تامة للكلمات)
135
  elif delta.trade_strategy and delta.trade_strategy.lower() in query_words:
136
- relevance_score = 0.8 # (مطابقة للاستراتيجية)
137
 
138
- # د. النتيجة الإجمالية (مستوحاة من النقطة 5)
139
- # score_total = 0.7*semantic_sim + 0.2*priority + 0.1*freshness
140
  final_score = (0.6 * relevance_score) + (0.3 * priority_score) + (0.1 * freshness_score)
141
-
142
  scored_deltas.append((final_score, delta))
143
 
144
  # 3. فرز واختيار أفضل K
145
  scored_deltas.sort(key=lambda x: x[0], reverse=True)
146
  top_deltas = [delta for score, delta in scored_deltas[:top_k]]
147
 
148
- # 4. تنسيق الموجه (النقطة 3 - ActiveContext)
149
  if not top_deltas:
150
- return "No relevant deltas (rules) found for this query."
151
 
152
  playbook_header = f"Playbook (Top {len(top_deltas)} Rules - Domain: {domain}):"
153
- delta_lines = [f"• {delta.text} (Ref: {delta.id})" for delta in top_deltas]
 
154
 
155
- # (ملاحظة: Distilled rule ستتم إضافتها لاحقاً بواسطة Curator)
156
 
157
  return "\n".join([playbook_header] + delta_lines)
158
 
159
  except Exception as e:
160
  print(f"❌ [MemoryStore] فشل جلب السياق النشط: {e}")
161
- return "Error retrieving learning context."
 
 
2
  import json
3
  import asyncio
4
  from datetime import datetime
5
+ # 🔴 --- START OF CHANGE --- 🔴
6
+ from typing import List, Dict, Optional, Any # (Import Any here)
7
+ # 🔴 --- END OF CHANGE --- 🔴
8
  from .schemas import Delta, ReflectorOutput
9
  from .policy_engine import PolicyEngine
10
 
 
12
  # (لا يمكننا استيراده مباشرة لتجنب التبعيات الدائرية)
13
 
14
  class MemoryStore:
15
+ # (The __init__ signature now correctly uses the imported Any)
16
  def __init__(self, r2_service: Any, policy_engine: PolicyEngine, llm_service: Any):
17
  self.r2_service = r2_service
18
  self.policy_engine = policy_engine
 
27
  }
28
 
29
  self.distill_threshold = 50 # (من النقطة 6)
30
+ print("✅ Learning Hub Module: Memory Store loaded (FIXED: Imported Any)")
31
 
32
  async def _load_deltas_from_r2(self, domain: str) -> List[Dict]:
33
  """تحميل ملف الدلتا المحدد من R2"""
 
45
  """حفظ ملف الدلتا المحدث إلى R2"""
46
  key = self.domain_files.get(domain, self.domain_files["general"])
47
  try:
48
+ # (Ensure list contains dicts before saving)
49
+ deltas_to_save = [d.model_dump() if isinstance(d, Delta) else d for d in deltas_list]
50
+ data_json = json.dumps(deltas_to_save, indent=2, ensure_ascii=False).encode('utf-8')
51
  self.r2_service.s3_client.put_object(
52
  Bucket="trading", Key=key, Body=data_json, ContentType="application/json"
53
  )
54
  except Exception as e:
55
  print(f"❌ [MemoryStore] فشل حفظ الدلتا إلى R2: {e}")
56
 
57
+ async def save_new_delta(self,
58
+ reflector_output: ReflectorOutput,
59
+ trade_object: Dict[str, Any],
60
  domain: str = "strategy"):
61
  """
62
  حفظ "دلتا" جديدة بناءً على مخرجات المنعكس وسياسة القبول.
 
63
  """
64
  try:
65
  trade_pnl_percent = trade_object.get('pnl_percent', 0)
66
 
67
+ # 1. التحقق من سياسة القبول
68
  is_approved, approval_reason = self.policy_engine.get_delta_acceptance(
69
+ reflector_output,
70
  trade_pnl_percent
71
  )
72
 
73
+ # 2. إنشاء كائن الدلتا
74
  new_delta = Delta(
75
  text=reflector_output.suggested_rule,
76
  domain=domain,
77
+ score=reflector_output.confidence,
78
  evidence_refs=[trade_object.get('id', 'unknown_trade_id')],
79
  approved=is_approved,
80
  trade_strategy=trade_object.get('strategy', 'unknown'),
 
83
 
84
  # 3. تحميل، إضافة، وحفظ الدلتا
85
  deltas_list = await self._load_deltas_from_r2(domain)
86
+ deltas_list.append(new_delta.model_dump()) # Use model_dump() for pydantic models
87
  await self._save_deltas_to_r2(domain, deltas_list)
88
 
89
  print(f"✅ [MemoryStore] تم حفظ دلتا جديدة لـ {domain}. الحالة: {approval_reason}")
90
 
91
+ # 4. تفعيل عملية "التقطير" (لا يتم تنفيذها هنا مباشرة)
92
+ if len([d for d in deltas_list if d.get('approved')]) % self.distill_threshold == 0 and is_approved:
93
+ print(f"ℹ️ [MemoryStore] تم الوصول إلى حد {self.distill_threshold} دلتا لـ {domain}. التقطير سيتم جدولته.")
94
+ # (Curator will handle the actual check and distillation)
 
 
 
95
 
96
  except Exception as e:
97
  print(f"❌ [MemoryStore] فشل فادح في حفظ الدلتا: {e}")
98
+ traceback.print_exc()
99
+
100
 
101
  async def get_active_context(self, domain: str, query: str, top_k: int = 3) -> str:
102
  """
103
  جلب "السياق النشط" (Active Context) لإرساله إلى النموذج.
 
104
  """
105
  try:
106
  all_deltas_dicts = await self._load_deltas_from_r2(domain)
 
109
  approved_deltas = [Delta(**d) for d in all_deltas_dicts if d.get('approved', False)]
110
 
111
  if not approved_deltas:
112
+ # (Return English text for consistency)
113
+ return "Playbook: No approved learning rules (Deltas) found for this domain yet."
114
+
115
+ # 2. خوارزمية الاسترجاع (نسخة مبسطة)
 
 
116
  scored_deltas = []
117
  for delta in approved_deltas:
 
118
  priority_map = {"high": 1.0, "medium": 0.6, "low": 0.2}
119
  priority_score = priority_map.get(delta.priority, 0.6)
120
 
 
121
  try:
122
  age_days = (datetime.now() - datetime.fromisoformat(delta.created_at)).days
123
+ freshness_score = max(0, 1.0 - (age_days / 90.0))
124
  except Exception:
125
  freshness_score = 0.5
126
 
127
+ relevance_score = 0.5
 
128
  query_words = set(query.lower().split())
129
  delta_words = set(delta.text.lower().split())
130
  if query_words.intersection(delta_words):
131
+ relevance_score = 1.0
132
  elif delta.trade_strategy and delta.trade_strategy.lower() in query_words:
133
+ relevance_score = 0.8
134
 
 
 
135
  final_score = (0.6 * relevance_score) + (0.3 * priority_score) + (0.1 * freshness_score)
 
136
  scored_deltas.append((final_score, delta))
137
 
138
  # 3. فرز واختيار أفضل K
139
  scored_deltas.sort(key=lambda x: x[0], reverse=True)
140
  top_deltas = [delta for score, delta in scored_deltas[:top_k]]
141
 
142
+ # 4. تنسيق الموجه (باللغة الإنجليزية)
143
  if not top_deltas:
144
+ return "Playbook: No relevant learning rules (Deltas) found for this query."
145
 
146
  playbook_header = f"Playbook (Top {len(top_deltas)} Rules - Domain: {domain}):"
147
+ # (Added score for context)
148
+ delta_lines = [f"• {delta.text} (Score: {delta.score:.2f}, Prio: {delta.priority})" for delta in top_deltas]
149
 
150
+ # (Distilled rules are just high-priority deltas in this implementation)
151
 
152
  return "\n".join([playbook_header] + delta_lines)
153
 
154
  except Exception as e:
155
  print(f"❌ [MemoryStore] فشل جلب السياق النشط: {e}")
156
+ # (Return English text for consistency)
157
+ return "Playbook: Error retrieving learning context."