code-puppy 0.0.348__py3-none-any.whl → 0.0.372__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.
Files changed (87) hide show
  1. code_puppy/agents/__init__.py +8 -0
  2. code_puppy/agents/agent_manager.py +272 -1
  3. code_puppy/agents/agent_pack_leader.py +383 -0
  4. code_puppy/agents/agent_qa_kitten.py +12 -7
  5. code_puppy/agents/agent_terminal_qa.py +323 -0
  6. code_puppy/agents/base_agent.py +11 -8
  7. code_puppy/agents/event_stream_handler.py +101 -8
  8. code_puppy/agents/pack/__init__.py +34 -0
  9. code_puppy/agents/pack/bloodhound.py +304 -0
  10. code_puppy/agents/pack/husky.py +321 -0
  11. code_puppy/agents/pack/retriever.py +393 -0
  12. code_puppy/agents/pack/shepherd.py +348 -0
  13. code_puppy/agents/pack/terrier.py +287 -0
  14. code_puppy/agents/pack/watchdog.py +367 -0
  15. code_puppy/agents/subagent_stream_handler.py +276 -0
  16. code_puppy/api/__init__.py +13 -0
  17. code_puppy/api/app.py +169 -0
  18. code_puppy/api/main.py +21 -0
  19. code_puppy/api/pty_manager.py +446 -0
  20. code_puppy/api/routers/__init__.py +12 -0
  21. code_puppy/api/routers/agents.py +36 -0
  22. code_puppy/api/routers/commands.py +217 -0
  23. code_puppy/api/routers/config.py +74 -0
  24. code_puppy/api/routers/sessions.py +232 -0
  25. code_puppy/api/templates/terminal.html +361 -0
  26. code_puppy/api/websocket.py +154 -0
  27. code_puppy/callbacks.py +73 -0
  28. code_puppy/chatgpt_codex_client.py +53 -0
  29. code_puppy/claude_cache_client.py +294 -41
  30. code_puppy/command_line/add_model_menu.py +13 -4
  31. code_puppy/command_line/agent_menu.py +662 -0
  32. code_puppy/command_line/core_commands.py +89 -112
  33. code_puppy/command_line/model_picker_completion.py +3 -20
  34. code_puppy/command_line/model_settings_menu.py +21 -3
  35. code_puppy/config.py +145 -70
  36. code_puppy/gemini_model.py +706 -0
  37. code_puppy/http_utils.py +6 -3
  38. code_puppy/messaging/__init__.py +15 -0
  39. code_puppy/messaging/messages.py +27 -0
  40. code_puppy/messaging/queue_console.py +1 -1
  41. code_puppy/messaging/rich_renderer.py +36 -1
  42. code_puppy/messaging/spinner/__init__.py +20 -2
  43. code_puppy/messaging/subagent_console.py +461 -0
  44. code_puppy/model_factory.py +50 -16
  45. code_puppy/model_switching.py +63 -0
  46. code_puppy/model_utils.py +27 -24
  47. code_puppy/models.json +12 -12
  48. code_puppy/plugins/antigravity_oauth/antigravity_model.py +206 -172
  49. code_puppy/plugins/antigravity_oauth/register_callbacks.py +15 -8
  50. code_puppy/plugins/antigravity_oauth/transport.py +236 -45
  51. code_puppy/plugins/chatgpt_oauth/register_callbacks.py +2 -2
  52. code_puppy/plugins/claude_code_oauth/register_callbacks.py +2 -30
  53. code_puppy/plugins/claude_code_oauth/utils.py +4 -1
  54. code_puppy/plugins/frontend_emitter/__init__.py +25 -0
  55. code_puppy/plugins/frontend_emitter/emitter.py +121 -0
  56. code_puppy/plugins/frontend_emitter/register_callbacks.py +261 -0
  57. code_puppy/prompts/antigravity_system_prompt.md +1 -0
  58. code_puppy/pydantic_patches.py +52 -0
  59. code_puppy/status_display.py +6 -2
  60. code_puppy/tools/__init__.py +37 -1
  61. code_puppy/tools/agent_tools.py +83 -33
  62. code_puppy/tools/browser/__init__.py +37 -0
  63. code_puppy/tools/browser/browser_control.py +6 -6
  64. code_puppy/tools/browser/browser_interactions.py +21 -20
  65. code_puppy/tools/browser/browser_locators.py +9 -9
  66. code_puppy/tools/browser/browser_manager.py +316 -0
  67. code_puppy/tools/browser/browser_navigation.py +7 -7
  68. code_puppy/tools/browser/browser_screenshot.py +78 -140
  69. code_puppy/tools/browser/browser_scripts.py +15 -13
  70. code_puppy/tools/browser/chromium_terminal_manager.py +259 -0
  71. code_puppy/tools/browser/terminal_command_tools.py +521 -0
  72. code_puppy/tools/browser/terminal_screenshot_tools.py +556 -0
  73. code_puppy/tools/browser/terminal_tools.py +525 -0
  74. code_puppy/tools/command_runner.py +292 -101
  75. code_puppy/tools/common.py +176 -1
  76. code_puppy/tools/display.py +84 -0
  77. code_puppy/tools/subagent_context.py +158 -0
  78. {code_puppy-0.0.348.data → code_puppy-0.0.372.data}/data/code_puppy/models.json +12 -12
  79. {code_puppy-0.0.348.dist-info → code_puppy-0.0.372.dist-info}/METADATA +17 -16
  80. {code_puppy-0.0.348.dist-info → code_puppy-0.0.372.dist-info}/RECORD +84 -51
  81. code_puppy/prompts/codex_system_prompt.md +0 -310
  82. code_puppy/tools/browser/camoufox_manager.py +0 -235
  83. code_puppy/tools/browser/vqa_agent.py +0 -90
  84. {code_puppy-0.0.348.data → code_puppy-0.0.372.data}/data/code_puppy/models_dev_api.json +0 -0
  85. {code_puppy-0.0.348.dist-info → code_puppy-0.0.372.dist-info}/WHEEL +0 -0
  86. {code_puppy-0.0.348.dist-info → code_puppy-0.0.372.dist-info}/entry_points.txt +0 -0
  87. {code_puppy-0.0.348.dist-info → code_puppy-0.0.372.dist-info}/licenses/LICENSE +0 -0
@@ -1,10 +1,13 @@
1
+ import asyncio
1
2
  import fnmatch
3
+ import functools
2
4
  import hashlib
5
+ import logging
3
6
  import os
4
7
  import sys
5
8
  import time
6
9
  from pathlib import Path
7
- from typing import Callable, Optional, Tuple
10
+ from typing import Any, Callable, Optional, Tuple
8
11
 
9
12
  from prompt_toolkit import Application
10
13
  from prompt_toolkit.formatted_text import HTML
@@ -1406,3 +1409,175 @@ def generate_group_id(tool_name: str, extra_context: str = "") -> str:
1406
1409
  short_hash = hash_obj.hexdigest()[:8]
1407
1410
 
1408
1411
  return f"{tool_name}_{short_hash}"
1412
+
1413
+
1414
+ # =============================================================================
1415
+ # TOOL CALLBACK WRAPPER
1416
+ # =============================================================================
1417
+
1418
+ logger = logging.getLogger(__name__)
1419
+
1420
+
1421
+ def with_tool_callbacks(tool_name: str) -> Callable:
1422
+ """Decorator that wraps tool functions with pre/post callback hooks.
1423
+
1424
+ This decorator enables plugins to hook into tool execution for:
1425
+ - Logging and analytics
1426
+ - Pre-execution validation or modification
1427
+ - Post-execution result processing
1428
+ - Performance monitoring
1429
+
1430
+ Args:
1431
+ tool_name: The name of the tool being wrapped (e.g., 'edit_file', 'list_files')
1432
+
1433
+ Returns:
1434
+ A decorator function that wraps the tool with callbacks.
1435
+
1436
+ Example:
1437
+ @with_tool_callbacks('my_tool')
1438
+ async def my_tool_impl(ctx, **kwargs):
1439
+ return result
1440
+ """
1441
+
1442
+ def decorator(func: Callable) -> Callable:
1443
+ @functools.wraps(func)
1444
+ async def async_wrapper(*args, **kwargs) -> Any:
1445
+ # Extract context from args if available (usually first arg is RunContext)
1446
+ context = None
1447
+ tool_args = kwargs.copy()
1448
+
1449
+ # Try to get session context
1450
+ try:
1451
+ from code_puppy.messaging import get_session_context
1452
+
1453
+ context = get_session_context()
1454
+ except ImportError:
1455
+ pass
1456
+
1457
+ # Fire pre-tool callback (non-blocking)
1458
+ try:
1459
+ from code_puppy import callbacks
1460
+
1461
+ asyncio.create_task(
1462
+ callbacks.on_pre_tool_call(tool_name, tool_args, context)
1463
+ )
1464
+ except ImportError:
1465
+ logger.debug("callbacks module not available for pre_tool_call")
1466
+ except Exception as e:
1467
+ logger.debug(f"Error in pre_tool_call callback: {e}")
1468
+
1469
+ # Execute the tool and measure duration
1470
+ start_time = time.perf_counter()
1471
+ result = None
1472
+ error = None
1473
+
1474
+ try:
1475
+ result = await func(*args, **kwargs)
1476
+ return result
1477
+ except Exception as e:
1478
+ error = e
1479
+ raise
1480
+ finally:
1481
+ end_time = time.perf_counter()
1482
+ duration_ms = (end_time - start_time) * 1000
1483
+
1484
+ # Fire post-tool callback (non-blocking)
1485
+ final_result = result if error is None else {"error": str(error)}
1486
+ try:
1487
+ from code_puppy import callbacks
1488
+
1489
+ asyncio.create_task(
1490
+ callbacks.on_post_tool_call(
1491
+ tool_name, tool_args, final_result, duration_ms, context
1492
+ )
1493
+ )
1494
+ except ImportError:
1495
+ logger.debug("callbacks module not available for post_tool_call")
1496
+ except Exception as e:
1497
+ logger.debug(f"Error in post_tool_call callback: {e}")
1498
+
1499
+ @functools.wraps(func)
1500
+ def sync_wrapper(*args, **kwargs) -> Any:
1501
+ """Sync wrapper for non-async tool functions."""
1502
+ # Extract context
1503
+ context = None
1504
+ tool_args = kwargs.copy()
1505
+
1506
+ try:
1507
+ from code_puppy.messaging import get_session_context
1508
+
1509
+ context = get_session_context()
1510
+ except ImportError:
1511
+ pass
1512
+
1513
+ # For sync functions, we can't use asyncio.create_task directly
1514
+ # Instead, we'll try to schedule it if there's a running loop
1515
+ def fire_pre_callback():
1516
+ try:
1517
+ from code_puppy import callbacks
1518
+
1519
+ loop = asyncio.get_running_loop()
1520
+ asyncio.run_coroutine_threadsafe(
1521
+ callbacks.on_pre_tool_call(tool_name, tool_args, context),
1522
+ loop,
1523
+ )
1524
+ except RuntimeError:
1525
+ # No running loop - skip async callback
1526
+ pass
1527
+ except ImportError:
1528
+ pass
1529
+ except Exception as e:
1530
+ logger.debug(f"Error in sync pre_tool_call: {e}")
1531
+
1532
+ fire_pre_callback()
1533
+
1534
+ # Execute the tool
1535
+ start_time = time.perf_counter()
1536
+ result = None
1537
+ error = None
1538
+
1539
+ try:
1540
+ result = func(*args, **kwargs)
1541
+ return result
1542
+ except Exception as e:
1543
+ error = e
1544
+ raise
1545
+ finally:
1546
+ end_time = time.perf_counter()
1547
+ duration_ms = (end_time - start_time) * 1000
1548
+
1549
+ # Fire post-tool callback
1550
+ final_result = result if error is None else {"error": str(error)}
1551
+
1552
+ def fire_post_callback():
1553
+ try:
1554
+ from code_puppy import callbacks
1555
+
1556
+ loop = asyncio.get_running_loop()
1557
+ asyncio.run_coroutine_threadsafe(
1558
+ callbacks.on_post_tool_call(
1559
+ tool_name,
1560
+ tool_args,
1561
+ final_result,
1562
+ duration_ms,
1563
+ context,
1564
+ ),
1565
+ loop,
1566
+ )
1567
+ except RuntimeError:
1568
+ # No running loop - skip async callback
1569
+ pass
1570
+ except ImportError:
1571
+ pass
1572
+ except Exception as e:
1573
+ logger.debug(f"Error in sync post_tool_call: {e}")
1574
+
1575
+ fire_post_callback()
1576
+
1577
+ # Return appropriate wrapper based on function type
1578
+ if asyncio.iscoroutinefunction(func):
1579
+ return async_wrapper
1580
+ else:
1581
+ return sync_wrapper
1582
+
1583
+ return decorator
@@ -0,0 +1,84 @@
1
+ """Common display utilities for rendering agent outputs.
2
+
3
+ This module provides non-streaming display functions for rendering
4
+ agent results and other structured content using termflow for markdown.
5
+ """
6
+
7
+ from typing import Optional
8
+
9
+ from rich.console import Console
10
+
11
+ from code_puppy.config import get_banner_color, get_subagent_verbose
12
+ from code_puppy.tools.subagent_context import is_subagent
13
+
14
+
15
+ def display_non_streamed_result(
16
+ content: str,
17
+ console: Optional[Console] = None,
18
+ banner_text: str = "AGENT RESPONSE",
19
+ banner_name: str = "agent_response",
20
+ ) -> None:
21
+ """Display a non-streamed result with markdown rendering via termflow.
22
+
23
+ This function renders markdown content using termflow for beautiful
24
+ terminal output. Use this instead of streaming for sub-agent responses
25
+ or any other content that arrives all at once.
26
+
27
+ Args:
28
+ content: The content to display (can include markdown).
29
+ console: Rich Console to use for output. If None, creates a new one.
30
+ banner_text: Text to display in the banner (default: "AGENT RESPONSE").
31
+ banner_name: Banner config key for color lookup (default: "agent_response").
32
+
33
+ Example:
34
+ >>> display_non_streamed_result("# Hello\n\nThis is **bold** text.")
35
+ # Renders with AGENT RESPONSE banner and formatted markdown
36
+ """
37
+ # Skip display for sub-agents unless verbose mode
38
+ if is_subagent() and not get_subagent_verbose():
39
+ return
40
+
41
+ import time
42
+
43
+ from rich.text import Text
44
+ from termflow import Parser as TermflowParser
45
+ from termflow import Renderer as TermflowRenderer
46
+
47
+ from code_puppy.messaging.spinner import pause_all_spinners, resume_all_spinners
48
+
49
+ if console is None:
50
+ console = Console()
51
+
52
+ # Pause spinners and give time to clear
53
+ pause_all_spinners()
54
+ time.sleep(0.1)
55
+
56
+ # Clear line and print banner
57
+ console.print(" " * 50, end="\r")
58
+ console.print() # Newline before banner
59
+
60
+ banner_color = get_banner_color(banner_name)
61
+ console.print(
62
+ Text.from_markup(
63
+ f"[bold white on {banner_color}] {banner_text} [/bold white on {banner_color}]"
64
+ )
65
+ )
66
+
67
+ # Use termflow for markdown rendering
68
+ parser = TermflowParser()
69
+ renderer = TermflowRenderer(output=console.file, width=console.width)
70
+
71
+ # Process content line by line
72
+ for line in content.split("\n"):
73
+ events = parser.parse_line(line)
74
+ renderer.render_all(events)
75
+
76
+ # Finalize to close any open markdown blocks
77
+ final_events = parser.finalize()
78
+ renderer.render_all(final_events)
79
+
80
+ # Resume spinners
81
+ resume_all_spinners()
82
+
83
+
84
+ __all__ = ["display_non_streamed_result"]
@@ -0,0 +1,158 @@
1
+ """Sub-agent context management with async-safe state tracking.
2
+
3
+ This module provides context-aware tracking of sub-agent execution state using
4
+ Python's contextvars for async-safe isolation. This ensures that sub-agent state
5
+ is properly isolated across different async tasks and execution contexts.
6
+
7
+ ## Why ContextVars?
8
+
9
+ ContextVars provide automatic context isolation in async environments:
10
+ - Each async task gets its own copy of the context
11
+ - State changes in one task don't affect others
12
+ - Perfect for tracking execution depth in nested agent calls
13
+ - Token-based reset ensures proper cleanup even with exceptions
14
+
15
+ ## Usage Example:
16
+
17
+ ```python
18
+ from code_puppy.tools.subagent_context import subagent_context, is_subagent
19
+
20
+ # Main agent
21
+ print(is_subagent()) # False
22
+
23
+ async def run_subagent():
24
+ with subagent_context("retriever"):
25
+ print(is_subagent()) # True
26
+ print(get_subagent_name()) # "retriever"
27
+ print(get_subagent_depth()) # 1
28
+
29
+ # Nested sub-agent
30
+ with subagent_context("terrier"):
31
+ print(get_subagent_depth()) # 2
32
+ print(get_subagent_name()) # "terrier"
33
+
34
+ # Back to parent sub-agent
35
+ print(get_subagent_name()) # "retriever"
36
+ print(get_subagent_depth()) # 1
37
+
38
+ # After context exits
39
+ print(is_subagent()) # False
40
+ ```
41
+
42
+ ## Benefits:
43
+
44
+ 1. **Async Safety**: Multiple sub-agents can run concurrently without interference
45
+ 2. **Nested Support**: Properly handles sub-agents calling other sub-agents
46
+ 3. **Clean Restoration**: Token-based reset ensures state is restored even on errors
47
+ 4. **Zero Overhead**: When not in a sub-agent context, minimal performance impact
48
+ """
49
+
50
+ from contextlib import contextmanager
51
+ from contextvars import ContextVar
52
+ from typing import Generator
53
+
54
+ __all__ = [
55
+ "subagent_context",
56
+ "is_subagent",
57
+ "get_subagent_name",
58
+ "get_subagent_depth",
59
+ ]
60
+
61
+ # Track sub-agent depth (0 = main agent, 1+ = sub-agent)
62
+ _subagent_depth: ContextVar[int] = ContextVar("subagent_depth", default=0)
63
+
64
+ # Track current sub-agent name (None = main agent)
65
+ _subagent_name: ContextVar[str | None] = ContextVar("subagent_name", default=None)
66
+
67
+
68
+ @contextmanager
69
+ def subagent_context(agent_name: str) -> Generator[None, None, None]:
70
+ """Context manager for tracking sub-agent execution.
71
+
72
+ Increments the sub-agent depth and sets the current agent name on entry,
73
+ then restores the previous state on exit. Uses token-based reset for
74
+ proper async isolation and exception safety.
75
+
76
+ Args:
77
+ agent_name: Name of the sub-agent being executed (e.g., "retriever", "husky")
78
+
79
+ Yields:
80
+ None
81
+
82
+ Example:
83
+ >>> with subagent_context("retriever"):
84
+ ... assert is_subagent() is True
85
+ ... assert get_subagent_name() == "retriever"
86
+ >>> assert is_subagent() is False
87
+
88
+ Note:
89
+ Token-based reset ensures that even if an exception occurs, the context
90
+ is properly restored. This is especially important in async environments
91
+ where multiple tasks may be running concurrently.
92
+ """
93
+ # Get current depth for incrementing
94
+ current_depth = _subagent_depth.get()
95
+
96
+ # Set new values and save tokens for restoration
97
+ depth_token = _subagent_depth.set(current_depth + 1)
98
+ name_token = _subagent_name.set(agent_name)
99
+
100
+ try:
101
+ yield
102
+ finally:
103
+ # Use token-based reset for proper async isolation
104
+ # This ensures the context is restored even if an exception occurs
105
+ _subagent_depth.reset(depth_token)
106
+ _subagent_name.reset(name_token)
107
+
108
+
109
+ def is_subagent() -> bool:
110
+ """Check if currently executing within a sub-agent context.
111
+
112
+ Returns:
113
+ True if depth > 0 (inside a sub-agent), False otherwise (main agent)
114
+
115
+ Example:
116
+ >>> is_subagent()
117
+ False
118
+ >>> with subagent_context("retriever"):
119
+ ... is_subagent()
120
+ True
121
+ """
122
+ return _subagent_depth.get() > 0
123
+
124
+
125
+ def get_subagent_name() -> str | None:
126
+ """Get the name of the current sub-agent.
127
+
128
+ Returns:
129
+ Current sub-agent name, or None if in main agent context
130
+
131
+ Example:
132
+ >>> get_subagent_name()
133
+ None
134
+ >>> with subagent_context("husky"):
135
+ ... get_subagent_name()
136
+ 'husky'
137
+ """
138
+ return _subagent_name.get()
139
+
140
+
141
+ def get_subagent_depth() -> int:
142
+ """Get the current sub-agent nesting depth.
143
+
144
+ Returns:
145
+ Current depth level (0 = main agent, 1 = first-level sub-agent,
146
+ 2 = nested sub-agent, etc.)
147
+
148
+ Example:
149
+ >>> get_subagent_depth()
150
+ 0
151
+ >>> with subagent_context("retriever"):
152
+ ... get_subagent_depth()
153
+ 1
154
+ ... with subagent_context("terrier"):
155
+ ... get_subagent_depth()
156
+ 2
157
+ """
158
+ return _subagent_depth.get()
@@ -7,7 +7,7 @@
7
7
  "api_key": "$SYN_API_KEY"
8
8
  },
9
9
  "context_length": 200000,
10
- "supported_settings": ["temperature", "seed"]
10
+ "supported_settings": ["temperature", "seed", "top_p"]
11
11
  },
12
12
  "synthetic-MiniMax-M2.1": {
13
13
  "type": "custom_openai",
@@ -17,7 +17,7 @@
17
17
  "api_key": "$SYN_API_KEY"
18
18
  },
19
19
  "context_length": 195000,
20
- "supported_settings": ["temperature", "seed"]
20
+ "supported_settings": ["temperature", "seed", "top_p"]
21
21
  },
22
22
  "synthetic-Kimi-K2-Thinking": {
23
23
  "type": "custom_openai",
@@ -27,32 +27,32 @@
27
27
  "api_key": "$SYN_API_KEY"
28
28
  },
29
29
  "context_length": 262144,
30
- "supported_settings": ["temperature", "seed"]
30
+ "supported_settings": ["temperature", "seed", "top_p"]
31
31
  },
32
32
  "Gemini-3": {
33
33
  "type": "gemini",
34
34
  "name": "gemini-3-pro-preview",
35
35
  "context_length": 200000,
36
- "supported_settings": ["temperature"]
36
+ "supported_settings": ["temperature", "top_p"]
37
37
  },
38
38
  "Gemini-3-Long-Context": {
39
39
  "type": "gemini",
40
40
  "name": "gemini-3-pro-preview",
41
41
  "context_length": 1000000,
42
- "supported_settings": ["temperature"]
42
+ "supported_settings": ["temperature", "top_p"]
43
43
  },
44
44
  "gpt-5.1": {
45
45
  "type": "openai",
46
46
  "name": "gpt-5.1",
47
47
  "context_length": 272000,
48
- "supported_settings": ["reasoning_effort", "verbosity"],
48
+ "supported_settings": ["temperature", "top_p", "reasoning_effort", "verbosity"],
49
49
  "supports_xhigh_reasoning": false
50
50
  },
51
51
  "gpt-5.1-codex-api": {
52
52
  "type": "openai",
53
53
  "name": "gpt-5.1-codex",
54
54
  "context_length": 272000,
55
- "supported_settings": ["reasoning_effort", "verbosity"],
55
+ "supported_settings": ["temperature", "top_p", "reasoning_effort", "verbosity"],
56
56
  "supports_xhigh_reasoning": true
57
57
  },
58
58
  "Cerebras-GLM-4.7": {
@@ -63,7 +63,7 @@
63
63
  "api_key": "$CEREBRAS_API_KEY"
64
64
  },
65
65
  "context_length": 131072,
66
- "supported_settings": ["temperature", "seed"]
66
+ "supported_settings": ["temperature", "seed", "top_p"]
67
67
  },
68
68
  "claude-4-5-haiku": {
69
69
  "type": "anthropic",
@@ -87,24 +87,24 @@
87
87
  "type": "zai_coding",
88
88
  "name": "glm-4.6",
89
89
  "context_length": 200000,
90
- "supported_settings": ["temperature"]
90
+ "supported_settings": ["temperature", "top_p"]
91
91
  },
92
92
  "zai-glm-4.6-api": {
93
93
  "type": "zai_api",
94
94
  "name": "glm-4.6",
95
95
  "context_length": 200000,
96
- "supported_settings": ["temperature"]
96
+ "supported_settings": ["temperature", "top_p"]
97
97
  },
98
98
  "zai-glm-4.7-coding": {
99
99
  "type": "zai_coding",
100
100
  "name": "glm-4.7",
101
101
  "context_length": 200000,
102
- "supported_settings": ["temperature"]
102
+ "supported_settings": ["temperature", "top_p"]
103
103
  },
104
104
  "zai-glm-4.7-api": {
105
105
  "type": "zai_api",
106
106
  "name": "glm-4.7",
107
107
  "context_length": 200000,
108
- "supported_settings": ["temperature"]
108
+ "supported_settings": ["temperature", "top_p"]
109
109
  }
110
110
  }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-puppy
3
- Version: 0.0.348
3
+ Version: 0.0.372
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
@@ -15,28 +15,28 @@ Classifier: Programming Language :: Python :: 3.12
15
15
  Classifier: Programming Language :: Python :: 3.13
16
16
  Classifier: Topic :: Software Development :: Code Generators
17
17
  Requires-Python: <3.14,>=3.11
18
- Requires-Dist: camoufox>=0.4.11
19
18
  Requires-Dist: dbos>=2.5.0
20
- Requires-Dist: fastapi>=0.111.0
19
+ Requires-Dist: fastapi>=0.109.0
21
20
  Requires-Dist: httpx[http2]>=0.24.1
22
21
  Requires-Dist: json-repair>=0.46.2
23
- Requires-Dist: logfire>=0.7.1
22
+ Requires-Dist: mcp>=1.9.4
24
23
  Requires-Dist: openai>=1.99.1
25
24
  Requires-Dist: pillow>=10.0.0
26
25
  Requires-Dist: playwright>=1.40.0
27
26
  Requires-Dist: prompt-toolkit>=3.0.52
28
- Requires-Dist: pydantic-ai==1.25.0
27
+ Requires-Dist: pydantic-ai-slim[anthropic,mcp,openai]==1.26.0
29
28
  Requires-Dist: pydantic>=2.4.0
30
29
  Requires-Dist: pyfiglet>=0.8.post1
31
- Requires-Dist: pytest-cov>=6.1.1
32
30
  Requires-Dist: python-dotenv>=1.0.0
33
31
  Requires-Dist: rapidfuzz>=3.13.0
32
+ Requires-Dist: requests>=2.28.0
34
33
  Requires-Dist: rich>=13.4.2
35
34
  Requires-Dist: ripgrep==14.1.0
36
- Requires-Dist: ruff>=0.11.11
37
35
  Requires-Dist: tenacity>=8.2.0
38
- Requires-Dist: termflow-md>=0.1.6
39
- Requires-Dist: uvicorn>=0.30.0
36
+ Requires-Dist: termflow-md>=0.1.8
37
+ Requires-Dist: typer>=0.12.0
38
+ Requires-Dist: uvicorn[standard]>=0.27.0
39
+ Requires-Dist: websockets>=12.0
40
40
  Description-Content-Type: text/markdown
41
41
 
42
42
  <div align="center">
@@ -46,20 +46,18 @@ Description-Content-Type: text/markdown
46
46
  **🐶✨The sassy AI code agent that makes IDEs look outdated** ✨🐶
47
47
 
48
48
  [![Version](https://img.shields.io/pypi/v/code-puppy?style=for-the-badge&logo=python&label=Version&color=purple)](https://pypi.org/project/code-puppy/)
49
- [![Downloads](https://img.shields.io/badge/Downloads-100k%2B-brightgreen?style=for-the-badge&logo=download)](https://pypi.org/project/code-puppy/)
49
+ [![Downloads](https://img.shields.io/badge/Downloads-170k%2B-brightgreen?style=for-the-badge&logo=download)](https://pypi.org/project/code-puppy/)
50
50
  [![Python](https://img.shields.io/badge/Python-3.11%2B-blue?style=for-the-badge&logo=python&logoColor=white)](https://python.org)
51
51
  [![License](https://img.shields.io/badge/License-MIT-green?style=for-the-badge)](LICENSE)
52
52
  [![Build Status](https://img.shields.io/badge/Build-Passing-brightgreen?style=for-the-badge&logo=github)](https://github.com/mpfaffenberger/code_puppy/actions)
53
- [![Coverage](https://img.shields.io/badge/Coverage-95%25-brightgreen?style=for-the-badge)](https://github.com/mpfaffenberger/code_puppy)
54
- [![Code Style](https://img.shields.io/badge/Code%20Style-Black-black?style=for-the-badge)](https://github.com/psf/black)
55
53
  [![Tests](https://img.shields.io/badge/Tests-Passing-success?style=for-the-badge&logo=pytest)](https://github.com/mpfaffenberger/code_puppy/tests)
56
54
 
57
- [![OpenAI](https://img.shields.io/badge/OpenAI-GPT--5-orange?style=flat-square&logo=openai)](https://openai.com)
55
+ [![OpenAI](https://img.shields.io/badge/OpenAI-GPT--5.2--Codex-orange?style=flat-square&logo=openai)](https://openai.com)
58
56
  [![Gemini](https://img.shields.io/badge/Google-Gemini-blue?style=flat-square&logo=google)](https://ai.google.dev/)
59
57
  [![Anthropic](https://img.shields.io/badge/Anthropic-Claude-orange?style=flat-square&logo=anthropic)](https://anthropic.com)
60
- [![Cerebras](https://img.shields.io/badge/Cerebras-GLM%204.6-red?style=flat-square)](https://cerebras.ai)
61
- [![Z.AI](https://img.shields.io/badge/Z.AI-GLM%204.6-purple?style=flat-square)](https://z.ai/)
62
- [![Synthetic](https://img.shields.io/badge/Synthetic-MINIMAX_M2-green?style=flat-square)](https://synthetic.new)
58
+ [![Cerebras](https://img.shields.io/badge/Cerebras-GLM%204.7-red?style=flat-square)](https://cerebras.ai)
59
+ [![Z.AI](https://img.shields.io/badge/Z.AI-GLM%204.7-purple?style=flat-square)](https://z.ai/)
60
+ [![Synthetic](https://img.shields.io/badge/Synthetic-MINIMAX_M2.1-green?style=flat-square)](https://synthetic.new)
63
61
 
64
62
  [![100% Open Source](https://img.shields.io/badge/100%25-Open%20Source-blue?style=for-the-badge)](https://github.com/mpfaffenberger/code_puppy)
65
63
  [![Pydantic AI](https://img.shields.io/badge/Pydantic-AI-success?style=for-the-badge)](https://github.com/pydantic/pydantic-ai)
@@ -69,6 +67,9 @@ Description-Content-Type: text/markdown
69
67
  [![GitHub stars](https://img.shields.io/github/stars/mpfaffenberger/code_puppy?style=for-the-badge&logo=github)](https://github.com/mpfaffenberger/code_puppy/stargazers)
70
68
  [![GitHub forks](https://img.shields.io/github/forks/mpfaffenberger/code_puppy?style=for-the-badge&logo=github)](https://github.com/mpfaffenberger/code_puppy/network)
71
69
 
70
+ [![Discord](https://img.shields.io/badge/Discord-Community-purple?style=for-the-badge&logo=discord&logoColor=white)](https://discord.gg/SqYAaXVy)
71
+ [![Docs](https://img.shields.io/badge/Read-The%20Docs-blue?style=for-the-badge&logo=readthedocs)](https://code-puppy.dev)
72
+
72
73
  **[⭐ Star this repo if you hate expensive IDEs! ⭐](#quick-start)**
73
74
 
74
75
  *"Who needs an IDE when you have 1024 angry puppies?"* - Someone, probably.