code-puppy 0.0.82__py3-none-any.whl → 0.0.84__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.
- code_puppy/agent.py +7 -34
- code_puppy/command_line/motd.py +15 -16
- code_puppy/main.py +1 -1
- code_puppy/message_history_processor.py +3 -1
- {code_puppy-0.0.82.dist-info → code_puppy-0.0.84.dist-info}/METADATA +1 -1
- {code_puppy-0.0.82.dist-info → code_puppy-0.0.84.dist-info}/RECORD +10 -11
- code_puppy/session_memory.py +0 -83
- {code_puppy-0.0.82.data → code_puppy-0.0.84.data}/data/code_puppy/models.json +0 -0
- {code_puppy-0.0.82.dist-info → code_puppy-0.0.84.dist-info}/WHEEL +0 -0
- {code_puppy-0.0.82.dist-info → code_puppy-0.0.84.dist-info}/entry_points.txt +0 -0
- {code_puppy-0.0.82.dist-info → code_puppy-0.0.84.dist-info}/licenses/LICENSE +0 -0
code_puppy/agent.py
CHANGED
|
@@ -7,7 +7,6 @@ from pydantic_ai.mcp import MCPServerSSE
|
|
|
7
7
|
|
|
8
8
|
from code_puppy.agent_prompts import get_system_prompt
|
|
9
9
|
from code_puppy.model_factory import ModelFactory
|
|
10
|
-
from code_puppy.session_memory import SessionMemory
|
|
11
10
|
from code_puppy.state_management import message_history_accumulator
|
|
12
11
|
from code_puppy.tools import register_all_tools
|
|
13
12
|
from code_puppy.tools.common import console
|
|
@@ -20,24 +19,16 @@ from code_puppy.tools.common import console
|
|
|
20
19
|
|
|
21
20
|
MODELS_JSON_PATH = os.environ.get("MODELS_JSON_PATH", None)
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
PUPPY_RULES_PATH = Path("AGENT.md")
|
|
25
|
-
PUPPY_RULES = None
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
def load_puppy_rules(path=None):
|
|
22
|
+
def load_puppy_rules():
|
|
29
23
|
global PUPPY_RULES
|
|
30
|
-
|
|
31
|
-
if
|
|
32
|
-
with open(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
PUPPY_RULES = None
|
|
36
|
-
|
|
24
|
+
puppy_rules_path = Path("AGENT.md")
|
|
25
|
+
if puppy_rules_path.exists():
|
|
26
|
+
with open(puppy_rules_path, "r") as f:
|
|
27
|
+
puppy_rules = f.read()
|
|
28
|
+
return puppy_rules
|
|
37
29
|
|
|
38
30
|
# Load at import
|
|
39
|
-
load_puppy_rules()
|
|
40
|
-
|
|
31
|
+
PUPPY_RULES = load_puppy_rules()
|
|
41
32
|
|
|
42
33
|
class AgentResponse(pydantic.BaseModel):
|
|
43
34
|
"""Represents a response from the agent."""
|
|
@@ -50,20 +41,7 @@ class AgentResponse(pydantic.BaseModel):
|
|
|
50
41
|
)
|
|
51
42
|
|
|
52
43
|
|
|
53
|
-
# --- NEW DYNAMIC AGENT LOGIC ---
|
|
54
|
-
_LAST_MODEL_NAME = None
|
|
55
44
|
_code_generation_agent = None
|
|
56
|
-
_session_memory = None
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
def session_memory():
|
|
60
|
-
"""
|
|
61
|
-
Returns a singleton SessionMemory instance to allow agent and tools to persist and recall context/history.
|
|
62
|
-
"""
|
|
63
|
-
global _session_memory
|
|
64
|
-
if _session_memory is None:
|
|
65
|
-
_session_memory = SessionMemory()
|
|
66
|
-
return _session_memory
|
|
67
45
|
|
|
68
46
|
|
|
69
47
|
def _load_mcp_servers():
|
|
@@ -106,11 +84,6 @@ def reload_code_generation_agent():
|
|
|
106
84
|
register_all_tools(agent)
|
|
107
85
|
_code_generation_agent = agent
|
|
108
86
|
_LAST_MODEL_NAME = model_name
|
|
109
|
-
# NEW: Log session event
|
|
110
|
-
try:
|
|
111
|
-
session_memory().log_task(f"Agent loaded with model: {model_name}")
|
|
112
|
-
except Exception:
|
|
113
|
-
pass
|
|
114
87
|
return _code_generation_agent
|
|
115
88
|
|
|
116
89
|
|
code_puppy/command_line/motd.py
CHANGED
|
@@ -5,26 +5,25 @@ Stores seen versions in ~/.puppy_cfg/motd.txt.
|
|
|
5
5
|
|
|
6
6
|
import os
|
|
7
7
|
|
|
8
|
-
MOTD_VERSION = "
|
|
8
|
+
MOTD_VERSION = "20250817"
|
|
9
9
|
MOTD_MESSAGE = """
|
|
10
10
|
|
|
11
|
-
🐾 Happy
|
|
11
|
+
🐾 Happy Sunday, Aug 17, 2025!
|
|
12
12
|
|
|
13
|
-
Biscuit the code puppy
|
|
13
|
+
Biscuit the code puppy learned two new tricks!
|
|
14
14
|
Major paws-ups:
|
|
15
|
-
1.
|
|
16
|
-
|
|
17
|
-
2.
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
•
|
|
21
|
-
•
|
|
22
|
-
•
|
|
23
|
-
• DRY
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
you need some puppy hype!
|
|
15
|
+
1. On-the-fly summarization: when your model's context hits 90%,
|
|
16
|
+
Biscuit auto-summarizes older messages to keep you cruising. No sweat, no tokens spilled.
|
|
17
|
+
2. AGENT.md support: ship your project rules and style guide,
|
|
18
|
+
and Biscuit will obey them like the good pup he is.
|
|
19
|
+
|
|
20
|
+
• Use ~m to swap models mid-session.
|
|
21
|
+
• YOLO_MODE=true skips command confirmations (danger, zoomies!).
|
|
22
|
+
• Keep files under 600 lines; split big ones like a responsible hooman.
|
|
23
|
+
• DRY code, happy pup.
|
|
24
|
+
|
|
25
|
+
Today's vibe: sniff context, summarize smartly, obey AGENT.md, and ship.
|
|
26
|
+
Run ~motd anytime you need more puppy hype!
|
|
28
27
|
|
|
29
28
|
"""
|
|
30
29
|
MOTD_TRACK_FILE = os.path.expanduser("~/.puppy_cfg/motd.txt")
|
code_puppy/main.py
CHANGED
|
@@ -10,7 +10,7 @@ from rich.syntax import Syntax
|
|
|
10
10
|
from rich.text import Text
|
|
11
11
|
|
|
12
12
|
from code_puppy import __version__, state_management
|
|
13
|
-
from code_puppy.agent import get_code_generation_agent
|
|
13
|
+
from code_puppy.agent import get_code_generation_agent
|
|
14
14
|
from code_puppy.command_line.prompt_toolkit_completion import (
|
|
15
15
|
get_input_with_combined_completion,
|
|
16
16
|
get_prompt_with_active_model,
|
|
@@ -158,7 +158,9 @@ def message_history_processor(messages: List[ModelMessage]) -> List[ModelMessage
|
|
|
158
158
|
model_max = get_model_context_length()
|
|
159
159
|
|
|
160
160
|
proportion_used = total_current_tokens / model_max
|
|
161
|
-
console.print(f"
|
|
161
|
+
console.print(f"""
|
|
162
|
+
[bold white on blue] Tokens in context: {total_current_tokens}, total model capacity: {model_max}, proportion used: {proportion_used}
|
|
163
|
+
""")
|
|
162
164
|
|
|
163
165
|
if proportion_used > 0.9:
|
|
164
166
|
summary = summarize_messages(messages)
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
code_puppy/__init__.py,sha256=oDE4GhaqOHsYi9XCGp6A2-PqhDqxJiYP_XmxmoKWoPU,168
|
|
2
|
-
code_puppy/agent.py,sha256=
|
|
2
|
+
code_puppy/agent.py,sha256=7On9mo4RWRaoINJr4Rv4c7Ot751FdQfSnTg0grrxzp8,3283
|
|
3
3
|
code_puppy/agent_prompts.py,sha256=13YIpTZa3R3lg60-fdkll7t7hgSBtQL0M53wcE1gzyQ,6834
|
|
4
4
|
code_puppy/config.py,sha256=r5nw5ChOP8xd_K5yo8U5OtO2gy2bFhARiyNtDp1JrwQ,5013
|
|
5
|
-
code_puppy/main.py,sha256=
|
|
6
|
-
code_puppy/message_history_processor.py,sha256=
|
|
5
|
+
code_puppy/main.py,sha256=WL1EGw86u_yQJDrkvnZbabldRKcYgFMuWQPQDz8zUgY,10428
|
|
6
|
+
code_puppy/message_history_processor.py,sha256=QOAQqxOJ2MSe6sTnZ6F4PMBqrtmV8RBQ0LmwQKh-o1A,6158
|
|
7
7
|
code_puppy/model_factory.py,sha256=3j7AcJfZAHbx_plL9oOxjGJO0MMTRaQFThCErg8VpH8,10909
|
|
8
8
|
code_puppy/models.json,sha256=jr0-LW87aJS79GosVwoZdHeeq5eflPzgdPoMbcqpVA8,2728
|
|
9
|
-
code_puppy/session_memory.py,sha256=4sgAAjbXdLSi8hETpd56tgtrG6hqMUuZWDlJOu6BQjA,2735
|
|
10
9
|
code_puppy/state_management.py,sha256=1QycApDBbXjayxXsYRecJib8TQ-MYMTeYvN5P_1Ipdg,1747
|
|
11
10
|
code_puppy/summarization_agent.py,sha256=N1UZg_R3wJFb7ZdVexDqx7L_8yxQ5m5nMOwGsLNfvKM,2744
|
|
12
11
|
code_puppy/version_checker.py,sha256=aRGulzuY4C4CdFvU1rITduyL-1xTFsn4GiD1uSfOl_Y,396
|
|
@@ -14,7 +13,7 @@ code_puppy/command_line/__init__.py,sha256=y7WeRemfYppk8KVbCGeAIiTuiOszIURCDjOMZ
|
|
|
14
13
|
code_puppy/command_line/file_path_completion.py,sha256=gw8NpIxa6GOpczUJRyh7VNZwoXKKn-yvCqit7h2y6Gg,2931
|
|
15
14
|
code_puppy/command_line/meta_command_handler.py,sha256=L7qP2g0Faz0V7bMH4YK3s03OWWuQFtK7Sh-Kt2zmmEQ,6182
|
|
16
15
|
code_puppy/command_line/model_picker_completion.py,sha256=NkyZZG7IhcVWSJ3ADytwCA5f8DpNeVs759Qtqs4fQtY,3733
|
|
17
|
-
code_puppy/command_line/motd.py,sha256=
|
|
16
|
+
code_puppy/command_line/motd.py,sha256=7ICNgfL4EgSrmCAHIsCK72R19obSQXkK8l7XGJBkvrQ,1571
|
|
18
17
|
code_puppy/command_line/prompt_toolkit_completion.py,sha256=_gP0FIOgHDNHTTWLNL0XNzr6sO0ISe7Mec1uQNo9kcM,8337
|
|
19
18
|
code_puppy/command_line/utils.py,sha256=7eyxDHjPjPB9wGDJQQcXV_zOsGdYsFgI0SGCetVmTqE,1251
|
|
20
19
|
code_puppy/tools/__init__.py,sha256=ozIGpLM7pKSjH4UeojkTodhfVYZeNzMsLtK_oyw41HA,456
|
|
@@ -23,9 +22,9 @@ code_puppy/tools/common.py,sha256=M53zhiXZAmPdvi1Y_bzCxgvEmifOvRRJvYPARYRZqHw,22
|
|
|
23
22
|
code_puppy/tools/file_modifications.py,sha256=nGI8gRD6Vtkg8EzBkErsv3khE3VI-_M1z_PdQLvjfLo,13847
|
|
24
23
|
code_puppy/tools/file_operations.py,sha256=eftkN-MxsRGQc8c1iIoNmN5r-Ppld5YJRT7a89kxpkM,11207
|
|
25
24
|
code_puppy/tools/ts_code_map.py,sha256=o-u8p5vsYwitfDtVEoPS-7MwWn2xHzwtIQLo1_WMhQs,17647
|
|
26
|
-
code_puppy-0.0.
|
|
27
|
-
code_puppy-0.0.
|
|
28
|
-
code_puppy-0.0.
|
|
29
|
-
code_puppy-0.0.
|
|
30
|
-
code_puppy-0.0.
|
|
31
|
-
code_puppy-0.0.
|
|
25
|
+
code_puppy-0.0.84.data/data/code_puppy/models.json,sha256=jr0-LW87aJS79GosVwoZdHeeq5eflPzgdPoMbcqpVA8,2728
|
|
26
|
+
code_puppy-0.0.84.dist-info/METADATA,sha256=NWnTj01yQNciyZLXZDYgWbU8St84wCea4wE4fLn27lE,6351
|
|
27
|
+
code_puppy-0.0.84.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
28
|
+
code_puppy-0.0.84.dist-info/entry_points.txt,sha256=d8YkBvIUxF-dHNJAj-x4fPEqizbY5d_TwvYpc01U5kw,58
|
|
29
|
+
code_puppy-0.0.84.dist-info/licenses/LICENSE,sha256=31u8x0SPgdOq3izJX41kgFazWsM43zPEF9eskzqbJMY,1075
|
|
30
|
+
code_puppy-0.0.84.dist-info/RECORD,,
|
code_puppy/session_memory.py
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
from datetime import datetime, timedelta
|
|
3
|
-
from pathlib import Path
|
|
4
|
-
from typing import Any, Dict, List, Optional
|
|
5
|
-
|
|
6
|
-
DEFAULT_MEMORY_PATH = Path(".puppy_session_memory.json")
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class SessionMemory:
|
|
10
|
-
"""
|
|
11
|
-
Simple persistent memory for Code Puppy agent sessions.
|
|
12
|
-
Stores short histories of tasks, notes, user preferences, and watched files.
|
|
13
|
-
"""
|
|
14
|
-
|
|
15
|
-
def __init__(
|
|
16
|
-
self, storage_path: Path = DEFAULT_MEMORY_PATH, memory_limit: int = 128
|
|
17
|
-
):
|
|
18
|
-
self.storage_path = storage_path
|
|
19
|
-
self.memory_limit = memory_limit
|
|
20
|
-
self._data = {
|
|
21
|
-
"history": [], # List of task/event dicts
|
|
22
|
-
"user_preferences": {},
|
|
23
|
-
"watched_files": [],
|
|
24
|
-
}
|
|
25
|
-
self._load()
|
|
26
|
-
|
|
27
|
-
def _load(self):
|
|
28
|
-
if self.storage_path.exists():
|
|
29
|
-
try:
|
|
30
|
-
self._data = json.loads(self.storage_path.read_text())
|
|
31
|
-
except Exception:
|
|
32
|
-
self._data = {
|
|
33
|
-
"history": [],
|
|
34
|
-
"user_preferences": {},
|
|
35
|
-
"watched_files": [],
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
def _save(self):
|
|
39
|
-
try:
|
|
40
|
-
self.storage_path.write_text(json.dumps(self._data, indent=2))
|
|
41
|
-
except Exception:
|
|
42
|
-
pass # Don't crash the agent for memory fails
|
|
43
|
-
|
|
44
|
-
def log_task(self, description: str, extras: Optional[Dict[str, Any]] = None):
|
|
45
|
-
entry = {
|
|
46
|
-
"timestamp": datetime.utcnow().isoformat(),
|
|
47
|
-
"description": description,
|
|
48
|
-
}
|
|
49
|
-
if extras:
|
|
50
|
-
entry.update(extras)
|
|
51
|
-
self._data["history"].append(entry)
|
|
52
|
-
# Trim memory
|
|
53
|
-
self._data["history"] = self._data["history"][-self.memory_limit :]
|
|
54
|
-
self._save()
|
|
55
|
-
|
|
56
|
-
def get_history(self, within_minutes: Optional[int] = None) -> List[Dict[str, Any]]:
|
|
57
|
-
if not within_minutes:
|
|
58
|
-
return list(self._data["history"])
|
|
59
|
-
cutoff = datetime.utcnow() - timedelta(minutes=within_minutes)
|
|
60
|
-
return [
|
|
61
|
-
h
|
|
62
|
-
for h in self._data["history"]
|
|
63
|
-
if datetime.fromisoformat(h["timestamp"]) >= cutoff
|
|
64
|
-
]
|
|
65
|
-
|
|
66
|
-
def set_preference(self, key: str, value: Any):
|
|
67
|
-
self._data["user_preferences"][key] = value
|
|
68
|
-
self._save()
|
|
69
|
-
|
|
70
|
-
def get_preference(self, key: str, default: Any = None) -> Any:
|
|
71
|
-
return self._data["user_preferences"].get(key, default)
|
|
72
|
-
|
|
73
|
-
def add_watched_file(self, path: str):
|
|
74
|
-
if path not in self._data["watched_files"]:
|
|
75
|
-
self._data["watched_files"].append(path)
|
|
76
|
-
self._save()
|
|
77
|
-
|
|
78
|
-
def list_watched_files(self) -> List[str]:
|
|
79
|
-
return list(self._data["watched_files"])
|
|
80
|
-
|
|
81
|
-
def clear(self):
|
|
82
|
-
self._data = {"history": [], "user_preferences": {}, "watched_files": []}
|
|
83
|
-
self._save()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|