zjcode 0.0.3__tar.gz → 0.0.4__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.
- {zjcode-0.0.3 → zjcode-0.0.4}/PKG-INFO +1 -1
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/_version.py +1 -1
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/input.py +75 -74
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/media_utils.py +44 -6
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/model_config.py +108 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/widgets/chat_input.py +12 -2
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/widgets/model_selector.py +305 -6
- zjcode-0.0.4/doc/2026-07-19-/345/210/207/346/215/242/345/210/260/345/205/254/345/274/200PyPI.md +423 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/pyproject.toml +1 -1
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_app.py +3 -3
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_media_utils.py +165 -130
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_model_config.py +133 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/tui/widgets/test_chat_input.py +81 -54
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/tui/widgets/test_model_selector.py +73 -3
- {zjcode-0.0.3 → zjcode-0.0.4}/uv.lock +1 -1
- zjcode-0.0.3/doc/2026-07-19-/345/210/207/346/215/242/345/210/260/345/205/254/345/274/200PyPI.md +0 -150
- {zjcode-0.0.3 → zjcode-0.0.4}/.gitignore +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/AGENTS.md +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/ARCHITECTURE.md +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/CHANGELOG.md +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/COMMANDS.md +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/DEVELOPMENT.md +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/Makefile +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/README.md +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/THREAT_MODEL.md +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/bump-version.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/dcode-dev.ps1 +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/__init__.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/__main__.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/_ask_user_types.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/_cli_context.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/_constants.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/_debug.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/_debug_buffer.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/_env_vars.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/_fake_models.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/_git.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/_paths.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/_server_config.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/_session_stats.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/_startup_error.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/_testing_models.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/_textual_patches.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/_tool_stream.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/agent.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/app.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/app.tcss +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/approval_mode.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/ask_user.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/auth_display.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/auth_store.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/built_in_skills/__init__.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/built_in_skills/remember/SKILL.md +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/built_in_skills/skill-creator/SKILL.md +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/built_in_skills/skill-creator/scripts/init_skill.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/built_in_skills/skill-creator/scripts/quick_validate.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/client/__init__.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/client/commands/__init__.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/client/commands/auth.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/client/commands/config.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/client/commands/mcp.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/client/commands/tools.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/client/launch/__init__.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/client/launch/server.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/client/launch/server_manager.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/client/non_interactive.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/client/remote_client.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/clipboard.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/command_registry.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/config.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/config_manifest.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/configurable_model.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/default_agent_prompt.md +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/doctor.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/editor.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/event_bus.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/extras_info.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/file_ops.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/formatting.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/goal_rubric.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/goal_tools.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/hooks.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/integrations/__init__.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/integrations/openai_codex.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/integrations/sandbox_config.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/integrations/sandbox_factory.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/integrations/sandbox_provider.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/integrations/sandbox_registry.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/iterm_cursor_guide.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/local_context.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/main.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/managed_tools.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/mcp_auth.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/mcp_config.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/mcp_disabled.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/mcp_login_service.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/mcp_oauth_ui.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/mcp_providers/__init__.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/mcp_providers/_registry.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/mcp_providers/base.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/mcp_providers/github.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/mcp_providers/slack.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/mcp_tools.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/mcp_trust.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/memory_guard.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/notifications.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/offload.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/onboarding.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/output.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/paste_collapse.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/project_utils.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/py.typed +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/reasoning_effort.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/reliable_rubric.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/resume_state.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/server_graph.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/session_end_summary.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/sessions.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/skills/__init__.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/skills/commands.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/skills/invocation.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/skills/load.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/skills/trust.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/state_migration.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/subagents.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/system_prompt.md +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/terminal_capabilities.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/terminal_escape.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/theme.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/todo_list_prompt.md +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tool_catalog.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tool_display.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tools.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/__init__.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/textual_adapter.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/widgets/__init__.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/widgets/_js_eval_display.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/widgets/_links.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/widgets/agent_selector.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/widgets/approval.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/widgets/ask_user.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/widgets/auth.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/widgets/autocomplete.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/widgets/codex_auth.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/widgets/cwd_switch.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/widgets/debug_console.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/widgets/diff.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/widgets/effort_selector.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/widgets/goal_review.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/widgets/goal_status.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/widgets/history.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/widgets/install_confirm.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/widgets/launch_init.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/widgets/loading.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/widgets/mcp_login.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/widgets/mcp_reconnect.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/widgets/mcp_viewer.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/widgets/message_store.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/widgets/messages.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/widgets/notification_center.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/widgets/notification_detail.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/widgets/notification_settings.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/widgets/restart_prompt.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/widgets/skill_trust.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/widgets/startup_tip.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/widgets/status.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/widgets/subagent_panel.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/widgets/theme_selector.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/widgets/thread_selector.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/widgets/tool_renderers.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/widgets/tool_widgets.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/widgets/update_available.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/widgets/update_confirm.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/widgets/update_progress.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/tui/widgets/welcome.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/turn_end_summary.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/ui.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/unicode_security.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/deepagents_code/update_check.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/doc/2025-01-24-/347/211/210/346/234/254/345/215/207/347/272/247/344/270/216Web/351/203/250/347/275/262.md" +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/doc/2025-07-27-/345/244/215/345/210/266/346/214/211/351/222/256-CopyTurnButton/345/256/236/347/216/260.md" +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/doc/2025-07-27-/351/241/271/347/233/256/345/210/206/346/236/220-deepagents-code/346/236/266/346/236/204/344/270/216/346/250/241/345/235/227/346/246/202/350/247/210.md" +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/doc/2026-01-24-/351/243/236/344/271/246/346/216/245/345/205/245deepagents/350/260/203/347/240/224.md" +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/doc/2026-07-08-windows-dev-deployment-script.md +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/doc/2026-07-11-/345/233/276/347/211/207/347/262/230/350/264/264BadRequestError-Agent/345/244/261/346/225/210/344/277/256/345/244/215.md" +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/doc/2026-07-12-/346/257/217/350/275/256/346/211/223/345/215/260/346/250/241/345/236/213/345/223/215/345/272/224/345/205/203/346/225/260/346/215/256.md" +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/doc/2026-07-12-/347/201/253/345/261/261/345/274/225/346/223/216/345/220/204/346/250/241/345/236/213/347/274/226/347/240/201/350/203/275/345/212/233/350/257/246/347/273/206/350/257/204/346/265/213/346/212/245/345/221/212.md" +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/doc/2026-07-12-/347/201/253/345/261/261/345/274/225/346/223/216/346/250/241/345/236/213/347/274/226/347/240/201/350/203/275/345/212/233/345/237/272/345/207/206/346/265/213/350/257/225.md" +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/doc/2026-07-15-learn/345/210/206/346/224/257/344/277/256/345/244/215-/346/265/213/350/257/225/344/270/216lint/345/205/250/347/273/277.md" +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/doc/2026-07-18-session-end-summary/345/206/205/347/275/256.md" +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/doc/2026-07-18-/345/267/245/345/205/267/347/273/204/351/273/230/350/256/244/345/261/225/345/274/200.md" +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/examples/skills/arxiv-search/SKILL.md +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/examples/skills/arxiv-search/arxiv_search.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/examples/skills/langgraph-docs/SKILL.md +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/examples/skills/skill-creator/SKILL.md +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/examples/skills/skill-creator/scripts/init_skill.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/examples/skills/skill-creator/scripts/quick_validate.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/examples/skills/web-research/SKILL.md +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/hatch_build.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/images/tui.png +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/run-dcode-dev.ps1 +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/run-dcode-dev.sh +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/run-publish.sh +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/run-setup-dev-env.sh +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/scripts/benchmark_huoshan_models.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/scripts/benchmark_report_20260712_151546.md +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/scripts/benchmark_results_20260712_151546.json +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/scripts/check_imports.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/scripts/debug_server.sh +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/scripts/generate_commands_catalog.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/scripts/install.sh +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/setup-dev-env.ps1 +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/README.md +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/integration_tests/__init__.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/integration_tests/benchmarks/__init__.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/integration_tests/benchmarks/test_codspeed_import_benchmarks.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/integration_tests/benchmarks/test_startup_benchmarks.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/integration_tests/conftest.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/integration_tests/test_acp_mode.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/integration_tests/test_auto_approve_remote.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/integration_tests/test_compact_resume.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/integration_tests/test_sandbox_factory.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/integration_tests/test_sandbox_operations.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/__init__.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/client/__init__.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/client/commands/__init__.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/client/commands/test_auth.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/client/commands/test_mcp.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/client/commands/test_tools.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/conftest.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/data/coding_agent_v1_validator.json +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/skills/__init__.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/skills/test_commands.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/skills/test_load.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/skills/test_skill_trust.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/skills/test_skills_json.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/smoke_tests/__init__.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/smoke_tests/conftest.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/smoke_tests/snapshots/system_prompt_interactive_local.md +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/smoke_tests/test_system_prompt.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test__tool_stream.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_agent.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_agent_friendly.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_approval_mode.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_args.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_ask_user_middleware.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_auth_display.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_auth_store.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_auth_web_search_restart.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_charset.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_clipboard.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_coding_agent_metadata.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_command_registry.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_compact_tool.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_config.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_config_manifest.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_configurable_model.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_cursor_blink.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_cursor_style.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_debug.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_debug_buffer.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_debug_console.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_doctor.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_editor.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_end_to_end.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_env_vars.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_error_handling.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_event_bus.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_exception_handling.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_extras_info.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_file_ops.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_formatting.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_git.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_goal_rubric.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_goal_tools.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_hatch_build.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_hooks.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_imports.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_input_parsing.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_install_command.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_install_script.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_iterm_cursor_guide.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_local_context.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_main.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_main_acp_mode.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_main_args.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_managed_tools.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_mcp_auth.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_mcp_config.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_mcp_disabled.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_mcp_login_service.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_mcp_oauth_ui.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_mcp_tools.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_mcp_trust.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_memory_guard.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_model_switch.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_non_interactive.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_notifications.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_offload.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_offload_dict_messages.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_onboarding.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_openai_codex_integration.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_output.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_paths.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_reasoning_effort.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_reliable_rubric.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_reload.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_remote_client.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_resume_state.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_rubric_cli.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_sandbox_config.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_sandbox_factory.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_sandbox_provider.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_sandbox_registry.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_server.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_server_config.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_server_graph.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_server_helpers.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_server_manager.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_session_end_summary.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_session_stats.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_sessions.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_shell_allow_list.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_skill_invocation.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_startup_fast_paths.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_state_migration.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_subagents.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_terminal_capabilities.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_terminal_escape.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_terminal_progress_preference.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_textual_patches.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_theme.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_threads_resume.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_tool_catalog.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_tool_display.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_tracing_replicas.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_transcript_virtualization.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_turn_end_summary.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_ui.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_unicode_security.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_update_check.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/test_version.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/tools/__init__.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/tools/test_current_thread.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/tools/test_fetch_url.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/tui/__init__.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/tui/test_subagent_stream.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/tui/test_textual_adapter.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/tui/widgets/__init__.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/tui/widgets/test_agent_selector.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/tui/widgets/test_approval.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/tui/widgets/test_ask_user.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/tui/widgets/test_auth_widgets.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/tui/widgets/test_autocomplete.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/tui/widgets/test_cwd_switch.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/tui/widgets/test_diff.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/tui/widgets/test_goal_review.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/tui/widgets/test_history.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/tui/widgets/test_install_confirm.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/tui/widgets/test_launch_init.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/tui/widgets/test_links.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/tui/widgets/test_loading.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/tui/widgets/test_mcp_login_modal.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/tui/widgets/test_mcp_reconnect.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/tui/widgets/test_mcp_viewer.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/tui/widgets/test_message_store.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/tui/widgets/test_messages.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/tui/widgets/test_notification_center.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/tui/widgets/test_notification_detail.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/tui/widgets/test_restart_prompt.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/tui/widgets/test_skill_trust_screen.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/tui/widgets/test_startup_tip.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/tui/widgets/test_status.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/tui/widgets/test_subagent_panel.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/tui/widgets/test_thread_selector.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/tui/widgets/test_tool_renderers.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/tui/widgets/test_update_available.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/tui/widgets/test_update_confirm.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/tui/widgets/test_update_progress.py +0 -0
- {zjcode-0.0.3 → zjcode-0.0.4}/tests/unit_tests/tui/widgets/test_welcome.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: zjcode
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.4
|
|
4
4
|
Summary: Private-branded terminal coding agent forked from deepagents-code.
|
|
5
5
|
Project-URL: Homepage, https://docs.langchain.com/oss/python/deepagents/overview
|
|
6
6
|
Project-URL: Documentation, https://reference.langchain.com/python/deepagents/
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# Keep the `x-release-please-version` annotation — release-please uses it to
|
|
4
4
|
# bump `__version__` in sync with `pyproject.toml` on every release PR.
|
|
5
|
-
__version__ = "0.0.
|
|
5
|
+
__version__ = "0.0.4" # x-release-please-version
|
|
6
6
|
|
|
7
7
|
DISTRIBUTION_NAME = "zjcode"
|
|
8
8
|
"""Distribution (wheel/PyPI) name for this private-branded build.
|
|
@@ -4,6 +4,7 @@ import logging
|
|
|
4
4
|
import re
|
|
5
5
|
import shlex
|
|
6
6
|
from dataclasses import dataclass, replace
|
|
7
|
+
from datetime import datetime
|
|
7
8
|
from difflib import SequenceMatcher
|
|
8
9
|
from pathlib import Path
|
|
9
10
|
from typing import Literal
|
|
@@ -59,20 +60,45 @@ slash commands, so a `/` mid-string is not highlighted.
|
|
|
59
60
|
MediaKind = Literal["image", "video"]
|
|
60
61
|
"""Accepted values for the `kind` parameter in `MediaTracker` methods."""
|
|
61
62
|
|
|
62
|
-
IMAGE_PLACEHOLDER_PATTERN = re.compile(
|
|
63
|
-
""
|
|
63
|
+
IMAGE_PLACEHOLDER_PATTERN = re.compile(
|
|
64
|
+
r"\[img_(?P<id>[0-9]+(?:_[0-9]+)?)\]"
|
|
65
|
+
)
|
|
66
|
+
"""Pattern for image placeholders (e.g. ``[img_20250115143022]``).
|
|
64
67
|
|
|
65
|
-
|
|
66
|
-
|
|
68
|
+
The id is either a local timestamp ``YYYYMMDDHHMMSS`` or (in tests) a plain
|
|
69
|
+
counter, optionally followed by ``_N`` to disambiguate same-second collisions.
|
|
67
70
|
"""
|
|
68
71
|
|
|
69
|
-
VIDEO_PLACEHOLDER_PATTERN = re.compile(
|
|
70
|
-
""
|
|
72
|
+
VIDEO_PLACEHOLDER_PATTERN = re.compile(
|
|
73
|
+
r"\[vid_(?P<id>[0-9]+(?:_[0-9]+)?)\]"
|
|
74
|
+
)
|
|
75
|
+
"""Pattern for video placeholders (e.g. ``[vid_20250115143022]``).
|
|
71
76
|
|
|
72
|
-
|
|
73
|
-
|
|
77
|
+
Same id scheme as `IMAGE_PLACEHOLDER_PATTERN` but with a ``vid_`` prefix so
|
|
78
|
+
images and videos never share an id namespace.
|
|
74
79
|
"""
|
|
75
80
|
|
|
81
|
+
_MEDIA_PLACEHOLDER_PREFIX: dict[MediaKind, str] = {
|
|
82
|
+
"image": "img_",
|
|
83
|
+
"video": "vid_",
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def _now_timestamp() -> str:
|
|
88
|
+
"""Return the current local time formatted as ``YYYYMMDDHHMMSS``."""
|
|
89
|
+
return datetime.now().strftime("%Y%m%d%H%M%S")
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _generate_media_id(kind: MediaKind) -> str: # noqa: ARG001
|
|
93
|
+
"""Generate a placeholder id for a new media attachment.
|
|
94
|
+
|
|
95
|
+
Exposed as a hook so tests can substitute a deterministic id generator
|
|
96
|
+
without patching `datetime`. ``kind`` is accepted for future
|
|
97
|
+
per-namespace override needs but the production path returns the same
|
|
98
|
+
timestamp for both images and videos.
|
|
99
|
+
"""
|
|
100
|
+
return _now_timestamp()
|
|
101
|
+
|
|
76
102
|
_UNICODE_SPACE_EQUIVALENTS = str.maketrans(
|
|
77
103
|
{
|
|
78
104
|
"\u00a0": " ", # NO-BREAK SPACE
|
|
@@ -111,13 +137,11 @@ class MediaTracker:
|
|
|
111
137
|
def __init__(self) -> None:
|
|
112
138
|
"""Initialize an empty media tracker.
|
|
113
139
|
|
|
114
|
-
Sets up empty lists to store images and videos
|
|
115
|
-
|
|
140
|
+
Sets up empty lists to store images and videos. Placeholder IDs are now
|
|
141
|
+
derived from timestamps, so there is no per-tracker counter to keep.
|
|
116
142
|
"""
|
|
117
143
|
self.images: list[ImageData] = []
|
|
118
144
|
self.videos: list[VideoData] = []
|
|
119
|
-
self.next_image_id: int = 1
|
|
120
|
-
self.next_video_id: int = 1
|
|
121
145
|
|
|
122
146
|
def add_media(
|
|
123
147
|
self,
|
|
@@ -131,38 +155,55 @@ class MediaTracker:
|
|
|
131
155
|
Args:
|
|
132
156
|
data: The image or video data to track.
|
|
133
157
|
kind: Media type key.
|
|
134
|
-
existing_text: Current draft text. Placeholder
|
|
135
|
-
|
|
158
|
+
existing_text: Current draft text. Placeholder tokens already
|
|
159
|
+
present there are skipped so literal user text is not rebound
|
|
160
|
+
to new media (a same-second collision falls through to a
|
|
161
|
+
``_2`` / ``_3`` suffix).
|
|
136
162
|
|
|
137
163
|
Returns:
|
|
138
|
-
Placeholder string like
|
|
164
|
+
Placeholder string like ``[img_20250115143022]`` or
|
|
165
|
+
``[vid_20250115143022]``. When the base timestamp is already used
|
|
166
|
+
in the current draft or by another tracked item, a ``_N`` suffix
|
|
167
|
+
is appended so every attachment gets a unique token.
|
|
139
168
|
"""
|
|
169
|
+
prefix = _MEDIA_PLACEHOLDER_PREFIX[kind]
|
|
170
|
+
base_id = _generate_media_id(kind)
|
|
171
|
+
existing = self._all_placeholders() | self._draft_placeholders(existing_text)
|
|
172
|
+
candidate = f"[{prefix}{base_id}]"
|
|
173
|
+
suffix = 2
|
|
174
|
+
while candidate in existing:
|
|
175
|
+
candidate = f"[{prefix}{base_id}_{suffix}]"
|
|
176
|
+
suffix += 1
|
|
177
|
+
data.placeholder = candidate
|
|
140
178
|
if kind == "image":
|
|
141
|
-
while f"[image {self.next_image_id}]" in existing_text:
|
|
142
|
-
self.next_image_id += 1
|
|
143
|
-
placeholder = f"[image {self.next_image_id}]"
|
|
144
|
-
data.placeholder = placeholder
|
|
145
179
|
self.images.append(data) # ty: ignore[invalid-argument-type]
|
|
146
|
-
self.next_image_id += 1
|
|
147
180
|
else:
|
|
148
|
-
while f"[video {self.next_video_id}]" in existing_text:
|
|
149
|
-
self.next_video_id += 1
|
|
150
|
-
placeholder = f"[video {self.next_video_id}]"
|
|
151
|
-
data.placeholder = placeholder
|
|
152
181
|
self.videos.append(data) # ty: ignore[invalid-argument-type]
|
|
153
|
-
|
|
154
|
-
|
|
182
|
+
return candidate
|
|
183
|
+
|
|
184
|
+
def _all_placeholders(self) -> set[str]:
|
|
185
|
+
"""Return placeholders currently held by this tracker."""
|
|
186
|
+
return {item.placeholder for item in (*self.images, *self.videos)}
|
|
187
|
+
|
|
188
|
+
@staticmethod
|
|
189
|
+
def _draft_placeholders(text: str) -> set[str]:
|
|
190
|
+
"""Return every media placeholder token literally present in `text`."""
|
|
191
|
+
tokens: set[str] = set()
|
|
192
|
+
for pattern in (IMAGE_PLACEHOLDER_PATTERN, VIDEO_PLACEHOLDER_PATTERN):
|
|
193
|
+
tokens.update(match.group(0) for match in pattern.finditer(text))
|
|
194
|
+
return tokens
|
|
155
195
|
|
|
156
196
|
def add_image(self, image_data: ImageData, *, existing_text: str = "") -> str:
|
|
157
197
|
"""Add an image and return its placeholder text.
|
|
158
198
|
|
|
159
199
|
Args:
|
|
160
200
|
image_data: The image data to track.
|
|
161
|
-
existing_text: Current draft text. Placeholder
|
|
162
|
-
|
|
201
|
+
existing_text: Current draft text. Placeholder tokens already
|
|
202
|
+
present there are skipped so literal user text is not bound to
|
|
203
|
+
new media.
|
|
163
204
|
|
|
164
205
|
Returns:
|
|
165
|
-
Placeholder string like
|
|
206
|
+
Placeholder string like ``[img_20250115143022]``.
|
|
166
207
|
"""
|
|
167
208
|
return self.add_media(image_data, "image", existing_text=existing_text)
|
|
168
209
|
|
|
@@ -171,11 +212,12 @@ class MediaTracker:
|
|
|
171
212
|
|
|
172
213
|
Args:
|
|
173
214
|
video_data: The video data to track.
|
|
174
|
-
existing_text: Current draft text. Placeholder
|
|
175
|
-
|
|
215
|
+
existing_text: Current draft text. Placeholder tokens already
|
|
216
|
+
present there are skipped so literal user text is not bound to
|
|
217
|
+
new media.
|
|
176
218
|
|
|
177
219
|
Returns:
|
|
178
|
-
Placeholder string like
|
|
220
|
+
Placeholder string like ``[vid_20250115143022]``.
|
|
179
221
|
"""
|
|
180
222
|
return self.add_media(video_data, "video", existing_text=existing_text)
|
|
181
223
|
|
|
@@ -196,19 +238,15 @@ class MediaTracker:
|
|
|
196
238
|
return list(self.videos)
|
|
197
239
|
|
|
198
240
|
def clear(self) -> None:
|
|
199
|
-
"""Clear all tracked media
|
|
241
|
+
"""Clear all tracked media."""
|
|
200
242
|
self.images.clear()
|
|
201
243
|
self.videos.clear()
|
|
202
|
-
self.next_image_id = 1
|
|
203
|
-
self.next_video_id = 1
|
|
204
244
|
|
|
205
245
|
def snapshot(self) -> "MediaTracker":
|
|
206
246
|
"""Return an independent copy of the currently tracked media."""
|
|
207
247
|
tracker = MediaTracker()
|
|
208
248
|
tracker.images = [replace(img) for img in self.images]
|
|
209
249
|
tracker.videos = [replace(vid) for vid in self.videos]
|
|
210
|
-
tracker.next_image_id = self.next_image_id
|
|
211
|
-
tracker.next_video_id = self.next_video_id
|
|
212
250
|
return tracker
|
|
213
251
|
|
|
214
252
|
def restore(self, snapshot: "MediaTracker") -> None:
|
|
@@ -219,8 +257,6 @@ class MediaTracker:
|
|
|
219
257
|
"""
|
|
220
258
|
self.images = [replace(img) for img in snapshot.images]
|
|
221
259
|
self.videos = [replace(vid) for vid in snapshot.videos]
|
|
222
|
-
self.next_image_id = snapshot.next_image_id
|
|
223
|
-
self.next_video_id = snapshot.next_video_id
|
|
224
260
|
|
|
225
261
|
def sync_to_text(
|
|
226
262
|
self,
|
|
@@ -298,12 +334,6 @@ class MediaTracker:
|
|
|
298
334
|
self._update_placeholder_spans(
|
|
299
335
|
self.images, matches, text, previous_text, cursor_offset
|
|
300
336
|
)
|
|
301
|
-
if not self.images:
|
|
302
|
-
self.next_image_id = 1
|
|
303
|
-
else:
|
|
304
|
-
self.next_image_id = self._max_placeholder_id(
|
|
305
|
-
self.images, IMAGE_PLACEHOLDER_PATTERN, len(self.images)
|
|
306
|
-
)
|
|
307
337
|
return bool(placeholders)
|
|
308
338
|
|
|
309
339
|
def _sync_kind_videos(
|
|
@@ -329,12 +359,6 @@ class MediaTracker:
|
|
|
329
359
|
self._update_placeholder_spans(
|
|
330
360
|
self.videos, matches, text, previous_text, cursor_offset
|
|
331
361
|
)
|
|
332
|
-
if not self.videos:
|
|
333
|
-
self.next_video_id = 1
|
|
334
|
-
else:
|
|
335
|
-
self.next_video_id = self._max_placeholder_id(
|
|
336
|
-
self.videos, VIDEO_PLACEHOLDER_PATTERN, len(self.videos)
|
|
337
|
-
)
|
|
338
362
|
return bool(placeholders)
|
|
339
363
|
|
|
340
364
|
def _update_placeholder_spans(
|
|
@@ -440,29 +464,6 @@ class MediaTracker:
|
|
|
440
464
|
break
|
|
441
465
|
return None
|
|
442
466
|
|
|
443
|
-
@staticmethod
|
|
444
|
-
def _max_placeholder_id(
|
|
445
|
-
items: list[ImageData] | list[VideoData],
|
|
446
|
-
pattern: re.Pattern[str],
|
|
447
|
-
fallback_count: int,
|
|
448
|
-
) -> int:
|
|
449
|
-
"""Compute next ID from the highest surviving placeholder.
|
|
450
|
-
|
|
451
|
-
Args:
|
|
452
|
-
items: Surviving media items.
|
|
453
|
-
pattern: Placeholder regex with an `id` group.
|
|
454
|
-
fallback_count: Fallback when no IDs can be parsed.
|
|
455
|
-
|
|
456
|
-
Returns:
|
|
457
|
-
Next ID value (max_id + 1).
|
|
458
|
-
"""
|
|
459
|
-
max_id = 0
|
|
460
|
-
for item in items:
|
|
461
|
-
match = pattern.fullmatch(item.placeholder)
|
|
462
|
-
if match is not None:
|
|
463
|
-
max_id = max(max_id, int(match.group("id")))
|
|
464
|
-
return max_id + 1 if max_id else fallback_count + 1
|
|
465
|
-
|
|
466
467
|
|
|
467
468
|
def parse_file_mentions(text: str) -> tuple[str, list[Path]]:
|
|
468
469
|
r"""Extract `@file` mentions and return the text with resolved file paths.
|
|
@@ -52,6 +52,44 @@ VIDEO_EXTENSIONS: frozenset[str] = frozenset(
|
|
|
52
52
|
MAX_MEDIA_BYTES: int = 20 * 1024 * 1024
|
|
53
53
|
"""Maximum media file size (20 MB). Keeps base64 payload under ~27 MB."""
|
|
54
54
|
|
|
55
|
+
PASTED_MEDIA_DIR: pathlib.Path = pathlib.Path.home() / ".zjcode" / "pasted"
|
|
56
|
+
"""Directory where pasted media is archived for local reference.
|
|
57
|
+
|
|
58
|
+
Images pasted into the TUI are decoded and written here so the user can inspect
|
|
59
|
+
or forward the original file later. The base64 payload is still what gets sent
|
|
60
|
+
to the model; this local copy is purely an archive of what was pasted.
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def save_pasted_media(base64_data: str, stem: str, image_format: str) -> pathlib.Path | None:
|
|
65
|
+
"""Persist a pasted media payload to `PASTED_MEDIA_DIR` as `<stem>.<ext>`.
|
|
66
|
+
|
|
67
|
+
Failures are logged and swallowed: the local archive is a convenience, not
|
|
68
|
+
a hard requirement. The caller keeps the in-memory base64 blob regardless.
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
base64_data: Base64-encoded media bytes (no data-URL prefix).
|
|
72
|
+
stem: File stem (typically the placeholder id such as
|
|
73
|
+
``img_20250115143022``). Callers guarantee uniqueness within the
|
|
74
|
+
current draft.
|
|
75
|
+
image_format: Image format label (e.g. ``"png"``, ``"jpeg"``); used to
|
|
76
|
+
derive the file extension.
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
The absolute path written on success, ``None`` when the write failed.
|
|
80
|
+
"""
|
|
81
|
+
try:
|
|
82
|
+
PASTED_MEDIA_DIR.mkdir(parents=True, exist_ok=True)
|
|
83
|
+
extension = image_format.lower() or "png"
|
|
84
|
+
if extension == "jpeg":
|
|
85
|
+
extension = "jpg"
|
|
86
|
+
target = PASTED_MEDIA_DIR / f"{stem}.{extension}"
|
|
87
|
+
target.write_bytes(base64.b64decode(base64_data))
|
|
88
|
+
except (OSError, ValueError) as exc:
|
|
89
|
+
logger.warning("Failed to archive pasted media to %s: %s", PASTED_MEDIA_DIR, exc)
|
|
90
|
+
return None
|
|
91
|
+
return target
|
|
92
|
+
|
|
55
93
|
|
|
56
94
|
def strip_media_placeholders(
|
|
57
95
|
text: str,
|
|
@@ -61,7 +99,7 @@ def strip_media_placeholders(
|
|
|
61
99
|
) -> str:
|
|
62
100
|
"""Remove display-only media placeholders from user text.
|
|
63
101
|
|
|
64
|
-
Placeholders like `[
|
|
102
|
+
Placeholders like `[img_20250115143022]` are inserted into the terminal input purely for
|
|
65
103
|
display; the actual media travels as structured content blocks. They must not
|
|
66
104
|
leak into the canonical model-facing message or LangSmith trace as if the user
|
|
67
105
|
typed them.
|
|
@@ -74,7 +112,7 @@ def strip_media_placeholders(
|
|
|
74
112
|
Args:
|
|
75
113
|
text: Raw user text that may contain media placeholders.
|
|
76
114
|
placeholders: Exact placeholder tokens for the media actually attached to
|
|
77
|
-
this message (e.g. ``["[
|
|
115
|
+
this message (e.g. ``["[img_20250115143022]", "[vid_20250115143022]"]``).
|
|
78
116
|
placeholder_spans: Exact `(start, end)` spans for tracked display tokens
|
|
79
117
|
in `text`, when known.
|
|
80
118
|
|
|
@@ -118,7 +156,7 @@ def strip_media_placeholders(
|
|
|
118
156
|
|
|
119
157
|
# Only strip spaces/tabs (not newlines) so code indentation on lines after a
|
|
120
158
|
# removed placeholder is preserved. A full .strip() would collapse
|
|
121
|
-
# "[
|
|
159
|
+
# "[img_20250115143022]\n def foo():" to "def foo():", losing the leading indent.
|
|
122
160
|
cleaned = text
|
|
123
161
|
for start, end in sorted(spans, reverse=True):
|
|
124
162
|
cleaned = cleaned[:start] + cleaned[end:]
|
|
@@ -183,7 +221,7 @@ class ImageData:
|
|
|
183
221
|
|
|
184
222
|
base64_data: str
|
|
185
223
|
format: str # "png", "jpeg", etc.
|
|
186
|
-
placeholder: str # Display text like "[
|
|
224
|
+
placeholder: str # Display text like "[img_20250115143022]"
|
|
187
225
|
placeholder_span: tuple[int, int] | None = None
|
|
188
226
|
|
|
189
227
|
def to_message_content(self) -> dict:
|
|
@@ -204,7 +242,7 @@ class VideoData:
|
|
|
204
242
|
|
|
205
243
|
base64_data: str
|
|
206
244
|
format: str # "mp4", "quicktime", etc.
|
|
207
|
-
placeholder: str # Display text like "[
|
|
245
|
+
placeholder: str # Display text like "[vid_20250115143022]"
|
|
208
246
|
placeholder_span: tuple[int, int] | None = None
|
|
209
247
|
|
|
210
248
|
def to_message_content(self) -> "VideoContentBlock":
|
|
@@ -796,7 +834,7 @@ def create_multimodal_content(
|
|
|
796
834
|
content_blocks = []
|
|
797
835
|
|
|
798
836
|
# Add text block. Strip only the display-only placeholders bound to the media
|
|
799
|
-
# actually attached here (e.g. "[
|
|
837
|
+
# actually attached here (e.g. "[img_20250115143022]") so the canonical/model-facing text
|
|
800
838
|
# never contains fake user-authored placeholder text. When a span is known,
|
|
801
839
|
# text that merely resembles the schema is preserved exactly; without a span
|
|
802
840
|
# `strip_media_placeholders` falls back to removing one occurrence per item,
|
|
@@ -4154,3 +4154,111 @@ def save_custom_provider(
|
|
|
4154
4154
|
|
|
4155
4155
|
clear_caches()
|
|
4156
4156
|
return True
|
|
4157
|
+
|
|
4158
|
+
|
|
4159
|
+
class ModelDiscoveryError(Exception):
|
|
4160
|
+
"""Raised when discovering models from a provider's `/models` endpoint fails.
|
|
4161
|
+
|
|
4162
|
+
The message is user-facing and safe to render verbatim in the TUI.
|
|
4163
|
+
"""
|
|
4164
|
+
|
|
4165
|
+
|
|
4166
|
+
def fetch_provider_models(
|
|
4167
|
+
base_url: str,
|
|
4168
|
+
api_key: str | None = None,
|
|
4169
|
+
*,
|
|
4170
|
+
timeout: float = 10.0,
|
|
4171
|
+
include_retiring: bool = True,
|
|
4172
|
+
) -> list[str]:
|
|
4173
|
+
"""Fetch the list of available models from an OpenAI-compatible provider.
|
|
4174
|
+
|
|
4175
|
+
Calls `GET {base_url}/models` with a Bearer token when `api_key` is
|
|
4176
|
+
provided. Filters out models whose `status` is `"Shutdown"` (a Volcengine
|
|
4177
|
+
Ark extension); other providers usually omit the field, in which case all
|
|
4178
|
+
models are kept.
|
|
4179
|
+
|
|
4180
|
+
Args:
|
|
4181
|
+
base_url: Provider's OpenAI-compatible API base URL (with or without a
|
|
4182
|
+
trailing slash).
|
|
4183
|
+
api_key: Optional API key sent as `Authorization: Bearer <key>`.
|
|
4184
|
+
timeout: Total request timeout in seconds.
|
|
4185
|
+
include_retiring: When `False`, also drop models with `status="Retiring"`.
|
|
4186
|
+
|
|
4187
|
+
Returns:
|
|
4188
|
+
Sorted list of unique model IDs.
|
|
4189
|
+
|
|
4190
|
+
Raises:
|
|
4191
|
+
ModelDiscoveryError: If the request fails, the response is not
|
|
4192
|
+
successful, or the payload cannot be parsed as an OpenAI-style
|
|
4193
|
+
model list.
|
|
4194
|
+
"""
|
|
4195
|
+
import httpx # local import to avoid pulling httpx at module import time
|
|
4196
|
+
|
|
4197
|
+
if not base_url:
|
|
4198
|
+
msg = "Base URL is required to discover models."
|
|
4199
|
+
raise ModelDiscoveryError(msg)
|
|
4200
|
+
|
|
4201
|
+
url = base_url.rstrip("/") + "/models"
|
|
4202
|
+
headers: dict[str, str] = {"Accept": "application/json"}
|
|
4203
|
+
if api_key:
|
|
4204
|
+
headers["Authorization"] = f"Bearer {api_key}"
|
|
4205
|
+
|
|
4206
|
+
try:
|
|
4207
|
+
response = httpx.get(url, headers=headers, timeout=timeout)
|
|
4208
|
+
except httpx.TimeoutException as exc:
|
|
4209
|
+
msg = f"Request to {url} timed out after {timeout:.0f}s."
|
|
4210
|
+
raise ModelDiscoveryError(msg) from exc
|
|
4211
|
+
except httpx.HTTPError as exc:
|
|
4212
|
+
msg = f"Could not reach {url}: {exc}"
|
|
4213
|
+
raise ModelDiscoveryError(msg) from exc
|
|
4214
|
+
|
|
4215
|
+
if response.status_code == 401: # noqa: PLR2004 -- HTTP status codes are self-documenting
|
|
4216
|
+
msg = "Authentication failed (HTTP 401). Check the API key."
|
|
4217
|
+
raise ModelDiscoveryError(msg)
|
|
4218
|
+
if response.status_code == 403: # noqa: PLR2004
|
|
4219
|
+
msg = "Forbidden (HTTP 403). The API key may lack permission."
|
|
4220
|
+
raise ModelDiscoveryError(msg)
|
|
4221
|
+
if response.status_code == 404: # noqa: PLR2004
|
|
4222
|
+
msg = f"{url} returned 404. This provider may not expose /models."
|
|
4223
|
+
raise ModelDiscoveryError(msg)
|
|
4224
|
+
if response.status_code >= 400: # noqa: PLR2004
|
|
4225
|
+
msg = f"HTTP {response.status_code} from {url}: {response.text[:200]}"
|
|
4226
|
+
raise ModelDiscoveryError(msg)
|
|
4227
|
+
|
|
4228
|
+
try:
|
|
4229
|
+
payload = response.json()
|
|
4230
|
+
except ValueError as exc:
|
|
4231
|
+
msg = f"{url} did not return JSON: {exc}"
|
|
4232
|
+
raise ModelDiscoveryError(msg) from exc
|
|
4233
|
+
|
|
4234
|
+
# OpenAI shape: {"object": "list", "data": [{"id": ..., ...}, ...]}
|
|
4235
|
+
# Some providers just return a bare list.
|
|
4236
|
+
if isinstance(payload, dict):
|
|
4237
|
+
data = payload.get("data", payload.get("models", []))
|
|
4238
|
+
else:
|
|
4239
|
+
data = payload
|
|
4240
|
+
|
|
4241
|
+
if not isinstance(data, list):
|
|
4242
|
+
msg = "Unexpected /models response shape (expected list under 'data')."
|
|
4243
|
+
raise ModelDiscoveryError(msg)
|
|
4244
|
+
|
|
4245
|
+
ids: set[str] = set()
|
|
4246
|
+
for entry in data:
|
|
4247
|
+
if isinstance(entry, str):
|
|
4248
|
+
ids.add(entry)
|
|
4249
|
+
continue
|
|
4250
|
+
if not isinstance(entry, dict):
|
|
4251
|
+
continue
|
|
4252
|
+
model_id = entry.get("id") or entry.get("name") or entry.get("model")
|
|
4253
|
+
if not isinstance(model_id, str) or not model_id:
|
|
4254
|
+
continue
|
|
4255
|
+
# Volcengine Ark surfaces lifecycle in `status`; hide retired entries.
|
|
4256
|
+
status = entry.get("status")
|
|
4257
|
+
if isinstance(status, str):
|
|
4258
|
+
if status == "Shutdown":
|
|
4259
|
+
continue
|
|
4260
|
+
if not include_retiring and status == "Retiring":
|
|
4261
|
+
continue
|
|
4262
|
+
ids.add(model_id)
|
|
4263
|
+
|
|
4264
|
+
return sorted(ids)
|
|
@@ -1449,8 +1449,18 @@ class ChatTextArea(TextArea):
|
|
|
1449
1449
|
if image is not None:
|
|
1450
1450
|
event.prevent_default()
|
|
1451
1451
|
event.stop()
|
|
1452
|
-
#
|
|
1453
|
-
|
|
1452
|
+
# Bind a timestamped placeholder before archiving so the local
|
|
1453
|
+
# filename matches the token the user sees (e.g. img_YYYYMMDDHHMMSS).
|
|
1454
|
+
existing_text = self.text
|
|
1455
|
+
placeholder = self._chat_input_owner._image_tracker.add_image(
|
|
1456
|
+
image, existing_text=existing_text
|
|
1457
|
+
)
|
|
1458
|
+
stem = placeholder.strip("[]")
|
|
1459
|
+
from deepagents_code.media_utils import save_pasted_media
|
|
1460
|
+
|
|
1461
|
+
await asyncio.to_thread(
|
|
1462
|
+
save_pasted_media, image.base64_data, stem, image.format
|
|
1463
|
+
)
|
|
1454
1464
|
# Insert placeholder at cursor position
|
|
1455
1465
|
self.insert(placeholder)
|
|
1456
1466
|
return
|