newcode 0.2.6__tar.gz → 0.2.9__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.
- {newcode-0.2.6 → newcode-0.2.9}/PKG-INFO +1 -2
- {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/base_agent.py +44 -145
- {newcode-0.2.6 → newcode-0.2.9}/newcode/claude_cache_client.py +13 -3
- {newcode-0.2.6 → newcode-0.2.9}/newcode/cli_runner.py +0 -35
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/config_commands.py +0 -10
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/core_commands.py +15 -1
- {newcode-0.2.6 → newcode-0.2.9}/newcode/config.py +0 -21
- {newcode-0.2.6 → newcode-0.2.9}/newcode/hook_engine/executor.py +1 -1
- {newcode-0.2.6 → newcode-0.2.9}/newcode/models.json +4 -4
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/chatgpt_oauth/oauth_flow.py +3 -2
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/chatgpt_oauth/test_plugin.py +7 -1
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/chatgpt_oauth/utils.py +25 -1
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/claude_code_oauth/utils.py +39 -3
- {newcode-0.2.6 → newcode-0.2.9}/newcode/summarization_agent.py +3 -3
- {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/agent_tools.py +21 -110
- {newcode-0.2.6 → newcode-0.2.9}/pyproject.toml +1 -2
- {newcode-0.2.6 → newcode-0.2.9}/.gitignore +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/LICENSE +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/README.md +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/__init__.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/__main__.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/__init__.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/agent_c_reviewer.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/agent_code_agent.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/agent_code_reviewer.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/agent_cpp_reviewer.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/agent_creator_agent.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/agent_golang_reviewer.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/agent_javascript_reviewer.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/agent_manager.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/agent_pack_leader.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/agent_planning.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/agent_python_programmer.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/agent_python_reviewer.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/agent_qa_browser.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/agent_qa_expert.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/agent_security_auditor.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/agent_terminal_qa.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/agent_typescript_reviewer.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/event_stream_handler.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/json_agent.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/pack/__init__.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/pack/bloodhound.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/pack/husky.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/pack/retriever.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/pack/shepherd.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/pack/terrier.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/pack/watchdog.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/prompt_reviewer.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/agents/subagent_stream_handler.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/api/__init__.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/api/app.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/api/main.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/api/pty_manager.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/api/routers/__init__.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/api/routers/agents.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/api/routers/commands.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/api/routers/config.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/api/routers/sessions.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/api/templates/terminal.html +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/api/websocket.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/callbacks.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/chatgpt_codex_client.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/__init__.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/add_model_menu.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/agent_menu.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/attachments.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/autosave_menu.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/clipboard.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/colors_menu.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/command_handler.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/command_registry.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/diff_menu.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/file_path_completion.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/load_context_completion.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/__init__.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/base.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/catalog_server_installer.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/custom_server_form.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/custom_server_installer.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/edit_command.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/handler.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/help_command.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/install_command.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/install_menu.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/list_command.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/logs_command.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/remove_command.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/restart_command.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/search_command.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/start_all_command.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/start_command.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/status_command.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/stop_all_command.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/stop_command.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/test_command.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/utils.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp/wizard_utils.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/mcp_completion.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/model_picker_completion.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/model_settings_menu.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/motd.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/onboarding_slides.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/onboarding_wizard.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/pin_command_completion.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/prompt_toolkit_completion.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/session_commands.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/skills_completion.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/uc_menu.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/utils.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/command_line/wiggum_state.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/error_logging.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/gemini_code_assist.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/gemini_model.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/hook_engine/README.md +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/hook_engine/__init__.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/hook_engine/aliases.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/hook_engine/engine.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/hook_engine/matcher.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/hook_engine/models.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/hook_engine/registry.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/hook_engine/validator.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/http_utils.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/image_utils.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/keymap.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/main.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/mcp_/__init__.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/mcp_/async_lifecycle.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/mcp_/blocking_startup.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/mcp_/captured_stdio_server.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/mcp_/circuit_breaker.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/mcp_/config_wizard.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/mcp_/dashboard.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/mcp_/error_isolation.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/mcp_/examples/retry_example.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/mcp_/health_monitor.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/mcp_/managed_server.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/mcp_/manager.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/mcp_/mcp_logs.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/mcp_/registry.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/mcp_/retry_manager.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/mcp_/server_registry_catalog.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/mcp_/status_tracker.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/mcp_/system_tools.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/mcp_prompts/__init__.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/mcp_prompts/hook_creator.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/messaging/__init__.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/messaging/bus.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/messaging/commands.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/messaging/markdown_patches.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/messaging/message_queue.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/messaging/messages.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/messaging/queue_console.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/messaging/renderers.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/messaging/rich_renderer.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/messaging/spinner/__init__.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/messaging/spinner/console_spinner.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/messaging/spinner/spinner_base.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/messaging/subagent_console.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/model_factory.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/model_switching.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/model_utils.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/models_dev_api.json +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/models_dev_parser.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/__init__.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/agent_skills/__init__.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/agent_skills/config.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/agent_skills/discovery.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/agent_skills/downloader.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/agent_skills/installer.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/agent_skills/metadata.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/agent_skills/prompt_builder.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/agent_skills/register_callbacks.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/agent_skills/remote_catalog.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/agent_skills/skill_catalog.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/agent_skills/skills_install_menu.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/agent_skills/skills_menu.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/antigravity_oauth/__init__.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/antigravity_oauth/accounts.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/antigravity_oauth/antigravity_model.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/antigravity_oauth/config.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/antigravity_oauth/constants.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/antigravity_oauth/oauth.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/antigravity_oauth/register_callbacks.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/antigravity_oauth/storage.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/antigravity_oauth/test_plugin.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/antigravity_oauth/token.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/antigravity_oauth/transport.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/antigravity_oauth/utils.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/chatgpt_oauth/__init__.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/chatgpt_oauth/config.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/chatgpt_oauth/register_callbacks.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/claude_code_hooks/__init__.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/claude_code_hooks/config.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/claude_code_hooks/register_callbacks.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/claude_code_oauth/README.md +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/claude_code_oauth/SETUP.md +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/claude_code_oauth/__init__.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/claude_code_oauth/config.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/claude_code_oauth/register_callbacks.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/claude_code_oauth/test_plugin.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/claude_code_oauth/token_refresh_heartbeat.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/customizable_commands/__init__.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/customizable_commands/register_callbacks.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/example_custom_command/README.md +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/example_custom_command/register_callbacks.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/file_permission_handler/__init__.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/file_permission_handler/register_callbacks.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/frontend_emitter/__init__.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/frontend_emitter/emitter.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/frontend_emitter/register_callbacks.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/hook_creator/__init__.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/hook_creator/register_callbacks.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/hook_manager/__init__.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/hook_manager/config.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/hook_manager/hooks_menu.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/hook_manager/register_callbacks.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/oauth_puppy_html.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/shell_safety/__init__.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/shell_safety/agent_shell_safety.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/shell_safety/command_cache.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/shell_safety/register_callbacks.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/synthetic_status/__init__.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/synthetic_status/register_callbacks.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/synthetic_status/status_api.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/universal_constructor/__init__.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/universal_constructor/models.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/universal_constructor/register_callbacks.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/universal_constructor/registry.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/plugins/universal_constructor/sandbox.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/prompts/antigravity_system_prompt.md +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/pydantic_patches.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/reopenable_async_client.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/round_robin_model.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/session_storage.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/status_display.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/terminal_utils.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/__init__.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/ask_user_question/__init__.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/ask_user_question/constants.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/ask_user_question/demo_tui.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/ask_user_question/handler.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/ask_user_question/models.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/ask_user_question/registration.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/ask_user_question/renderers.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/ask_user_question/terminal_ui.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/ask_user_question/theme.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/ask_user_question/tui_loop.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/browser/__init__.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/browser/browser_control.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/browser/browser_interactions.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/browser/browser_locators.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/browser/browser_manager.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/browser/browser_navigation.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/browser/browser_screenshot.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/browser/browser_scripts.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/browser/browser_workflows.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/browser/chromium_terminal_manager.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/browser/terminal_command_tools.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/browser/terminal_screenshot_tools.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/browser/terminal_tools.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/command_runner.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/common.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/display.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/file_modifications.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/file_operations.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/skills_tools.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/subagent_context.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/tools_content.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/tools/universal_constructor.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/uvx_detection.py +0 -0
- {newcode-0.2.6 → newcode-0.2.9}/newcode/version_checker.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: newcode
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.9
|
|
4
4
|
Summary: AI-powered code generation agent platform
|
|
5
5
|
Project-URL: repository, https://github.com/janfeddersen-wq/new_code
|
|
6
6
|
Project-URL: HomePage, https://github.com/janfeddersen-wq/new_code
|
|
@@ -17,7 +17,6 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
17
17
|
Classifier: Topic :: Software Development :: Code Generators
|
|
18
18
|
Requires-Python: <3.14,>=3.11
|
|
19
19
|
Requires-Dist: anthropic==0.79.0
|
|
20
|
-
Requires-Dist: dbos>=2.11.0
|
|
21
20
|
Requires-Dist: fastapi>=0.109.0
|
|
22
21
|
Requires-Dist: httpx[http2]>=0.24.1
|
|
23
22
|
Requires-Dist: json-repair>=0.46.2
|
|
@@ -27,7 +27,6 @@ from typing import (
|
|
|
27
27
|
import mcp
|
|
28
28
|
import pydantic
|
|
29
29
|
import pydantic_ai.models
|
|
30
|
-
from dbos import DBOS, SetWorkflowID
|
|
31
30
|
from pydantic_ai import Agent as PydanticAgent
|
|
32
31
|
from pydantic_ai import (
|
|
33
32
|
BinaryContent,
|
|
@@ -37,7 +36,6 @@ from pydantic_ai import (
|
|
|
37
36
|
UsageLimitExceeded,
|
|
38
37
|
UsageLimits,
|
|
39
38
|
)
|
|
40
|
-
from pydantic_ai.durable_exec.dbos import DBOSAgent
|
|
41
39
|
from pydantic_ai.messages import (
|
|
42
40
|
ModelMessage,
|
|
43
41
|
ModelRequest,
|
|
@@ -67,7 +65,6 @@ from newcode.config import (
|
|
|
67
65
|
get_global_model_name,
|
|
68
66
|
get_message_limit,
|
|
69
67
|
get_protected_token_count,
|
|
70
|
-
get_use_dbos,
|
|
71
68
|
get_value,
|
|
72
69
|
)
|
|
73
70
|
from newcode.error_logging import log_error
|
|
@@ -1319,6 +1316,12 @@ class BaseAgent(ABC):
|
|
|
1319
1316
|
"""Force-reload the pydantic-ai Agent based on current config and model."""
|
|
1320
1317
|
from newcode.tools import register_tools_for_agent
|
|
1321
1318
|
|
|
1319
|
+
# Invalidate the project-local rules cache so a fresh read from the
|
|
1320
|
+
# current working directory is performed on the next load_agent_rules()
|
|
1321
|
+
# call. This is critical for /cd: the user may have switched to a
|
|
1322
|
+
# different project that has its own AGENT.md (or none at all).
|
|
1323
|
+
self._agent_rules = None
|
|
1324
|
+
|
|
1322
1325
|
if message_group is None:
|
|
1323
1326
|
message_group = str(uuid.uuid4())
|
|
1324
1327
|
|
|
@@ -1417,64 +1420,25 @@ class BaseAgent(ABC):
|
|
|
1417
1420
|
)
|
|
1418
1421
|
|
|
1419
1422
|
self._last_model_name = resolved_model_name
|
|
1420
|
-
# expose for run_with_mcp
|
|
1421
|
-
# Wrap it with DBOS, but handle MCP servers separately to avoid serialization issues
|
|
1422
1423
|
global _reload_count
|
|
1423
1424
|
_reload_count += 1
|
|
1424
|
-
if get_use_dbos():
|
|
1425
|
-
# Don't pass MCP servers to the agent constructor when using DBOS
|
|
1426
|
-
# This prevents the "cannot pickle async_generator object" error
|
|
1427
|
-
# MCP servers will be handled separately in run_with_mcp
|
|
1428
|
-
agent_without_mcp = PydanticAgent(
|
|
1429
|
-
model=model,
|
|
1430
|
-
instructions=instructions,
|
|
1431
|
-
output_type=str,
|
|
1432
|
-
retries=10,
|
|
1433
|
-
toolsets=[], # Don't include MCP servers here
|
|
1434
|
-
history_processors=[self.message_history_accumulator],
|
|
1435
|
-
model_settings=model_settings,
|
|
1436
|
-
)
|
|
1437
|
-
|
|
1438
|
-
# Register regular tools (non-MCP) on the new agent
|
|
1439
|
-
agent_tools = self.get_available_tools()
|
|
1440
|
-
register_tools_for_agent(
|
|
1441
|
-
agent_without_mcp, agent_tools, model_name=resolved_model_name
|
|
1442
|
-
)
|
|
1443
|
-
|
|
1444
|
-
# Wrap with DBOS - pass event_stream_handler at construction time
|
|
1445
|
-
# so DBOSModel gets the handler for streaming output
|
|
1446
|
-
dbos_agent = DBOSAgent(
|
|
1447
|
-
agent_without_mcp,
|
|
1448
|
-
name=f"{self.name}-{_reload_count}",
|
|
1449
|
-
event_stream_handler=event_stream_handler,
|
|
1450
|
-
)
|
|
1451
|
-
self.pydantic_agent = dbos_agent
|
|
1452
|
-
self._code_generation_agent = dbos_agent
|
|
1453
1425
|
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
model_settings=model_settings,
|
|
1467
|
-
)
|
|
1468
|
-
# Register regular tools on the agent
|
|
1469
|
-
agent_tools = self.get_available_tools()
|
|
1470
|
-
register_tools_for_agent(
|
|
1471
|
-
p_agent, agent_tools, model_name=resolved_model_name
|
|
1472
|
-
)
|
|
1426
|
+
p_agent = PydanticAgent(
|
|
1427
|
+
model=model,
|
|
1428
|
+
instructions=instructions,
|
|
1429
|
+
output_type=str,
|
|
1430
|
+
retries=10,
|
|
1431
|
+
toolsets=filtered_mcp_servers,
|
|
1432
|
+
history_processors=[self.message_history_accumulator],
|
|
1433
|
+
model_settings=model_settings,
|
|
1434
|
+
)
|
|
1435
|
+
# Register regular tools on the agent
|
|
1436
|
+
agent_tools = self.get_available_tools()
|
|
1437
|
+
register_tools_for_agent(p_agent, agent_tools, model_name=resolved_model_name)
|
|
1473
1438
|
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
self._mcp_servers = mcp_servers
|
|
1439
|
+
self.pydantic_agent = p_agent
|
|
1440
|
+
self._code_generation_agent = p_agent
|
|
1441
|
+
self._mcp_servers = filtered_mcp_servers
|
|
1478
1442
|
return self._code_generation_agent
|
|
1479
1443
|
|
|
1480
1444
|
def _create_agent_with_output_type(self, output_type: Type[Any]) -> PydanticAgent:
|
|
@@ -1488,7 +1452,7 @@ class BaseAgent(ABC):
|
|
|
1488
1452
|
output_type: The Pydantic model or type for structured output.
|
|
1489
1453
|
|
|
1490
1454
|
Returns:
|
|
1491
|
-
A configured PydanticAgent
|
|
1455
|
+
A configured PydanticAgent with the custom output_type.
|
|
1492
1456
|
"""
|
|
1493
1457
|
from newcode.model_utils import prepare_prompt_for_model
|
|
1494
1458
|
from newcode.tools import register_tools_for_agent
|
|
@@ -1515,45 +1479,21 @@ class BaseAgent(ABC):
|
|
|
1515
1479
|
global _reload_count
|
|
1516
1480
|
_reload_count += 1
|
|
1517
1481
|
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
# Pass event_stream_handler at construction time for streaming output
|
|
1533
|
-
dbos_agent = DBOSAgent(
|
|
1534
|
-
temp_agent,
|
|
1535
|
-
name=f"{self.name}-structured-{_reload_count}",
|
|
1536
|
-
event_stream_handler=event_stream_handler,
|
|
1537
|
-
)
|
|
1538
|
-
return dbos_agent
|
|
1539
|
-
else:
|
|
1540
|
-
temp_agent = PydanticAgent(
|
|
1541
|
-
model=model,
|
|
1542
|
-
instructions=instructions,
|
|
1543
|
-
output_type=output_type,
|
|
1544
|
-
retries=10,
|
|
1545
|
-
toolsets=mcp_servers,
|
|
1546
|
-
history_processors=[self.message_history_accumulator],
|
|
1547
|
-
model_settings=model_settings,
|
|
1548
|
-
)
|
|
1549
|
-
agent_tools = self.get_available_tools()
|
|
1550
|
-
register_tools_for_agent(
|
|
1551
|
-
temp_agent, agent_tools, model_name=resolved_model_name
|
|
1552
|
-
)
|
|
1553
|
-
return temp_agent
|
|
1482
|
+
temp_agent = PydanticAgent(
|
|
1483
|
+
model=model,
|
|
1484
|
+
instructions=instructions,
|
|
1485
|
+
output_type=output_type,
|
|
1486
|
+
retries=10,
|
|
1487
|
+
toolsets=mcp_servers,
|
|
1488
|
+
history_processors=[self.message_history_accumulator],
|
|
1489
|
+
model_settings=model_settings,
|
|
1490
|
+
)
|
|
1491
|
+
agent_tools = self.get_available_tools()
|
|
1492
|
+
register_tools_for_agent(
|
|
1493
|
+
temp_agent, agent_tools, model_name=resolved_model_name
|
|
1494
|
+
)
|
|
1495
|
+
return temp_agent
|
|
1554
1496
|
|
|
1555
|
-
# It's okay to decorate it with DBOS.step even if not using DBOS; the decorator is a no-op in that case.
|
|
1556
|
-
@DBOS.step()
|
|
1557
1497
|
def message_history_accumulator(self, ctx: RunContext, messages: List[Any]):
|
|
1558
1498
|
_message_history = self.get_message_history()
|
|
1559
1499
|
|
|
@@ -1908,51 +1848,14 @@ class BaseAgent(ABC):
|
|
|
1908
1848
|
|
|
1909
1849
|
usage_limits = UsageLimits(request_limit=get_message_limit())
|
|
1910
1850
|
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
pydantic_agent._toolsets = original_toolsets + self._mcp_servers
|
|
1920
|
-
pydantic_agent._toolsets = original_toolsets + self._mcp_servers
|
|
1921
|
-
|
|
1922
|
-
try:
|
|
1923
|
-
# Set the workflow ID for DBOS context so DBOS and the agent ID match
|
|
1924
|
-
with SetWorkflowID(group_id):
|
|
1925
|
-
result_ = await pydantic_agent.run(
|
|
1926
|
-
prompt_payload,
|
|
1927
|
-
message_history=self.get_message_history(),
|
|
1928
|
-
usage_limits=usage_limits,
|
|
1929
|
-
event_stream_handler=event_stream_handler,
|
|
1930
|
-
**kwargs,
|
|
1931
|
-
)
|
|
1932
|
-
return result_
|
|
1933
|
-
finally:
|
|
1934
|
-
# Always restore original toolsets
|
|
1935
|
-
pydantic_agent._toolsets = original_toolsets
|
|
1936
|
-
elif get_use_dbos():
|
|
1937
|
-
with SetWorkflowID(group_id):
|
|
1938
|
-
result_ = await pydantic_agent.run(
|
|
1939
|
-
prompt_payload,
|
|
1940
|
-
message_history=self.get_message_history(),
|
|
1941
|
-
usage_limits=usage_limits,
|
|
1942
|
-
event_stream_handler=event_stream_handler,
|
|
1943
|
-
**kwargs,
|
|
1944
|
-
)
|
|
1945
|
-
return result_
|
|
1946
|
-
else:
|
|
1947
|
-
# Non-DBOS path (MCP servers are already included)
|
|
1948
|
-
result_ = await pydantic_agent.run(
|
|
1949
|
-
prompt_payload,
|
|
1950
|
-
message_history=self.get_message_history(),
|
|
1951
|
-
usage_limits=usage_limits,
|
|
1952
|
-
event_stream_handler=event_stream_handler,
|
|
1953
|
-
**kwargs,
|
|
1954
|
-
)
|
|
1955
|
-
return result_
|
|
1851
|
+
result_ = await pydantic_agent.run(
|
|
1852
|
+
prompt_payload,
|
|
1853
|
+
message_history=self.get_message_history(),
|
|
1854
|
+
usage_limits=usage_limits,
|
|
1855
|
+
event_stream_handler=event_stream_handler,
|
|
1856
|
+
**kwargs,
|
|
1857
|
+
)
|
|
1858
|
+
return result_
|
|
1956
1859
|
except* UsageLimitExceeded as ule:
|
|
1957
1860
|
emit_info(f"Usage limit exceeded: {str(ule)}", group_id=group_id)
|
|
1958
1861
|
emit_info(
|
|
@@ -1968,12 +1871,8 @@ class BaseAgent(ABC):
|
|
|
1968
1871
|
)
|
|
1969
1872
|
except* asyncio.exceptions.CancelledError:
|
|
1970
1873
|
emit_info("Cancelled")
|
|
1971
|
-
if get_use_dbos():
|
|
1972
|
-
await DBOS.cancel_workflow_async(group_id)
|
|
1973
1874
|
except* InterruptedError as ie:
|
|
1974
1875
|
emit_info(f"Interrupted: {str(ie)}")
|
|
1975
|
-
if get_use_dbos():
|
|
1976
|
-
await DBOS.cancel_workflow_async(group_id)
|
|
1977
1876
|
except* Exception as other_error:
|
|
1978
1877
|
|
|
1979
1878
|
def contains_cloudflare_auth_error(exc: Exception) -> bool:
|
|
@@ -371,7 +371,7 @@ class ClaudeCacheAsyncClient(httpx.AsyncClient):
|
|
|
371
371
|
is_auth_error = response.status_code in (401, 403)
|
|
372
372
|
|
|
373
373
|
if response.status_code == 400:
|
|
374
|
-
is_auth_error = self._is_cloudflare_html_error(response)
|
|
374
|
+
is_auth_error = await self._is_cloudflare_html_error(response)
|
|
375
375
|
if is_auth_error:
|
|
376
376
|
logger.info(
|
|
377
377
|
"Detected Cloudflare 400 error (expired token), attempting token refresh"
|
|
@@ -531,7 +531,7 @@ class ClaudeCacheAsyncClient(httpx.AsyncClient):
|
|
|
531
531
|
headers["Authorization"] = bearer_value
|
|
532
532
|
|
|
533
533
|
@staticmethod
|
|
534
|
-
def _is_cloudflare_html_error(response: httpx.Response) -> bool:
|
|
534
|
+
async def _is_cloudflare_html_error(response: httpx.Response) -> bool:
|
|
535
535
|
"""Check if this is a Cloudflare HTML error response.
|
|
536
536
|
|
|
537
537
|
Cloudflare often returns HTML error pages with status 400 when
|
|
@@ -546,10 +546,20 @@ class ClaudeCacheAsyncClient(httpx.AsyncClient):
|
|
|
546
546
|
"""
|
|
547
547
|
try:
|
|
548
548
|
body = None
|
|
549
|
-
|
|
549
|
+
|
|
550
|
+
# For async httpx, read the body if content is not available yet.
|
|
551
|
+
if not hasattr(response, "_content") or not response._content:
|
|
552
|
+
try:
|
|
553
|
+
await response.aread()
|
|
554
|
+
except Exception as read_exc:
|
|
555
|
+
logger.debug("Failed to read response body: %s", read_exc)
|
|
556
|
+
return False
|
|
557
|
+
|
|
558
|
+
# Prefer raw _content if present (already consumed responses).
|
|
550
559
|
if hasattr(response, "_content") and response._content:
|
|
551
560
|
body = response._content.decode("utf-8", errors="ignore")
|
|
552
561
|
else:
|
|
562
|
+
# Fallback to text property.
|
|
553
563
|
try:
|
|
554
564
|
body = response.text
|
|
555
565
|
except Exception:
|
|
@@ -12,10 +12,8 @@ import argparse
|
|
|
12
12
|
import asyncio
|
|
13
13
|
import os
|
|
14
14
|
import sys
|
|
15
|
-
import time
|
|
16
15
|
from pathlib import Path
|
|
17
16
|
|
|
18
|
-
from dbos import DBOS, DBOSConfig
|
|
19
17
|
from rich.console import Console
|
|
20
18
|
|
|
21
19
|
from newcode import __version__, callbacks, plugins
|
|
@@ -25,10 +23,8 @@ from newcode.command_line.clipboard import get_clipboard_manager
|
|
|
25
23
|
from newcode.config import (
|
|
26
24
|
AUTOSAVE_DIR,
|
|
27
25
|
COMMAND_HISTORY_FILE,
|
|
28
|
-
DBOS_DATABASE_URL,
|
|
29
26
|
ensure_config_exists,
|
|
30
27
|
finalize_autosave_session,
|
|
31
|
-
get_use_dbos,
|
|
32
28
|
initialize_command_history_file,
|
|
33
29
|
save_command_to_history,
|
|
34
30
|
)
|
|
@@ -271,33 +267,6 @@ async def main():
|
|
|
271
267
|
|
|
272
268
|
await callbacks.on_startup()
|
|
273
269
|
|
|
274
|
-
# Initialize DBOS if not disabled
|
|
275
|
-
if get_use_dbos():
|
|
276
|
-
# Append a Unix timestamp in ms to the version for uniqueness
|
|
277
|
-
dbos_app_version = os.environ.get(
|
|
278
|
-
"DBOS_APP_VERSION", f"{current_version}-{int(time.time() * 1000)}"
|
|
279
|
-
)
|
|
280
|
-
dbos_config: DBOSConfig = {
|
|
281
|
-
"name": "dbos-code-agent",
|
|
282
|
-
"system_database_url": DBOS_DATABASE_URL,
|
|
283
|
-
"run_admin_server": False,
|
|
284
|
-
"conductor_key": os.environ.get(
|
|
285
|
-
"DBOS_CONDUCTOR_KEY"
|
|
286
|
-
), # Optional, if set in env, connect to conductor
|
|
287
|
-
"log_level": os.environ.get(
|
|
288
|
-
"DBOS_LOG_LEVEL", "ERROR"
|
|
289
|
-
), # Default to ERROR level to suppress verbose logs
|
|
290
|
-
"application_version": dbos_app_version, # Match DBOS app version
|
|
291
|
-
}
|
|
292
|
-
try:
|
|
293
|
-
DBOS(config=dbos_config)
|
|
294
|
-
DBOS.launch()
|
|
295
|
-
except Exception as e:
|
|
296
|
-
emit_error(f"Error initializing DBOS: {e}")
|
|
297
|
-
sys.exit(1)
|
|
298
|
-
else:
|
|
299
|
-
pass
|
|
300
|
-
|
|
301
270
|
global shutdown_flag
|
|
302
271
|
shutdown_flag = False
|
|
303
272
|
try:
|
|
@@ -322,8 +291,6 @@ async def main():
|
|
|
322
291
|
if bus_renderer:
|
|
323
292
|
bus_renderer.stop()
|
|
324
293
|
await callbacks.on_shutdown()
|
|
325
|
-
if get_use_dbos():
|
|
326
|
-
DBOS.destroy()
|
|
327
294
|
|
|
328
295
|
|
|
329
296
|
async def interactive_mode(message_renderer, initial_command: str = None) -> None:
|
|
@@ -981,8 +948,6 @@ def main_entry():
|
|
|
981
948
|
asyncio.run(main())
|
|
982
949
|
except KeyboardInterrupt:
|
|
983
950
|
# Normal exit via Ctrl+C – not a crash, so just clean up quietly
|
|
984
|
-
if get_use_dbos():
|
|
985
|
-
DBOS.destroy()
|
|
986
951
|
return 0
|
|
987
952
|
finally:
|
|
988
953
|
# Reset terminal on Unix-like systems (not Windows)
|
|
@@ -42,7 +42,6 @@ def handle_show_command(command: str) -> bool:
|
|
|
42
42
|
get_protected_token_count,
|
|
43
43
|
get_resume_message_count,
|
|
44
44
|
get_temperature,
|
|
45
|
-
get_use_dbos,
|
|
46
45
|
get_yolo_mode,
|
|
47
46
|
)
|
|
48
47
|
from newcode.keymap import (
|
|
@@ -69,7 +68,6 @@ def handle_show_command(command: str) -> bool:
|
|
|
69
68
|
[bold]default_agent:[/bold] [cyan]{default_agent}[/cyan]
|
|
70
69
|
[bold]model:[/bold] [green]{model}[/green]
|
|
71
70
|
[bold]YOLO_MODE:[/bold] {"[red]ON[/red]" if yolo_mode else "[yellow]off[/yellow]"}
|
|
72
|
-
[bold]DBOS:[/bold] {"[green]enabled[/green]" if get_use_dbos() else "[yellow]disabled[/yellow]"} (toggle: /set enable_dbos true|false)
|
|
73
71
|
[bold]auto_save_session:[/bold] {"[green]enabled[/green]" if auto_save else "[yellow]disabled[/yellow]"}
|
|
74
72
|
[bold]protected_tokens:[/bold] [cyan]{protected_tokens:,}[/cyan] recent tokens preserved
|
|
75
73
|
[bold]compaction_threshold:[/bold] [cyan]{compaction_threshold:.1%}[/cyan] context usage triggers compaction
|
|
@@ -211,14 +209,6 @@ def handle_set_command(command: str) -> bool:
|
|
|
211
209
|
)
|
|
212
210
|
return True
|
|
213
211
|
if key:
|
|
214
|
-
# Check if we're toggling DBOS enablement
|
|
215
|
-
if key == "enable_dbos":
|
|
216
|
-
emit_info(
|
|
217
|
-
Text.from_markup(
|
|
218
|
-
"[yellow]⚠️ DBOS configuration changed. Please restart the application for this change to take effect.[/yellow]"
|
|
219
|
-
)
|
|
220
|
-
)
|
|
221
|
-
|
|
222
212
|
# Validate cancel_agent_key before setting
|
|
223
213
|
if key == "cancel_agent_key":
|
|
224
214
|
from newcode.keymap import VALID_CANCEL_KEYS
|
|
@@ -55,7 +55,7 @@ def handle_cd_command(command: str) -> bool:
|
|
|
55
55
|
# Use shlex.split to handle quoted paths properly
|
|
56
56
|
import shlex
|
|
57
57
|
|
|
58
|
-
from newcode.messaging import emit_error, emit_info, emit_success
|
|
58
|
+
from newcode.messaging import emit_error, emit_info, emit_success, emit_warning
|
|
59
59
|
|
|
60
60
|
try:
|
|
61
61
|
tokens = shlex.split(command)
|
|
@@ -77,6 +77,20 @@ def handle_cd_command(command: str) -> bool:
|
|
|
77
77
|
if os.path.isdir(target):
|
|
78
78
|
os.chdir(target)
|
|
79
79
|
emit_success(f"Changed directory to: {target}")
|
|
80
|
+
# Reload the agent so the system prompt and project-local
|
|
81
|
+
# AGENT.md rules reflect the new working directory. Without
|
|
82
|
+
# this, the LLM keeps receiving stale path information for the
|
|
83
|
+
# remainder of the session (the PydanticAgent instructions are
|
|
84
|
+
# baked in at construction time and never refreshed otherwise).
|
|
85
|
+
try:
|
|
86
|
+
from newcode.agents import get_current_agent
|
|
87
|
+
|
|
88
|
+
get_current_agent().reload_code_generation_agent()
|
|
89
|
+
except Exception as e:
|
|
90
|
+
emit_warning(
|
|
91
|
+
f"Directory changed, but agent reload failed: {e}. "
|
|
92
|
+
"You may need to run /agent or /model to force a refresh."
|
|
93
|
+
)
|
|
80
94
|
else:
|
|
81
95
|
emit_error(f"Not a directory: {dirname}")
|
|
82
96
|
return True
|
|
@@ -49,7 +49,6 @@ EXTRA_MODELS_FILE = os.path.join(DATA_DIR, "extra_models.json")
|
|
|
49
49
|
AGENTS_DIR = os.path.join(DATA_DIR, "agents")
|
|
50
50
|
SKILLS_DIR = os.path.join(DATA_DIR, "skills")
|
|
51
51
|
CONTEXTS_DIR = os.path.join(DATA_DIR, "contexts")
|
|
52
|
-
_DEFAULT_SQLITE_FILE = os.path.join(DATA_DIR, "dbos_store.sqlite")
|
|
53
52
|
|
|
54
53
|
# OAuth plugin model files (XDG_DATA_HOME)
|
|
55
54
|
GEMINI_MODELS_FILE = os.path.join(DATA_DIR, "gemini_models.json")
|
|
@@ -62,19 +61,6 @@ AUTOSAVE_DIR = os.path.join(CACHE_DIR, "autosaves")
|
|
|
62
61
|
|
|
63
62
|
# State files (XDG_STATE_HOME)
|
|
64
63
|
COMMAND_HISTORY_FILE = os.path.join(STATE_DIR, "command_history.txt")
|
|
65
|
-
DBOS_DATABASE_URL = os.environ.get(
|
|
66
|
-
"DBOS_SYSTEM_DATABASE_URL", f"sqlite:///{_DEFAULT_SQLITE_FILE}"
|
|
67
|
-
)
|
|
68
|
-
# DBOS enable switch is controlled solely via puppy.cfg using key 'enable_dbos'.
|
|
69
|
-
# Default: True (DBOS enabled) unless explicitly disabled.
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
def get_use_dbos() -> bool:
|
|
73
|
-
"""Return True if DBOS should be used based on 'enable_dbos' (default True)."""
|
|
74
|
-
cfg_val = get_value("enable_dbos")
|
|
75
|
-
if cfg_val is None:
|
|
76
|
-
return True
|
|
77
|
-
return str(cfg_val).strip().lower() in {"1", "true", "yes", "on"}
|
|
78
64
|
|
|
79
65
|
|
|
80
66
|
def get_subagent_verbose() -> bool:
|
|
@@ -288,8 +274,6 @@ def get_config_keys():
|
|
|
288
274
|
"frontend_emitter_max_recent_events",
|
|
289
275
|
"frontend_emitter_queue_size",
|
|
290
276
|
]
|
|
291
|
-
# Add DBOS control key
|
|
292
|
-
default_keys.append("enable_dbos")
|
|
293
277
|
# Add pack agents control key
|
|
294
278
|
default_keys.append("enable_pack_agents")
|
|
295
279
|
# Add universal constructor control key
|
|
@@ -1193,11 +1177,6 @@ def set_http2(enabled: bool) -> None:
|
|
|
1193
1177
|
set_config_value("http2", "true" if enabled else "false")
|
|
1194
1178
|
|
|
1195
1179
|
|
|
1196
|
-
def set_enable_dbos(enabled: bool) -> None:
|
|
1197
|
-
"""Enable DBOS via config (true enables, default false)."""
|
|
1198
|
-
set_config_value("enable_dbos", "true" if enabled else "false")
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
1180
|
def get_message_limit(default: int = 1000) -> int:
|
|
1202
1181
|
"""
|
|
1203
1182
|
Returns the user-configured message/request limit for the agent.
|
|
@@ -193,7 +193,7 @@ def _substitute_variables(
|
|
|
193
193
|
result = command
|
|
194
194
|
for var, value in substitutions.items():
|
|
195
195
|
result = result.replace(f"${{{var}}}", str(value))
|
|
196
|
-
result = re.sub(rf"\${re.escape(var)}(?=\W|$)", str(value), result)
|
|
196
|
+
result = re.sub(rf"\${re.escape(var)}(?=\W|$)", lambda m: str(value), result)
|
|
197
197
|
return result
|
|
198
198
|
|
|
199
199
|
|
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
"context_length": 200000,
|
|
10
10
|
"supported_settings": ["temperature", "seed", "top_p"]
|
|
11
11
|
},
|
|
12
|
-
"synthetic-MiniMax-M2.
|
|
12
|
+
"synthetic-MiniMax-M2.5": {
|
|
13
13
|
"type": "custom_openai",
|
|
14
|
-
"name": "hf:MiniMaxAI/MiniMax-M2.
|
|
14
|
+
"name": "hf:MiniMaxAI/MiniMax-M2.5",
|
|
15
15
|
"custom_endpoint": {
|
|
16
16
|
"url": "https://api.synthetic.new/openai/v1/",
|
|
17
17
|
"api_key": "$SYN_API_KEY"
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
"context_length": 195000,
|
|
20
20
|
"supported_settings": ["temperature", "seed", "top_p"]
|
|
21
21
|
},
|
|
22
|
-
"synthetic-
|
|
22
|
+
"synthetic-qwen3.5-397b": {
|
|
23
23
|
"type": "custom_openai",
|
|
24
|
-
"name": "hf:
|
|
24
|
+
"name": "hf:Qwen/Qwen3.5-397B-A17B",
|
|
25
25
|
"custom_endpoint": {
|
|
26
26
|
"url": "https://api.synthetic.new/openai/v1/",
|
|
27
27
|
"api_key": "$SYN_API_KEY"
|
|
@@ -318,9 +318,10 @@ def run_oauth_flow() -> None:
|
|
|
318
318
|
|
|
319
319
|
if api_key:
|
|
320
320
|
emit_info("Registering ChatGPT Codex models…")
|
|
321
|
-
from .utils import
|
|
321
|
+
from .utils import fetch_chatgpt_models
|
|
322
322
|
|
|
323
|
-
|
|
323
|
+
account_id = tokens.get("account_id", "")
|
|
324
|
+
models = fetch_chatgpt_models(api_key, account_id)
|
|
324
325
|
if models:
|
|
325
326
|
if add_models_to_extra_config(models):
|
|
326
327
|
emit_success(
|
|
@@ -251,6 +251,10 @@ def test_fetch_chatgpt_models(mock_get):
|
|
|
251
251
|
|
|
252
252
|
models = utils.fetch_chatgpt_models("test_access_token", "test_account_id")
|
|
253
253
|
assert models is not None
|
|
254
|
+
# Required models always injected
|
|
255
|
+
assert "gpt-5.4" in models
|
|
256
|
+
assert "gpt-5.3-instant" in models
|
|
257
|
+
# API-returned models present too
|
|
254
258
|
assert "gpt-4o" in models
|
|
255
259
|
assert "gpt-3.5-turbo" in models
|
|
256
260
|
assert "o1-preview" in models
|
|
@@ -267,7 +271,9 @@ def test_fetch_chatgpt_models_fallback(mock_get):
|
|
|
267
271
|
|
|
268
272
|
models = utils.fetch_chatgpt_models("test_access_token", "test_account_id")
|
|
269
273
|
assert models is not None
|
|
270
|
-
# Should return default models
|
|
274
|
+
# Should return default models (including new required ones)
|
|
275
|
+
assert "gpt-5.4" in models
|
|
276
|
+
assert "gpt-5.3-instant" in models
|
|
271
277
|
assert "gpt-5.3-codex-spark" in models
|
|
272
278
|
assert "gpt-5.3-codex" in models
|
|
273
279
|
assert "gpt-5.2-codex" in models
|
|
@@ -344,19 +344,43 @@ def exchange_code_for_tokens(
|
|
|
344
344
|
# These are the known models that work with ChatGPT OAuth tokens
|
|
345
345
|
# Based on codex-rs CLI and shell-scripts/codex-call.sh
|
|
346
346
|
DEFAULT_CODEX_MODELS = [
|
|
347
|
+
"gpt-5.4",
|
|
348
|
+
"gpt-5.3-instant",
|
|
347
349
|
"gpt-5.3-codex-spark",
|
|
348
350
|
"gpt-5.3-codex",
|
|
349
351
|
"gpt-5.2-codex",
|
|
350
352
|
"gpt-5.2",
|
|
351
353
|
]
|
|
352
354
|
|
|
355
|
+
# Models that MUST always be registered, even if the /models endpoint
|
|
356
|
+
# doesn't return them (e.g. newly launched, not yet in the API catalogue).
|
|
357
|
+
# These are merged into whatever the endpoint returns.
|
|
358
|
+
REQUIRED_CODEX_MODELS = [
|
|
359
|
+
"gpt-5.4",
|
|
360
|
+
"gpt-5.3-instant",
|
|
361
|
+
"gpt-5.3-codex",
|
|
362
|
+
]
|
|
363
|
+
|
|
353
364
|
# Per-model context length overrides (tokens).
|
|
354
365
|
# Models not listed here use CHATGPT_OAUTH_CONFIG["default_context_length"] (272,000).
|
|
355
366
|
CODEX_MODEL_CONTEXT_LENGTHS = {
|
|
356
367
|
"gpt-5.3-codex-spark": 131000,
|
|
368
|
+
"gpt-5.3-instant": 192000,
|
|
357
369
|
}
|
|
358
370
|
|
|
359
371
|
|
|
372
|
+
def _ensure_required_models(models: List[str]) -> List[str]:
|
|
373
|
+
"""Merge REQUIRED_CODEX_MODELS into the given list, preserving order.
|
|
374
|
+
|
|
375
|
+
Any required model not already present is prepended so it appears first.
|
|
376
|
+
"""
|
|
377
|
+
existing = set(models)
|
|
378
|
+
missing = [m for m in REQUIRED_CODEX_MODELS if m not in existing]
|
|
379
|
+
if missing:
|
|
380
|
+
logger.info("Injecting required models not returned by API: %s", missing)
|
|
381
|
+
return missing + models
|
|
382
|
+
|
|
383
|
+
|
|
360
384
|
def fetch_chatgpt_models(access_token: str, account_id: str) -> Optional[List[str]]:
|
|
361
385
|
"""Fetch available models from ChatGPT Codex API.
|
|
362
386
|
|
|
@@ -419,7 +443,7 @@ def fetch_chatgpt_models(access_token: str, account_id: str) -> Optional[List[st
|
|
|
419
443
|
if model_id:
|
|
420
444
|
models.append(model_id)
|
|
421
445
|
if models:
|
|
422
|
-
return models
|
|
446
|
+
return _ensure_required_models(models)
|
|
423
447
|
except (json.JSONDecodeError, ValueError) as exc:
|
|
424
448
|
logger.warning("Failed to parse models response: %s", exc)
|
|
425
449
|
|