code-puppy 0.0.204__tar.gz → 0.0.206__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.
- {code_puppy-0.0.204 → code_puppy-0.0.206}/PKG-INFO +2 -2
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/command_line/attachments.py +36 -7
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/command_line/prompt_toolkit_completion.py +18 -8
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/config.py +22 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/http_utils.py +37 -6
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/models.json +5 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/pyproject.toml +2 -2
- {code_puppy-0.0.204 → code_puppy-0.0.206}/.gitignore +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/LICENSE +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/README.md +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/__init__.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/__main__.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/agents/__init__.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/agents/agent_c_reviewer.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/agents/agent_code_puppy.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/agents/agent_code_reviewer.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/agents/agent_cpp_reviewer.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/agents/agent_creator_agent.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/agents/agent_golang_reviewer.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/agents/agent_javascript_reviewer.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/agents/agent_manager.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/agents/agent_python_reviewer.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/agents/agent_qa_expert.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/agents/agent_qa_kitten.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/agents/agent_security_auditor.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/agents/agent_typescript_reviewer.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/agents/base_agent.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/agents/json_agent.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/callbacks.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/command_line/__init__.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/command_line/command_handler.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/command_line/file_path_completion.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/command_line/load_context_completion.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/command_line/mcp/__init__.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/command_line/mcp/add_command.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/command_line/mcp/base.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/command_line/mcp/handler.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/command_line/mcp/help_command.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/command_line/mcp/install_command.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/command_line/mcp/list_command.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/command_line/mcp/logs_command.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/command_line/mcp/remove_command.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/command_line/mcp/restart_command.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/command_line/mcp/search_command.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/command_line/mcp/start_all_command.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/command_line/mcp/start_command.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/command_line/mcp/status_command.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/command_line/mcp/stop_all_command.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/command_line/mcp/stop_command.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/command_line/mcp/test_command.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/command_line/mcp/utils.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/command_line/mcp/wizard_utils.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/command_line/model_picker_completion.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/command_line/motd.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/command_line/utils.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/main.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/mcp_/__init__.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/mcp_/async_lifecycle.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/mcp_/blocking_startup.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/mcp_/captured_stdio_server.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/mcp_/circuit_breaker.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/mcp_/config_wizard.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/mcp_/dashboard.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/mcp_/error_isolation.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/mcp_/examples/retry_example.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/mcp_/health_monitor.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/mcp_/managed_server.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/mcp_/manager.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/mcp_/registry.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/mcp_/retry_manager.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/mcp_/server_registry_catalog.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/mcp_/status_tracker.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/mcp_/system_tools.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/messaging/__init__.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/messaging/message_queue.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/messaging/queue_console.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/messaging/renderers.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/messaging/spinner/__init__.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/messaging/spinner/console_spinner.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/messaging/spinner/spinner_base.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/messaging/spinner/textual_spinner.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/model_factory.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/plugins/__init__.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/plugins/example_custom_command/register_callbacks.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/reopenable_async_client.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/round_robin_model.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/session_storage.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/status_display.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/summarization_agent.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/tools/__init__.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/tools/agent_tools.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/tools/browser/__init__.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/tools/browser/browser_control.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/tools/browser/browser_interactions.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/tools/browser/browser_locators.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/tools/browser/browser_navigation.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/tools/browser/browser_screenshot.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/tools/browser/browser_scripts.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/tools/browser/browser_workflows.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/tools/browser/camoufox_manager.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/tools/browser/vqa_agent.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/tools/command_runner.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/tools/common.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/tools/file_modifications.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/tools/file_operations.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/tools/tools_content.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/tui/__init__.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/tui/app.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/tui/components/__init__.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/tui/components/chat_view.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/tui/components/command_history_modal.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/tui/components/copy_button.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/tui/components/custom_widgets.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/tui/components/human_input_modal.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/tui/components/input_area.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/tui/components/sidebar.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/tui/components/status_bar.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/tui/messages.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/tui/models/__init__.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/tui/models/chat_message.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/tui/models/command_history.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/tui/models/enums.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/tui/screens/__init__.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/tui/screens/autosave_picker.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/tui/screens/help.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/tui/screens/mcp_install_wizard.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/tui/screens/settings.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/tui/screens/tools.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/tui_state.py +0 -0
- {code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/version_checker.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: code-puppy
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.206
|
4
4
|
Summary: Code generation agent
|
5
5
|
Project-URL: repository, https://github.com/mpfaffenberger/code_puppy
|
6
6
|
Project-URL: HomePage, https://github.com/mpfaffenberger/code_puppy
|
@@ -19,7 +19,7 @@ Requires-Dist: bs4>=0.0.2
|
|
19
19
|
Requires-Dist: camoufox>=0.4.11
|
20
20
|
Requires-Dist: fastapi>=0.110.0
|
21
21
|
Requires-Dist: httpx-limiter>=0.3.0
|
22
|
-
Requires-Dist: httpx>=0.24.1
|
22
|
+
Requires-Dist: httpx[http2]>=0.24.1
|
23
23
|
Requires-Dist: json-repair>=0.46.2
|
24
24
|
Requires-Dist: logfire>=0.7.1
|
25
25
|
Requires-Dist: openai>=1.99.1
|
@@ -13,6 +13,10 @@ from pydantic_ai import BinaryContent, DocumentUrl, ImageUrl
|
|
13
13
|
|
14
14
|
SUPPORTED_INLINE_SCHEMES = {"http", "https"}
|
15
15
|
|
16
|
+
# Maximum path length to consider - conservative limit to avoid OS errors
|
17
|
+
# Most OS have limits around 4096, but we set lower to catch garbage early
|
18
|
+
MAX_PATH_LENGTH = 1024
|
19
|
+
|
16
20
|
# Allow common extensions people drag in the terminal.
|
17
21
|
DEFAULT_ACCEPTED_IMAGE_EXTENSIONS = {
|
18
22
|
".png",
|
@@ -61,6 +65,9 @@ def _is_probable_path(token: str) -> bool:
|
|
61
65
|
|
62
66
|
if not token:
|
63
67
|
return False
|
68
|
+
# Reject absurdly long tokens before any processing to avoid OS errors
|
69
|
+
if len(token) > MAX_PATH_LENGTH:
|
70
|
+
return False
|
64
71
|
if token.startswith("#"):
|
65
72
|
return False
|
66
73
|
# Windows drive letters or Unix absolute/relative paths
|
@@ -69,7 +76,7 @@ def _is_probable_path(token: str) -> bool:
|
|
69
76
|
if len(token) >= 2 and token[1] == ":":
|
70
77
|
return True
|
71
78
|
# Things like `path/to/file.png`
|
72
|
-
return os.sep in token or "
|
79
|
+
return os.sep in token or '"' in token
|
73
80
|
|
74
81
|
|
75
82
|
def _unescape_dragged_path(token: str) -> str:
|
@@ -107,9 +114,13 @@ def _load_binary(path: Path) -> bytes:
|
|
107
114
|
except FileNotFoundError as exc:
|
108
115
|
raise AttachmentParsingError(f"Attachment not found: {path}") from exc
|
109
116
|
except PermissionError as exc:
|
110
|
-
raise AttachmentParsingError(
|
117
|
+
raise AttachmentParsingError(
|
118
|
+
f"Cannot read attachment (permission denied): {path}"
|
119
|
+
) from exc
|
111
120
|
except OSError as exc:
|
112
|
-
raise AttachmentParsingError(
|
121
|
+
raise AttachmentParsingError(
|
122
|
+
f"Failed to read attachment {path}: {exc}"
|
123
|
+
) from exc
|
113
124
|
|
114
125
|
|
115
126
|
def _tokenise(prompt: str) -> Iterable[str]:
|
@@ -147,7 +158,10 @@ def _candidate_paths(
|
|
147
158
|
|
148
159
|
def _is_supported_extension(path: Path) -> bool:
|
149
160
|
suffix = path.suffix.lower()
|
150
|
-
return
|
161
|
+
return (
|
162
|
+
suffix
|
163
|
+
in DEFAULT_ACCEPTED_IMAGE_EXTENSIONS | DEFAULT_ACCEPTED_DOCUMENT_EXTENSIONS
|
164
|
+
)
|
151
165
|
|
152
166
|
|
153
167
|
def _parse_link(token: str) -> PromptLinkAttachment | None:
|
@@ -203,6 +217,11 @@ def _detect_path_tokens(prompt: str) -> tuple[list[_DetectedPath], list[str]]:
|
|
203
217
|
index += 1
|
204
218
|
continue
|
205
219
|
|
220
|
+
# Additional guard: skip if stripped token exceeds reasonable path length
|
221
|
+
if len(stripped_token) > MAX_PATH_LENGTH:
|
222
|
+
index += 1
|
223
|
+
continue
|
224
|
+
|
206
225
|
start_index = index
|
207
226
|
consumed_until = index + 1
|
208
227
|
candidate_path_token = stripped_token
|
@@ -223,7 +242,16 @@ def _detect_path_tokens(prompt: str) -> tuple[list[_DetectedPath], list[str]]:
|
|
223
242
|
index = consumed_until
|
224
243
|
continue
|
225
244
|
|
226
|
-
|
245
|
+
# Guard filesystem operations against OS errors (ENAMETOOLONG, etc.)
|
246
|
+
try:
|
247
|
+
path_exists = path.exists()
|
248
|
+
path_is_file = path.is_file() if path_exists else False
|
249
|
+
except OSError:
|
250
|
+
# Skip this token if filesystem check fails (path too long, etc.)
|
251
|
+
index = consumed_until
|
252
|
+
continue
|
253
|
+
|
254
|
+
if not path_exists or not path_is_file:
|
227
255
|
found_span = False
|
228
256
|
last_path = path
|
229
257
|
for joined, end_index in _candidate_paths(tokens, index):
|
@@ -328,7 +356,8 @@ def parse_prompt_attachments(prompt: str) -> ProcessedPrompt:
|
|
328
356
|
spans = [
|
329
357
|
(d.start_index, d.consumed_until)
|
330
358
|
for d in detections
|
331
|
-
if (d.path is not None and not d.unsupported)
|
359
|
+
if (d.path is not None and not d.unsupported)
|
360
|
+
or (d.link is not None and d.path is None)
|
332
361
|
]
|
333
362
|
cleaned_parts: list[str] = []
|
334
363
|
i = 0
|
@@ -360,4 +389,4 @@ __all__ = [
|
|
360
389
|
"PromptLinkAttachment",
|
361
390
|
"AttachmentParsingError",
|
362
391
|
"parse_prompt_attachments",
|
363
|
-
]
|
392
|
+
]
|
{code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/command_line/prompt_toolkit_completion.py
RENAMED
@@ -12,14 +12,20 @@ from typing import Optional
|
|
12
12
|
|
13
13
|
from prompt_toolkit import PromptSession
|
14
14
|
from prompt_toolkit.completion import Completer, Completion, merge_completers
|
15
|
+
from prompt_toolkit.filters import is_searching
|
15
16
|
from prompt_toolkit.formatted_text import FormattedText
|
16
17
|
from prompt_toolkit.history import FileHistory
|
17
|
-
from prompt_toolkit.filters import is_searching
|
18
18
|
from prompt_toolkit.key_binding import KeyBindings
|
19
19
|
from prompt_toolkit.keys import Keys
|
20
20
|
from prompt_toolkit.layout.processors import Processor, Transformation
|
21
21
|
from prompt_toolkit.styles import Style
|
22
22
|
|
23
|
+
from code_puppy.command_line.attachments import (
|
24
|
+
DEFAULT_ACCEPTED_DOCUMENT_EXTENSIONS,
|
25
|
+
DEFAULT_ACCEPTED_IMAGE_EXTENSIONS,
|
26
|
+
_detect_path_tokens,
|
27
|
+
_tokenise,
|
28
|
+
)
|
23
29
|
from code_puppy.command_line.file_path_completion import FilePathCompleter
|
24
30
|
from code_puppy.command_line.load_context_completion import LoadContextCompleter
|
25
31
|
from code_puppy.command_line.model_picker_completion import (
|
@@ -34,11 +40,6 @@ from code_puppy.config import (
|
|
34
40
|
get_puppy_name,
|
35
41
|
get_value,
|
36
42
|
)
|
37
|
-
from code_puppy.command_line.attachments import (
|
38
|
-
DEFAULT_ACCEPTED_DOCUMENT_EXTENSIONS,
|
39
|
-
DEFAULT_ACCEPTED_IMAGE_EXTENSIONS,
|
40
|
-
_detect_path_tokens, _tokenise,
|
41
|
-
)
|
42
43
|
|
43
44
|
|
44
45
|
class SetCompleter(Completer):
|
@@ -108,6 +109,8 @@ class AttachmentPlaceholderProcessor(Processor):
|
|
108
109
|
"""Display friendly placeholders for recognised attachments."""
|
109
110
|
|
110
111
|
_PLACEHOLDER_STYLE = "class:attachment-placeholder"
|
112
|
+
# Skip expensive path detection for very long input (likely pasted content)
|
113
|
+
_MAX_TEXT_LENGTH_FOR_REALTIME = 500
|
111
114
|
|
112
115
|
def apply_transformation(self, transformation_input):
|
113
116
|
document = transformation_input.document
|
@@ -115,6 +118,10 @@ class AttachmentPlaceholderProcessor(Processor):
|
|
115
118
|
if not text:
|
116
119
|
return Transformation(list(transformation_input.fragments))
|
117
120
|
|
121
|
+
# Skip real-time path detection for long text to avoid slowdown
|
122
|
+
if len(text) > self._MAX_TEXT_LENGTH_FOR_REALTIME:
|
123
|
+
return Transformation(list(transformation_input.fragments))
|
124
|
+
|
118
125
|
detections, _warnings = _detect_path_tokens(text)
|
119
126
|
replacements: list[tuple[int, int, str]] = []
|
120
127
|
search_cursor = 0
|
@@ -138,7 +145,7 @@ class AttachmentPlaceholderProcessor(Processor):
|
|
138
145
|
continue
|
139
146
|
|
140
147
|
# Use token-span for robust lookup (handles escaped spaces)
|
141
|
-
span_tokens = token_view[detection.start_index:detection.consumed_until]
|
148
|
+
span_tokens = token_view[detection.start_index : detection.consumed_until]
|
142
149
|
raw_span = " ".join(span_tokens).replace(ESCAPE_MARKER, r"\ ")
|
143
150
|
index = text.find(raw_span, search_cursor)
|
144
151
|
span_len = len(raw_span)
|
@@ -188,7 +195,9 @@ class AttachmentPlaceholderProcessor(Processor):
|
|
188
195
|
display_index += 1
|
189
196
|
|
190
197
|
for _ in text[source_index:end]:
|
191
|
-
source_to_display_map.append(
|
198
|
+
source_to_display_map.append(
|
199
|
+
placeholder_start if placeholder else display_index
|
200
|
+
)
|
192
201
|
source_index += 1
|
193
202
|
|
194
203
|
if source_index < len(text):
|
@@ -340,6 +349,7 @@ async def get_input_with_combined_completion(
|
|
340
349
|
|
341
350
|
# Also allow Ctrl+Enter for newline (terminal-dependent)
|
342
351
|
try:
|
352
|
+
|
343
353
|
@bindings.add("c-enter", eager=True)
|
344
354
|
def _(event):
|
345
355
|
event.app.current_buffer.insert_text("\n")
|
@@ -132,6 +132,7 @@ def get_config_keys():
|
|
132
132
|
"openai_reasoning_effort",
|
133
133
|
"auto_save_session",
|
134
134
|
"max_saved_sessions",
|
135
|
+
"http2",
|
135
136
|
]
|
136
137
|
config = configparser.ConfigParser()
|
137
138
|
config.read(CONFIG_FILE)
|
@@ -589,6 +590,27 @@ def get_compaction_strategy() -> str:
|
|
589
590
|
return "truncation"
|
590
591
|
|
591
592
|
|
593
|
+
def get_http2() -> bool:
|
594
|
+
"""
|
595
|
+
Get the http2 configuration value.
|
596
|
+
Returns False if not set (default).
|
597
|
+
"""
|
598
|
+
val = get_value("http2")
|
599
|
+
if val is None:
|
600
|
+
return False
|
601
|
+
return str(val).lower() in ("1", "true", "yes", "on")
|
602
|
+
|
603
|
+
|
604
|
+
def set_http2(enabled: bool) -> None:
|
605
|
+
"""
|
606
|
+
Sets the http2 configuration value.
|
607
|
+
|
608
|
+
Args:
|
609
|
+
enabled: Whether to enable HTTP/2 for httpx clients
|
610
|
+
"""
|
611
|
+
set_config_value("http2", "true" if enabled else "false")
|
612
|
+
|
613
|
+
|
592
614
|
def get_message_limit(default: int = 100) -> int:
|
593
615
|
"""
|
594
616
|
Returns the user-configured message/request limit for the agent.
|
@@ -12,6 +12,8 @@ import httpx
|
|
12
12
|
import requests
|
13
13
|
from tenacity import stop_after_attempt, wait_exponential
|
14
14
|
|
15
|
+
from code_puppy.config import get_http2
|
16
|
+
|
15
17
|
try:
|
16
18
|
from pydantic_ai.retries import (
|
17
19
|
AsyncTenacityTransport,
|
@@ -55,6 +57,9 @@ def create_client(
|
|
55
57
|
if verify is None:
|
56
58
|
verify = get_cert_bundle_path()
|
57
59
|
|
60
|
+
# Check if HTTP/2 is enabled in config
|
61
|
+
http2_enabled = get_http2()
|
62
|
+
|
58
63
|
# If retry components are available, create a client with retry transport
|
59
64
|
if TenacityTransport and RetryConfig and wait_retry_after:
|
60
65
|
|
@@ -81,11 +86,17 @@ def create_client(
|
|
81
86
|
)
|
82
87
|
|
83
88
|
return httpx.Client(
|
84
|
-
transport=transport,
|
89
|
+
transport=transport,
|
90
|
+
verify=verify,
|
91
|
+
headers=headers or {},
|
92
|
+
timeout=timeout,
|
93
|
+
http2=http2_enabled,
|
85
94
|
)
|
86
95
|
else:
|
87
96
|
# Fallback to regular client if retry components are not available
|
88
|
-
return httpx.Client(
|
97
|
+
return httpx.Client(
|
98
|
+
verify=verify, headers=headers or {}, timeout=timeout, http2=http2_enabled
|
99
|
+
)
|
89
100
|
|
90
101
|
|
91
102
|
def create_async_client(
|
@@ -97,6 +108,9 @@ def create_async_client(
|
|
97
108
|
if verify is None:
|
98
109
|
verify = get_cert_bundle_path()
|
99
110
|
|
111
|
+
# Check if HTTP/2 is enabled in config
|
112
|
+
http2_enabled = get_http2()
|
113
|
+
|
100
114
|
# If retry components are available, create a client with retry transport
|
101
115
|
if AsyncTenacityTransport and RetryConfig and wait_retry_after:
|
102
116
|
|
@@ -120,11 +134,17 @@ def create_async_client(
|
|
120
134
|
)
|
121
135
|
|
122
136
|
return httpx.AsyncClient(
|
123
|
-
transport=transport,
|
137
|
+
transport=transport,
|
138
|
+
verify=verify,
|
139
|
+
headers=headers or {},
|
140
|
+
timeout=timeout,
|
141
|
+
http2=http2_enabled,
|
124
142
|
)
|
125
143
|
else:
|
126
144
|
# Fallback to regular client if retry components are not available
|
127
|
-
return httpx.AsyncClient(
|
145
|
+
return httpx.AsyncClient(
|
146
|
+
verify=verify, headers=headers or {}, timeout=timeout, http2=http2_enabled
|
147
|
+
)
|
128
148
|
|
129
149
|
|
130
150
|
def create_requests_session(
|
@@ -176,6 +196,9 @@ def create_reopenable_async_client(
|
|
176
196
|
if verify is None:
|
177
197
|
verify = get_cert_bundle_path()
|
178
198
|
|
199
|
+
# Check if HTTP/2 is enabled in config
|
200
|
+
http2_enabled = get_http2()
|
201
|
+
|
179
202
|
# If retry components are available, create a client with retry transport
|
180
203
|
if AsyncTenacityTransport and RetryConfig and wait_retry_after:
|
181
204
|
|
@@ -207,6 +230,7 @@ def create_reopenable_async_client(
|
|
207
230
|
verify=verify,
|
208
231
|
headers=headers or {},
|
209
232
|
timeout=timeout,
|
233
|
+
http2=http2_enabled,
|
210
234
|
)
|
211
235
|
else:
|
212
236
|
# Fallback to regular AsyncClient if ReopenableAsyncClient is not available
|
@@ -215,17 +239,24 @@ def create_reopenable_async_client(
|
|
215
239
|
verify=verify,
|
216
240
|
headers=headers or {},
|
217
241
|
timeout=timeout,
|
242
|
+
http2=http2_enabled,
|
218
243
|
)
|
219
244
|
else:
|
220
245
|
# Fallback to regular clients if retry components are not available
|
221
246
|
if ReopenableAsyncClient is not None:
|
222
247
|
return ReopenableAsyncClient(
|
223
|
-
verify=verify,
|
248
|
+
verify=verify,
|
249
|
+
headers=headers or {},
|
250
|
+
timeout=timeout,
|
251
|
+
http2=http2_enabled,
|
224
252
|
)
|
225
253
|
else:
|
226
254
|
# Fallback to regular AsyncClient if ReopenableAsyncClient is not available
|
227
255
|
return httpx.AsyncClient(
|
228
|
-
verify=verify,
|
256
|
+
verify=verify,
|
257
|
+
headers=headers or {},
|
258
|
+
timeout=timeout,
|
259
|
+
http2=http2_enabled,
|
229
260
|
)
|
230
261
|
|
231
262
|
|
@@ -50,6 +50,11 @@
|
|
50
50
|
"name": "claude-sonnet-4-5-20250929",
|
51
51
|
"context_length": 200000
|
52
52
|
},
|
53
|
+
"claude-4-1-opus": {
|
54
|
+
"type": "anthropic",
|
55
|
+
"name": "claude-opus-4-1-20250805",
|
56
|
+
"context_length": 200000
|
57
|
+
},
|
53
58
|
"glm-4.5-coding": {
|
54
59
|
"type": "zai_coding",
|
55
60
|
"name": "glm-4.5"
|
@@ -4,13 +4,13 @@ build-backend = "hatchling.build"
|
|
4
4
|
|
5
5
|
[project]
|
6
6
|
name = "code-puppy"
|
7
|
-
version = "0.0.
|
7
|
+
version = "0.0.206"
|
8
8
|
description = "Code generation agent"
|
9
9
|
readme = "README.md"
|
10
10
|
requires-python = ">=3.11"
|
11
11
|
dependencies = [
|
12
12
|
"pydantic-ai==1.0.5",
|
13
|
-
"httpx>=0.24.1",
|
13
|
+
"httpx[http2]>=0.24.1",
|
14
14
|
"rich>=13.4.2",
|
15
15
|
"logfire>=0.7.1",
|
16
16
|
"pydantic>=2.4.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
|
{code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/command_line/load_context_completion.py
RENAMED
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
|
{code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/command_line/model_picker_completion.py
RENAMED
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
|
{code_puppy-0.0.204 → code_puppy-0.0.206}/code_puppy/tui/components/command_history_modal.py
RENAMED
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
|