deepagents-cli 0.0.54__tar.gz → 0.0.55__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.
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/CHANGELOG.md +6 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/PKG-INFO +1 -1
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/_version.py +1 -1
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/textual_adapter.py +15 -2
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/widgets/messages.py +154 -20
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/pyproject.toml +1 -1
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_messages.py +116 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_textual_adapter.py +53 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/uv.lock +1 -1
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/.gitignore +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/DEV.md +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/Makefile +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/README.md +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/THREAT_MODEL.md +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/__init__.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/__main__.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/_ask_user_types.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/_cli_context.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/_constants.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/_debug.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/_env_vars.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/_git.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/_server_config.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/_session_stats.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/_testing_models.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/_textual_patches.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/agent.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/app.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/app.tcss +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/ask_user.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/auth_store.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/built_in_skills/__init__.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/built_in_skills/remember/SKILL.md +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/built_in_skills/skill-creator/SKILL.md +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/built_in_skills/skill-creator/scripts/init_skill.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/built_in_skills/skill-creator/scripts/quick_validate.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/clipboard.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/command_registry.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/config.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/configurable_model.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/default_agent_prompt.md +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/deploy/__init__.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/deploy/bundler.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/deploy/commands.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/deploy/config.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/deploy/context_hub.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/deploy/frontend_dist/assets/anonymous-B9UzAXQd.js +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/deploy/frontend_dist/assets/clerk-5xHgyQyG.js +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/deploy/frontend_dist/assets/highlighted-body-OFNGDK62-rX-7qT8o.js +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/deploy/frontend_dist/assets/index-DM3gptpu.js +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/deploy/frontend_dist/assets/index-Ddy7F6KI.css +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/deploy/frontend_dist/assets/supabase-S6NACDgm.js +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/deploy/frontend_dist/index.html +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/deploy/frontend_dist/logo-dark.svg +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/deploy/frontend_dist/logo-light.svg +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/deploy/templates.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/editor.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/event_bus.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/extras_info.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/file_ops.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/formatting.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/hooks.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/input.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/integrations/__init__.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/integrations/sandbox_factory.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/integrations/sandbox_provider.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/iterm_cursor_guide.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/local_context.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/main.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/mcp_auth.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/mcp_commands.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/mcp_providers/__init__.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/mcp_providers/_registry.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/mcp_providers/base.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/mcp_providers/github.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/mcp_providers/slack.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/mcp_tools.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/mcp_trust.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/media_utils.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/model_config.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/non_interactive.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/notifications.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/offload.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/onboarding.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/output.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/project_utils.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/py.typed +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/remote_client.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/server.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/server_graph.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/server_manager.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/sessions.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/skills/__init__.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/skills/commands.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/skills/invocation.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/skills/load.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/state_migration.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/subagents.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/system_prompt.md +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/terminal_capabilities.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/theme.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/token_state.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/tool_display.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/tools.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/ui.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/unicode_security.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/update_check.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/widgets/__init__.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/widgets/_links.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/widgets/agent_selector.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/widgets/approval.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/widgets/ask_user.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/widgets/auth.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/widgets/autocomplete.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/widgets/chat_input.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/widgets/diff.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/widgets/history.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/widgets/launch_init.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/widgets/loading.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/widgets/mcp_viewer.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/widgets/message_store.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/widgets/model_selector.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/widgets/notification_center.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/widgets/notification_detail.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/widgets/notification_settings.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/widgets/status.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/widgets/theme_selector.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/widgets/thread_selector.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/widgets/tool_renderers.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/widgets/tool_widgets.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/widgets/update_available.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/widgets/update_progress.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/widgets/welcome.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/examples/deploy-content-writer/.env.example +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/examples/deploy-content-writer/skills/blog-post/SKILL.md +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/examples/deploy-content-writer/skills/social-media/SKILL.md +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/examples/deploy-content-writer/user/context.md +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/examples/deploy-content-writer/user/preferences.md +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/examples/skills/arxiv-search/SKILL.md +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/examples/skills/arxiv-search/arxiv_search.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/examples/skills/langgraph-docs/SKILL.md +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/examples/skills/skill-creator/SKILL.md +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/examples/skills/skill-creator/scripts/init_skill.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/examples/skills/skill-creator/scripts/quick_validate.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/examples/skills/web-research/SKILL.md +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/frontend/.nvmrc +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/frontend/index.html +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/frontend/package-lock.json +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/frontend/package.json +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/frontend/postcss.config.js +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/frontend/public/logo-dark.svg +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/frontend/public/logo-light.svg +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/frontend/src/App.tsx +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/frontend/src/ThemeProvider.tsx +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/frontend/src/auth/anonymous.tsx +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/frontend/src/auth/clerk.tsx +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/frontend/src/auth/loader.tsx +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/frontend/src/auth/supabase.tsx +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/frontend/src/auth/types.ts +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/frontend/src/components/AppHeader.tsx +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/frontend/src/components/FilePanels.tsx +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/frontend/src/components/MessageList.tsx +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/frontend/src/components/SubagentActivity.tsx +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/frontend/src/components/ThreadPicker.tsx +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/frontend/src/components/TodosPanel.tsx +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/frontend/src/components/ToolCallCard.tsx +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/frontend/src/components/toolcalls/FileToolCard.tsx +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/frontend/src/components/toolcalls/SearchCard.tsx +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/frontend/src/components/toolcalls/ThinkCard.tsx +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/frontend/src/components/toolcalls/TodosCard.tsx +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/frontend/src/components/toolcalls/index.ts +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/frontend/src/constants.ts +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/frontend/src/index.css +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/frontend/src/main.tsx +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/frontend/src/runtimeConfig.ts +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/frontend/src/types.ts +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/frontend/src/vite-env.d.ts +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/frontend/tsconfig.json +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/frontend/vite.config.ts +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/images/cli.png +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/scripts/check_imports.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/scripts/debug_server.sh +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/scripts/install.sh +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/README.md +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/integration_tests/__init__.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/integration_tests/benchmarks/__init__.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/integration_tests/benchmarks/test_codspeed_import_benchmarks.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/integration_tests/benchmarks/test_startup_benchmarks.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/integration_tests/conftest.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/integration_tests/test_acp_mode.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/integration_tests/test_compact_resume.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/integration_tests/test_context_hub.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/integration_tests/test_deploy_hub.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/integration_tests/test_sandbox_factory.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/integration_tests/test_sandbox_operations.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/__init__.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/conftest.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/deploy/__init__.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/deploy/test_bundler.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/deploy/test_commands.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/deploy/test_config.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/deploy/test_context_hub.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/deploy/test_frontend_bundle.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/deploy/test_frontend_config.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/skills/__init__.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/skills/test_commands.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/skills/test_load.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/skills/test_skills_json.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_agent.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_agent_friendly.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_agent_selector.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_app.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_approval.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_args.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_ask_user.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_ask_user_middleware.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_auth_store.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_auth_widgets.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_autocomplete.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_charset.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_chat_input.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_clipboard.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_command_registry.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_compact_tool.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_config.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_configurable_model.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_debug.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_editor.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_end_to_end.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_env_vars.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_event_bus.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_exception_handling.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_extras_info.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_file_ops.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_formatting.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_git.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_history.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_hooks.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_imports.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_input_parsing.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_iterm_cursor_guide.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_launch_init.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_links.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_loading.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_local_context.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_main.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_main_acp_mode.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_main_args.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_mcp_auth.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_mcp_commands.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_mcp_tools.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_mcp_trust.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_mcp_viewer.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_media_utils.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_message_store.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_model_config.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_model_selector.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_model_switch.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_non_interactive.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_notification_center.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_notification_detail.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_notifications.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_offload.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_offload_dict_messages.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_onboarding.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_output.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_reload.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_remote_client.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_sandbox_factory.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_server.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_server_config.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_server_graph.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_server_helpers.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_server_manager.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_session_stats.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_sessions.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_shell_allow_list.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_skill_invocation.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_startup_fast_paths.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_state_migration.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_status.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_subagents.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_terminal_capabilities.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_textual_patches.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_theme.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_thread_selector.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_token_tracker.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_tool_display.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_ui.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_unicode_security.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_update_available.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_update_check.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_update_progress.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_version.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/test_welcome.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/tools/__init__.py +0 -0
- {deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/tests/unit_tests/tools/test_fetch_url.py +0 -0
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Deep Agents CLI Changelog
|
|
2
2
|
|
|
3
|
+
## [0.0.55](https://github.com/langchain-ai/deepagents/compare/deepagents-cli==0.0.54...deepagents-cli==0.0.55) (2026-05-11)
|
|
4
|
+
|
|
5
|
+
### Bug Fixes
|
|
6
|
+
|
|
7
|
+
* Keep Thinking spinner during `edit_file` approval ([#3310](https://github.com/langchain-ai/deepagents/issues/3310)) ([d06133f](https://github.com/langchain-ai/deepagents/commit/d06133f8dd7cb924c82e46ece3e165d561ef7d9e))
|
|
8
|
+
|
|
3
9
|
## [0.0.54](https://github.com/langchain-ai/deepagents/compare/deepagents-cli==0.0.53...deepagents-cli==0.0.54) (2026-05-11)
|
|
4
10
|
|
|
5
11
|
### Features
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: deepagents-cli
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.55
|
|
4
4
|
Summary: Terminal interface for Deep Agents - interactive AI agent with file operations, shell access, and sub-agent capabilities.
|
|
5
5
|
Project-URL: Homepage, https://docs.langchain.com/oss/python/deepagents/overview
|
|
6
6
|
Project-URL: Documentation, https://reference.langchain.com/python/deepagents/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Version information and lightweight constants for `deepagents-cli`."""
|
|
2
2
|
|
|
3
|
-
__version__ = "0.0.
|
|
3
|
+
__version__ = "0.0.55" # x-release-please-version
|
|
4
4
|
|
|
5
5
|
DOCS_URL = "https://docs.langchain.com/oss/python/deepagents/cli"
|
|
6
6
|
"""URL for `deepagents-cli` documentation."""
|
|
@@ -77,6 +77,9 @@ _hitl_adapter_cache: TypeAdapter | None = None
|
|
|
77
77
|
|
|
78
78
|
_ASK_USER_UNSUPPORTED_ERROR = "ask_user not supported by this UI"
|
|
79
79
|
|
|
80
|
+
_TOOL_CALLS_KEEP_THINKING_SPINNER = frozenset({"edit_file"})
|
|
81
|
+
"""Tool calls whose argument/approval phase can be long enough to need feedback."""
|
|
82
|
+
|
|
80
83
|
|
|
81
84
|
def _get_hitl_request_adapter(hitl_request_type: type) -> TypeAdapter:
|
|
82
85
|
"""Return a cached `TypeAdapter(HITLRequest)`.
|
|
@@ -929,8 +932,16 @@ async def execute_task_textual(
|
|
|
929
932
|
buffer_name, parsed_args, buffer_id
|
|
930
933
|
)
|
|
931
934
|
|
|
932
|
-
|
|
933
|
-
|
|
935
|
+
keep_thinking_spinner = (
|
|
936
|
+
buffer_name in _TOOL_CALLS_KEEP_THINKING_SPINNER
|
|
937
|
+
)
|
|
938
|
+
|
|
939
|
+
# Hide spinner before showing most tool calls.
|
|
940
|
+
# `edit_file` can spend noticeable time between
|
|
941
|
+
# argument streaming, HITL interrupt delivery, and
|
|
942
|
+
# approval handling, so re-anchor Thinking below
|
|
943
|
+
# the row instead of leaving the UI visually idle.
|
|
944
|
+
if adapter._set_spinner and not keep_thinking_spinner:
|
|
934
945
|
await adapter._set_spinner(None)
|
|
935
946
|
|
|
936
947
|
# Mount tool call message
|
|
@@ -942,6 +953,8 @@ async def execute_task_textual(
|
|
|
942
953
|
tool_msg = ToolCallMessage(buffer_name, parsed_args)
|
|
943
954
|
await adapter._mount_message(tool_msg)
|
|
944
955
|
adapter._current_tool_messages[buffer_id] = tool_msg
|
|
956
|
+
if adapter._set_spinner and keep_thinking_spinner:
|
|
957
|
+
await adapter._set_spinner("Thinking")
|
|
945
958
|
|
|
946
959
|
tool_call_buffers.pop(buffer_key, None)
|
|
947
960
|
|
|
@@ -6,6 +6,7 @@ import ast
|
|
|
6
6
|
import json
|
|
7
7
|
import logging
|
|
8
8
|
import re
|
|
9
|
+
import textwrap
|
|
9
10
|
from dataclasses import dataclass
|
|
10
11
|
from pathlib import Path
|
|
11
12
|
from time import time
|
|
@@ -15,6 +16,7 @@ from textual import on
|
|
|
15
16
|
from textual.containers import Vertical
|
|
16
17
|
from textual.content import Content
|
|
17
18
|
from textual.events import Click
|
|
19
|
+
from textual.message_pump import NoActiveAppError
|
|
18
20
|
from textual.reactive import var
|
|
19
21
|
from textual.widgets import Static
|
|
20
22
|
|
|
@@ -123,6 +125,8 @@ _MAX_INLINE_ARGS = 3
|
|
|
123
125
|
|
|
124
126
|
# Truncation limits for display
|
|
125
127
|
_MAX_TODO_CONTENT_LEN = 70
|
|
128
|
+
_DEFAULT_TODO_WRAP_WIDTH = 80
|
|
129
|
+
_TODO_WRAP_GUARD_COLUMNS = 4
|
|
126
130
|
_MAX_WEB_CONTENT_LEN = 100
|
|
127
131
|
|
|
128
132
|
# Tools that have their key info already in the header (no need for args line)
|
|
@@ -1063,6 +1067,8 @@ class ToolCallMessage(Vertical):
|
|
|
1063
1067
|
"""Toggle expansion of the tool's preview/full output."""
|
|
1064
1068
|
if not self._output:
|
|
1065
1069
|
return
|
|
1070
|
+
if not self._expanded and not self._has_expandable_output():
|
|
1071
|
+
return
|
|
1066
1072
|
self._expanded = not self._expanded
|
|
1067
1073
|
self._update_output_display()
|
|
1068
1074
|
|
|
@@ -1135,6 +1141,21 @@ class ToolCallMessage(Vertical):
|
|
|
1135
1141
|
# Default: plain text (Content treats input as literal)
|
|
1136
1142
|
return FormattedOutput(content=Content(output))
|
|
1137
1143
|
|
|
1144
|
+
def _has_expandable_output(self) -> bool:
|
|
1145
|
+
"""Return whether collapsed output has hidden content to expand."""
|
|
1146
|
+
output = self._output.strip()
|
|
1147
|
+
if not output:
|
|
1148
|
+
return False
|
|
1149
|
+
|
|
1150
|
+
lines = output.split("\n")
|
|
1151
|
+
if len(lines) > self._PREVIEW_LINES or len(output) > self._PREVIEW_CHARS:
|
|
1152
|
+
return True
|
|
1153
|
+
|
|
1154
|
+
if self._tool_name == "write_todos":
|
|
1155
|
+
return self._format_output(output, is_preview=True).truncation is not None
|
|
1156
|
+
|
|
1157
|
+
return False
|
|
1158
|
+
|
|
1138
1159
|
def _prefix_output(self, content: Content) -> Content: # noqa: PLR6301 # Grouped as method for widget cohesion
|
|
1139
1160
|
"""Prefix output with output marker and indent continuation lines.
|
|
1140
1161
|
|
|
@@ -1177,14 +1198,38 @@ class ToolCallMessage(Vertical):
|
|
|
1177
1198
|
lines.extend([Content.assemble(" ", stats), Content("")])
|
|
1178
1199
|
|
|
1179
1200
|
# Format each item
|
|
1180
|
-
lines.extend(
|
|
1201
|
+
lines.extend(
|
|
1202
|
+
self._format_single_todo(item, is_preview=is_preview)
|
|
1203
|
+
for item in items[:max_items]
|
|
1204
|
+
)
|
|
1181
1205
|
|
|
1182
1206
|
truncation = None
|
|
1183
|
-
if is_preview
|
|
1184
|
-
|
|
1207
|
+
if is_preview:
|
|
1208
|
+
hidden_items = len(items) - max_items
|
|
1209
|
+
if hidden_items > 0:
|
|
1210
|
+
truncation = f"{hidden_items} more"
|
|
1211
|
+
elif any(
|
|
1212
|
+
len(self._todo_text(item)) > _MAX_TODO_CONTENT_LEN
|
|
1213
|
+
for item in items[:max_items]
|
|
1214
|
+
):
|
|
1215
|
+
truncation = "full todo text"
|
|
1185
1216
|
|
|
1186
1217
|
return FormattedOutput(content=Content("\n").join(lines), truncation=truncation)
|
|
1187
1218
|
|
|
1219
|
+
@staticmethod
|
|
1220
|
+
def _todo_text(item: dict | str) -> str:
|
|
1221
|
+
"""Return display text for a todo item.
|
|
1222
|
+
|
|
1223
|
+
Args:
|
|
1224
|
+
item: Todo item dictionary or plain string.
|
|
1225
|
+
|
|
1226
|
+
Returns:
|
|
1227
|
+
Todo content text.
|
|
1228
|
+
"""
|
|
1229
|
+
if isinstance(item, dict):
|
|
1230
|
+
return str(item.get("content", str(item)))
|
|
1231
|
+
return str(item)
|
|
1232
|
+
|
|
1188
1233
|
def _parse_todo_items(self, output: str) -> list | None: # noqa: PLR6301 # Grouped as method for widget cohesion
|
|
1189
1234
|
"""Parse todo items from output.
|
|
1190
1235
|
|
|
@@ -1227,37 +1272,113 @@ class ToolCallMessage(Vertical):
|
|
|
1227
1272
|
parts.append(Content.styled(f"{completed} done", colors.success))
|
|
1228
1273
|
return Content.styled(" | ", "dim").join(parts) if parts else Content("")
|
|
1229
1274
|
|
|
1230
|
-
def
|
|
1275
|
+
def _todo_content_width(self, indent_width: int) -> int:
|
|
1276
|
+
"""Return the todo content wrap width for the current widget size.
|
|
1277
|
+
|
|
1278
|
+
Args:
|
|
1279
|
+
indent_width: Display width before todo content starts.
|
|
1280
|
+
|
|
1281
|
+
Returns:
|
|
1282
|
+
Width available for todo content wrapping.
|
|
1283
|
+
"""
|
|
1284
|
+
display_width = 0
|
|
1285
|
+
for widget in (self._full_widget, self._preview_widget, self):
|
|
1286
|
+
if widget and widget.is_mounted and widget.size.width > 0:
|
|
1287
|
+
display_width = widget.size.width
|
|
1288
|
+
break
|
|
1289
|
+
|
|
1290
|
+
if not display_width:
|
|
1291
|
+
try:
|
|
1292
|
+
display_width = self.app.size.width
|
|
1293
|
+
except NoActiveAppError:
|
|
1294
|
+
display_width = _DEFAULT_TODO_WRAP_WIDTH
|
|
1295
|
+
|
|
1296
|
+
output_prefix_width = len(get_glyphs().output_prefix) + 1
|
|
1297
|
+
available = (
|
|
1298
|
+
display_width
|
|
1299
|
+
- output_prefix_width
|
|
1300
|
+
- indent_width
|
|
1301
|
+
- _TODO_WRAP_GUARD_COLUMNS
|
|
1302
|
+
)
|
|
1303
|
+
return max(20, available)
|
|
1304
|
+
|
|
1305
|
+
def _format_todo_line(
|
|
1306
|
+
self,
|
|
1307
|
+
prefix: Content,
|
|
1308
|
+
text: str,
|
|
1309
|
+
*,
|
|
1310
|
+
is_preview: bool,
|
|
1311
|
+
text_style: str | None = None,
|
|
1312
|
+
) -> Content:
|
|
1313
|
+
"""Format a todo row, wrapping expanded content under the text column.
|
|
1314
|
+
|
|
1315
|
+
Args:
|
|
1316
|
+
prefix: Styled status prefix before todo content.
|
|
1317
|
+
text: Todo text to render.
|
|
1318
|
+
is_preview: Whether the compact preview is being rendered.
|
|
1319
|
+
text_style: Optional style for todo content.
|
|
1320
|
+
|
|
1321
|
+
Returns:
|
|
1322
|
+
Styled `Content` for one todo row.
|
|
1323
|
+
"""
|
|
1324
|
+
if is_preview and len(text) > _MAX_TODO_CONTENT_LEN:
|
|
1325
|
+
text = text[: _MAX_TODO_CONTENT_LEN - 3] + "..."
|
|
1326
|
+
|
|
1327
|
+
if is_preview:
|
|
1328
|
+
content = Content.styled(text, text_style) if text_style else Content(text)
|
|
1329
|
+
return Content.assemble(prefix, content)
|
|
1330
|
+
|
|
1331
|
+
indent = " " * len(prefix.plain)
|
|
1332
|
+
wrapped = textwrap.wrap(
|
|
1333
|
+
text,
|
|
1334
|
+
width=self._todo_content_width(len(prefix.plain)),
|
|
1335
|
+
break_long_words=True,
|
|
1336
|
+
break_on_hyphens=False,
|
|
1337
|
+
) or [""]
|
|
1338
|
+
parts: list[Content] = [prefix]
|
|
1339
|
+
for index, line in enumerate(wrapped):
|
|
1340
|
+
if index:
|
|
1341
|
+
parts.append(Content("\n" + indent))
|
|
1342
|
+
content = Content.styled(line, text_style) if text_style else Content(line)
|
|
1343
|
+
parts.append(content)
|
|
1344
|
+
return Content.assemble(*parts)
|
|
1345
|
+
|
|
1346
|
+
def _format_single_todo(self, item: dict | str, *, is_preview: bool) -> Content:
|
|
1231
1347
|
"""Format a single todo item.
|
|
1232
1348
|
|
|
1349
|
+
Args:
|
|
1350
|
+
item: Todo item dictionary or plain string.
|
|
1351
|
+
is_preview: Whether the compact preview is being rendered.
|
|
1352
|
+
|
|
1233
1353
|
Returns:
|
|
1234
1354
|
Styled `Content` with checkbox and status styling.
|
|
1235
1355
|
"""
|
|
1236
1356
|
colors = theme.get_theme_colors(self)
|
|
1237
1357
|
if isinstance(item, dict):
|
|
1238
|
-
text =
|
|
1358
|
+
text = self._todo_text(item)
|
|
1239
1359
|
status = item.get("status", "pending")
|
|
1240
1360
|
else:
|
|
1241
|
-
text =
|
|
1361
|
+
text = self._todo_text(item)
|
|
1242
1362
|
status = "pending"
|
|
1243
1363
|
|
|
1244
|
-
if len(text) > _MAX_TODO_CONTENT_LEN:
|
|
1245
|
-
text = text[: _MAX_TODO_CONTENT_LEN - 3] + "..."
|
|
1246
|
-
|
|
1247
1364
|
glyphs = get_glyphs()
|
|
1248
1365
|
if status == "completed":
|
|
1249
|
-
return
|
|
1250
|
-
Content.styled(f" {glyphs.checkmark} done", colors.success),
|
|
1251
|
-
|
|
1366
|
+
return self._format_todo_line(
|
|
1367
|
+
Content.styled(f" {glyphs.checkmark} done ", colors.success),
|
|
1368
|
+
text,
|
|
1369
|
+
is_preview=is_preview,
|
|
1370
|
+
text_style="dim",
|
|
1252
1371
|
)
|
|
1253
1372
|
if status == "in_progress":
|
|
1254
|
-
return
|
|
1255
|
-
Content.styled(f" {glyphs.circle_filled} active", colors.warning),
|
|
1256
|
-
|
|
1373
|
+
return self._format_todo_line(
|
|
1374
|
+
Content.styled(f" {glyphs.circle_filled} active ", colors.warning),
|
|
1375
|
+
text,
|
|
1376
|
+
is_preview=is_preview,
|
|
1257
1377
|
)
|
|
1258
|
-
return
|
|
1259
|
-
Content.styled(f" {glyphs.circle_empty} todo", "dim"),
|
|
1260
|
-
|
|
1378
|
+
return self._format_todo_line(
|
|
1379
|
+
Content.styled(f" {glyphs.circle_empty} todo ", "dim"),
|
|
1380
|
+
text,
|
|
1381
|
+
is_preview=is_preview,
|
|
1261
1382
|
)
|
|
1262
1383
|
|
|
1263
1384
|
def _format_ls_output( # noqa: PLR6301 # Grouped as method for widget cohesion
|
|
@@ -1574,11 +1695,24 @@ class ToolCallMessage(Vertical):
|
|
|
1574
1695
|
self._hint_widget.display = True
|
|
1575
1696
|
elif output_stripped:
|
|
1576
1697
|
# Output fits in preview, show formatted
|
|
1577
|
-
|
|
1698
|
+
is_tool_preview = self._tool_name == "write_todos"
|
|
1699
|
+
result = self._format_output(
|
|
1700
|
+
output_stripped,
|
|
1701
|
+
is_preview=is_tool_preview,
|
|
1702
|
+
)
|
|
1578
1703
|
prefixed = self._prefix_output(result.content)
|
|
1579
1704
|
self._preview_widget.update(prefixed)
|
|
1580
1705
|
self._preview_widget.display = True
|
|
1581
|
-
|
|
1706
|
+
if result.truncation:
|
|
1707
|
+
ellipsis = get_glyphs().ellipsis
|
|
1708
|
+
hint = Content.styled(
|
|
1709
|
+
f"{ellipsis} {result.truncation} — click or Ctrl+O to expand",
|
|
1710
|
+
"dim",
|
|
1711
|
+
)
|
|
1712
|
+
self._hint_widget.update(hint)
|
|
1713
|
+
self._hint_widget.display = True
|
|
1714
|
+
else:
|
|
1715
|
+
self._hint_widget.display = False
|
|
1582
1716
|
else:
|
|
1583
1717
|
self._preview_widget.display = False
|
|
1584
1718
|
self._hint_widget.display = False
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "deepagents-cli"
|
|
7
|
-
version = "0.0.
|
|
7
|
+
version = "0.0.55"
|
|
8
8
|
description = "Terminal interface for Deep Agents - interactive AI agent with file operations, shell access, and sub-agent capabilities."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
@@ -394,6 +394,122 @@ class TestToolCallMessageMarkupSafety:
|
|
|
394
394
|
assert msg.has_expandable_args is True
|
|
395
395
|
|
|
396
396
|
|
|
397
|
+
class TestToolCallMessageTodos:
|
|
398
|
+
"""Tests for `write_todos` output formatting."""
|
|
399
|
+
|
|
400
|
+
def test_todo_preview_truncates_long_content(self) -> None:
|
|
401
|
+
"""Collapsed todo preview should keep the compact character limit."""
|
|
402
|
+
long = "Implement " + "very detailed authentication flow " * 4
|
|
403
|
+
msg = ToolCallMessage("write_todos")
|
|
404
|
+
|
|
405
|
+
result = msg._format_todos_output(
|
|
406
|
+
repr([{"content": long, "status": "in_progress"}]),
|
|
407
|
+
is_preview=True,
|
|
408
|
+
)
|
|
409
|
+
|
|
410
|
+
assert result.content.plain.endswith("...")
|
|
411
|
+
assert long not in result.content.plain
|
|
412
|
+
assert result.truncation == "full todo text"
|
|
413
|
+
|
|
414
|
+
async def test_todo_collapsed_short_output_uses_preview_formatting(self) -> None:
|
|
415
|
+
"""Collapsed todos should truncate even when raw output fits generically."""
|
|
416
|
+
from textual.app import App, ComposeResult
|
|
417
|
+
|
|
418
|
+
long = "Implement " + "very detailed authentication flow " * 3
|
|
419
|
+
assert len(long) > 70
|
|
420
|
+
output = repr([{"content": long, "status": "pending"}])
|
|
421
|
+
assert len(output) < ToolCallMessage._PREVIEW_CHARS
|
|
422
|
+
|
|
423
|
+
class _Harness(App[None]):
|
|
424
|
+
def __init__(self) -> None:
|
|
425
|
+
super().__init__()
|
|
426
|
+
self.msg = ToolCallMessage("write_todos")
|
|
427
|
+
|
|
428
|
+
def compose(self) -> ComposeResult:
|
|
429
|
+
yield self.msg
|
|
430
|
+
|
|
431
|
+
app = _Harness()
|
|
432
|
+
async with app.run_test() as pilot:
|
|
433
|
+
await pilot.pause()
|
|
434
|
+
app.msg.set_success(output)
|
|
435
|
+
await pilot.pause()
|
|
436
|
+
|
|
437
|
+
assert app.msg._preview_widget is not None
|
|
438
|
+
assert app.msg._hint_widget is not None
|
|
439
|
+
content = app.msg._preview_widget._Static__content # type: ignore[attr-defined]
|
|
440
|
+
assert isinstance(content, Content)
|
|
441
|
+
assert "..." in content.plain
|
|
442
|
+
assert long not in content.plain
|
|
443
|
+
assert app.msg._hint_widget.display is True
|
|
444
|
+
|
|
445
|
+
async def test_todo_short_fully_visible_output_does_not_expand(self) -> None:
|
|
446
|
+
"""Clicking fully visible todo output should not show a collapse hint."""
|
|
447
|
+
from textual.app import App, ComposeResult
|
|
448
|
+
|
|
449
|
+
output = repr([{"content": "Write tests", "status": "pending"}])
|
|
450
|
+
|
|
451
|
+
class _Harness(App[None]):
|
|
452
|
+
def __init__(self) -> None:
|
|
453
|
+
super().__init__()
|
|
454
|
+
self.msg = ToolCallMessage("write_todos")
|
|
455
|
+
|
|
456
|
+
def compose(self) -> ComposeResult:
|
|
457
|
+
yield self.msg
|
|
458
|
+
|
|
459
|
+
app = _Harness()
|
|
460
|
+
async with app.run_test() as pilot:
|
|
461
|
+
await pilot.pause()
|
|
462
|
+
app.msg.set_success(output)
|
|
463
|
+
await pilot.pause()
|
|
464
|
+
|
|
465
|
+
assert app.msg._hint_widget is not None
|
|
466
|
+
assert app.msg._hint_widget.display is False
|
|
467
|
+
|
|
468
|
+
app.msg.toggle_output()
|
|
469
|
+
await pilot.pause()
|
|
470
|
+
|
|
471
|
+
assert app.msg._expanded is False
|
|
472
|
+
assert app.msg._hint_widget.display is False
|
|
473
|
+
|
|
474
|
+
def test_todo_expanded_shows_full_wrapped_content(self) -> None:
|
|
475
|
+
"""Expanded todo output should wrap long content without truncating."""
|
|
476
|
+
long = (
|
|
477
|
+
"Implement the new authentication flow using OAuth2 with PKCE for "
|
|
478
|
+
"the CLI login command and preserve readable todo output"
|
|
479
|
+
)
|
|
480
|
+
msg = ToolCallMessage("write_todos")
|
|
481
|
+
|
|
482
|
+
result = msg._format_todos_output(
|
|
483
|
+
repr([{"content": long, "status": "in_progress"}]),
|
|
484
|
+
is_preview=False,
|
|
485
|
+
)
|
|
486
|
+
plain = result.content.plain
|
|
487
|
+
|
|
488
|
+
assert "..." not in plain
|
|
489
|
+
assert long.replace(" ", "") == plain.split("active ", 1)[1].replace(
|
|
490
|
+
"\n ",
|
|
491
|
+
"",
|
|
492
|
+
).replace(" ", "")
|
|
493
|
+
assert "\n " in plain
|
|
494
|
+
|
|
495
|
+
def test_todo_expanded_continuation_aligns_content_column(self) -> None:
|
|
496
|
+
"""Wrapped continuation lines should align under the todo text."""
|
|
497
|
+
long = "Write integration tests for " + "token refresh revocation " * 4
|
|
498
|
+
msg = ToolCallMessage("write_todos")
|
|
499
|
+
|
|
500
|
+
result = msg._format_todos_output(
|
|
501
|
+
repr([{"content": long, "status": "pending"}]),
|
|
502
|
+
is_preview=False,
|
|
503
|
+
)
|
|
504
|
+
lines = result.content.plain.splitlines()
|
|
505
|
+
todo_start = next(
|
|
506
|
+
index for index, line in enumerate(lines) if "todo " in line
|
|
507
|
+
)
|
|
508
|
+
|
|
509
|
+
assert len(lines) > todo_start + 1
|
|
510
|
+
assert lines[todo_start + 1].startswith(" ")
|
|
511
|
+
|
|
512
|
+
|
|
397
513
|
class TestToolCallMessageExpandableArgs:
|
|
398
514
|
"""Tests for the `ask_user` expandable-arguments toggle."""
|
|
399
515
|
|
|
@@ -789,6 +789,59 @@ class TestExecuteTaskTextualParallelToolSpinner:
|
|
|
789
789
|
|
|
790
790
|
assert statuses[-1] == "Thinking"
|
|
791
791
|
|
|
792
|
+
async def test_edit_file_tool_keeps_thinking_spinner_while_pending(self) -> None:
|
|
793
|
+
"""`edit_file` should not leave a visual gap before approval/execution."""
|
|
794
|
+
statuses: list[str | None] = []
|
|
795
|
+
|
|
796
|
+
async def record_spinner(status: str | None) -> None:
|
|
797
|
+
await asyncio.sleep(0)
|
|
798
|
+
statuses.append(status)
|
|
799
|
+
|
|
800
|
+
chunks = [
|
|
801
|
+
(
|
|
802
|
+
(),
|
|
803
|
+
"messages",
|
|
804
|
+
(
|
|
805
|
+
_tool_call_message(
|
|
806
|
+
"edit_file",
|
|
807
|
+
{
|
|
808
|
+
"file_path": "example.py",
|
|
809
|
+
"old_string": "old",
|
|
810
|
+
"new_string": "new",
|
|
811
|
+
},
|
|
812
|
+
"tool-1",
|
|
813
|
+
),
|
|
814
|
+
{},
|
|
815
|
+
),
|
|
816
|
+
),
|
|
817
|
+
(
|
|
818
|
+
(),
|
|
819
|
+
"messages",
|
|
820
|
+
(
|
|
821
|
+
ToolMessage(content="edited", tool_call_id="tool-1"),
|
|
822
|
+
{},
|
|
823
|
+
),
|
|
824
|
+
),
|
|
825
|
+
]
|
|
826
|
+
|
|
827
|
+
adapter = TextualUIAdapter(
|
|
828
|
+
mount_message=_mock_mount,
|
|
829
|
+
update_status=_noop_status,
|
|
830
|
+
request_approval=_mock_approval,
|
|
831
|
+
set_spinner=record_spinner,
|
|
832
|
+
)
|
|
833
|
+
|
|
834
|
+
await execute_task_textual(
|
|
835
|
+
user_input="edit the file",
|
|
836
|
+
agent=_FakeAgent(chunks),
|
|
837
|
+
assistant_id="assistant",
|
|
838
|
+
session_state=SimpleNamespace(thread_id="thread-1", auto_approve=True),
|
|
839
|
+
adapter=adapter,
|
|
840
|
+
)
|
|
841
|
+
|
|
842
|
+
assert statuses[:2] == ["Thinking", "Thinking"]
|
|
843
|
+
assert None not in statuses
|
|
844
|
+
|
|
792
845
|
async def test_spinner_with_three_parallel_tools_out_of_order(self) -> None:
|
|
793
846
|
"""Three parallel tools completed out of order; Thinking after all."""
|
|
794
847
|
statuses: list[str | None] = []
|
|
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
|
{deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/built_in_skills/remember/SKILL.md
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
|
{deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/deploy/frontend_dist/index.html
RENAMED
|
File without changes
|
{deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/deploy/frontend_dist/logo-dark.svg
RENAMED
|
File without changes
|
{deepagents_cli-0.0.54 → deepagents_cli-0.0.55}/deepagents_cli/deploy/frontend_dist/logo-light.svg
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|