coreinsight-cli 0.2.6__tar.gz → 0.2.8__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.
- {coreinsight_cli-0.2.6/coreinsight_cli.egg-info → coreinsight_cli-0.2.8}/PKG-INFO +2 -1
- {coreinsight_cli-0.2.6 → coreinsight_cli-0.2.8}/coreinsight/analyzer.py +106 -15
- {coreinsight_cli-0.2.6 → coreinsight_cli-0.2.8}/coreinsight/config.py +3 -0
- {coreinsight_cli-0.2.6 → coreinsight_cli-0.2.8}/coreinsight/main.py +227 -164
- {coreinsight_cli-0.2.6 → coreinsight_cli-0.2.8}/coreinsight/memory.py +71 -0
- {coreinsight_cli-0.2.6 → coreinsight_cli-0.2.8}/coreinsight/sandbox.py +4 -3
- coreinsight_cli-0.2.8/coreinsight/tui.py +878 -0
- {coreinsight_cli-0.2.6 → coreinsight_cli-0.2.8/coreinsight_cli.egg-info}/PKG-INFO +2 -1
- {coreinsight_cli-0.2.6 → coreinsight_cli-0.2.8}/coreinsight_cli.egg-info/SOURCES.txt +1 -0
- {coreinsight_cli-0.2.6 → coreinsight_cli-0.2.8}/coreinsight_cli.egg-info/requires.txt +1 -0
- {coreinsight_cli-0.2.6 → coreinsight_cli-0.2.8}/pyproject.toml +2 -1
- {coreinsight_cli-0.2.6 → coreinsight_cli-0.2.8}/LICENSE +0 -0
- {coreinsight_cli-0.2.6 → coreinsight_cli-0.2.8}/README.md +0 -0
- {coreinsight_cli-0.2.6 → coreinsight_cli-0.2.8}/coreinsight/Dockerfile.cpp-sandbox +0 -0
- {coreinsight_cli-0.2.6 → coreinsight_cli-0.2.8}/coreinsight/Dockerfile.python-sandbox +0 -0
- {coreinsight_cli-0.2.6 → coreinsight_cli-0.2.8}/coreinsight/__init__.py +0 -0
- {coreinsight_cli-0.2.6 → coreinsight_cli-0.2.8}/coreinsight/demo/__init__.py +0 -0
- {coreinsight_cli-0.2.6 → coreinsight_cli-0.2.8}/coreinsight/demo/bad_loop.py +0 -0
- {coreinsight_cli-0.2.6 → coreinsight_cli-0.2.8}/coreinsight/demo/data_processor.py +0 -0
- {coreinsight_cli-0.2.6 → coreinsight_cli-0.2.8}/coreinsight/demo/slow.cpp +0 -0
- {coreinsight_cli-0.2.6 → coreinsight_cli-0.2.8}/coreinsight/hardware.py +0 -0
- {coreinsight_cli-0.2.6 → coreinsight_cli-0.2.8}/coreinsight/indexer.py +0 -0
- {coreinsight_cli-0.2.6 → coreinsight_cli-0.2.8}/coreinsight/parser.py +0 -0
- {coreinsight_cli-0.2.6 → coreinsight_cli-0.2.8}/coreinsight/profiler.py +0 -0
- {coreinsight_cli-0.2.6 → coreinsight_cli-0.2.8}/coreinsight/prompts.py +0 -0
- {coreinsight_cli-0.2.6 → coreinsight_cli-0.2.8}/coreinsight/scanner.py +0 -0
- {coreinsight_cli-0.2.6 → coreinsight_cli-0.2.8}/coreinsight_cli.egg-info/dependency_links.txt +0 -0
- {coreinsight_cli-0.2.6 → coreinsight_cli-0.2.8}/coreinsight_cli.egg-info/entry_points.txt +0 -0
- {coreinsight_cli-0.2.6 → coreinsight_cli-0.2.8}/coreinsight_cli.egg-info/top_level.txt +0 -0
- {coreinsight_cli-0.2.6 → coreinsight_cli-0.2.8}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: coreinsight-cli
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.8
|
|
4
4
|
Summary: Local-first AI performance profiler that mathematically verifies optimizations for Python, C++, and CUDA
|
|
5
5
|
Author: Varun Jani
|
|
6
6
|
License: GPL-3.0-or-later
|
|
@@ -32,6 +32,7 @@ Requires-Dist: langchain-anthropic>=0.1.0
|
|
|
32
32
|
Requires-Dist: pydantic>=2.0
|
|
33
33
|
Requires-Dist: chromadb>=0.5.0
|
|
34
34
|
Requires-Dist: sentence-transformers>=3.0.0
|
|
35
|
+
Requires-Dist: textual>=0.60.0
|
|
35
36
|
Requires-Dist: psutil>=5.9
|
|
36
37
|
Provides-Extra: compat
|
|
37
38
|
Requires-Dist: pysqlite3-binary>=0.5.0; extra == "compat"
|
|
@@ -14,6 +14,35 @@ from langchain_anthropic import ChatAnthropic
|
|
|
14
14
|
|
|
15
15
|
from coreinsight.prompts import SYSTEM_PROMPT, ANALYSIS_TEMPLATE, HARNESS_ADDENDUM
|
|
16
16
|
|
|
17
|
+
# Phrases that appear at the start of a truncated LLM response
|
|
18
|
+
_TRUNCATION_HINTS = (
|
|
19
|
+
"context length",
|
|
20
|
+
"context_length_exceeded",
|
|
21
|
+
"maximum context",
|
|
22
|
+
"token limit",
|
|
23
|
+
"finish_reason: length",
|
|
24
|
+
"finish_reason\":\"length",
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
def _is_truncated(raw: str) -> bool:
|
|
28
|
+
"""
|
|
29
|
+
Returns True if the raw LLM output looks like it was cut off mid-generation.
|
|
30
|
+
Catches both explicit error messages and structural truncation signs.
|
|
31
|
+
"""
|
|
32
|
+
if not raw or len(raw.strip()) < 20:
|
|
33
|
+
return True
|
|
34
|
+
low = raw.lower()
|
|
35
|
+
if any(hint in low for hint in _TRUNCATION_HINTS):
|
|
36
|
+
return True
|
|
37
|
+
stripped = raw.strip()
|
|
38
|
+
# JSON truncation: opened but never closed
|
|
39
|
+
if stripped.startswith("{") and not stripped.endswith("}"):
|
|
40
|
+
return True
|
|
41
|
+
# Code truncation: opens a block but ends mid-statement
|
|
42
|
+
if stripped.endswith(("...", "/*", "//", "\"", "'")):
|
|
43
|
+
return True
|
|
44
|
+
return False
|
|
45
|
+
|
|
17
46
|
logger = logging.getLogger(__name__)
|
|
18
47
|
|
|
19
48
|
|
|
@@ -163,12 +192,15 @@ class AnalyzerAgent:
|
|
|
163
192
|
self.json_llm = self.base_llm
|
|
164
193
|
|
|
165
194
|
elif provider == "local_server":
|
|
166
|
-
|
|
195
|
+
from coreinsight.prompts import ModelTier
|
|
196
|
+
base_url = api_keys.get("local_url", "http://localhost:1234/v1")
|
|
197
|
+
_max_tokens = 2048 if model_tier == ModelTier.SMALL else 4096
|
|
167
198
|
self.base_llm = ChatOpenAI(
|
|
168
199
|
model=model_name,
|
|
169
200
|
api_key="not-needed",
|
|
170
201
|
base_url=base_url,
|
|
171
202
|
temperature=0.1,
|
|
203
|
+
max_tokens=_max_tokens,
|
|
172
204
|
model_kwargs={"response_format": {"type": "json_object"}},
|
|
173
205
|
)
|
|
174
206
|
self.json_llm = self.base_llm
|
|
@@ -196,11 +228,20 @@ class AnalyzerAgent:
|
|
|
196
228
|
self.json_llm = self.base_llm
|
|
197
229
|
|
|
198
230
|
else: # Ollama default
|
|
231
|
+
from coreinsight.prompts import ModelTier
|
|
232
|
+
# Small models (7B) typically have 4096 native context.
|
|
233
|
+
# Asking for more causes silent degradation or OOM on the host.
|
|
234
|
+
# Medium/large local models can handle 8192 comfortably.
|
|
235
|
+
_ctx = 4096 if model_tier == ModelTier.SMALL else 8192
|
|
236
|
+
# num_predict: small models need room for JSON + code in one shot.
|
|
237
|
+
# Capping at 2048 for small prevents runaway generation that hits
|
|
238
|
+
# the limit mid-JSON and returns truncated garbage.
|
|
239
|
+
_predict = 2048 if model_tier == ModelTier.SMALL else 4096
|
|
199
240
|
self.base_llm = ChatOllama(
|
|
200
241
|
model=model_name,
|
|
201
242
|
temperature=0.1,
|
|
202
|
-
num_predict=
|
|
203
|
-
num_ctx=
|
|
243
|
+
num_predict=_predict,
|
|
244
|
+
num_ctx=_ctx,
|
|
204
245
|
)
|
|
205
246
|
self.json_llm = self.base_llm.bind(format="json")
|
|
206
247
|
|
|
@@ -258,14 +299,31 @@ class AnalyzerAgent:
|
|
|
258
299
|
def _invoke_code_chain(self, template: str, variables: dict, language: str) -> str:
|
|
259
300
|
"""Shared invocation + extraction logic for harness and fix chains."""
|
|
260
301
|
chain = PromptTemplate.from_template(template) | self.base_llm
|
|
261
|
-
|
|
302
|
+
try:
|
|
303
|
+
result = chain.invoke(variables)
|
|
304
|
+
except Exception as e:
|
|
305
|
+
err = str(e).lower()
|
|
306
|
+
if any(h in err for h in _TRUNCATION_HINTS):
|
|
307
|
+
raise RuntimeError(
|
|
308
|
+
f"Model hit its context limit. Try a smaller file, fewer functions, "
|
|
309
|
+
f"or a model with a larger context window. Detail: {e}"
|
|
310
|
+
) from e
|
|
311
|
+
raise
|
|
262
312
|
raw = result.content if hasattr(result, "content") else str(result)
|
|
263
|
-
# Handle Anthropic returning a list of content blocks
|
|
264
313
|
if isinstance(raw, list):
|
|
265
314
|
raw = "\n".join(
|
|
266
315
|
item["text"] if isinstance(item, dict) and "text" in item else str(item)
|
|
267
316
|
for item in raw
|
|
268
317
|
)
|
|
318
|
+
if _is_truncated(raw):
|
|
319
|
+
logger.warning(
|
|
320
|
+
f"LLM output appears truncated (len={len(raw)}). "
|
|
321
|
+
f"Model likely hit its context/predict limit."
|
|
322
|
+
)
|
|
323
|
+
raise RuntimeError(
|
|
324
|
+
"Model output was truncated — hit context or token limit. "
|
|
325
|
+
"Try a model with a larger context window, or reduce the function size."
|
|
326
|
+
)
|
|
269
327
|
return self._extract_executable_code(raw)
|
|
270
328
|
|
|
271
329
|
def generate_harness(
|
|
@@ -421,12 +479,14 @@ def _build_llm(provider: str, model_name: str, api_keys: dict):
|
|
|
421
479
|
return llm, llm
|
|
422
480
|
|
|
423
481
|
if provider == "local_server":
|
|
424
|
-
base_url
|
|
482
|
+
base_url = api_keys.get("local_url", "http://localhost:1234/v1")
|
|
483
|
+
_max_tokens = api_keys.pop("_predict", 4096) # reuse same key as Ollama path
|
|
425
484
|
llm = ChatOpenAI(
|
|
426
485
|
model=model_name,
|
|
427
486
|
api_key="not-needed",
|
|
428
487
|
base_url=base_url,
|
|
429
488
|
temperature=0.1,
|
|
489
|
+
max_tokens=_max_tokens,
|
|
430
490
|
model_kwargs={"response_format": {"type": "json_object"}},
|
|
431
491
|
)
|
|
432
492
|
return llm, llm
|
|
@@ -452,16 +512,33 @@ def _build_llm(provider: str, model_name: str, api_keys: dict):
|
|
|
452
512
|
)
|
|
453
513
|
return llm, llm
|
|
454
514
|
|
|
455
|
-
# Ollama default
|
|
515
|
+
# Ollama default — context and predict budget are passed in from the
|
|
516
|
+
# calling agent which knows its own model_tier.
|
|
517
|
+
# Default to medium-safe values; callers override via kwargs if needed.
|
|
518
|
+
_ctx = api_keys.pop("_ctx", 8192)
|
|
519
|
+
_predict = api_keys.pop("_predict", 4096)
|
|
456
520
|
base = ChatOllama(
|
|
457
521
|
model=model_name,
|
|
458
522
|
temperature=0.1,
|
|
459
|
-
num_predict=
|
|
460
|
-
num_ctx=
|
|
523
|
+
num_predict=_predict,
|
|
524
|
+
num_ctx=_ctx,
|
|
461
525
|
)
|
|
462
526
|
return base, base.bind(format="json")
|
|
463
527
|
|
|
464
528
|
|
|
529
|
+
def _build_llm_tiered(provider: str, model_name: str, api_keys: dict, model_tier: str):
|
|
530
|
+
"""Wraps _build_llm with tier-aware context settings for local providers."""
|
|
531
|
+
from coreinsight.prompts import ModelTier
|
|
532
|
+
keys = dict(api_keys or {})
|
|
533
|
+
if provider == "ollama":
|
|
534
|
+
keys["_ctx"] = 4096 if model_tier == ModelTier.SMALL else 8192
|
|
535
|
+
keys["_predict"] = 2048 if model_tier == ModelTier.SMALL else 4096
|
|
536
|
+
elif provider == "local_server":
|
|
537
|
+
# max_tokens controls response length — context window is server-side
|
|
538
|
+
keys["_predict"] = 2048 if model_tier == ModelTier.SMALL else 4096
|
|
539
|
+
return _build_llm(provider, model_name, keys)
|
|
540
|
+
|
|
541
|
+
|
|
465
542
|
class BottleneckAgent:
|
|
466
543
|
"""
|
|
467
544
|
Agent 1 — analysis only.
|
|
@@ -480,7 +557,7 @@ class BottleneckAgent:
|
|
|
480
557
|
from coreinsight.prompts import BOTTLENECK_TEMPLATE, SYSTEM_PROMPT
|
|
481
558
|
self.model_tier = model_tier
|
|
482
559
|
self.parser = JsonOutputParser(pydantic_object=AuditResult)
|
|
483
|
-
self._base_llm, self._json_llm =
|
|
560
|
+
self._base_llm, self._json_llm = _build_llm_tiered(provider, model_name, api_keys, model_tier)
|
|
484
561
|
|
|
485
562
|
self._prompt = PromptTemplate(
|
|
486
563
|
template=BOTTLENECK_TEMPLATE,
|
|
@@ -544,7 +621,7 @@ class OptimizerAgent:
|
|
|
544
621
|
) -> None:
|
|
545
622
|
from coreinsight.prompts import OPTIMIZER_TEMPLATE
|
|
546
623
|
self.model_tier = model_tier
|
|
547
|
-
self._base_llm, _ =
|
|
624
|
+
self._base_llm, _ = _build_llm_tiered(provider, model_name, api_keys, model_tier)
|
|
548
625
|
self._template = OPTIMIZER_TEMPLATE
|
|
549
626
|
|
|
550
627
|
def _extract_code(self, raw: str) -> str:
|
|
@@ -620,7 +697,7 @@ class HarnessAgent:
|
|
|
620
697
|
HARNESS_ADDENDUM_MULTI,
|
|
621
698
|
)
|
|
622
699
|
self.model_tier = model_tier
|
|
623
|
-
self._base_llm, _ =
|
|
700
|
+
self._base_llm, _ = _build_llm_tiered(provider, model_name, api_keys, model_tier)
|
|
624
701
|
self._harness_tmpl = HARNESS_TEMPLATE_MULTI + HARNESS_ADDENDUM_MULTI.get(model_tier, "")
|
|
625
702
|
self._fix_tmpl = FIX_TEMPLATE_MULTI + HARNESS_ADDENDUM_MULTI.get(model_tier, "")
|
|
626
703
|
|
|
@@ -638,14 +715,28 @@ class HarnessAgent:
|
|
|
638
715
|
|
|
639
716
|
def _invoke(self, template: str, variables: dict) -> str:
|
|
640
717
|
chain = PromptTemplate.from_template(template) | self._base_llm
|
|
641
|
-
|
|
642
|
-
|
|
718
|
+
try:
|
|
719
|
+
result = chain.invoke(variables)
|
|
720
|
+
except Exception as e:
|
|
721
|
+
err = str(e).lower()
|
|
722
|
+
if any(h in err for h in _TRUNCATION_HINTS):
|
|
723
|
+
raise RuntimeError(
|
|
724
|
+
f"Model hit its context limit during harness generation. "
|
|
725
|
+
f"Detail: {e}"
|
|
726
|
+
) from e
|
|
727
|
+
raise
|
|
728
|
+
raw = result.content if hasattr(result, "content") else str(result)
|
|
643
729
|
if isinstance(raw, list):
|
|
644
730
|
raw = "\n".join(
|
|
645
731
|
item["text"] if isinstance(item, dict) and "text" in item
|
|
646
732
|
else str(item)
|
|
647
733
|
for item in raw
|
|
648
734
|
)
|
|
735
|
+
if _is_truncated(raw):
|
|
736
|
+
raise RuntimeError(
|
|
737
|
+
"Harness output was truncated — model hit its token limit. "
|
|
738
|
+
"Switching to fix loop with truncation note."
|
|
739
|
+
)
|
|
649
740
|
return self._extract_code(raw)
|
|
650
741
|
|
|
651
742
|
def _check_speedup(self, success: bool, logs: str) -> bool:
|
|
@@ -738,7 +829,7 @@ class TestCaseAgent:
|
|
|
738
829
|
model_tier: str,
|
|
739
830
|
) -> None:
|
|
740
831
|
self.model_tier = model_tier
|
|
741
|
-
self._base_llm, _ =
|
|
832
|
+
self._base_llm, _ = _build_llm_tiered(provider, model_name, api_keys, model_tier)
|
|
742
833
|
|
|
743
834
|
def generate(
|
|
744
835
|
self,
|
|
@@ -18,6 +18,7 @@ FREE_TIER_LIMITS = {
|
|
|
18
18
|
"max_retries": 2,
|
|
19
19
|
"num_test_cases": 8,
|
|
20
20
|
"hardware_profiling": False,
|
|
21
|
+
"max_files": 2,
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
PRO_TIER_LIMITS = {
|
|
@@ -25,6 +26,7 @@ PRO_TIER_LIMITS = {
|
|
|
25
26
|
"max_retries": 5,
|
|
26
27
|
"num_test_cases": 15,
|
|
27
28
|
"hardware_profiling": True,
|
|
29
|
+
"max_files": None,
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
SMALL_MODELS = ["llama3.2:3b", "llama3.2:1b", "codellama:7b", "llama3:7b", "mistral:7b"]
|
|
@@ -168,6 +170,7 @@ def run_configure(pro_key: str = None, agent_mode: str = None):
|
|
|
168
170
|
if provider == "ollama":
|
|
169
171
|
config["model_name"] = Prompt.ask("Ollama model name", default=config.get("model_name", "llama3.2"))
|
|
170
172
|
elif provider == "local_server":
|
|
173
|
+
from rich.panel import Panel
|
|
171
174
|
console.print(Panel(
|
|
172
175
|
"[bold]Local inference server setup[/bold]\n\n"
|
|
173
176
|
"CoreInsight talks to any OpenAI-compatible local server.\n"
|