codent 0.3.4__tar.gz → 0.3.6__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.
Files changed (133) hide show
  1. {codent-0.3.4 → codent-0.3.6}/PKG-INFO +1 -1
  2. {codent-0.3.4 → codent-0.3.6}/codent.egg-info/PKG-INFO +1 -1
  3. {codent-0.3.4 → codent-0.3.6}/core/context_utils.py +3 -0
  4. {codent-0.3.4 → codent-0.3.6}/core/identity.py +14 -88
  5. {codent-0.3.4 → codent-0.3.6}/core/init_cmd.py +67 -1
  6. {codent-0.3.4 → codent-0.3.6}/core/prompts.py +44 -126
  7. {codent-0.3.4 → codent-0.3.6}/core/tool_helpers.py +3 -3
  8. {codent-0.3.4 → codent-0.3.6}/pyproject.toml +1 -1
  9. {codent-0.3.4 → codent-0.3.6}/codent.egg-info/SOURCES.txt +0 -0
  10. {codent-0.3.4 → codent-0.3.6}/codent.egg-info/dependency_links.txt +0 -0
  11. {codent-0.3.4 → codent-0.3.6}/codent.egg-info/entry_points.txt +0 -0
  12. {codent-0.3.4 → codent-0.3.6}/codent.egg-info/requires.txt +0 -0
  13. {codent-0.3.4 → codent-0.3.6}/codent.egg-info/top_level.txt +0 -0
  14. {codent-0.3.4 → codent-0.3.6}/cont.py +0 -0
  15. {codent-0.3.4 → codent-0.3.6}/cont_ui/__init__.py +0 -0
  16. {codent-0.3.4 → codent-0.3.6}/cont_ui/frontend.html +0 -0
  17. {codent-0.3.4 → codent-0.3.6}/cont_ui/server.py +0 -0
  18. {codent-0.3.4 → codent-0.3.6}/cont_watcher.py +0 -0
  19. {codent-0.3.4 → codent-0.3.6}/core/__init__.py +0 -0
  20. {codent-0.3.4 → codent-0.3.6}/core/adaptive_prompt.py +0 -0
  21. {codent-0.3.4 → codent-0.3.6}/core/advanced_overnight.py +0 -0
  22. {codent-0.3.4 → codent-0.3.6}/core/anomaly_tools.py +0 -0
  23. {codent-0.3.4 → codent-0.3.6}/core/app.py +0 -0
  24. {codent-0.3.4 → codent-0.3.6}/core/auto_eval.py +0 -0
  25. {codent-0.3.4 → codent-0.3.6}/core/automations.py +0 -0
  26. {codent-0.3.4 → codent-0.3.6}/core/benchmark.py +0 -0
  27. {codent-0.3.4 → codent-0.3.6}/core/bridge_server.py +0 -0
  28. {codent-0.3.4 → codent-0.3.6}/core/browser.py +0 -0
  29. {codent-0.3.4 → codent-0.3.6}/core/browser_agent.py +0 -0
  30. {codent-0.3.4 → codent-0.3.6}/core/budget_committee.py +0 -0
  31. {codent-0.3.4 → codent-0.3.6}/core/cc_auditor.py +0 -0
  32. {codent-0.3.4 → codent-0.3.6}/core/cleaning_tools.py +0 -0
  33. {codent-0.3.4 → codent-0.3.6}/core/cli.py +0 -0
  34. {codent-0.3.4 → codent-0.3.6}/core/curriculum_runner.py +0 -0
  35. {codent-0.3.4 → codent-0.3.6}/core/daemon.py +0 -0
  36. {codent-0.3.4 → codent-0.3.6}/core/data_tools.py +0 -0
  37. {codent-0.3.4 → codent-0.3.6}/core/decomposer.py +0 -0
  38. {codent-0.3.4 → codent-0.3.6}/core/domain_tools.py +0 -0
  39. {codent-0.3.4 → codent-0.3.6}/core/endpoint_discovery.py +0 -0
  40. {codent-0.3.4 → codent-0.3.6}/core/env_snapshot.py +0 -0
  41. {codent-0.3.4 → codent-0.3.6}/core/episodic.py +0 -0
  42. {codent-0.3.4 → codent-0.3.6}/core/escalation.py +0 -0
  43. {codent-0.3.4 → codent-0.3.6}/core/events.py +0 -0
  44. {codent-0.3.4 → codent-0.3.6}/core/feedback_training.py +0 -0
  45. {codent-0.3.4 → codent-0.3.6}/core/file_context.py +0 -0
  46. {codent-0.3.4 → codent-0.3.6}/core/fitness.py +0 -0
  47. {codent-0.3.4 → codent-0.3.6}/core/formatters.py +0 -0
  48. {codent-0.3.4 → codent-0.3.6}/core/genesis.py +0 -0
  49. {codent-0.3.4 → codent-0.3.6}/core/golden_test_runner.py +0 -0
  50. {codent-0.3.4 → codent-0.3.6}/core/guardian.py +0 -0
  51. {codent-0.3.4 → codent-0.3.6}/core/hive_recall.py +0 -0
  52. {codent-0.3.4 → codent-0.3.6}/core/intent_detection.py +0 -0
  53. {codent-0.3.4 → codent-0.3.6}/core/intent_gate.py +0 -0
  54. {codent-0.3.4 → codent-0.3.6}/core/learning_loop.py +0 -0
  55. {codent-0.3.4 → codent-0.3.6}/core/lmstudio.py +0 -0
  56. {codent-0.3.4 → codent-0.3.6}/core/local_llm.py +0 -0
  57. {codent-0.3.4 → codent-0.3.6}/core/memory_eviction.py +0 -0
  58. {codent-0.3.4 → codent-0.3.6}/core/memory_gate.py +0 -0
  59. {codent-0.3.4 → codent-0.3.6}/core/memory_store.py +0 -0
  60. {codent-0.3.4 → codent-0.3.6}/core/ml_tools.py +0 -0
  61. {codent-0.3.4 → codent-0.3.6}/core/model.py +0 -0
  62. {codent-0.3.4 → codent-0.3.6}/core/model_routing.py +0 -0
  63. {codent-0.3.4 → codent-0.3.6}/core/network_audit.py +0 -0
  64. {codent-0.3.4 → codent-0.3.6}/core/ocr.py +0 -0
  65. {codent-0.3.4 → codent-0.3.6}/core/overfit_test.py +0 -0
  66. {codent-0.3.4 → codent-0.3.6}/core/overnight_training.py +0 -0
  67. {codent-0.3.4 → codent-0.3.6}/core/path_resolution.py +0 -0
  68. {codent-0.3.4 → codent-0.3.6}/core/postprocess.py +0 -0
  69. {codent-0.3.4 → codent-0.3.6}/core/prefetch.py +0 -0
  70. {codent-0.3.4 → codent-0.3.6}/core/prompt_patches.py +0 -0
  71. {codent-0.3.4 → codent-0.3.6}/core/provider_router.py +0 -0
  72. {codent-0.3.4 → codent-0.3.6}/core/quick_overfit_test.py +0 -0
  73. {codent-0.3.4 → codent-0.3.6}/core/recipe_factory.py +0 -0
  74. {codent-0.3.4 → codent-0.3.6}/core/recipe_feedback.py +0 -0
  75. {codent-0.3.4 → codent-0.3.6}/core/recipe_learner.py +0 -0
  76. {codent-0.3.4 → codent-0.3.6}/core/recipes.py +0 -0
  77. {codent-0.3.4 → codent-0.3.6}/core/relation_discovery.py +0 -0
  78. {codent-0.3.4 → codent-0.3.6}/core/relay.py +0 -0
  79. {codent-0.3.4 → codent-0.3.6}/core/repl.py +0 -0
  80. {codent-0.3.4 → codent-0.3.6}/core/router.py +0 -0
  81. {codent-0.3.4 → codent-0.3.6}/core/rpc.py +0 -0
  82. {codent-0.3.4 → codent-0.3.6}/core/run_logger.py +0 -0
  83. {codent-0.3.4 → codent-0.3.6}/core/runtime.py +0 -0
  84. {codent-0.3.4 → codent-0.3.6}/core/safety.py +0 -0
  85. {codent-0.3.4 → codent-0.3.6}/core/scheduler.py +0 -0
  86. {codent-0.3.4 → codent-0.3.6}/core/scratchpad.py +0 -0
  87. {codent-0.3.4 → codent-0.3.6}/core/self_improve.py +0 -0
  88. {codent-0.3.4 → codent-0.3.6}/core/spreading_activation.py +0 -0
  89. {codent-0.3.4 → codent-0.3.6}/core/sql_guard.py +0 -0
  90. {codent-0.3.4 → codent-0.3.6}/core/sticky_config.py +0 -0
  91. {codent-0.3.4 → codent-0.3.6}/core/structured_output.py +0 -0
  92. {codent-0.3.4 → codent-0.3.6}/core/system_executor.py +0 -0
  93. {codent-0.3.4 → codent-0.3.6}/core/system_map.py +0 -0
  94. {codent-0.3.4 → codent-0.3.6}/core/task_classifier.py +0 -0
  95. {codent-0.3.4 → codent-0.3.6}/core/task_utils.py +0 -0
  96. {codent-0.3.4 → codent-0.3.6}/core/teacher.py +0 -0
  97. {codent-0.3.4 → codent-0.3.6}/core/tool_budget.py +0 -0
  98. {codent-0.3.4 → codent-0.3.6}/core/tool_schemas.py +0 -0
  99. {codent-0.3.4 → codent-0.3.6}/core/tools.py +0 -0
  100. {codent-0.3.4 → codent-0.3.6}/core/trace.py +0 -0
  101. {codent-0.3.4 → codent-0.3.6}/core/types.py +0 -0
  102. {codent-0.3.4 → codent-0.3.6}/core/utils.py +0 -0
  103. {codent-0.3.4 → codent-0.3.6}/core/verification.py +0 -0
  104. {codent-0.3.4 → codent-0.3.6}/core/verify_minions.py +0 -0
  105. {codent-0.3.4 → codent-0.3.6}/core/vocabulary.py +0 -0
  106. {codent-0.3.4 → codent-0.3.6}/core/voice.py +0 -0
  107. {codent-0.3.4 → codent-0.3.6}/core/web.py +0 -0
  108. {codent-0.3.4 → codent-0.3.6}/core/yis_deep_training.py +0 -0
  109. {codent-0.3.4 → codent-0.3.6}/setup.cfg +0 -0
  110. {codent-0.3.4 → codent-0.3.6}/tests/test_auto_eval.py +0 -0
  111. {codent-0.3.4 → codent-0.3.6}/tests/test_browser.py +0 -0
  112. {codent-0.3.4 → codent-0.3.6}/tests/test_browser_agent.py +0 -0
  113. {codent-0.3.4 → codent-0.3.6}/tests/test_commands_and_teach.py +0 -0
  114. {codent-0.3.4 → codent-0.3.6}/tests/test_cont.py +0 -0
  115. {codent-0.3.4 → codent-0.3.6}/tests/test_corpus_parser.py +0 -0
  116. {codent-0.3.4 → codent-0.3.6}/tests/test_episodic.py +0 -0
  117. {codent-0.3.4 → codent-0.3.6}/tests/test_eviction.py +0 -0
  118. {codent-0.3.4 → codent-0.3.6}/tests/test_formatters.py +0 -0
  119. {codent-0.3.4 → codent-0.3.6}/tests/test_golden.py +0 -0
  120. {codent-0.3.4 → codent-0.3.6}/tests/test_health_report_valid_json.py +0 -0
  121. {codent-0.3.4 → codent-0.3.6}/tests/test_integrity_and_memory_gate.py +0 -0
  122. {codent-0.3.4 → codent-0.3.6}/tests/test_known_bugs.py +0 -0
  123. {codent-0.3.4 → codent-0.3.6}/tests/test_model_agnostic.py +0 -0
  124. {codent-0.3.4 → codent-0.3.6}/tests/test_new_tools.py +0 -0
  125. {codent-0.3.4 → codent-0.3.6}/tests/test_provider_router.py +0 -0
  126. {codent-0.3.4 → codent-0.3.6}/tests/test_recipes.py +0 -0
  127. {codent-0.3.4 → codent-0.3.6}/tests/test_teacher.py +0 -0
  128. {codent-0.3.4 → codent-0.3.6}/tests/test_verification.py +0 -0
  129. {codent-0.3.4 → codent-0.3.6}/tests/test_web_fetch.py +0 -0
  130. {codent-0.3.4 → codent-0.3.6}/vendor/__init__.py +0 -0
  131. {codent-0.3.4 → codent-0.3.6}/vendor/bin/__init__.py +0 -0
  132. {codent-0.3.4 → codent-0.3.6}/vendor/bin/ollama +0 -0
  133. {codent-0.3.4 → codent-0.3.6}/vendor/wheels/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codent
3
- Version: 0.3.4
3
+ Version: 0.3.6
4
4
  Requires-Python: >=3.10
5
5
  Requires-Dist: rich>=13.0
6
6
  Requires-Dist: openai>=1.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codent
3
- Version: 0.3.4
3
+ Version: 0.3.6
4
4
  Requires-Python: >=3.10
5
5
  Requires-Dist: rich>=13.0
6
6
  Requires-Dist: openai>=1.0
@@ -1,3 +1,6 @@
1
+ import os
2
+
3
+ from core.tool_helpers import _classify_llm_error
1
4
 
2
5
 
3
6
  # Additional extractions from runtime.py
@@ -447,93 +447,19 @@ def get_current_state() -> dict:
447
447
  return {"_fresh": False}
448
448
 
449
449
  def get_startup_context() -> str:
450
- """Build startup context string for system prompt."""
451
- context_parts = []
452
-
453
- # 1. Location awareness
450
+ """Build minimal per-turn startup context (location only).
451
+
452
+ ADIM 2: Memory/learning/automation stats kaldırıldı.
453
+ Bunlar on-demand:
454
+ - Hafıza → memory_gate proaktif inject
455
+ - Recipes/vocabulary → recall tool
456
+ - Automations → list_automations tool
457
+ - Live state → where_am_i tool
458
+ """
454
459
  cont_home = get_cont_home()
455
460
  cwd = Path.cwd()
456
-
457
- context_parts.append(f"""
458
- ## Current Location
459
- - My home: {cont_home}
460
- - Current working directory: {cwd}
461
- - In my home: {cwd.resolve() == cont_home.resolve()}
462
- """)
463
-
464
- # 2. Current state (if watcher is running)
465
- state = get_current_state()
466
- if state:
467
- context_parts.append("## Live System State")
468
-
469
- if "recent_files" in state:
470
- recent = state["recent_files"][:5]
471
- if recent:
472
- context_parts.append("Recent file changes:")
473
- for f in recent:
474
- context_parts.append(f" - {f.get('action', '?')}: {f.get('path', '?')} ({f.get('time', '?')})")
475
-
476
- if "recent_commands" in state:
477
- recent = state["recent_commands"][:5]
478
- if recent:
479
- context_parts.append("Recent commands:")
480
- for c in recent:
481
- context_parts.append(f" - {c.get('cmd', '?')} ({c.get('time', '?')})")
482
-
483
- if "git_status" in state:
484
- git = state["git_status"]
485
- context_parts.append(f"Git: branch={git.get('branch', '?')}, uncommitted={git.get('uncommitted_changes', 0)}")
486
-
487
- # 3. Key memories (lazy import to avoid circular deps)
488
- try:
489
- from core.memory_store import memory_get_context
490
- key_memories = memory_get_context(limit=5)
491
- if key_memories:
492
- context_parts.append("\n## Key Memories")
493
- for mem in key_memories:
494
- context_parts.append(f"- [{mem['memory_type']}] {mem['content']}")
495
- except Exception:
496
- pass
497
-
498
- # 4. Learning system stats (lazy imports)
499
- try:
500
- from core.vocabulary import get_vocabulary_stats
501
- from core.recipes import load_recipes
502
- from core.prompt_patches import load_file_patches
503
- learning_parts = []
504
- # Vocabulary
505
- vstats = get_vocabulary_stats()
506
- if vstats.get("total", 0) > 0:
507
- learning_parts.append(f"Vocabulary: {vstats['commands']} commands, {vstats['context_words']} context words")
508
- # Recipes
509
- recipes = load_recipes()
510
- if recipes:
511
- learning_parts.append(f"Recipes: {len(recipes)} loaded")
512
- # File patches
513
- patches = load_file_patches()
514
- if patches:
515
- active = sum(1 for p in patches if p.get("active", True))
516
- learning_parts.append(f"Patches: {active} active")
517
-
518
- if learning_parts:
519
- context_parts.append("\n## Learning System")
520
- for lp in learning_parts:
521
- context_parts.append(f"- {lp}")
522
- except Exception:
523
- pass
524
-
525
- # 5. Automation system stats (lazy import)
526
- try:
527
- from core.automations import load_automations
528
- autos = load_automations()
529
- if autos:
530
- enabled = sum(1 for a in autos if a.get("enabled", True))
531
- context_parts.append(f"\n## Automations")
532
- context_parts.append(f"- {enabled}/{len(autos)} automations enabled")
533
- enabled_names = [a["name"] for a in autos if a.get("enabled", True)]
534
- if enabled_names:
535
- context_parts.append(f"- Active: {', '.join(enabled_names[:5])}")
536
- except Exception:
537
- pass
538
-
539
- return "\n".join(context_parts)
461
+ return (
462
+ f"## Current Location\n"
463
+ f"- My home: {cont_home}\n"
464
+ f"- CWD: {cwd}\n"
465
+ )
@@ -109,13 +109,79 @@ def _model_exists(ollama_bin: str, model_name: str) -> bool:
109
109
  return False
110
110
 
111
111
 
112
+ _QWEN3_CODER_TEMPLATE = '''{{- if .Messages }}
113
+ {{- if or .System .Tools }}<|im_start|>system
114
+ {{- if .System }}
115
+ {{ .System }}
116
+ {{- end }}
117
+ {{- if .Tools }}
118
+
119
+ # Tools
120
+
121
+ You may call one or more functions to assist with the user query.
122
+
123
+ You are provided with function signatures within <tools></tools> XML tags:
124
+ <tools>
125
+ {{- range .Tools }}
126
+ {"type": "function", "function": {{ .Function }}}
127
+ {{- end }}
128
+ </tools>
129
+
130
+ For each function call, return a json object with function name and arguments within <tool_call></tool_call> XML tags:
131
+ <tool_call>
132
+ {"name": <function-name>, "arguments": <args-json-object>}
133
+ </tool_call>
134
+ {{- end }}<|im_end|>
135
+ {{ end }}
136
+ {{- range $i, $_ := .Messages }}
137
+ {{- $last := eq (len (slice $.Messages $i)) 1 -}}
138
+ {{- if eq .Role "user" }}<|im_start|>user
139
+ {{ .Content }}<|im_end|>
140
+ {{ else if eq .Role "assistant" }}<|im_start|>assistant
141
+ {{ if .Content }}{{ .Content }}
142
+ {{- else if .ToolCalls }}<tool_call>
143
+ {{ range .ToolCalls }}{"name": "{{ .Function.Name }}", "arguments": {{ .Function.Arguments }}}
144
+ {{ end }}</tool_call>
145
+ {{- end }}{{ if not $last }}<|im_end|>
146
+ {{ end }}
147
+ {{- else if eq .Role "tool" }}<|im_start|>user
148
+ <tool_response>
149
+ {{ .Content }}
150
+ </tool_response><|im_end|>
151
+ {{ end }}
152
+ {{- if and (ne .Role "assistant") $last }}<|im_start|>assistant
153
+ {{ end }}
154
+ {{- end }}
155
+ {{- else }}
156
+ {{- if .System }}<|im_start|>system
157
+ {{ .System }}<|im_end|>
158
+ {{ end }}{{ if .Prompt }}<|im_start|>user
159
+ {{ .Prompt }}<|im_end|>
160
+ {{ end }}<|im_start|>assistant
161
+ {{ end }}{{ .Response }}{{ if .Response }}<|im_end|>{{ end }}'''
162
+
163
+
164
+ def _build_modelfile(gguf_path: Path) -> str:
165
+ """Qwen3-Coder tool-calling template + parameters."""
166
+ return (
167
+ f"FROM {gguf_path}\n\n"
168
+ f'TEMPLATE """{_QWEN3_CODER_TEMPLATE}"""\n\n'
169
+ 'PARAMETER num_ctx 10000\n'
170
+ 'PARAMETER temperature 0.1\n'
171
+ 'PARAMETER stop "<|im_start|>"\n'
172
+ 'PARAMETER stop "<|im_end|>"\n'
173
+ 'PARAMETER stop "<|endoftext|>"\n\n'
174
+ 'SYSTEM """You are a helpful coding assistant."""\n'
175
+ )
176
+
177
+
112
178
  def _create_model_from_gguf(ollama_bin: str, gguf_path: Path,
113
179
  model_name: str = "cont-local") -> bool:
114
180
  """Generate Modelfile + run `ollama create`."""
115
181
  print(f"[*] {model_name} modeli {gguf_path.name} GGUF'undan oluşturuluyor...")
116
182
  modelfile = Path.home() / ".cache" / "cont" / "Modelfile.cont"
117
183
  modelfile.parent.mkdir(parents=True, exist_ok=True)
118
- modelfile.write_text(f"FROM {gguf_path}\n", encoding="utf-8")
184
+ modelfile.write_text(_build_modelfile(gguf_path), encoding="utf-8")
119
185
 
120
186
  try:
121
187
  subprocess.run(
@@ -34,95 +34,13 @@ def _get_identity_context():
34
34
  return "", "", ""
35
35
 
36
36
  EVIDENCE_RULES = """
37
- STRICT EVIDENCE RULES - VIOLATIONS WILL BE REJECTED:
38
-
39
- 1. CITE YOUR SOURCE: Every factual claim must reference a specific tool call.
40
- BAD: "The file contains a function called main()"
41
- GOOD: "read_file('app.py') returned content showing line 15: 'def main():'"
42
-
43
- 2. DISTINGUISH VERIFIED vs UNVERIFIED:
44
- - VERIFIED: Information from tool calls THIS session
45
- - UNVERIFIED: Your training knowledge (mark with "[FROM KNOWLEDGE]")
46
-
47
- 3. FORBIDDEN PHRASES (will trigger verification failure):
48
- - "I assume..."
49
- - "Typically..."
50
- - "Usually..."
51
- - "The file probably..."
52
- - "Standard practice suggests..."
53
- - "It should have..."
54
- - "Most likely..."
55
-
56
- 4. MANDATORY VERIFICATION after file operations:
57
- - After write_file -> read_file to confirm
58
- - After run_shell -> check exit code, parse output
59
- - After repo_fetch -> list_dir on returned path
60
-
61
- 5. WHEN UNCERTAIN: Say "I did not verify this" or ask for clarification.
62
-
63
- 6. EMPTY/ERROR RESULTS: If a tool returns empty or error:
64
- - Report exactly what happened
65
- - Do NOT invent alternative results
66
- - Do NOT guess what "should" be there
37
+ EVIDENCE: Tool sonucu olmadan tablo/kolon/satır/sayı iddia etme. Her iddia bu session'daki bir tool çıktısına dayanmalı. Tool boş döndüyse "boş döndü" de — alternatif uydurma. Bilmiyorsan "bilmiyorum" veya "doğrulamadım" de.
67
38
  """
68
39
 
69
- STRUCTURED_RESPONSE_FORMAT = """
70
- FORMAT YOUR FINAL RESPONSE AS:
71
-
72
- ## Verified Facts
73
- List each fact with its source tool call:
74
- - [read_file('path')] Found: <exact content snippet>
75
- - [list_dir('path')] Contents: <actual listing>
76
- - [run_shell('cmd')] Exit code: X, Output: <summary>
77
-
78
- ## Actions Taken
79
- List each action with verification:
80
- - [write_file('path')] Created/Modified file
81
- - [VERIFIED via read_file: content matches]
82
- - [run_shell('cmd')] Executed command
83
- - [VERIFIED: exit code 0, output shows success]
84
-
85
- ## Unverified Information (if any)
86
- - [FROM KNOWLEDGE] <information from training, not tools>
87
-
88
- ## Answer
89
- <Your actual response to the user>
90
- """
40
+ STRUCTURED_RESPONSE_FORMAT = "" # ADIM 3: silindi (Cont kullanıcıya bu şablonu göstermiyordu zaten)
91
41
 
92
42
  MEMORY_INSTRUCTIONS = """
93
- MEMORY SYSTEM:
94
- You have persistent memory across conversations. Use it wisely:
95
-
96
- 1. PROACTIVE REMEMBERING: When you learn something important about the user or project,
97
- use the 'remember' tool immediately. Don't wait to be asked.
98
- - User mentions their name, role, preferences -> remember
99
- - Project details, tech stack, conventions -> remember
100
- - User corrects you or gives feedback -> remember as preference
101
-
102
- 2. PROACTIVE RECALL: Before making assumptions, check your memory:
103
- - Starting a task? recall("project context")
104
- - User asks about preferences? recall("user preference")
105
- - Unsure about something discussed before? recall relevant terms
106
-
107
- 3. MEMORY TYPES:
108
- - fact: Objective info ("User's name is Sertan", "Project uses FastAPI")
109
- - preference: Likes/dislikes ("User prefers short answers", "Dislikes verbose output")
110
- - context: Situational ("Working on RAG project", "Debugging auth module")
111
- - skill: Learned capabilities ("User taught me to use pytest this way")
112
-
113
- 4. IMPORTANCE LEVELS:
114
- - 0.9: Critical (name, key preferences, project identity)
115
- - 0.7: Important (tech choices, patterns, frequent requests)
116
- - 0.5: Normal (general context, one-time info)
117
- - 0.3: Low (temporary context, might change)
118
-
119
- 5. EXAMPLES:
120
- User: "I'm Sertan and I prefer Turkish responses"
121
- -> remember("User's name is Sertan", "fact", 0.9)
122
- -> remember("User prefers responses in Turkish", "preference", 0.8)
123
-
124
- User: "Show me the config"
125
- -> recall("config preference") first to check if user has display preferences
43
+ MEMORY: remember(content, type, importance) ile önemli bilgileri kaydet (importance 0.1-1.0; isim/tercih=0.9, normal=0.5). Soru gelince recall(query) ile ara. Proaktif kaydet, sorulunca hatırla.
126
44
  """
127
45
 
128
46
  ANTI_LOOP_RULES = """
@@ -203,48 +121,23 @@ You are running in WSL (Windows Subsystem for Linux). Users may give paths in va
203
121
  """
204
122
 
205
123
  CONVERSATION_CONTEXT_RULES = """
206
- CONVERSATION CONTEXT RULES:
207
-
208
- 1. REFERENCE RESOLUTION:
209
- - "that file" -> Look at previous turns, find mentioned file
210
- - "search better" -> Use same target, improve search strategy
211
- - "do it" -> Execute the action you suggested
212
- - "there" / "that folder" -> Location from previous context
213
-
214
- 2. CONTINUITY:
215
- - Remember paths, files, and targets from earlier turns
216
- - If user gives partial info, combine with previous context
217
- - Don't ask for info that was already provided
218
-
219
- 3. CONTEXT PRIORITY:
220
- - Current request > Recent turns > Older turns
221
- - If conflict, ask for clarification
222
-
223
- 4. EXAMPLES:
224
- Turn 1: "find PDF at /path/to/data"
225
- Turn 2: "search in html folder too"
226
- -> Combine: search /path/to/data AND /path/to/html
227
-
228
- Turn 1: "list files in project"
229
- Turn 2: "open the config one"
230
- -> Find config file from Turn 1 results, open it
124
+ CONTEXT: Kullanıcı "o dosya / şunu yap / devam et / orada" derse önceki turn'deki dosya/tool/görev referansını kullan. Daha önce verilen bilgiyi tekrar sorma.
231
125
  """
232
126
 
233
127
  QUICK_ANSWER_RULES = """
234
128
  VERİMLİLİK KURALLARI / EFFICIENCY RULES:
235
- 1. "list dir" veya "klasörü listele" = SADECE list_dir {"path": "."} çağır ve sonucu göster. Başka tool çağırma.
236
- 2. Basit komutlar (list, show, find, bul, göster) için MAX 2 tool call kullan.
129
+ 1. "list dir" veya "klasörü listele" / "dosyaları listele" = SADECE list_dir tool'unu çağır (path="."). İzin sorma, JSON gösterme DİREKT ÇAĞIR.
130
+ 2. Basit komutlar (list, show, find, bul, göster, oku, aç, listele) için TEK tool çağrısı yap. Sonra cevap ver.
237
131
  3. İlk tool sonucu yeterliyse HEMEN cevap ver, ekstra arama yapma.
238
- 4. "X loglarını aç" = system_search ile "X" + "log" ara, sonra open_file ile aç. Başka klasörlere bakma.
239
- 5. Kullanıcı "list dir" dediğinde kosgebot/kosgeb-bot aramayacaksın. SADECE mevcut dizini listele.
240
- 6. "X altındaki Y dosyalarını bul/listele" ONE search_files or list_dir call, then answer.
241
- 7. "show file" veya "dosyayı göster" ONE read_file call, then answer.
242
- Do NOT over-search. If one tool call gives you the answer, STOP and respond immediately.
243
-
244
- SELF-REFERENCE SHORTCUTS (tool çağırmana gerek yok, doğrudan biliyorsun):
245
- - "cont log" veya "cont loglarını" = cont projesinin logs/cont_runs/ klasörü. Doğrudan open_in_explorer ile aç. Arama yapma.
246
- - "cont klasörü" = workspace root (yukarıda yazıyor).
247
- - "kendi logların" = logs/cont_runs/ altında.
132
+ 4. "show file" / "dosyayı göster" / "oku" ONE read_file call, then answer.
133
+ 5. "X loglarını aç" = system_search ile "X" + "log" ara, sonra open_file ile aç.
134
+ 6. KULLANICIYA İZİN SORMA kullanıcı zaten istedi. Tool'u çağır, sonucu ver.
135
+ 7. JSON tool çağrısını cevap metninde GÖSTERME gerçekten çağır (tool_calls).
136
+ Do NOT over-search. Do NOT ask permission. CALL the tool, return result.
137
+
138
+ SELF-REFERENCE SHORTCUTS:
139
+ - "cont log" / "cont loglarını" / "loglarım" = logs/cont_runs/. open_in_explorer ile aç.
140
+ - "cont klasörü" / "kendin" = workspace root.
248
141
  """
249
142
 
250
143
  WORKFLOW_RULES = """
@@ -257,8 +150,30 @@ WORKFLOW:
257
150
  SAFETY: Stay inside repo root. Dangerous commands are blocked.
258
151
  """
259
152
 
153
+ _SYSTEM_PROMPT_CACHE: dict = {}
154
+ _SYSTEM_PROMPT_CACHE_TS: float = 0.0
155
+ _SYSTEM_PROMPT_CACHE_TTL = 300.0 # 5 dakika
156
+
157
+
260
158
  def build_system_prompt(repo_root: str, tool_budget: int, strict_mode: bool = True) -> str:
261
- """Build the complete system prompt with identity and context."""
159
+ """Build the complete system prompt with identity and context.
160
+
161
+ ADIM 4: 5 dakikalık TTL cache.
162
+ Key: (repo_root, cwd, tool_budget, strict_mode).
163
+ İlk çağrı I/O yapar (~700ms cold), sonrakiler <1ms.
164
+ """
165
+ import time
166
+ from pathlib import Path
167
+ global _SYSTEM_PROMPT_CACHE_TS
168
+
169
+ cache_key = (repo_root, str(Path.cwd()), tool_budget, strict_mode)
170
+ now = time.time()
171
+ if (now - _SYSTEM_PROMPT_CACHE_TS) > _SYSTEM_PROMPT_CACHE_TTL:
172
+ _SYSTEM_PROMPT_CACHE.clear()
173
+ _SYSTEM_PROMPT_CACHE_TS = now
174
+ cached = _SYSTEM_PROMPT_CACHE.get(cache_key)
175
+ if cached is not None:
176
+ return cached
262
177
 
263
178
  # Get identity
264
179
  try:
@@ -297,12 +212,15 @@ TOOL BUDGET: {tool_budget} calls maximum. Plan efficiently.
297
212
  base += "\n" + EVIDENCE_RULES
298
213
  base += "\n" + STRUCTURED_RESPONSE_FORMAT
299
214
 
300
- base += "\n" + ANTI_LOOP_RULES
215
+ # ADIM 1: Duplikasyonlar silindi (runtime garantili)
216
+ # ANTI_LOOP_RULES — tool_budget + cooldown set
217
+ # WRITE_PROTECTION_RULES — safety.py TIER kontrolleri
218
+ # PATH_RESOLUTION_RULES — path normalize otomatik
219
+ # BASE_CAPABILITIES — Ollama tools schema bloğu
301
220
  base += "\n" + MEMORY_INSTRUCTIONS
302
- base += "\n" + WRITE_PROTECTION_RULES
303
- base += "\n" + PATH_RESOLUTION_RULES
304
221
  base += "\n" + CONVERSATION_CONTEXT_RULES
305
222
  base += "\n" + QUICK_ANSWER_RULES
306
223
  base += "\n" + WORKFLOW_RULES
307
224
 
225
+ _SYSTEM_PROMPT_CACHE[cache_key] = base
308
226
  return base
@@ -97,9 +97,9 @@ def extract_fenced_tool_requests(text: str) -> list:
97
97
 
98
98
  # b2) <tools>...</tools> wrapper (Qwen3-Coder bare emit) — may contain
99
99
  # one or more JSON objects, possibly without closing </tools> tag.
100
- if "<tools>" in text:
101
- # Capture from <tools> until </tools> OR end of string
102
- wrapper_match = re.search(r'<tools>\s*(.*?)(?:</tools>|$)', text, re.DOTALL)
100
+ # Also catches <.tools>, <tool>, <Tool>, <.tool> variants.
101
+ if re.search(r'<\.?tools?>', text, re.IGNORECASE):
102
+ wrapper_match = re.search(r'<\.?tools?>\s*(.*?)(?:</\.?tools?>|$)', text, re.DOTALL | re.IGNORECASE)
103
103
  if wrapper_match:
104
104
  inner = wrapper_match.group(1).strip()
105
105
  # Try parse as single dict, list, or multiple concatenated dicts
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "codent"
7
- version = "0.3.4"
7
+ version = "0.3.6"
8
8
  requires-python = ">=3.10"
9
9
  dependencies = [
10
10
  "rich>=13.0",
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