codent 0.3.1__tar.gz → 0.3.3__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.
- {codent-0.3.1 → codent-0.3.3}/PKG-INFO +1 -1
- {codent-0.3.1 → codent-0.3.3}/codent.egg-info/PKG-INFO +1 -1
- {codent-0.3.1 → codent-0.3.3}/codent.egg-info/SOURCES.txt +6 -1
- {codent-0.3.1 → codent-0.3.3}/codent.egg-info/top_level.txt +1 -0
- {codent-0.3.1 → codent-0.3.3}/cont.py +14 -1
- {codent-0.3.1 → codent-0.3.3}/core/cli.py +2 -0
- {codent-0.3.1 → codent-0.3.3}/core/guardian.py +28 -0
- codent-0.3.3/core/init_cmd.py +181 -0
- {codent-0.3.1 → codent-0.3.3}/core/runtime.py +2 -0
- {codent-0.3.1 → codent-0.3.3}/core/self_improve.py +14 -3
- {codent-0.3.1 → codent-0.3.3}/core/tool_helpers.py +17 -0
- {codent-0.3.1 → codent-0.3.3}/core/tools.py +8 -0
- {codent-0.3.1 → codent-0.3.3}/core/trace.py +109 -58
- {codent-0.3.1 → codent-0.3.3}/pyproject.toml +9 -2
- codent-0.3.3/vendor/__init__.py +0 -0
- codent-0.3.3/vendor/bin/__init__.py +0 -0
- codent-0.3.3/vendor/bin/ollama +0 -0
- codent-0.3.3/vendor/wheels/__init__.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/codent.egg-info/dependency_links.txt +0 -0
- {codent-0.3.1 → codent-0.3.3}/codent.egg-info/entry_points.txt +0 -0
- {codent-0.3.1 → codent-0.3.3}/codent.egg-info/requires.txt +0 -0
- {codent-0.3.1 → codent-0.3.3}/cont_ui/__init__.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/cont_ui/frontend.html +0 -0
- {codent-0.3.1 → codent-0.3.3}/cont_ui/server.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/cont_watcher.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/__init__.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/adaptive_prompt.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/advanced_overnight.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/anomaly_tools.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/app.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/auto_eval.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/automations.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/benchmark.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/bridge_server.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/browser.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/browser_agent.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/budget_committee.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/cc_auditor.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/cleaning_tools.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/context_utils.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/curriculum_runner.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/daemon.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/data_tools.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/decomposer.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/domain_tools.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/endpoint_discovery.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/env_snapshot.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/episodic.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/escalation.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/events.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/feedback_training.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/file_context.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/fitness.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/formatters.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/genesis.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/golden_test_runner.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/hive_recall.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/identity.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/intent_detection.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/intent_gate.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/learning_loop.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/lmstudio.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/local_llm.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/memory_eviction.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/memory_gate.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/memory_store.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/ml_tools.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/model.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/model_routing.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/network_audit.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/ocr.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/overfit_test.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/overnight_training.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/path_resolution.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/postprocess.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/prefetch.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/prompt_patches.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/prompts.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/provider_router.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/quick_overfit_test.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/recipe_factory.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/recipe_feedback.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/recipe_learner.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/recipes.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/relation_discovery.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/relay.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/repl.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/router.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/rpc.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/run_logger.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/safety.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/scheduler.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/scratchpad.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/spreading_activation.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/sql_guard.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/sticky_config.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/structured_output.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/system_executor.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/system_map.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/task_classifier.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/task_utils.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/teacher.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/tool_budget.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/tool_schemas.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/types.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/utils.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/verification.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/verify_minions.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/vocabulary.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/voice.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/web.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/core/yis_deep_training.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/setup.cfg +0 -0
- {codent-0.3.1 → codent-0.3.3}/tests/test_auto_eval.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/tests/test_browser.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/tests/test_browser_agent.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/tests/test_commands_and_teach.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/tests/test_cont.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/tests/test_corpus_parser.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/tests/test_episodic.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/tests/test_eviction.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/tests/test_formatters.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/tests/test_golden.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/tests/test_health_report_valid_json.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/tests/test_integrity_and_memory_gate.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/tests/test_known_bugs.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/tests/test_model_agnostic.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/tests/test_new_tools.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/tests/test_provider_router.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/tests/test_recipes.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/tests/test_teacher.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/tests/test_verification.py +0 -0
- {codent-0.3.1 → codent-0.3.3}/tests/test_web_fetch.py +0 -0
|
@@ -45,6 +45,7 @@ core/golden_test_runner.py
|
|
|
45
45
|
core/guardian.py
|
|
46
46
|
core/hive_recall.py
|
|
47
47
|
core/identity.py
|
|
48
|
+
core/init_cmd.py
|
|
48
49
|
core/intent_detection.py
|
|
49
50
|
core/intent_gate.py
|
|
50
51
|
core/learning_loop.py
|
|
@@ -123,4 +124,8 @@ tests/test_provider_router.py
|
|
|
123
124
|
tests/test_recipes.py
|
|
124
125
|
tests/test_teacher.py
|
|
125
126
|
tests/test_verification.py
|
|
126
|
-
tests/test_web_fetch.py
|
|
127
|
+
tests/test_web_fetch.py
|
|
128
|
+
vendor/__init__.py
|
|
129
|
+
vendor/bin/__init__.py
|
|
130
|
+
vendor/bin/ollama
|
|
131
|
+
vendor/wheels/__init__.py
|
|
@@ -416,8 +416,12 @@ from core.provider_router import (
|
|
|
416
416
|
)
|
|
417
417
|
|
|
418
418
|
# Discover working base URL at startup (LM Studio → Ollama fallback)
|
|
419
|
-
#
|
|
419
|
+
# Skip the hard-exit when running offline-only flags (--init, --local-list, --help)
|
|
420
|
+
_OFFLINE_FLAGS = {"--init", "--local-list", "--help", "-h", "--version"}
|
|
421
|
+
_OFFLINE_MODE = any(a in _OFFLINE_FLAGS for a in sys.argv[1:])
|
|
420
422
|
_PROVIDER_NAME = "lmstudio"
|
|
423
|
+
BASE_URL = "http://127.0.0.1:1234/v1"
|
|
424
|
+
_TRIED_URLS = []
|
|
421
425
|
try:
|
|
422
426
|
BASE_URL, _TRIED_URLS = discover_openai_base_url()
|
|
423
427
|
except EndpointNotFoundError:
|
|
@@ -428,6 +432,9 @@ except EndpointNotFoundError:
|
|
|
428
432
|
_TRIED_URLS = [OLLAMA_BASE]
|
|
429
433
|
_PROVIDER_NAME = "ollama"
|
|
430
434
|
console.print("[yellow]LM Studio unavailable, using Ollama fallback.[/yellow]")
|
|
435
|
+
elif _OFFLINE_MODE:
|
|
436
|
+
# --init / --local-list: provider gerek yok, sessizce devam et
|
|
437
|
+
_PROVIDER_NAME = "offline"
|
|
431
438
|
else:
|
|
432
439
|
console.print("[bold red]Error: No LLM provider available.[/bold red]")
|
|
433
440
|
console.print("\n[yellow]Hint:[/yellow] Start LM Studio (port 1234) or Ollama (port 11434).")
|
|
@@ -1879,6 +1886,12 @@ def main():
|
|
|
1879
1886
|
list_presets()
|
|
1880
1887
|
sys.exit(0)
|
|
1881
1888
|
|
|
1889
|
+
# Handle --init (install bundled wheels for offline llama-cpp-python)
|
|
1890
|
+
if getattr(args, 'init', None) is not None:
|
|
1891
|
+
from core.init_cmd import run_init
|
|
1892
|
+
run_init(args.init or None)
|
|
1893
|
+
sys.exit(0)
|
|
1894
|
+
|
|
1882
1895
|
# Handle all exit flags (--set-home, --show-home, --self-report, --memory-*, etc.)
|
|
1883
1896
|
handle_exit_flags(args)
|
|
1884
1897
|
|
|
@@ -268,6 +268,8 @@ Model selection:
|
|
|
268
268
|
# Local LLM — fallback GGUF presets (LM Studio kapalıysa)
|
|
269
269
|
parser.add_argument("--local-list", action="store_true",
|
|
270
270
|
help="List available local GGUF model presets")
|
|
271
|
+
parser.add_argument("--init", nargs="?", const="", metavar="GGUF_PATH",
|
|
272
|
+
help="Bundled wheel'lardan llama-cpp-python yükle (opsiyonel: GGUF path)")
|
|
271
273
|
|
|
272
274
|
# Genesis — owner recognition
|
|
273
275
|
parser.add_argument("--set-keyphrase", action="store_true",
|
|
@@ -1140,6 +1140,33 @@ def check_network_safety() -> tuple[bool, list[str]]:
|
|
|
1140
1140
|
|
|
1141
1141
|
# ── Kontrol 27: Halüsinasyon guard ──
|
|
1142
1142
|
|
|
1143
|
+
def check_system_search_meta_filter() -> tuple[bool, list[str]]:
|
|
1144
|
+
"""system_search META dizinleri (logs/, pheromone/, inbox/, __pycache__/)
|
|
1145
|
+
filtrelemeli — bunlar DATA değil, arama gürültüsü.
|
|
1146
|
+
"""
|
|
1147
|
+
violations = []
|
|
1148
|
+
tools_path = Path(__file__).parent / "tools.py"
|
|
1149
|
+
if not tools_path.exists():
|
|
1150
|
+
return True, []
|
|
1151
|
+
src = tools_path.read_text(encoding="utf-8", errors="ignore")
|
|
1152
|
+
# system_search içinde meta filtre var mı?
|
|
1153
|
+
try:
|
|
1154
|
+
idx = src.index("def system_search")
|
|
1155
|
+
except ValueError:
|
|
1156
|
+
return True, []
|
|
1157
|
+
end = src.find("\ndef ", idx + 1)
|
|
1158
|
+
body = src[idx:end if end != -1 else len(src)]
|
|
1159
|
+
required = ["/logs/", "/.cont/hive/pheromone/",
|
|
1160
|
+
"/.cont/hive/inbox/", "/__pycache__/"]
|
|
1161
|
+
missing = [tok for tok in required if tok not in body]
|
|
1162
|
+
if missing:
|
|
1163
|
+
violations.append(
|
|
1164
|
+
f"system_search META filtresi eksik: {missing}. "
|
|
1165
|
+
"core/tools.py system_search içinde bu dizinler hariç tutulmalı."
|
|
1166
|
+
)
|
|
1167
|
+
return not violations, violations
|
|
1168
|
+
|
|
1169
|
+
|
|
1143
1170
|
def check_hallucination_guard() -> tuple[bool, list[str]]:
|
|
1144
1171
|
"""Tablo/kolon iddiası yapan görevlerde SQL çalıştırılmış mı?
|
|
1145
1172
|
|
|
@@ -1365,6 +1392,7 @@ def run_guardian(full: bool = False) -> GuardianReport:
|
|
|
1365
1392
|
("cc_audit", check_cc_audit),
|
|
1366
1393
|
("network_safety", check_network_safety),
|
|
1367
1394
|
("hallucination_guard", check_hallucination_guard),
|
|
1395
|
+
("system_search_meta_filter", check_system_search_meta_filter),
|
|
1368
1396
|
]
|
|
1369
1397
|
|
|
1370
1398
|
checks = operational_checks + (code_checks if full else [])
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
"""cont --init — bundled binaries + wheels for offline setup.
|
|
2
|
+
|
|
3
|
+
Adımlar:
|
|
4
|
+
1. Ollama yüklü mü? Yoksa vendor/bin/ollama → ~/.local/bin/ kopyala
|
|
5
|
+
2. ollama serve & başlat (zaten çalışmıyorsa)
|
|
6
|
+
3. GGUF verildiyse `ollama create` ile model kaydet
|
|
7
|
+
4. /api/tags ile test et
|
|
8
|
+
|
|
9
|
+
llama-cpp-python wheel kurulumu opsiyonel kalıyor (Ollama önceliklidir).
|
|
10
|
+
"""
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import os
|
|
14
|
+
import shutil
|
|
15
|
+
import subprocess
|
|
16
|
+
import sys
|
|
17
|
+
import time
|
|
18
|
+
import urllib.request
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
|
|
21
|
+
OLLAMA_PORT = 11434
|
|
22
|
+
OLLAMA_URL = f"http://127.0.0.1:{OLLAMA_PORT}"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _vendor_dir(sub: str) -> Path:
|
|
26
|
+
"""Locate vendor/<sub> in source tree OR installed package."""
|
|
27
|
+
here = Path(__file__).resolve().parent
|
|
28
|
+
candidate = here.parent / "vendor" / sub
|
|
29
|
+
if candidate.exists():
|
|
30
|
+
return candidate
|
|
31
|
+
try:
|
|
32
|
+
import vendor # type: ignore
|
|
33
|
+
candidate = Path(vendor.__file__).parent / sub
|
|
34
|
+
if candidate.exists():
|
|
35
|
+
return candidate
|
|
36
|
+
except ImportError:
|
|
37
|
+
pass
|
|
38
|
+
return candidate
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _which(name: str) -> str | None:
|
|
42
|
+
return shutil.which(name)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _ollama_serve_running() -> bool:
|
|
46
|
+
try:
|
|
47
|
+
with urllib.request.urlopen(f"{OLLAMA_URL}/api/tags", timeout=2) as r:
|
|
48
|
+
return r.status == 200
|
|
49
|
+
except Exception:
|
|
50
|
+
return False
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _install_ollama() -> str:
|
|
54
|
+
"""Copy bundled ollama to ~/.local/bin/. Returns installed path."""
|
|
55
|
+
src = _vendor_dir("bin") / "ollama"
|
|
56
|
+
if not src.exists():
|
|
57
|
+
print(f"[HATA] vendor/bin/ollama bulunamadı: {src}")
|
|
58
|
+
sys.exit(1)
|
|
59
|
+
|
|
60
|
+
dest_dir = Path.home() / ".local" / "bin"
|
|
61
|
+
dest_dir.mkdir(parents=True, exist_ok=True)
|
|
62
|
+
dest = dest_dir / "ollama"
|
|
63
|
+
shutil.copy2(src, dest)
|
|
64
|
+
dest.chmod(0o755)
|
|
65
|
+
print(f"[OK] ollama → {dest}")
|
|
66
|
+
|
|
67
|
+
# PATH uyarısı
|
|
68
|
+
if str(dest_dir) not in os.environ.get("PATH", "").split(":"):
|
|
69
|
+
print(f"[UYARI] {dest_dir} PATH'te değil. ~/.bashrc'ye ekle:")
|
|
70
|
+
print(f' export PATH="{dest_dir}:$PATH"')
|
|
71
|
+
return str(dest)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _start_ollama_serve(ollama_bin: str) -> bool:
|
|
75
|
+
"""Start `ollama serve` in background. Returns True if up within 10s."""
|
|
76
|
+
if _ollama_serve_running():
|
|
77
|
+
print("[OK] ollama serve zaten çalışıyor")
|
|
78
|
+
return True
|
|
79
|
+
|
|
80
|
+
print("[*] ollama serve başlatılıyor...")
|
|
81
|
+
log_path = Path.home() / ".cache" / "cont" / "ollama_serve.log"
|
|
82
|
+
log_path.parent.mkdir(parents=True, exist_ok=True)
|
|
83
|
+
log_fp = open(log_path, "ab")
|
|
84
|
+
subprocess.Popen(
|
|
85
|
+
[ollama_bin, "serve"],
|
|
86
|
+
stdout=log_fp, stderr=log_fp,
|
|
87
|
+
start_new_session=True,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
for _ in range(20):
|
|
91
|
+
time.sleep(0.5)
|
|
92
|
+
if _ollama_serve_running():
|
|
93
|
+
print(f"[OK] ollama serve hazır (log: {log_path})")
|
|
94
|
+
return True
|
|
95
|
+
|
|
96
|
+
print(f"[HATA] ollama serve 10s içinde yanıt vermedi (log: {log_path})")
|
|
97
|
+
return False
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def _create_model_from_gguf(ollama_bin: str, gguf_path: Path,
|
|
101
|
+
model_name: str = "cont-local") -> bool:
|
|
102
|
+
"""Generate Modelfile + run `ollama create`."""
|
|
103
|
+
print(f"[*] {model_name} modeli {gguf_path.name} GGUF'undan oluşturuluyor...")
|
|
104
|
+
modelfile = Path.home() / ".cache" / "cont" / "Modelfile.cont"
|
|
105
|
+
modelfile.parent.mkdir(parents=True, exist_ok=True)
|
|
106
|
+
modelfile.write_text(f"FROM {gguf_path}\n", encoding="utf-8")
|
|
107
|
+
|
|
108
|
+
try:
|
|
109
|
+
subprocess.run(
|
|
110
|
+
[ollama_bin, "create", model_name, "-f", str(modelfile)],
|
|
111
|
+
check=True,
|
|
112
|
+
)
|
|
113
|
+
print(f"[OK] model kaydedildi: {model_name}")
|
|
114
|
+
return True
|
|
115
|
+
except subprocess.CalledProcessError as e:
|
|
116
|
+
print(f"[HATA] ollama create başarısız: {e}")
|
|
117
|
+
return False
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _smoke_test(model_name: str) -> bool:
|
|
121
|
+
"""Hızlı /api/generate çağrısı — model yanıt veriyor mu?"""
|
|
122
|
+
print(f"[*] {model_name} smoke test...")
|
|
123
|
+
import json
|
|
124
|
+
body = json.dumps({
|
|
125
|
+
"model": model_name,
|
|
126
|
+
"prompt": "2+2=?",
|
|
127
|
+
"stream": False,
|
|
128
|
+
}).encode()
|
|
129
|
+
req = urllib.request.Request(
|
|
130
|
+
f"{OLLAMA_URL}/api/generate",
|
|
131
|
+
data=body,
|
|
132
|
+
headers={"Content-Type": "application/json"},
|
|
133
|
+
method="POST",
|
|
134
|
+
)
|
|
135
|
+
try:
|
|
136
|
+
with urllib.request.urlopen(req, timeout=120) as r:
|
|
137
|
+
resp = json.loads(r.read())
|
|
138
|
+
ans = (resp.get("response") or "").strip()[:80]
|
|
139
|
+
print(f"[OK] yanıt: {ans!r}")
|
|
140
|
+
return True
|
|
141
|
+
except Exception as e:
|
|
142
|
+
print(f"[HATA] smoke test başarısız: {e}")
|
|
143
|
+
return False
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def run_init(gguf_path: str | None = None) -> None:
|
|
147
|
+
print("Cont init başlıyor...\n")
|
|
148
|
+
|
|
149
|
+
# 1. Ollama var mı?
|
|
150
|
+
ollama_bin = _which("ollama")
|
|
151
|
+
if ollama_bin:
|
|
152
|
+
print(f"[OK] ollama zaten yüklü: {ollama_bin}")
|
|
153
|
+
else:
|
|
154
|
+
ollama_bin = _install_ollama()
|
|
155
|
+
|
|
156
|
+
# 2. Servis ayağa kalksın
|
|
157
|
+
if not _start_ollama_serve(ollama_bin):
|
|
158
|
+
sys.exit(1)
|
|
159
|
+
|
|
160
|
+
# 3. GGUF verildiyse model oluştur
|
|
161
|
+
if gguf_path:
|
|
162
|
+
gp = Path(gguf_path).expanduser()
|
|
163
|
+
if not gp.exists():
|
|
164
|
+
print(f"[HATA] GGUF bulunamadı: {gp}")
|
|
165
|
+
sys.exit(1)
|
|
166
|
+
|
|
167
|
+
model_name = "cont-local"
|
|
168
|
+
if not _create_model_from_gguf(ollama_bin, gp, model_name):
|
|
169
|
+
sys.exit(1)
|
|
170
|
+
|
|
171
|
+
# 4. Test
|
|
172
|
+
if not _smoke_test(model_name):
|
|
173
|
+
sys.exit(1)
|
|
174
|
+
|
|
175
|
+
print(f"\n[BAŞARILI] Cont kullanıma hazır.")
|
|
176
|
+
print(f" Modeli kullanmak için: cont --model ollama:{model_name}")
|
|
177
|
+
else:
|
|
178
|
+
print("\n[INFO] GGUF verilmedi — model oluşturulmadı.")
|
|
179
|
+
print(" Daha sonra: cont --init <model.gguf>")
|
|
180
|
+
|
|
181
|
+
print("\nInit tamamlandı.")
|
|
@@ -1168,6 +1168,8 @@ def run_task(task: str, logger=None, event_callback=None) -> tuple:
|
|
|
1168
1168
|
tool_choice="none" if budget_exhausted else "auto",
|
|
1169
1169
|
base_url=getattr(_ctx, "base_url", ""),
|
|
1170
1170
|
iteration=iteration,
|
|
1171
|
+
budget_used=budget.phase_calls,
|
|
1172
|
+
budget_total=budget.BUDGET_PER_PHASE,
|
|
1171
1173
|
)
|
|
1172
1174
|
|
|
1173
1175
|
_spin_stop = threading.Event()
|
|
@@ -457,9 +457,20 @@ class SelfImproveLoop:
|
|
|
457
457
|
self._thread.start()
|
|
458
458
|
|
|
459
459
|
def _print_background_status(self, message):
|
|
460
|
-
"""
|
|
461
|
-
|
|
462
|
-
|
|
460
|
+
"""Write status to daemon log — NEVER to terminal (would break input).
|
|
461
|
+
|
|
462
|
+
Use `cont --triage` or `cont --status` to view recent activity.
|
|
463
|
+
"""
|
|
464
|
+
try:
|
|
465
|
+
from datetime import datetime
|
|
466
|
+
from pathlib import Path
|
|
467
|
+
log_dir = Path.home() / ".config" / "cont" / "daemon"
|
|
468
|
+
log_dir.mkdir(parents=True, exist_ok=True)
|
|
469
|
+
log_file = log_dir / "self_improve.log"
|
|
470
|
+
with open(log_file, "a", encoding="utf-8") as f:
|
|
471
|
+
f.write(f"[{datetime.now().isoformat(timespec='seconds')}] {message}\n")
|
|
472
|
+
except Exception:
|
|
473
|
+
pass
|
|
463
474
|
|
|
464
475
|
def _should_stop(self) -> bool:
|
|
465
476
|
"""Check if we should stop (user active or stop requested)."""
|
|
@@ -132,6 +132,23 @@ def extract_fenced_tool_requests(text: str) -> list:
|
|
|
132
132
|
except json.JSONDecodeError:
|
|
133
133
|
idx = brace + 1
|
|
134
134
|
|
|
135
|
+
# b3) Parenthesized form: (tool_name\n {...}) — Qwen3 emit fallback
|
|
136
|
+
# Example: "(web_search\n {\"query\": \"...\"})"
|
|
137
|
+
if "(" in text:
|
|
138
|
+
for m in re.finditer(r'\(\s*([a-z_][a-z0-9_]*)\s+', text):
|
|
139
|
+
name = m.group(1)
|
|
140
|
+
# Try raw_decode JSON starting after the tool name
|
|
141
|
+
tail = text[m.end():]
|
|
142
|
+
brace = tail.find("{")
|
|
143
|
+
if brace == -1 or brace > 5:
|
|
144
|
+
continue
|
|
145
|
+
try:
|
|
146
|
+
obj, _ = json.JSONDecoder().raw_decode(tail[brace:])
|
|
147
|
+
if isinstance(obj, dict):
|
|
148
|
+
tool_calls.append({"name": name, "args": obj})
|
|
149
|
+
except json.JSONDecodeError:
|
|
150
|
+
pass
|
|
151
|
+
|
|
135
152
|
# c) Bare JSON tool call (Ollama Qwen3 fallback)
|
|
136
153
|
# Pattern: yanıt bir tool call JSON ile başlıyor veya tek satır
|
|
137
154
|
if not tool_calls and text.strip().startswith(("{", "[")):
|
|
@@ -779,6 +779,14 @@ def system_search(query: str, type: str = None, extension: str = None,
|
|
|
779
779
|
extension=extension, project=project
|
|
780
780
|
)
|
|
781
781
|
|
|
782
|
+
# META veri filtresi: log/pheromone/inbox/__pycache__ dosyaları DATA değil
|
|
783
|
+
_META_DIR_TOKENS = ("/logs/", "/.cont/hive/pheromone/",
|
|
784
|
+
"/.cont/hive/inbox/", "/__pycache__/")
|
|
785
|
+
results = [
|
|
786
|
+
r for r in results
|
|
787
|
+
if not any(tok in r.get("path", "") for tok in _META_DIR_TOKENS)
|
|
788
|
+
]
|
|
789
|
+
|
|
782
790
|
if not results:
|
|
783
791
|
return json.dumps({
|
|
784
792
|
"status": "not_found",
|
|
@@ -226,6 +226,40 @@ _ROLE_COLORS = {
|
|
|
226
226
|
}
|
|
227
227
|
_ROLE_TAGS = {"system": "S", "user": "U", "assistant": "A", "tool": "T"}
|
|
228
228
|
|
|
229
|
+
# FULL-mode role styling: tag → (rich color, label)
|
|
230
|
+
_FULL_ROLE_STYLE = {
|
|
231
|
+
"system": ("dim", "S"),
|
|
232
|
+
"user": ("bold white", "U"),
|
|
233
|
+
"assistant": ("green", "A"),
|
|
234
|
+
"tool": ("cyan", "T"),
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def _box_lines(title: str, body_lines: list, color: str = "yellow", width: int = 70) -> list:
|
|
239
|
+
"""Build a Rich-markup box: ┌─ title ──┐ / │ ... │ / └────────┘"""
|
|
240
|
+
inner_w = width - 2
|
|
241
|
+
title_str = f" {title} "
|
|
242
|
+
top = f"[{color}]┌─{title_str}{'─' * max(0, inner_w - len(title_str) - 1)}┐[/{color}]"
|
|
243
|
+
out = [top]
|
|
244
|
+
for ln in body_lines:
|
|
245
|
+
# Strip rich tags for length calc
|
|
246
|
+
plain = re.sub(r"\[/?[^\]]+\]", "", ln)
|
|
247
|
+
pad = max(0, inner_w - len(plain) - 1)
|
|
248
|
+
out.append(f"[{color}]│[/{color}] {ln}{' ' * pad}[{color}]│[/{color}]")
|
|
249
|
+
out.append(f"[{color}]└{'─' * inner_w}┘[/{color}]")
|
|
250
|
+
return out
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def _budget_bar(used: int, total: int, width: int = 16) -> str:
|
|
254
|
+
"""ASCII progress bar: ████░░░░░░░░ 3/12"""
|
|
255
|
+
if total <= 0:
|
|
256
|
+
return ""
|
|
257
|
+
filled = int(round(width * used / total))
|
|
258
|
+
filled = max(0, min(width, filled))
|
|
259
|
+
bar = "█" * filled + "░" * (width - filled)
|
|
260
|
+
color = "green" if used < total * 0.7 else ("yellow" if used < total else "red")
|
|
261
|
+
return f"[{color}]{bar}[/{color}] [dim]{used}/{total}[/dim]"
|
|
262
|
+
|
|
229
263
|
|
|
230
264
|
# ── Public hooks ─────────────────────────────────────────────────
|
|
231
265
|
|
|
@@ -237,6 +271,8 @@ def trace_llm_request(
|
|
|
237
271
|
tool_choice: Optional[str],
|
|
238
272
|
base_url: str = "",
|
|
239
273
|
iteration: int = 0,
|
|
274
|
+
budget_used: int = 0,
|
|
275
|
+
budget_total: int = 0,
|
|
240
276
|
):
|
|
241
277
|
"""Hook: BEFORE LLM API call. Caller must guard with is_off()."""
|
|
242
278
|
if _level == TraceLevel.OFF:
|
|
@@ -254,42 +290,30 @@ def trace_llm_request(
|
|
|
254
290
|
tc = tool_choice or "auto"
|
|
255
291
|
|
|
256
292
|
if _level == TraceLevel.STORY:
|
|
257
|
-
#
|
|
258
|
-
|
|
259
|
-
_rich(f"[bold white on #333333] 🎬 TURN #{_turn_counter} [/bold white on #333333]"
|
|
260
|
-
f"
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
# Section A: INPUT (to LLM) — last K messages
|
|
264
|
-
_rich("[bold #6699cc] 🧠 INPUT (to LLM)[/bold #6699cc]")
|
|
265
|
-
tail = messages[-_last_k:]
|
|
266
|
-
for m in tail:
|
|
267
|
-
role = m.get("role", "?")
|
|
268
|
-
tag = _ROLE_TAGS.get(role, "?")
|
|
269
|
-
color = _ROLE_COLORS.get(role, "dim")
|
|
270
|
-
raw_content = m.get("content", "") or ""
|
|
271
|
-
|
|
272
|
-
# Special: tool results show tool name
|
|
273
|
-
if role == "tool":
|
|
274
|
-
tool_id = m.get("tool_call_id", "")
|
|
275
|
-
short = _sanitize(_preview(raw_content, 120))
|
|
276
|
-
_rich(f" [{color}]\\[T][/{color}] [dim]{short}[/dim]")
|
|
277
|
-
else:
|
|
278
|
-
short = _sanitize(_preview(raw_content, 140))
|
|
279
|
-
_rich(f" [{color}]\\[{tag}][/{color}] {short}")
|
|
280
|
-
|
|
281
|
-
elif _level == TraceLevel.COMPACT or _level == TraceLevel.FULL:
|
|
282
|
-
# ── COMPACT/FULL: technical one-liner ──
|
|
293
|
+
# STORY: minimal turn header only — intent+result come from
|
|
294
|
+
# trace_story_intent and trace_tool_result.
|
|
295
|
+
_rich(f"\n[bold white on #333333] 🎬 TURN #{_turn_counter} [/bold white on #333333] "
|
|
296
|
+
f"[dim]{provider} {model} ~{est_tok}tok[/dim]")
|
|
297
|
+
|
|
298
|
+
elif _level == TraceLevel.COMPACT:
|
|
283
299
|
_emit(
|
|
284
300
|
f"LLM→ provider={provider} model={model} msgs={msg_count} "
|
|
285
301
|
f"roles={roles} tools={tools_str} tool_choice={tc} est_tok_in={est_tok}"
|
|
286
302
|
)
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
303
|
+
|
|
304
|
+
elif _level == TraceLevel.FULL:
|
|
305
|
+
# FULL: rich formatted LLM INPUT block + budget bar
|
|
306
|
+
_rich("")
|
|
307
|
+
_rich(f"[bold white on #2255aa] 🎬 TURN #{_turn_counter} [/bold white on #2255aa] "
|
|
308
|
+
f"[dim]{provider} • {model} • ~{est_tok}tok • tools={tools_str}/{tc}[/dim]")
|
|
309
|
+
if budget_total > 0:
|
|
310
|
+
_rich(f" [bold]📊 BÜTÇE:[/bold] {_budget_bar(budget_used, budget_total)} call")
|
|
311
|
+
_rich("[bold #6699cc]🧠 LLM INPUT[/bold #6699cc]")
|
|
312
|
+
for m in messages[-_last_k:]:
|
|
313
|
+
role = m.get("role", "?")
|
|
314
|
+
color, tag = _FULL_ROLE_STYLE.get(role, ("dim", "?"))
|
|
315
|
+
content = _sanitize(_preview(m.get("content", "") or "", 220))
|
|
316
|
+
_rich(f" [{color}]\\[{tag}][/{color}] {content}")
|
|
293
317
|
|
|
294
318
|
_emit_jsonl({
|
|
295
319
|
"event": "llm_request",
|
|
@@ -318,30 +342,27 @@ def trace_llm_response(
|
|
|
318
342
|
out_chars = len(content or "")
|
|
319
343
|
|
|
320
344
|
if _level == TraceLevel.STORY:
|
|
321
|
-
#
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
if tool_calls_count:
|
|
326
|
-
names = ", ".join(tool_names[:4]) if tool_names else f"{tool_calls_count} tool(s)"
|
|
327
|
-
_rich(f" [yellow]→ Tool calls: {names}[/yellow]")
|
|
345
|
+
# STORY: minimal — trace_story_intent handles intent+chain
|
|
346
|
+
if not tool_calls_count and content and content.strip():
|
|
347
|
+
short = _sanitize(_preview(content, 200))
|
|
348
|
+
_rich(f" [green]💬[/green] [dim]{short}[/dim] [dim]({latency_ms}ms)[/dim]")
|
|
328
349
|
|
|
329
|
-
|
|
330
|
-
lines = content.strip().split("\n")
|
|
331
|
-
for ln in lines[:_max_lines]:
|
|
332
|
-
short = _sanitize(ln[:200])
|
|
333
|
-
_rich(f" [dim]{short}[/dim]")
|
|
334
|
-
|
|
335
|
-
elif _level == TraceLevel.COMPACT or _level == TraceLevel.FULL:
|
|
336
|
-
# ── COMPACT/FULL: technical one-liner ──
|
|
350
|
+
elif _level == TraceLevel.COMPACT:
|
|
337
351
|
line = f"LLM← stop={finish_reason} out_chars={out_chars} latency={latency_ms}ms"
|
|
338
352
|
if tool_calls_count:
|
|
339
353
|
line += f" tool_calls={tool_calls_count}"
|
|
340
354
|
_emit(line)
|
|
341
355
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
356
|
+
elif _level == TraceLevel.FULL:
|
|
357
|
+
# FULL: rich model thought block
|
|
358
|
+
_rich(f"[bold #66cc99]💭 MODEL DÜŞÜNCE[/bold #66cc99] "
|
|
359
|
+
f"[dim]{latency_ms}ms • {out_chars} chars • stop={finish_reason}[/dim]")
|
|
360
|
+
if content and content.strip():
|
|
361
|
+
for ln in content.strip().split("\n")[:_max_lines]:
|
|
362
|
+
_rich(f" [dim italic]\"{_sanitize(ln[:200])}\"[/dim italic]")
|
|
363
|
+
if tool_calls_count:
|
|
364
|
+
names = ", ".join(tool_names[:4]) if tool_names else f"{tool_calls_count} tool(s)"
|
|
365
|
+
_rich(f" [yellow]→ next: {names}[/yellow]")
|
|
345
366
|
|
|
346
367
|
_emit_jsonl({
|
|
347
368
|
"event": "llm_response",
|
|
@@ -365,11 +386,23 @@ def trace_tool_call(
|
|
|
365
386
|
h = _args_hash(args)
|
|
366
387
|
|
|
367
388
|
if _level == TraceLevel.STORY:
|
|
368
|
-
# ── STORY: narrative tool beat ──
|
|
369
389
|
human = _sanitize(_human_args(tool_name, args))
|
|
370
390
|
_rich(f" [bold yellow]⚙️ {tool_name}[/bold yellow] [dim]{human}[/dim]")
|
|
391
|
+
|
|
392
|
+
elif _level == TraceLevel.FULL:
|
|
393
|
+
# FULL: 🔧 boxed tool call
|
|
394
|
+
_rich("[bold yellow]🔧 TOOL CALL[/bold yellow]")
|
|
395
|
+
body = []
|
|
396
|
+
for k, v in list(args.items())[:6]:
|
|
397
|
+
val = _sanitize(_preview(str(v), 60))
|
|
398
|
+
body.append(f"[dim]{k}:[/dim] {val}")
|
|
399
|
+
if not body:
|
|
400
|
+
body = ["[dim](no args)[/dim]"]
|
|
401
|
+
for ln in _box_lines(tool_name, body, color="yellow", width=72):
|
|
402
|
+
_rich(ln)
|
|
403
|
+
|
|
371
404
|
else:
|
|
372
|
-
#
|
|
405
|
+
# COMPACT
|
|
373
406
|
prev = _sanitize(_preview(json.dumps(args, ensure_ascii=False), 160))
|
|
374
407
|
_emit(f"TOOL→ {tool_name} args_hash={h} args_preview=\"{prev}\"")
|
|
375
408
|
|
|
@@ -398,15 +431,25 @@ def trace_tool_result(
|
|
|
398
431
|
preview = _sanitize(_preview(result_preview, 120))
|
|
399
432
|
|
|
400
433
|
if _level == TraceLevel.STORY:
|
|
401
|
-
# ── STORY: narrative result ──
|
|
402
434
|
if error:
|
|
403
435
|
err_short = _sanitize(_preview(str(error), 80))
|
|
404
436
|
_rich(f" [bold red]❌ ERROR[/bold red] [dim]{err_short} ({latency_ms}ms)[/dim]")
|
|
405
437
|
else:
|
|
406
438
|
_rich(f" [green]✅ ok[/green] [dim]{result_chars} chars {latency_ms}ms[/dim]"
|
|
407
439
|
f" [dim italic]{preview[:80]}[/dim italic]")
|
|
440
|
+
|
|
441
|
+
elif _level == TraceLevel.FULL:
|
|
442
|
+
if error:
|
|
443
|
+
err_short = _sanitize(_preview(str(error), 100))
|
|
444
|
+
_rich(f" [bold red]→ ❌ {err_short}[/bold red] [dim]({latency_ms}ms)[/dim]")
|
|
445
|
+
else:
|
|
446
|
+
_rich(f" [bold green]→ ✅ {result_chars} chars[/bold green] [dim]({latency_ms}ms)[/dim]")
|
|
447
|
+
if result_preview:
|
|
448
|
+
for ln in result_preview.split("\n")[:_max_lines]:
|
|
449
|
+
_rich(f" [cyan]{_sanitize(ln[:200])}[/cyan]")
|
|
450
|
+
|
|
408
451
|
else:
|
|
409
|
-
#
|
|
452
|
+
# COMPACT
|
|
410
453
|
status = "err" if error else "ok"
|
|
411
454
|
line = f"TOOL← {status} {tool_name} chars={result_chars} latency={latency_ms}ms"
|
|
412
455
|
if error:
|
|
@@ -415,10 +458,6 @@ def trace_tool_result(
|
|
|
415
458
|
line += f" preview=\"{preview}\""
|
|
416
459
|
_emit(line)
|
|
417
460
|
|
|
418
|
-
if _level >= TraceLevel.FULL and result_preview:
|
|
419
|
-
for ln in result_preview.split("\n")[:_max_lines]:
|
|
420
|
-
_emit(f" | {_sanitize(ln[:200])}")
|
|
421
|
-
|
|
422
461
|
_emit_jsonl({
|
|
423
462
|
"event": "tool_result",
|
|
424
463
|
"tool_name": tool_name,
|
|
@@ -538,6 +577,18 @@ def trace_memory_recall(
|
|
|
538
577
|
content = _sanitize(_preview(snip.get("content", ""), 120))
|
|
539
578
|
color = "green" if level == "HIGH" else "dim"
|
|
540
579
|
_rich(f" [{color}]\\[{level}][/{color}] {content}")
|
|
580
|
+
elif _level == TraceLevel.FULL:
|
|
581
|
+
snips = list(top_snippets or [])
|
|
582
|
+
_rich(f"[bold #cc99ff]🧠 MEMORY[/bold #cc99ff] [dim]({source}, {result_count} hits)[/dim]")
|
|
583
|
+
for i, snip in enumerate(snips[:4]):
|
|
584
|
+
is_last = (i == min(3, len(snips) - 1))
|
|
585
|
+
branch = "└─" if is_last else "├─"
|
|
586
|
+
level = snip.get("level", "?")
|
|
587
|
+
content = _sanitize(_preview(snip.get("content", ""), 120))
|
|
588
|
+
color = "yellow" if level == "HIGH" else "dim"
|
|
589
|
+
_rich(f" [{color}]{branch} [{level}][/{color}] {content}")
|
|
590
|
+
if not snips:
|
|
591
|
+
_rich(f" [dim]└─ (no snippets)[/dim]")
|
|
541
592
|
else:
|
|
542
593
|
_emit(f"MEMORY {source}: {entity_count} entities → {result_count} results")
|
|
543
594
|
for snip in (top_snippets or [])[:2]:
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "codent"
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.3"
|
|
8
8
|
requires-python = ">=3.10"
|
|
9
9
|
dependencies = [
|
|
10
10
|
"rich>=13.0",
|
|
@@ -26,7 +26,14 @@ cont = "cont:main"
|
|
|
26
26
|
|
|
27
27
|
[tool.setuptools]
|
|
28
28
|
py-modules = ["cont", "cont_watcher"]
|
|
29
|
-
packages = ["core", "cont_ui"]
|
|
29
|
+
packages = ["core", "cont_ui", "vendor", "vendor.wheels", "vendor.bin"]
|
|
30
|
+
|
|
31
|
+
[tool.setuptools.package-dir]
|
|
32
|
+
vendor = "vendor"
|
|
33
|
+
"vendor.wheels" = "vendor/wheels"
|
|
34
|
+
"vendor.bin" = "vendor/bin"
|
|
30
35
|
|
|
31
36
|
[tool.setuptools.package-data]
|
|
32
37
|
"*" = ["*.toml", "*.html", "*.yaml"]
|
|
38
|
+
"vendor.wheels" = ["*.whl"]
|
|
39
|
+
"vendor.bin" = ["ollama"]
|
|
File without changes
|
|
File without changes
|
|
Binary file
|
|
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
|
|
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
|