npcpy 1.2.18__py3-none-any.whl → 1.2.20__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,164 +1,171 @@
1
- import torch
2
- import torch.nn as nn
3
1
  try:
4
- from transformers import AutoTokenizer, AutoModelForSequenceClassification, Trainer, TrainingArguments
5
2
  from torch.utils.data import Dataset
6
- except:
7
- pass
8
- import json
9
- from typing import List, Dict, Tuple
10
- import random
3
+ import torch
4
+ import torch.nn as nn
5
+ from transformers import AutoTokenizer, AutoModelForSequenceClassification, Trainer, TrainingArguments
11
6
 
12
- class MemoryDataset(Dataset):
13
- def __init__(self, examples: List[Dict], tokenizer, max_length=512):
14
- self.examples = examples
15
- self.tokenizer = tokenizer
16
- self.max_length = max_length
17
-
18
- def __len__(self):
19
- return len(self.examples)
20
-
21
- def __getitem__(self, idx):
22
- example = self.examples[idx]
23
-
24
-
25
- text = f"Memory: {example['memory']}\nContext: {example.get('context', '')}"
26
-
27
- encoding = self.tokenizer(
28
- text,
29
- truncation=True,
30
- padding='max_length',
31
- max_length=self.max_length,
32
- return_tensors='pt'
33
- )
34
-
35
- return {
36
- 'input_ids': encoding['input_ids'].flatten(),
37
- 'attention_mask': encoding['attention_mask'].flatten(),
38
- 'labels': torch.tensor(example['label'], dtype=torch.long)
39
- }
7
+ import json
8
+ from typing import List, Dict, Tuple
9
+ import random
40
10
 
41
- class MemoryTrainer:
42
- def __init__(self, model_name="google/gemma-2b", device="cpu"):
43
- self.device = device
44
- self.tokenizer = AutoTokenizer.from_pretrained(model_name)
45
- if self.tokenizer.pad_token is None:
46
- self.tokenizer.pad_token = self.tokenizer.eos_token
47
-
48
-
49
- self.model = AutoModelForSequenceClassification.from_pretrained(
50
- model_name,
51
- num_labels=3
52
- ).to(device)
53
-
54
- def prepare_training_data(self, approved_memories: List[Dict],
55
- rejected_memories: List[Dict]) -> List[Dict]:
56
- """Prepare training data from memory examples"""
57
- examples = []
58
-
59
-
60
- for memory in approved_memories:
61
- examples.append({
62
- "memory": memory.get("final_memory") or memory.get("initial_memory"),
63
- "context": memory.get("context", ""),
64
- "label": 1
65
- })
66
-
67
-
68
- for memory in rejected_memories:
69
- examples.append({
70
- "memory": memory.get("initial_memory"),
71
- "context": memory.get("context", ""),
72
- "label": 0
73
- })
74
-
75
-
76
- edited_examples = []
77
- for memory in approved_memories[:len(rejected_memories)//2]:
78
- if memory.get("final_memory") and memory.get("initial_memory"):
79
-
80
- edited_examples.append({
11
+ class MemoryDataset(Dataset):
12
+ def __init__(self, examples: List[Dict], tokenizer, max_length=512):
13
+ self.examples = examples
14
+ self.tokenizer = tokenizer
15
+ self.max_length = max_length
16
+
17
+ def __len__(self):
18
+ return len(self.examples)
19
+
20
+ def __getitem__(self, idx):
21
+ example = self.examples[idx]
22
+
23
+
24
+ text = f"Memory: {example['memory']}\nContext: {example.get('context', '')}"
25
+
26
+ encoding = self.tokenizer(
27
+ text,
28
+ truncation=True,
29
+ padding='max_length',
30
+ max_length=self.max_length,
31
+ return_tensors='pt'
32
+ )
33
+
34
+ return {
35
+ 'input_ids': encoding['input_ids'].flatten(),
36
+ 'attention_mask': encoding['attention_mask'].flatten(),
37
+ 'labels': torch.tensor(example['label'], dtype=torch.long)
38
+ }
39
+
40
+ class MemoryTrainer:
41
+ def __init__(self, model_name="google/gemma-2b", device="cpu"):
42
+ self.device = device
43
+ self.tokenizer = AutoTokenizer.from_pretrained(model_name)
44
+ if self.tokenizer.pad_token is None:
45
+ self.tokenizer.pad_token = self.tokenizer.eos_token
46
+
47
+
48
+ self.model = AutoModelForSequenceClassification.from_pretrained(
49
+ model_name,
50
+ num_labels=3
51
+ ).to(device)
52
+
53
+ def prepare_training_data(self, approved_memories: List[Dict],
54
+ rejected_memories: List[Dict]) -> List[Dict]:
55
+ """Prepare training data from memory examples"""
56
+ examples = []
57
+
58
+
59
+ for memory in approved_memories:
60
+ examples.append({
61
+ "memory": memory.get("final_memory") or memory.get("initial_memory"),
62
+ "context": memory.get("context", ""),
63
+ "label": 1
64
+ })
65
+
66
+
67
+ for memory in rejected_memories:
68
+ examples.append({
81
69
  "memory": memory.get("initial_memory"),
82
70
  "context": memory.get("context", ""),
83
- "label": 2
71
+ "label": 0
84
72
  })
85
-
86
- examples.extend(edited_examples)
87
- random.shuffle(examples)
88
- return examples
73
+
74
+
75
+ edited_examples = []
76
+ for memory in approved_memories[:len(rejected_memories)//2]:
77
+ if memory.get("final_memory") and memory.get("initial_memory"):
78
+
79
+ edited_examples.append({
80
+ "memory": memory.get("initial_memory"),
81
+ "context": memory.get("context", ""),
82
+ "label": 2
83
+ })
84
+
85
+ examples.extend(edited_examples)
86
+ random.shuffle(examples)
87
+ return examples
89
88
 
90
- def train(self, approved_memories: List[Dict], rejected_memories: List[Dict],
91
- output_dir: str = "./memory_model", epochs: int = 3):
92
- """Train the memory classification model"""
93
-
94
- if len(approved_memories) < 10 or len(rejected_memories) < 10:
95
- print("Not enough training data. Need at least 10 approved and 10 rejected memories.")
96
- return False
97
-
98
- training_data = self.prepare_training_data(approved_memories, rejected_memories)
99
-
100
-
101
- split_idx = int(0.8 * len(training_data))
102
- train_data = training_data[:split_idx]
103
- val_data = training_data[split_idx:]
104
-
105
- train_dataset = MemoryDataset(train_data, self.tokenizer)
106
- val_dataset = MemoryDataset(val_data, self.tokenizer)
107
-
108
- training_args = TrainingArguments(
109
- output_dir=output_dir,
110
- num_train_epochs=epochs,
111
- per_device_train_batch_size=4,
112
- per_device_eval_batch_size=4,
113
- warmup_steps=100,
114
- weight_decay=0.01,
115
- logging_dir='./logs',
116
- evaluation_strategy="epoch",
117
- save_strategy="epoch",
118
- load_best_model_at_end=True,
119
- )
120
-
121
- trainer = Trainer(
122
- model=self.model,
123
- args=training_args,
124
- train_dataset=train_dataset,
125
- eval_dataset=val_dataset,
126
- )
127
-
128
- trainer.train()
129
- trainer.save_model()
130
- self.tokenizer.save_pretrained(output_dir)
131
-
132
- print(f"Model trained and saved to {output_dir}")
133
- return True
89
+ def train(self, approved_memories: List[Dict], rejected_memories: List[Dict],
90
+ output_dir: str = "./memory_model", epochs: int = 3):
91
+ """Train the memory classification model"""
92
+
93
+ if len(approved_memories) < 10 or len(rejected_memories) < 10:
94
+ print("Not enough training data. Need at least 10 approved and 10 rejected memories.")
95
+ return False
96
+
97
+ training_data = self.prepare_training_data(approved_memories, rejected_memories)
98
+
99
+
100
+ split_idx = int(0.8 * len(training_data))
101
+ train_data = training_data[:split_idx]
102
+ val_data = training_data[split_idx:]
103
+
104
+ train_dataset = MemoryDataset(train_data, self.tokenizer)
105
+ val_dataset = MemoryDataset(val_data, self.tokenizer)
106
+
107
+ training_args = TrainingArguments(
108
+ output_dir=output_dir,
109
+ num_train_epochs=epochs,
110
+ per_device_train_batch_size=4,
111
+ per_device_eval_batch_size=4,
112
+ warmup_steps=100,
113
+ weight_decay=0.01,
114
+ logging_dir='./logs',
115
+ evaluation_strategy="epoch",
116
+ save_strategy="epoch",
117
+ load_best_model_at_end=True,
118
+ )
119
+
120
+ trainer = Trainer(
121
+ model=self.model,
122
+ args=training_args,
123
+ train_dataset=train_dataset,
124
+ eval_dataset=val_dataset,
125
+ )
126
+
127
+ trainer.train()
128
+ trainer.save_model()
129
+ self.tokenizer.save_pretrained(output_dir)
130
+
131
+ print(f"Model trained and saved to {output_dir}")
132
+ return True
134
133
 
135
- def predict_memory_action(self, memory_content: str, context: str = "") -> Tuple[str, float]:
136
- """Predict what action to take on a memory"""
137
- text = f"Memory: {memory_content}\nContext: {context}"
138
-
139
- encoding = self.tokenizer(
140
- text,
141
- truncation=True,
142
- padding=True,
143
- max_length=512,
144
- return_tensors='pt'
145
- ).to(self.device)
146
-
147
- with torch.no_grad():
148
- outputs = self.model(**encoding)
149
- probabilities = torch.softmax(outputs.logits, dim=-1)
150
- predicted_class = torch.argmax(probabilities, dim=-1).item()
151
- confidence = probabilities[0][predicted_class].item()
152
-
153
- actions = {0: "model-rejected", 1: "model-approved", 2: "needs-editing"}
154
- return actions[predicted_class], confidence
134
+ def predict_memory_action(self, memory_content: str, context: str = "") -> Tuple[str, float]:
135
+ """Predict what action to take on a memory"""
136
+ text = f"Memory: {memory_content}\nContext: {context}"
137
+
138
+ encoding = self.tokenizer(
139
+ text,
140
+ truncation=True,
141
+ padding=True,
142
+ max_length=512,
143
+ return_tensors='pt'
144
+ ).to(self.device)
145
+
146
+ with torch.no_grad():
147
+ outputs = self.model(**encoding)
148
+ probabilities = torch.softmax(outputs.logits, dim=-1)
149
+ predicted_class = torch.argmax(probabilities, dim=-1).item()
150
+ confidence = probabilities[0][predicted_class].item()
151
+
152
+ actions = {0: "model-rejected", 1: "model-approved", 2: "needs-editing"}
153
+ return actions[predicted_class], confidence
155
154
 
156
- def auto_approve_memory(self, memory_content: str, context: str = "",
157
- confidence_threshold: float = 0.8) -> Dict:
158
- """Auto-approve memory if confidence is high enough"""
159
- action, confidence = self.predict_memory_action(memory_content, context)
160
-
161
- if confidence >= confidence_threshold:
162
- return {"action": action, "confidence": confidence, "auto_processed": True}
163
- else:
164
- return {"action": "pending_approval", "confidence": confidence, "auto_processed": False}
155
+ def auto_approve_memory(self, memory_content: str, context: str = "",
156
+ confidence_threshold: float = 0.8) -> Dict:
157
+ """Auto-approve memory if confidence is high enough"""
158
+ action, confidence = self.predict_memory_action(memory_content, context)
159
+
160
+ if confidence >= confidence_threshold:
161
+ return {"action": action, "confidence": confidence, "auto_processed": True}
162
+ else:
163
+ return {"action": "pending_approval", "confidence": confidence, "auto_processed": False}
164
+ except:
165
+ Dataset = None
166
+ nn = None
167
+ Trainer = None
168
+ TrainingArguments = None
169
+
170
+ MemoryDataset = None
171
+ MemoryTrainer = None
@@ -17,96 +17,6 @@ class MemoryItem:
17
17
  model: str
18
18
  provider: str
19
19
 
20
- class MemoryApprovalQueue:
21
- def __init__(self, command_history):
22
- self.command_history = command_history
23
- self.pending_queue = queue.Queue()
24
- self.approval_results = queue.Queue()
25
- self.processing_thread = None
26
- self.running = False
27
-
28
- def add_memory(self, memory_item: MemoryItem):
29
- """Add memory to processing queue (non-blocking)"""
30
- self.pending_queue.put(memory_item)
31
-
32
- def start_background_processing(self):
33
- """Start background thread for memory processing"""
34
- if self.processing_thread and self.processing_thread.is_alive():
35
- return
36
-
37
- self.running = True
38
- self.processing_thread = threading.Thread(target=self._process_queue)
39
- self.processing_thread.daemon = True
40
- self.processing_thread.start()
41
-
42
- def _process_queue(self):
43
- """Background processing of memory queue"""
44
- while self.running:
45
- try:
46
-
47
- batch = []
48
- try:
49
-
50
- memory = self.pending_queue.get(timeout=1.0)
51
- batch.append(memory)
52
-
53
-
54
- while len(batch) < 10:
55
- try:
56
- memory = self.pending_queue.get_nowait()
57
- batch.append(memory)
58
- except queue.Empty:
59
- break
60
-
61
- self._process_memory_batch(batch)
62
-
63
- except queue.Empty:
64
- continue
65
-
66
- except Exception as e:
67
- print(f"Error in memory processing: {e}")
68
- time.sleep(1)
69
-
70
- def _process_memory_batch(self, memories: List[MemoryItem]):
71
- """Process a batch of memories"""
72
- for memory in memories:
73
-
74
- memory_id = self.command_history.add_memory_to_database(
75
- message_id=memory.message_id,
76
- conversation_id=memory.conversation_id,
77
- npc=memory.npc,
78
- team=memory.team,
79
- directory_path=memory.directory_path,
80
- initial_memory=memory.content,
81
- status="pending_approval",
82
- model=memory.model,
83
- provider=memory.provider
84
- )
85
-
86
-
87
- self.approval_results.put({
88
- "memory_id": memory_id,
89
- "content": memory.content,
90
- "context": memory.context,
91
- "npc": memory.npc
92
- })
93
-
94
- def get_approval_batch(self, max_items: int = 5) -> List[Dict]:
95
- """Get batch of memories ready for approval"""
96
- batch = []
97
- try:
98
- while len(batch) < max_items:
99
- item = self.approval_results.get_nowait()
100
- batch.append(item)
101
- except queue.Empty:
102
- pass
103
- return batch
104
-
105
- def stop_processing(self):
106
- """Stop background processing"""
107
- self.running = False
108
- if self.processing_thread:
109
- self.processing_thread.join(timeout=2.0)
110
20
 
111
21
  def memory_approval_ui(memories: List[Dict]) -> List[Dict]:
112
22
  """Simple CLI interface for memory approval"""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: npcpy
3
- Version: 1.2.18
3
+ Version: 1.2.20
4
4
  Summary: npcpy is the premier open-source library for integrating LLMs and Agents into python systems.
5
5
  Home-page: https://github.com/NPC-Worldwide/npcpy
6
6
  Author: Christopher Agostino
@@ -17,7 +17,7 @@ npcpy/data/web.py,sha256=ARGoVKUlQmaiX0zJbSvvFmRCwOv_Z7Pcan9c5GxYObQ,5117
17
17
  npcpy/ft/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
18
  npcpy/ft/diff.py,sha256=R3Qo6v0-6M1iI0wiXhUzyuYI2ja0q_0i9bE0z3coxzU,28
19
19
  npcpy/ft/ge.py,sha256=my5LtGyVTT40V0i1h9FR-tFFA1FHSga-PeCCgUX1UUI,61
20
- npcpy/ft/memory_trainer.py,sha256=Ne-qoDnCUl-tRQ_iSZjsUy8C8_-FoL89I9ovo7jqCBU,5896
20
+ npcpy/ft/memory_trainer.py,sha256=QZPznxEEwXbOGroHdMUMa5xpqlNwgV6nqOazI2xgrnQ,6635
21
21
  npcpy/ft/rl.py,sha256=l3RUkEJe4b2yB6pildveu2LJymtNq0F17COwf_CCq3U,34
22
22
  npcpy/ft/sft.py,sha256=i4ENygRPArbLWN4XZZuBnPWaehs8M-J68JB_mewGJHI,62
23
23
  npcpy/gen/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -30,7 +30,7 @@ npcpy/memory/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
30
  npcpy/memory/command_history.py,sha256=Ww7vZTSjQDuElQXuOjsvu7NTljOLAg07QIFrfKARpVg,45562
31
31
  npcpy/memory/kg_vis.py,sha256=TrQQCRh_E7Pyr-GPAHLSsayubAfGyf4HOEFrPB6W86Q,31280
32
32
  npcpy/memory/knowledge_graph.py,sha256=2XpIlsyPdAOnzQ6kkwP6MWPGwL3P6V33_3suNJYMMJE,48681
33
- npcpy/memory/memory_processor.py,sha256=nK5vWTLeevAQDXM15wF9MSTK6Yr-qYCjgiwmCKXWTSI,5288
33
+ npcpy/memory/memory_processor.py,sha256=bLfzT-uDgwNegs1hVBqW3Hl2fYtdmFQbdc5To_f4i5E,2106
34
34
  npcpy/memory/search.py,sha256=glN6WYzaixcoDphTEHAXSMX3vKZGjR12Jx9YVL_gYfE,18433
35
35
  npcpy/mix/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
36
  npcpy/mix/debate.py,sha256=lQXxC7nl6Rwyf7HIYrsVQILMUmYYx55Tjt2pkTg56qY,9019
@@ -41,8 +41,8 @@ npcpy/work/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
41
41
  npcpy/work/desktop.py,sha256=F3I8mUtJp6LAkXodsh8hGZIncoads6c_2Utty-0EdDA,2986
42
42
  npcpy/work/plan.py,sha256=QyUwg8vElWiHuoS-xK4jXTxxHvkMD3VkaCEsCmrEPQk,8300
43
43
  npcpy/work/trigger.py,sha256=P1Y8u1wQRsS2WACims_2IdkBEar-iBQix-2TDWoW0OM,9948
44
- npcpy-1.2.18.dist-info/licenses/LICENSE,sha256=j0YPvce7Ng9e32zYOu0EmXjXeJ0Nwawd0RA3uSGGH4E,1070
45
- npcpy-1.2.18.dist-info/METADATA,sha256=uewXn2ASHxuVuCjL3UmFjyVUCV6LuWaEsSmx1uogluo,26084
46
- npcpy-1.2.18.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
47
- npcpy-1.2.18.dist-info/top_level.txt,sha256=g1pbSvrOOncB74Bg5-J0Olg4V0A5VzDw-Xz5YObq8BU,6
48
- npcpy-1.2.18.dist-info/RECORD,,
44
+ npcpy-1.2.20.dist-info/licenses/LICENSE,sha256=j0YPvce7Ng9e32zYOu0EmXjXeJ0Nwawd0RA3uSGGH4E,1070
45
+ npcpy-1.2.20.dist-info/METADATA,sha256=P5knjysgVTcYCKlMkbJT-iiw_t9cy1SlskD2YuyknHE,26084
46
+ npcpy-1.2.20.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
47
+ npcpy-1.2.20.dist-info/top_level.txt,sha256=g1pbSvrOOncB74Bg5-J0Olg4V0A5VzDw-Xz5YObq8BU,6
48
+ npcpy-1.2.20.dist-info/RECORD,,
File without changes