npcpy 1.3.19__py3-none-any.whl → 1.3.21__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.
- npcpy/data/web.py +113 -8
- npcpy/llm_funcs.py +3 -4
- npcpy/memory/command_history.py +85 -9
- npcpy/memory/knowledge_graph.py +554 -33
- npcpy/memory/memory_processor.py +269 -53
- npcpy/npc_compiler.py +6 -0
- npcpy/npc_sysenv.py +24 -2
- npcpy/serve.py +25 -1
- {npcpy-1.3.19.dist-info → npcpy-1.3.21.dist-info}/METADATA +3 -1
- {npcpy-1.3.19.dist-info → npcpy-1.3.21.dist-info}/RECORD +13 -13
- {npcpy-1.3.19.dist-info → npcpy-1.3.21.dist-info}/WHEEL +1 -1
- {npcpy-1.3.19.dist-info → npcpy-1.3.21.dist-info}/licenses/LICENSE +0 -0
- {npcpy-1.3.19.dist-info → npcpy-1.3.21.dist-info}/top_level.txt +0 -0
npcpy/memory/memory_processor.py
CHANGED
|
@@ -4,6 +4,13 @@ from datetime import datetime
|
|
|
4
4
|
import threading
|
|
5
5
|
import queue
|
|
6
6
|
import time
|
|
7
|
+
import os
|
|
8
|
+
|
|
9
|
+
try:
|
|
10
|
+
from termcolor import colored
|
|
11
|
+
except ImportError:
|
|
12
|
+
def colored(text, color=None, on_color=None, attrs=None):
|
|
13
|
+
return text
|
|
7
14
|
|
|
8
15
|
@dataclass
|
|
9
16
|
class MemoryItem:
|
|
@@ -17,65 +24,274 @@ class MemoryItem:
|
|
|
17
24
|
model: str
|
|
18
25
|
provider: str
|
|
19
26
|
|
|
20
|
-
|
|
27
|
+
|
|
28
|
+
def _clear_line():
|
|
29
|
+
"""Clear current line in terminal."""
|
|
30
|
+
print('\r' + ' ' * 80 + '\r', end='')
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _print_header(title: str, width: int = 60):
|
|
34
|
+
"""Print a styled header."""
|
|
35
|
+
print(colored("=" * width, "cyan"))
|
|
36
|
+
print(colored(f" {title}", "cyan", attrs=["bold"]))
|
|
37
|
+
print(colored("=" * width, "cyan"))
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _print_memory_box(memory: Dict, index: int, total: int):
|
|
41
|
+
"""Print a memory in a nice box format."""
|
|
42
|
+
width = 70
|
|
43
|
+
|
|
44
|
+
# Header with progress
|
|
45
|
+
progress = f"[{index}/{total}]"
|
|
46
|
+
npc_info = f"NPC: {memory.get('npc', 'unknown')}"
|
|
47
|
+
header = f"{progress} {npc_info}"
|
|
48
|
+
print(colored("+" + "-" * (width - 2) + "+", "blue"))
|
|
49
|
+
print(colored(f"| {header:<{width-4}} |", "blue"))
|
|
50
|
+
print(colored("+" + "-" * (width - 2) + "+", "blue"))
|
|
51
|
+
|
|
52
|
+
# Content
|
|
53
|
+
content = memory.get('content', '')
|
|
54
|
+
# Wrap content to fit in box
|
|
55
|
+
lines = []
|
|
56
|
+
words = content.split()
|
|
57
|
+
current_line = ""
|
|
58
|
+
for word in words:
|
|
59
|
+
if len(current_line) + len(word) + 1 <= width - 6:
|
|
60
|
+
current_line += (" " if current_line else "") + word
|
|
61
|
+
else:
|
|
62
|
+
if current_line:
|
|
63
|
+
lines.append(current_line)
|
|
64
|
+
current_line = word
|
|
65
|
+
if current_line:
|
|
66
|
+
lines.append(current_line)
|
|
67
|
+
|
|
68
|
+
for line in lines[:6]: # Max 6 lines
|
|
69
|
+
print(colored(f"| {line:<{width-5}} |", "white"))
|
|
70
|
+
|
|
71
|
+
if len(lines) > 6:
|
|
72
|
+
print(colored(f"| {'...':<{width-5}} |", "grey"))
|
|
73
|
+
|
|
74
|
+
# Context if available
|
|
75
|
+
ctx = memory.get('context', '')
|
|
76
|
+
if ctx:
|
|
77
|
+
print(colored("+" + "-" * (width - 2) + "+", "blue"))
|
|
78
|
+
ctx_short = ctx[:width-8] + "..." if len(ctx) > width - 8 else ctx
|
|
79
|
+
print(colored(f"| {ctx_short:<{width-4}} |", "grey"))
|
|
80
|
+
|
|
81
|
+
print(colored("+" + "-" * (width - 2) + "+", "blue"))
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _print_options():
|
|
85
|
+
"""Print available options."""
|
|
86
|
+
print()
|
|
87
|
+
options = [
|
|
88
|
+
(colored("a", "green", attrs=["bold"]), "approve"),
|
|
89
|
+
(colored("r", "red", attrs=["bold"]), "reject"),
|
|
90
|
+
(colored("e", "yellow", attrs=["bold"]), "edit"),
|
|
91
|
+
(colored("s", "grey"), "skip"),
|
|
92
|
+
(colored("A", "green"), "approve all"),
|
|
93
|
+
(colored("R", "red"), "reject all"),
|
|
94
|
+
(colored("D", "cyan"), "defer (review later)"),
|
|
95
|
+
]
|
|
96
|
+
print(" " + " | ".join([f"({k}) {v}" for k, v in options]))
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def _print_summary(stats: Dict):
|
|
100
|
+
"""Print approval summary."""
|
|
101
|
+
print()
|
|
102
|
+
_print_header("Memory Review Summary")
|
|
103
|
+
print(f" {colored('Approved:', 'green')} {stats.get('approved', 0)}")
|
|
104
|
+
print(f" {colored('Rejected:', 'red')} {stats.get('rejected', 0)}")
|
|
105
|
+
print(f" {colored('Edited:', 'yellow')} {stats.get('edited', 0)}")
|
|
106
|
+
print(f" {colored('Skipped:', 'grey')} {stats.get('skipped', 0)}")
|
|
107
|
+
print(f" {colored('Deferred:', 'cyan')} {stats.get('deferred', 0)}")
|
|
108
|
+
print()
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def memory_approval_ui(memories: List[Dict], show_context: bool = True) -> List[Dict]:
|
|
112
|
+
"""
|
|
113
|
+
Enhanced memory approval UI with better formatting.
|
|
114
|
+
|
|
115
|
+
Args:
|
|
116
|
+
memories: List of memory dicts with 'memory_id', 'content', 'npc', 'context'
|
|
117
|
+
show_context: Whether to show context info
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
List of approval dicts with 'memory_id', 'decision', optionally 'final_memory'
|
|
121
|
+
"""
|
|
21
122
|
if not memories:
|
|
22
123
|
return []
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
124
|
+
|
|
125
|
+
# Stats tracking
|
|
126
|
+
stats = {'approved': 0, 'rejected': 0, 'edited': 0, 'skipped': 0, 'deferred': 0}
|
|
26
127
|
approvals = []
|
|
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
|
-
|
|
128
|
+
|
|
129
|
+
print()
|
|
130
|
+
_print_header(f"Memory Review - {len(memories)} memories")
|
|
131
|
+
print()
|
|
132
|
+
|
|
133
|
+
i = 0
|
|
134
|
+
while i < len(memories):
|
|
135
|
+
memory = memories[i]
|
|
136
|
+
os.system('clear' if os.name == 'posix' else 'cls') if len(memories) > 3 else None
|
|
137
|
+
|
|
138
|
+
_print_memory_box(memory, i + 1, len(memories))
|
|
139
|
+
_print_options()
|
|
140
|
+
|
|
141
|
+
try:
|
|
142
|
+
choice = input("\n Your choice: ").strip()
|
|
143
|
+
except (EOFError, KeyboardInterrupt):
|
|
144
|
+
print("\n Review cancelled.")
|
|
145
|
+
break
|
|
146
|
+
|
|
147
|
+
if choice == 'a':
|
|
148
|
+
approvals.append({
|
|
149
|
+
"memory_id": memory['memory_id'],
|
|
150
|
+
"decision": "human-approved"
|
|
151
|
+
})
|
|
152
|
+
stats['approved'] += 1
|
|
153
|
+
print(colored(" ✓ Approved", "green"))
|
|
154
|
+
i += 1
|
|
155
|
+
|
|
156
|
+
elif choice == 'r':
|
|
157
|
+
approvals.append({
|
|
158
|
+
"memory_id": memory['memory_id'],
|
|
159
|
+
"decision": "human-rejected"
|
|
160
|
+
})
|
|
161
|
+
stats['rejected'] += 1
|
|
162
|
+
print(colored(" ✗ Rejected", "red"))
|
|
163
|
+
i += 1
|
|
164
|
+
|
|
165
|
+
elif choice == 'e':
|
|
166
|
+
print(colored("\n Current:", "grey"), memory['content'][:100])
|
|
167
|
+
print(colored(" Enter new text (or empty to cancel):", "yellow"))
|
|
168
|
+
try:
|
|
169
|
+
edited = input(" > ").strip()
|
|
55
170
|
if edited:
|
|
56
171
|
approvals.append({
|
|
57
172
|
"memory_id": memory['memory_id'],
|
|
58
173
|
"decision": "human-edited",
|
|
59
174
|
"final_memory": edited
|
|
60
175
|
})
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
176
|
+
stats['edited'] += 1
|
|
177
|
+
print(colored(" ✎ Edited and approved", "yellow"))
|
|
178
|
+
i += 1
|
|
179
|
+
else:
|
|
180
|
+
print(colored(" Edit cancelled", "grey"))
|
|
181
|
+
except (EOFError, KeyboardInterrupt):
|
|
182
|
+
print(colored(" Edit cancelled", "grey"))
|
|
183
|
+
|
|
184
|
+
elif choice == 's':
|
|
185
|
+
stats['skipped'] += 1
|
|
186
|
+
print(colored(" ○ Skipped", "grey"))
|
|
187
|
+
i += 1
|
|
188
|
+
|
|
189
|
+
elif choice == 'A':
|
|
190
|
+
# Approve all remaining
|
|
191
|
+
for remaining in memories[i:]:
|
|
192
|
+
approvals.append({
|
|
193
|
+
"memory_id": remaining['memory_id'],
|
|
194
|
+
"decision": "human-approved"
|
|
195
|
+
})
|
|
196
|
+
stats['approved'] += 1
|
|
197
|
+
print(colored(f" ✓ Approved all {len(memories) - i} remaining", "green"))
|
|
198
|
+
break
|
|
199
|
+
|
|
200
|
+
elif choice == 'R':
|
|
201
|
+
# Reject all remaining
|
|
202
|
+
for remaining in memories[i:]:
|
|
203
|
+
approvals.append({
|
|
204
|
+
"memory_id": remaining['memory_id'],
|
|
205
|
+
"decision": "human-rejected"
|
|
206
|
+
})
|
|
207
|
+
stats['rejected'] += 1
|
|
208
|
+
print(colored(f" ✗ Rejected all {len(memories) - i} remaining", "red"))
|
|
209
|
+
break
|
|
210
|
+
|
|
211
|
+
elif choice == 'D':
|
|
212
|
+
# Defer - don't add to approvals, will remain pending
|
|
213
|
+
stats['deferred'] += len(memories) - i
|
|
214
|
+
print(colored(f" ⏸ Deferred {len(memories) - i} memories for later review", "cyan"))
|
|
215
|
+
break
|
|
216
|
+
|
|
217
|
+
elif choice == 'q':
|
|
218
|
+
print(colored(" Review ended", "grey"))
|
|
219
|
+
break
|
|
220
|
+
|
|
221
|
+
else:
|
|
222
|
+
print(colored(" Invalid choice. Use a/r/e/s/A/R/D", "red"))
|
|
223
|
+
|
|
224
|
+
time.sleep(0.2) # Brief pause for readability
|
|
225
|
+
|
|
226
|
+
_print_summary(stats)
|
|
227
|
+
return approvals
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def memory_batch_review_ui(
|
|
231
|
+
command_history,
|
|
232
|
+
npc_filter: str = None,
|
|
233
|
+
team_filter: str = None,
|
|
234
|
+
limit: int = 50
|
|
235
|
+
) -> Dict[str, int]:
|
|
236
|
+
"""
|
|
237
|
+
Review pending memories from the database in batch.
|
|
238
|
+
|
|
239
|
+
Args:
|
|
240
|
+
command_history: CommandHistory instance
|
|
241
|
+
npc_filter: Optional NPC name filter
|
|
242
|
+
team_filter: Optional team name filter
|
|
243
|
+
limit: Max memories to review
|
|
244
|
+
|
|
245
|
+
Returns:
|
|
246
|
+
Dict with counts of approved/rejected/etc
|
|
247
|
+
"""
|
|
248
|
+
# Get pending memories
|
|
249
|
+
pending = command_history.get_pending_memories(limit=limit)
|
|
250
|
+
|
|
251
|
+
if not pending:
|
|
252
|
+
print(colored("No pending memories to review.", "grey"))
|
|
253
|
+
return {'approved': 0, 'rejected': 0, 'edited': 0, 'skipped': 0}
|
|
254
|
+
|
|
255
|
+
# Filter if specified
|
|
256
|
+
if npc_filter:
|
|
257
|
+
pending = [m for m in pending if m.get('npc') == npc_filter]
|
|
258
|
+
if team_filter:
|
|
259
|
+
pending = [m for m in pending if m.get('team') == team_filter]
|
|
260
|
+
|
|
261
|
+
if not pending:
|
|
262
|
+
print(colored("No memories match the filter criteria.", "grey"))
|
|
263
|
+
return {'approved': 0, 'rejected': 0, 'edited': 0, 'skipped': 0}
|
|
264
|
+
|
|
265
|
+
# Convert to format expected by approval UI
|
|
266
|
+
memories_for_ui = []
|
|
267
|
+
for m in pending:
|
|
268
|
+
memories_for_ui.append({
|
|
269
|
+
'memory_id': m.get('id'),
|
|
270
|
+
'content': m.get('initial_memory', ''),
|
|
271
|
+
'npc': m.get('npc', 'unknown'),
|
|
272
|
+
'context': f"Team: {m.get('team', 'unknown')} | Path: {m.get('directory_path', '')[:30]}"
|
|
273
|
+
})
|
|
274
|
+
|
|
275
|
+
# Run approval UI
|
|
276
|
+
approvals = memory_approval_ui(memories_for_ui)
|
|
277
|
+
|
|
278
|
+
# Apply approvals to database
|
|
279
|
+
stats = {'approved': 0, 'rejected': 0, 'edited': 0, 'skipped': 0}
|
|
280
|
+
|
|
281
|
+
for approval in approvals:
|
|
282
|
+
memory_id = approval['memory_id']
|
|
283
|
+
decision = approval['decision']
|
|
284
|
+
final_memory = approval.get('final_memory')
|
|
285
|
+
|
|
286
|
+
command_history.update_memory_status(memory_id, decision, final_memory)
|
|
287
|
+
|
|
288
|
+
if 'approved' in decision:
|
|
289
|
+
stats['approved'] += 1
|
|
290
|
+
elif 'rejected' in decision:
|
|
291
|
+
stats['rejected'] += 1
|
|
292
|
+
elif 'edited' in decision:
|
|
293
|
+
stats['edited'] += 1
|
|
294
|
+
|
|
295
|
+
stats['skipped'] = len(pending) - len(approvals)
|
|
296
|
+
|
|
297
|
+
return stats
|
npcpy/npc_compiler.py
CHANGED
|
@@ -1370,6 +1370,12 @@ class NPC:
|
|
|
1370
1370
|
# Fallback to direct name match if no base dir
|
|
1371
1371
|
matched_names = [jinx_spec] if jinx_spec in self.team.jinxs_dict else []
|
|
1372
1372
|
|
|
1373
|
+
if not matched_names:
|
|
1374
|
+
raise FileNotFoundError(
|
|
1375
|
+
f"NPC '{self.name}' references jinx '{jinx_spec}' but no matching jinx was found. "
|
|
1376
|
+
f"Available jinxs: {list(self.team.jinxs_dict.keys())[:20]}..."
|
|
1377
|
+
)
|
|
1378
|
+
|
|
1373
1379
|
for jinx_name in matched_names:
|
|
1374
1380
|
if jinx_name in self.team.jinxs_dict:
|
|
1375
1381
|
self.jinxs_dict[jinx_name] = self.team.jinxs_dict[jinx_name]
|
npcpy/npc_sysenv.py
CHANGED
|
@@ -1010,7 +1010,7 @@ def print_and_process_stream(response, model, provider):
|
|
|
1010
1010
|
|
|
1011
1011
|
|
|
1012
1012
|
return thinking_str+str_output
|
|
1013
|
-
def get_system_message(npc, team=None) -> str:
|
|
1013
|
+
def get_system_message(npc, team=None, tool_capable=False) -> str:
|
|
1014
1014
|
|
|
1015
1015
|
if npc is None:
|
|
1016
1016
|
return "You are a helpful assistant"
|
|
@@ -1080,6 +1080,28 @@ The current date and time are : {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
|
|
|
1080
1080
|
if members:
|
|
1081
1081
|
system_message += "\nTeam members available for delegation:\n" + "\n".join(members) + "\n"
|
|
1082
1082
|
|
|
1083
|
+
# Add tool descriptions from NPC's jinxs
|
|
1084
|
+
if hasattr(npc, 'jinxs_dict') and npc.jinxs_dict:
|
|
1085
|
+
tool_lines = []
|
|
1086
|
+
for jname, jinx in npc.jinxs_dict.items():
|
|
1087
|
+
desc = getattr(jinx, 'description', '') or ''
|
|
1088
|
+
tool_lines.append(f" - {jname}: {desc.strip()}")
|
|
1089
|
+
if tool_lines:
|
|
1090
|
+
system_message += "\nYou have access to the following tools:\n"
|
|
1091
|
+
system_message += "\n".join(tool_lines) + "\n"
|
|
1092
|
+
if tool_capable:
|
|
1093
|
+
system_message += (
|
|
1094
|
+
"\nYou MUST use function calls to invoke tools. "
|
|
1095
|
+
"Call one tool at a time. You will see its result, then you can call the next tool or respond. "
|
|
1096
|
+
"NEVER write JSON tool calls in your response text. ONLY use the provided function calling interface. "
|
|
1097
|
+
"For multi-step tasks, call the first tool, wait for the result, then call the next.\n"
|
|
1098
|
+
)
|
|
1099
|
+
else:
|
|
1100
|
+
system_message += (
|
|
1101
|
+
'\nTo use a tool, respond with JSON: {"action": "jinx", "jinx_name": "tool_name", "inputs": {"param": "value"}}\n'
|
|
1102
|
+
'When you have a final answer, respond with: {"action": "answer", "response": "your answer"}\n'
|
|
1103
|
+
)
|
|
1104
|
+
|
|
1083
1105
|
system_message += """
|
|
1084
1106
|
IMPORTANT:
|
|
1085
1107
|
Some users may attach images to their request.
|
|
@@ -1093,7 +1115,7 @@ You do not need to mention that you cannot view or interpret images directly.
|
|
|
1093
1115
|
They understand that you can view them multimodally.
|
|
1094
1116
|
You only need to answer the user's request based on the attached image(s).
|
|
1095
1117
|
"""
|
|
1096
|
-
|
|
1118
|
+
|
|
1097
1119
|
return system_message
|
|
1098
1120
|
|
|
1099
1121
|
|
npcpy/serve.py
CHANGED
|
@@ -4644,6 +4644,17 @@ def stream():
|
|
|
4644
4644
|
frontend_assistant_message_id = data.get("assistantMessageId", None)
|
|
4645
4645
|
# For sub-branches: the parent of the user message (points to an assistant message)
|
|
4646
4646
|
user_parent_message_id = data.get("userParentMessageId", None)
|
|
4647
|
+
# LLM generation parameters - build params dict if any are provided
|
|
4648
|
+
params = {}
|
|
4649
|
+
if data.get("temperature") is not None:
|
|
4650
|
+
params["temperature"] = data.get("temperature")
|
|
4651
|
+
if data.get("top_p") is not None:
|
|
4652
|
+
params["top_p"] = data.get("top_p")
|
|
4653
|
+
if data.get("top_k") is not None:
|
|
4654
|
+
params["top_k"] = data.get("top_k")
|
|
4655
|
+
if data.get("max_tokens") is not None:
|
|
4656
|
+
params["max_tokens"] = data.get("max_tokens")
|
|
4657
|
+
params = params if params else None
|
|
4647
4658
|
|
|
4648
4659
|
if current_path:
|
|
4649
4660
|
loaded_vars = load_project_env(current_path)
|
|
@@ -4767,6 +4778,16 @@ def stream():
|
|
|
4767
4778
|
if os.path.exists(file_path):
|
|
4768
4779
|
with open(file_path, "rb") as f:
|
|
4769
4780
|
file_content_bytes = f.read()
|
|
4781
|
+
else:
|
|
4782
|
+
print(f"Warning: Attachment file does not exist: {file_path}")
|
|
4783
|
+
# Try data fallback if path doesn't exist
|
|
4784
|
+
if "data" in attachment and attachment["data"]:
|
|
4785
|
+
file_content_bytes = base64.b64decode(attachment["data"])
|
|
4786
|
+
import tempfile
|
|
4787
|
+
temp_dir = tempfile.mkdtemp()
|
|
4788
|
+
file_path = os.path.join(temp_dir, file_name)
|
|
4789
|
+
with open(file_path, "wb") as f:
|
|
4790
|
+
f.write(file_content_bytes)
|
|
4770
4791
|
|
|
4771
4792
|
# Fall back to base64 data if no path
|
|
4772
4793
|
elif "data" in attachment and attachment["data"]:
|
|
@@ -4778,7 +4799,8 @@ def stream():
|
|
|
4778
4799
|
with open(file_path, "wb") as f:
|
|
4779
4800
|
f.write(file_content_bytes)
|
|
4780
4801
|
|
|
4781
|
-
if not file_path:
|
|
4802
|
+
if not file_path or file_content_bytes is None:
|
|
4803
|
+
print(f"Warning: Skipping attachment {file_name} - no valid path or data")
|
|
4782
4804
|
continue
|
|
4783
4805
|
|
|
4784
4806
|
attachment_paths_for_llm.append(file_path)
|
|
@@ -5175,6 +5197,7 @@ def stream():
|
|
|
5175
5197
|
attachments=attachments_for_db,
|
|
5176
5198
|
message_id=message_id,
|
|
5177
5199
|
parent_message_id=user_parent_message_id, # For sub-branches: points to assistant message
|
|
5200
|
+
gen_params=params,
|
|
5178
5201
|
)
|
|
5179
5202
|
|
|
5180
5203
|
|
|
@@ -5472,6 +5495,7 @@ def stream():
|
|
|
5472
5495
|
tool_calls=accumulated_tool_calls if accumulated_tool_calls else None,
|
|
5473
5496
|
tool_results=tool_results_for_db if tool_results_for_db else None,
|
|
5474
5497
|
parent_message_id=parent_message_id,
|
|
5498
|
+
gen_params=params,
|
|
5475
5499
|
)
|
|
5476
5500
|
|
|
5477
5501
|
# Start background tasks for memory extraction and context compression
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: npcpy
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.21
|
|
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
|
|
@@ -45,6 +45,7 @@ Requires-Dist: mcp
|
|
|
45
45
|
Provides-Extra: lite
|
|
46
46
|
Requires-Dist: anthropic; extra == "lite"
|
|
47
47
|
Requires-Dist: openai; extra == "lite"
|
|
48
|
+
Requires-Dist: ollama; extra == "lite"
|
|
48
49
|
Requires-Dist: google-generativeai; extra == "lite"
|
|
49
50
|
Requires-Dist: google-genai; extra == "lite"
|
|
50
51
|
Provides-Extra: local
|
|
@@ -66,6 +67,7 @@ Requires-Dist: pyttsx3; extra == "yap"
|
|
|
66
67
|
Provides-Extra: all
|
|
67
68
|
Requires-Dist: anthropic; extra == "all"
|
|
68
69
|
Requires-Dist: openai; extra == "all"
|
|
70
|
+
Requires-Dist: ollama; extra == "all"
|
|
69
71
|
Requires-Dist: google-generativeai; extra == "all"
|
|
70
72
|
Requires-Dist: google-genai; extra == "all"
|
|
71
73
|
Requires-Dist: sentence_transformers; extra == "all"
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
npcpy/__init__.py,sha256=uJcJGjR1mWvE69GySNAufkgiRwJA28zdObDBWaxp0tY,505
|
|
2
2
|
npcpy/build_funcs.py,sha256=vOz6pjV0zS-kYKo0ux-pn9AcppVaR8KIDi2ldOxb3RQ,7479
|
|
3
|
-
npcpy/llm_funcs.py,sha256=
|
|
3
|
+
npcpy/llm_funcs.py,sha256=87aPFenz0a6FD2j5ig1rynmHGeBJC7xCs3HwEEgc_nc,75139
|
|
4
4
|
npcpy/main.py,sha256=RWoRIj6VQLxKdOKvdVyaq2kwG35oRpeXPvp1CAAoG-w,81
|
|
5
5
|
npcpy/ml_funcs.py,sha256=smgeOLnjxGWjmDngE-bcA2ozXX_IzY_7_pS9h2iocEg,24249
|
|
6
6
|
npcpy/npc_array.py,sha256=5qjaA9KjmJ_Zk_VxLrCyVrj73aDXpm3iJf0ngq1yIJk,45721
|
|
7
|
-
npcpy/npc_compiler.py,sha256=
|
|
8
|
-
npcpy/npc_sysenv.py,sha256=
|
|
7
|
+
npcpy/npc_compiler.py,sha256=s_67cyvoao0UwUa4N-jrceWDadvBB9TWYpxcjNPfO18,121941
|
|
8
|
+
npcpy/npc_sysenv.py,sha256=cjMkjSIucx4rZkMPZ9EMjMxwd455Sl0Sn0zzTkNL6rM,46545
|
|
9
9
|
npcpy/npcs.py,sha256=eExuVsbTfrRobTRRptRpDm46jCLWUgbvy4_U7IUQo-c,744
|
|
10
|
-
npcpy/serve.py,sha256=
|
|
10
|
+
npcpy/serve.py,sha256=P71oa4eVvG0SePkOoeeQ44LkRAfnlgElxZi9GUVG7qg,280598
|
|
11
11
|
npcpy/tools.py,sha256=A5_oVmZkzGnI3BI-NmneuxeXQq-r29PbpAZP4nV4jrc,5303
|
|
12
12
|
npcpy/data/__init__.py,sha256=1tcoChR-Hjn905JDLqaW9ElRmcISCTJdE7BGXPlym2Q,642
|
|
13
13
|
npcpy/data/audio.py,sha256=o4auV8DQrAmZ4y84U3SofiwEuq5-ZBjGEZipQ9zPpGQ,22816
|
|
@@ -16,7 +16,7 @@ npcpy/data/image.py,sha256=UQcioNPDd5HYMLL_KStf45SuiIPXDcUY-dEFHwSWUeE,6564
|
|
|
16
16
|
npcpy/data/load.py,sha256=rVe1xSHerIpo6MDaY5eIeqRSm0gssX5sHukNsUNVwJw,9228
|
|
17
17
|
npcpy/data/text.py,sha256=jP0a1qZZaSJdK-LdZTn2Jjdxqmkd3efxDLEoxflJQeY,5010
|
|
18
18
|
npcpy/data/video.py,sha256=H-V3mTu_ktD9u-QhYeo4aW3u9z0AtoAdRZmvRPEpE98,2887
|
|
19
|
-
npcpy/data/web.py,sha256=
|
|
19
|
+
npcpy/data/web.py,sha256=qmioqCxxWddRnNm2ke39_SWXXNSqRZ1Nx86_-1JGq_A,9139
|
|
20
20
|
npcpy/ft/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
21
21
|
npcpy/ft/diff.py,sha256=0ScRR4AxXtVX2bgZ-Jr_dSwv3LAlU1JXDUq4F4n1Ea4,12839
|
|
22
22
|
npcpy/ft/ge.py,sha256=0VzIiXq2wCzGcK1x0Wd-myJ3xRf-FNaPg0GkHEZegUM,3552
|
|
@@ -34,10 +34,10 @@ npcpy/gen/response.py,sha256=EYsIOvNOmn6dBs-4j3SyZNMvDf5N9lW-QxMbpjnF7Kw,57081
|
|
|
34
34
|
npcpy/gen/video_gen.py,sha256=RFi3Zcq_Hn3HIcfoF3mijQ6G7RYFZaM_9pjPTh-8E64,3239
|
|
35
35
|
npcpy/gen/world_gen.py,sha256=_8ytE7E3QVQ5qiX8DmOby-xd0d9zV20rRI6Wkpf-qcY,18922
|
|
36
36
|
npcpy/memory/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
37
|
-
npcpy/memory/command_history.py,sha256=
|
|
37
|
+
npcpy/memory/command_history.py,sha256=_2ygoMO4EwX8H2f5G2Q62hrgqMwL7weOI8CTaFPn-I0,66258
|
|
38
38
|
npcpy/memory/kg_vis.py,sha256=TrQQCRh_E7Pyr-GPAHLSsayubAfGyf4HOEFrPB6W86Q,31280
|
|
39
|
-
npcpy/memory/knowledge_graph.py,sha256=
|
|
40
|
-
npcpy/memory/memory_processor.py,sha256=
|
|
39
|
+
npcpy/memory/knowledge_graph.py,sha256=RHznD_Dt5Ka_eD015QuXnh3aG61c0Tf4oRIfY_JzPDQ,67554
|
|
40
|
+
npcpy/memory/memory_processor.py,sha256=T6VAeLYNfwP1jjDDY4x6Me_l5xcVShIcU95I1ye5nEM,9453
|
|
41
41
|
npcpy/memory/search.py,sha256=glN6WYzaixcoDphTEHAXSMX3vKZGjR12Jx9YVL_gYfE,18433
|
|
42
42
|
npcpy/mix/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
43
43
|
npcpy/mix/debate.py,sha256=lQXxC7nl6Rwyf7HIYrsVQILMUmYYx55Tjt2pkTg56qY,9019
|
|
@@ -53,8 +53,8 @@ npcpy/work/browser.py,sha256=p2PeaoZdAXipFuAgKCCB3aXXLE_p3yIRqC87KlZKZWc,679
|
|
|
53
53
|
npcpy/work/desktop.py,sha256=F3I8mUtJp6LAkXodsh8hGZIncoads6c_2Utty-0EdDA,2986
|
|
54
54
|
npcpy/work/plan.py,sha256=QyUwg8vElWiHuoS-xK4jXTxxHvkMD3VkaCEsCmrEPQk,8300
|
|
55
55
|
npcpy/work/trigger.py,sha256=P1Y8u1wQRsS2WACims_2IdkBEar-iBQix-2TDWoW0OM,9948
|
|
56
|
-
npcpy-1.3.
|
|
57
|
-
npcpy-1.3.
|
|
58
|
-
npcpy-1.3.
|
|
59
|
-
npcpy-1.3.
|
|
60
|
-
npcpy-1.3.
|
|
56
|
+
npcpy-1.3.21.dist-info/licenses/LICENSE,sha256=j0YPvce7Ng9e32zYOu0EmXjXeJ0Nwawd0RA3uSGGH4E,1070
|
|
57
|
+
npcpy-1.3.21.dist-info/METADATA,sha256=OJthZtnT23usrcUIlB9ZcG1DgrhVX0SYy1jBrl765so,37947
|
|
58
|
+
npcpy-1.3.21.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
59
|
+
npcpy-1.3.21.dist-info/top_level.txt,sha256=g1pbSvrOOncB74Bg5-J0Olg4V0A5VzDw-Xz5YObq8BU,6
|
|
60
|
+
npcpy-1.3.21.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|