lcode-cli 0.2.2__py3-none-any.whl → 0.3.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lcode/__init__.py +1 -1
- lcode/agent.py +23 -0
- lcode/bench.py +1082 -0
- lcode/checkpoints.py +449 -0
- lcode/cli.py +92 -2
- lcode/config.py +1 -0
- lcode/ollama.py +4 -0
- lcode/repl.py +163 -1
- lcode/tools.py +3 -0
- {lcode_cli-0.2.2.dist-info → lcode_cli-0.3.1.dist-info}/METADATA +7 -4
- lcode_cli-0.3.1.dist-info/RECORD +23 -0
- lcode_cli-0.2.2.dist-info/RECORD +0 -21
- {lcode_cli-0.2.2.dist-info → lcode_cli-0.3.1.dist-info}/WHEEL +0 -0
- {lcode_cli-0.2.2.dist-info → lcode_cli-0.3.1.dist-info}/entry_points.txt +0 -0
- {lcode_cli-0.2.2.dist-info → lcode_cli-0.3.1.dist-info}/licenses/LICENSE +0 -0
lcode/__init__.py
CHANGED
lcode/agent.py
CHANGED
|
@@ -19,6 +19,7 @@ from rich.panel import Panel
|
|
|
19
19
|
from rich.text import Text
|
|
20
20
|
|
|
21
21
|
from lcode import catalog, limits, sessions, web
|
|
22
|
+
from lcode.checkpoints import Checkpoints
|
|
22
23
|
from lcode.config import format_tokens
|
|
23
24
|
from lcode.ollama import Ollama, OllamaError
|
|
24
25
|
from lcode.permissions import Permissions
|
|
@@ -136,6 +137,7 @@ class Settings:
|
|
|
136
137
|
web: str = "on" # on | ask | off
|
|
137
138
|
search_backend: str = "auto"
|
|
138
139
|
searxng_url: str | None = None
|
|
140
|
+
checkpoints: bool = True # snapshot files before the model changes them, for /undo
|
|
139
141
|
|
|
140
142
|
|
|
141
143
|
class Agent:
|
|
@@ -147,10 +149,12 @@ class Agent:
|
|
|
147
149
|
self.perms = Permissions(self.console, settings.permission_mode)
|
|
148
150
|
self.tools = Toolbox(self)
|
|
149
151
|
self.session_id = self.new_session_id()
|
|
152
|
+
self.checkpoints = Checkpoints(self.console, settings.checkpoints)
|
|
150
153
|
self.session_name = ""
|
|
151
154
|
self.session_title = ""
|
|
152
155
|
self.ctx_used = 0
|
|
153
156
|
self.last_speed = 0.0
|
|
157
|
+
self.usage = {"requests": 0, "prompt_tokens": 0, "prompt_ns": 0, "output_tokens": 0, "output_ns": 0}
|
|
154
158
|
self.messages: list[dict] = []
|
|
155
159
|
self.reset()
|
|
156
160
|
|
|
@@ -220,6 +224,7 @@ class Agent:
|
|
|
220
224
|
"name": self.session_name,
|
|
221
225
|
"title": self.session_title,
|
|
222
226
|
"messages": self.messages,
|
|
227
|
+
"checkpoints": self.checkpoints.to_json(),
|
|
223
228
|
}
|
|
224
229
|
f.write_text(json.dumps(data))
|
|
225
230
|
|
|
@@ -228,6 +233,7 @@ class Agent:
|
|
|
228
233
|
self.session_id = self.new_session_id()
|
|
229
234
|
self.session_name = ""
|
|
230
235
|
self.session_title = ""
|
|
236
|
+
self.checkpoints.reset(self.session_id)
|
|
231
237
|
|
|
232
238
|
def rename(self, name: str) -> None:
|
|
233
239
|
self.session_name = " ".join(name.split())
|
|
@@ -249,6 +255,7 @@ class Agent:
|
|
|
249
255
|
note = f"The session's directory {saved_cwd} no longer exists; staying in {self.cwd}"
|
|
250
256
|
self.messages = [{"role": "system", "content": self.system_prompt()}, *data.get("messages", [])[1:]]
|
|
251
257
|
self.session_id = info.id
|
|
258
|
+
self.checkpoints.load(info.id, data.get("checkpoints") or [])
|
|
252
259
|
self.session_name = data.get("name", "")
|
|
253
260
|
self.session_title = data.get("title") or sessions.title_from(self.messages)
|
|
254
261
|
self.tools.read_mtimes.clear() # files may have changed since; the model must read them again
|
|
@@ -384,6 +391,11 @@ class Agent:
|
|
|
384
391
|
message["tool_calls"] = tool_calls
|
|
385
392
|
self.messages.append(message)
|
|
386
393
|
if final:
|
|
394
|
+
self.usage["requests"] += 1
|
|
395
|
+
self.usage["prompt_tokens"] += final.get("prompt_eval_count", 0)
|
|
396
|
+
self.usage["prompt_ns"] += final.get("prompt_eval_duration", 0)
|
|
397
|
+
self.usage["output_tokens"] += final.get("eval_count", 0)
|
|
398
|
+
self.usage["output_ns"] += final.get("eval_duration", 0)
|
|
387
399
|
self.ctx_used = final.get("prompt_eval_count", 0) + final.get("eval_count", 0)
|
|
388
400
|
seconds = final.get("eval_duration", 0) / 1e9
|
|
389
401
|
self.last_speed = final.get("eval_count", 0) / seconds if seconds else 0.0
|
|
@@ -406,6 +418,17 @@ class Agent:
|
|
|
406
418
|
return name
|
|
407
419
|
|
|
408
420
|
def run_turn(self, user_text: str) -> None:
|
|
421
|
+
self.checkpoints.begin_turn(self.session_id, user_text, len(self.messages))
|
|
422
|
+
try:
|
|
423
|
+
self._run_turn(user_text)
|
|
424
|
+
finally:
|
|
425
|
+
self.checkpoints.end_turn()
|
|
426
|
+
|
|
427
|
+
def checkpoint(self) -> None:
|
|
428
|
+
"""Called before the model changes files: snapshot them once per request, for /undo."""
|
|
429
|
+
self.checkpoints.before_change(self.cwd)
|
|
430
|
+
|
|
431
|
+
def _run_turn(self, user_text: str) -> None:
|
|
409
432
|
self.messages.append({"role": "user", "content": self.expand_mentions(user_text)})
|
|
410
433
|
malformed = 0
|
|
411
434
|
for _ in range(MAX_STEPS_PER_TURN):
|