npcpy 1.2.31__tar.gz → 1.2.32__tar.gz
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-1.2.31/npcpy.egg-info → npcpy-1.2.32}/PKG-INFO +1 -1
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/gen/response.py +73 -20
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/llm_funcs.py +1 -1
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/npc_sysenv.py +44 -20
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/serve.py +1 -0
- {npcpy-1.2.31 → npcpy-1.2.32/npcpy.egg-info}/PKG-INFO +1 -1
- {npcpy-1.2.31 → npcpy-1.2.32}/setup.py +1 -1
- {npcpy-1.2.31 → npcpy-1.2.32}/LICENSE +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/MANIFEST.in +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/README.md +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/__init__.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/data/__init__.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/data/audio.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/data/data_models.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/data/image.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/data/load.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/data/text.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/data/video.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/data/web.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/ft/__init__.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/ft/diff.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/ft/ge.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/ft/memory_trainer.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/ft/model_ensembler.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/ft/rl.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/ft/sft.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/ft/usft.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/gen/__init__.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/gen/audio_gen.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/gen/embeddings.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/gen/image_gen.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/gen/video_gen.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/main.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/memory/__init__.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/memory/command_history.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/memory/kg_vis.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/memory/knowledge_graph.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/memory/memory_processor.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/memory/search.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/mix/__init__.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/mix/debate.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/npc_compiler.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/npcs.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/sql/__init__.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/sql/ai_function_tools.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/sql/database_ai_adapters.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/sql/database_ai_functions.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/sql/model_runner.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/sql/npcsql.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/sql/sql_model_compiler.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/tools.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/work/__init__.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/work/desktop.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/work/plan.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy/work/trigger.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy.egg-info/SOURCES.txt +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy.egg-info/dependency_links.txt +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy.egg-info/requires.txt +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/npcpy.egg-info/top_level.txt +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/setup.cfg +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/tests/test_audio.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/tests/test_command_history.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/tests/test_image.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/tests/test_llm_funcs.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/tests/test_load.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/tests/test_npc_compiler.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/tests/test_npcsql.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/tests/test_response.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/tests/test_serve.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/tests/test_text.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/tests/test_tools.py +0 -0
- {npcpy-1.2.31 → npcpy-1.2.32}/tests/test_web.py +0 -0
|
@@ -378,21 +378,50 @@ def get_ollama_response(
|
|
|
378
378
|
|
|
379
379
|
result["response"] = ollama.chat(**stream_api_params, options=options)
|
|
380
380
|
else:
|
|
381
|
-
|
|
381
|
+
|
|
382
382
|
if format == "json":
|
|
383
383
|
try:
|
|
384
|
-
if isinstance(
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
384
|
+
if isinstance(llm_response, str):
|
|
385
|
+
llm_response = llm_response.strip()
|
|
386
|
+
|
|
387
|
+
if '```json' in llm_response:
|
|
388
|
+
start = llm_response.find('```json') + 7
|
|
389
|
+
end = llm_response.rfind('```')
|
|
390
|
+
if end > start:
|
|
391
|
+
llm_response = llm_response[start:end].strip()
|
|
392
|
+
|
|
393
|
+
first_brace = llm_response.find('{')
|
|
394
|
+
first_bracket = llm_response.find('[')
|
|
395
|
+
|
|
396
|
+
if first_brace == -1 and first_bracket == -1:
|
|
397
|
+
result["response"] = {}
|
|
398
|
+
result["error"] = "No JSON found in response"
|
|
399
|
+
return result
|
|
400
|
+
|
|
401
|
+
if first_brace != -1 and (first_bracket == -1 or first_brace < first_bracket):
|
|
402
|
+
llm_response = llm_response[first_brace:]
|
|
403
|
+
last_brace = llm_response.rfind('}')
|
|
404
|
+
if last_brace != -1:
|
|
405
|
+
llm_response = llm_response[:last_brace+1]
|
|
406
|
+
else:
|
|
407
|
+
llm_response = llm_response[first_bracket:]
|
|
408
|
+
last_bracket = llm_response.rfind(']')
|
|
409
|
+
if last_bracket != -1:
|
|
410
|
+
llm_response = llm_response[:last_bracket+1]
|
|
411
|
+
|
|
412
|
+
parsed_json = json.loads(llm_response, strict=False)
|
|
413
|
+
|
|
414
|
+
if "json" in parsed_json:
|
|
415
|
+
result["response"] = parsed_json["json"]
|
|
416
|
+
else:
|
|
417
|
+
result["response"] = parsed_json
|
|
418
|
+
|
|
419
|
+
except (json.JSONDecodeError, TypeError) as e:
|
|
420
|
+
print(f"JSON parsing error: {str(e)}")
|
|
421
|
+
print(f"Raw response: {llm_response[:500]}")
|
|
422
|
+
result["response"] = {}
|
|
423
|
+
result["error"] = "Invalid JSON response"
|
|
424
|
+
|
|
396
425
|
return result
|
|
397
426
|
|
|
398
427
|
import time
|
|
@@ -553,7 +582,7 @@ def get_litellm_response(
|
|
|
553
582
|
litellm.include_cost_in_streaming_usage = True
|
|
554
583
|
api_params['stream_options'] = {"include_usage": True}
|
|
555
584
|
|
|
556
|
-
if api_url is not None and (provider == "openai-like" or provider == "openai"):
|
|
585
|
+
if api_url is not None and ('openai-like' in provider or provider == "openai-like" or provider == "openai"):
|
|
557
586
|
api_params["api_base"] = api_url
|
|
558
587
|
provider = "openai"
|
|
559
588
|
|
|
@@ -609,14 +638,37 @@ def get_litellm_response(
|
|
|
609
638
|
|
|
610
639
|
if hasattr(resp.choices[0].message, 'tool_calls') and resp.choices[0].message.tool_calls:
|
|
611
640
|
result["tool_calls"] = resp.choices[0].message.tool_calls
|
|
612
|
-
|
|
613
|
-
|
|
614
641
|
if format == "json":
|
|
615
642
|
try:
|
|
616
643
|
if isinstance(llm_response, str):
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
644
|
+
llm_response = llm_response.strip()
|
|
645
|
+
|
|
646
|
+
if '```json' in llm_response:
|
|
647
|
+
start = llm_response.find('```json') + 7
|
|
648
|
+
end = llm_response.rfind('```')
|
|
649
|
+
if end > start:
|
|
650
|
+
llm_response = llm_response[start:end].strip()
|
|
651
|
+
|
|
652
|
+
first_brace = llm_response.find('{')
|
|
653
|
+
first_bracket = llm_response.find('[')
|
|
654
|
+
|
|
655
|
+
if first_brace == -1 and first_bracket == -1:
|
|
656
|
+
result["response"] = {}
|
|
657
|
+
result["error"] = "No JSON found in response"
|
|
658
|
+
return result
|
|
659
|
+
|
|
660
|
+
if first_brace != -1 and (first_bracket == -1 or first_brace < first_bracket):
|
|
661
|
+
llm_response = llm_response[first_brace:]
|
|
662
|
+
last_brace = llm_response.rfind('}')
|
|
663
|
+
if last_brace != -1:
|
|
664
|
+
llm_response = llm_response[:last_brace+1]
|
|
665
|
+
else:
|
|
666
|
+
llm_response = llm_response[first_bracket:]
|
|
667
|
+
last_bracket = llm_response.rfind(']')
|
|
668
|
+
if last_bracket != -1:
|
|
669
|
+
llm_response = llm_response[:last_bracket+1]
|
|
670
|
+
|
|
671
|
+
parsed_json = json.loads(llm_response, strict=False)
|
|
620
672
|
|
|
621
673
|
if "json" in parsed_json:
|
|
622
674
|
result["response"] = parsed_json["json"]
|
|
@@ -625,7 +677,8 @@ def get_litellm_response(
|
|
|
625
677
|
|
|
626
678
|
except (json.JSONDecodeError, TypeError) as e:
|
|
627
679
|
print(f"JSON parsing error: {str(e)}")
|
|
628
|
-
print(f"Raw response: {llm_response}")
|
|
680
|
+
print(f"Raw response: {llm_response[:500]}")
|
|
681
|
+
result["response"] = {}
|
|
629
682
|
result["error"] = "Invalid JSON response"
|
|
630
683
|
|
|
631
684
|
return result
|
|
@@ -594,7 +594,7 @@ def handle_jinx_call(
|
|
|
594
594
|
render_markdown(f""" ## jinx OUTPUT FROM CALLING {jinx_name} \n \n output:{jinx_output['output']}""" )
|
|
595
595
|
response = get_llm_response(f"""
|
|
596
596
|
The user had the following request: {command}.
|
|
597
|
-
Here were the jinx outputs from calling {jinx_name}: {jinx_output}
|
|
597
|
+
Here were the jinx outputs from calling {jinx_name}: {jinx_output.get('output', '')}
|
|
598
598
|
|
|
599
599
|
Given the jinx outputs and the user request, please format a simple answer that
|
|
600
600
|
provides the answer without requiring the user to carry out any further steps.
|
|
@@ -144,7 +144,7 @@ def get_locally_available_models(project_directory, airplane_mode=False):
|
|
|
144
144
|
|
|
145
145
|
models = fetch_custom_models()
|
|
146
146
|
for model in models:
|
|
147
|
-
available_models[model] =
|
|
147
|
+
available_models[model] = 'openai-like'
|
|
148
148
|
|
|
149
149
|
logging.info(
|
|
150
150
|
f"Loaded {len(models)} models "
|
|
@@ -157,32 +157,56 @@ def get_locally_available_models(project_directory, airplane_mode=False):
|
|
|
157
157
|
f"custom provider '{provider_name}': {e}"
|
|
158
158
|
)
|
|
159
159
|
|
|
160
|
-
|
|
160
|
+
|
|
161
161
|
airplane_mode = False
|
|
162
162
|
if not airplane_mode:
|
|
163
163
|
timeout_seconds = 3.5
|
|
164
164
|
|
|
165
165
|
|
|
166
166
|
with concurrent.futures.ThreadPoolExecutor(max_workers=1) as executor:
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
167
|
+
|
|
168
|
+
if 'NPCSH_API_URL' in env_vars or os.environ.get('NPCSH_API_URL'):
|
|
169
|
+
try:
|
|
170
|
+
import requests
|
|
171
|
+
|
|
172
|
+
def fetch_custom_models():
|
|
173
|
+
base_url = env_vars.get('NPCSH_API_URL') or os.environ.get('NPCSH_API_URL')
|
|
174
|
+
models_endpoint = f"{base_url.rstrip('/')}/models"
|
|
175
|
+
response = requests.get(
|
|
176
|
+
models_endpoint,
|
|
177
|
+
|
|
178
|
+
timeout=3.5
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
if response.status_code == 200:
|
|
182
|
+
data = response.json()
|
|
183
|
+
|
|
184
|
+
if isinstance(data, dict) and 'data' in data:
|
|
185
|
+
return [
|
|
186
|
+
m['id'] for m in data['data']
|
|
187
|
+
if 'id' in m
|
|
188
|
+
]
|
|
189
|
+
elif isinstance(data, list):
|
|
190
|
+
return [
|
|
191
|
+
m['id'] for m in data
|
|
192
|
+
if isinstance(m, dict) and 'id' in m
|
|
193
|
+
]
|
|
194
|
+
return []
|
|
195
|
+
|
|
196
|
+
models = fetch_custom_models()
|
|
197
|
+
for model in models:
|
|
198
|
+
available_models[model] = 'openai-like'
|
|
199
|
+
|
|
185
200
|
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
except Exception as e:
|
|
204
|
+
logging.warning(
|
|
205
|
+
f"Failed to load models from "
|
|
206
|
+
f"custom provider 'openai-like': {e}"
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
|
|
186
210
|
if "ANTHROPIC_API_KEY" in env_vars or os.environ.get("ANTHROPIC_API_KEY"):
|
|
187
211
|
try:
|
|
188
212
|
import anthropic
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|