code-puppy-core-plugins 0.0.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- code_puppy_core_plugins/__init__.py +5 -0
- code_puppy_core_plugins/acp/README.md +266 -0
- code_puppy_core_plugins/acp/__init__.py +8 -0
- code_puppy_core_plugins/acp/agent.py +494 -0
- code_puppy_core_plugins/acp/bridge.py +309 -0
- code_puppy_core_plugins/acp/capabilities.py +73 -0
- code_puppy_core_plugins/acp/commands.py +116 -0
- code_puppy_core_plugins/acp/content.py +115 -0
- code_puppy_core_plugins/acp/io_delegation.py +231 -0
- code_puppy_core_plugins/acp/mcp_config.py +66 -0
- code_puppy_core_plugins/acp/permissions.py +159 -0
- code_puppy_core_plugins/acp/persistence.py +197 -0
- code_puppy_core_plugins/acp/register_callbacks.py +110 -0
- code_puppy_core_plugins/acp/replay.py +114 -0
- code_puppy_core_plugins/acp/session.py +329 -0
- code_puppy_core_plugins/acp/session_config.py +179 -0
- code_puppy_core_plugins/acp/state.py +135 -0
- code_puppy_core_plugins/agent_skills/__init__.py +22 -0
- code_puppy_core_plugins/agent_skills/config.py +208 -0
- code_puppy_core_plugins/agent_skills/discovery.py +337 -0
- code_puppy_core_plugins/agent_skills/downloader.py +392 -0
- code_puppy_core_plugins/agent_skills/enabled_skills.py +82 -0
- code_puppy_core_plugins/agent_skills/installer.py +22 -0
- code_puppy_core_plugins/agent_skills/metadata.py +219 -0
- code_puppy_core_plugins/agent_skills/prompt_builder.py +49 -0
- code_puppy_core_plugins/agent_skills/provider.py +52 -0
- code_puppy_core_plugins/agent_skills/register_callbacks.py +309 -0
- code_puppy_core_plugins/agent_skills/remote_catalog.py +322 -0
- code_puppy_core_plugins/agent_skills/skill_catalog.py +257 -0
- code_puppy_core_plugins/agent_skills/skill_commands.py +102 -0
- code_puppy_core_plugins/agent_skills/skills_install_menu.py +698 -0
- code_puppy_core_plugins/agent_skills/skills_menu.py +794 -0
- code_puppy_core_plugins/aws_bedrock/__init__.py +14 -0
- code_puppy_core_plugins/aws_bedrock/config.py +101 -0
- code_puppy_core_plugins/aws_bedrock/register_callbacks.py +243 -0
- code_puppy_core_plugins/aws_bedrock/utils.py +186 -0
- code_puppy_core_plugins/azure_foundry/README.md +238 -0
- code_puppy_core_plugins/azure_foundry/__init__.py +15 -0
- code_puppy_core_plugins/azure_foundry/config.py +126 -0
- code_puppy_core_plugins/azure_foundry/discovery.py +189 -0
- code_puppy_core_plugins/azure_foundry/register_callbacks.py +506 -0
- code_puppy_core_plugins/azure_foundry/token.py +182 -0
- code_puppy_core_plugins/azure_foundry/utils.py +375 -0
- code_puppy_core_plugins/btw/__init__.py +1 -0
- code_puppy_core_plugins/btw/inline_view.py +135 -0
- code_puppy_core_plugins/btw/register_callbacks.py +106 -0
- code_puppy_core_plugins/btw/side_query.py +91 -0
- code_puppy_core_plugins/chatgpt_oauth/IMAGEGEN_SKILL.md +83 -0
- code_puppy_core_plugins/chatgpt_oauth/__init__.py +8 -0
- code_puppy_core_plugins/chatgpt_oauth/config.py +52 -0
- code_puppy_core_plugins/chatgpt_oauth/image_generation.py +253 -0
- code_puppy_core_plugins/chatgpt_oauth/image_tool.py +70 -0
- code_puppy_core_plugins/chatgpt_oauth/oauth_flow.py +461 -0
- code_puppy_core_plugins/chatgpt_oauth/register_callbacks.py +288 -0
- code_puppy_core_plugins/chatgpt_oauth/test_plugin.py +663 -0
- code_puppy_core_plugins/chatgpt_oauth/usage.py +113 -0
- code_puppy_core_plugins/chatgpt_oauth/utils.py +534 -0
- code_puppy_core_plugins/claude_code_hooks/__init__.py +1 -0
- code_puppy_core_plugins/claude_code_hooks/config.py +137 -0
- code_puppy_core_plugins/claude_code_hooks/register_callbacks.py +383 -0
- code_puppy_core_plugins/claude_code_oauth/README.md +167 -0
- code_puppy_core_plugins/claude_code_oauth/SETUP.md +93 -0
- code_puppy_core_plugins/claude_code_oauth/__init__.py +25 -0
- code_puppy_core_plugins/claude_code_oauth/config.py +59 -0
- code_puppy_core_plugins/claude_code_oauth/fast_mode.py +122 -0
- code_puppy_core_plugins/claude_code_oauth/prompt_handler.py +64 -0
- code_puppy_core_plugins/claude_code_oauth/register_callbacks.py +719 -0
- code_puppy_core_plugins/claude_code_oauth/test_plugin.py +285 -0
- code_puppy_core_plugins/claude_code_oauth/token_refresh_heartbeat.py +240 -0
- code_puppy_core_plugins/claude_code_oauth/utils.py +663 -0
- code_puppy_core_plugins/code_puppy_agent/AGENTS_AND_TOOLS.md +155 -0
- code_puppy_core_plugins/code_puppy_agent/MODELS_AND_MCP.md +104 -0
- code_puppy_core_plugins/code_puppy_agent/PLUGINS_AND_CALLBACKS.md +147 -0
- code_puppy_core_plugins/code_puppy_agent/SESSIONS_AND_HISTORY.md +39 -0
- code_puppy_core_plugins/code_puppy_agent/SKILL.md +180 -0
- code_puppy_core_plugins/code_puppy_agent/SKILLS_SYSTEM.md +136 -0
- code_puppy_core_plugins/code_puppy_agent/SYSTEM_PROMPT_CONFIG_AND_I18N.md +160 -0
- code_puppy_core_plugins/code_puppy_agent/__init__.py +5 -0
- code_puppy_core_plugins/code_puppy_agent/register_callbacks.py +46 -0
- code_puppy_core_plugins/computer_use/NativeCapture.swift +123 -0
- code_puppy_core_plugins/computer_use/README.md +109 -0
- code_puppy_core_plugins/computer_use/__init__.py +1 -0
- code_puppy_core_plugins/computer_use/accessibility.py +163 -0
- code_puppy_core_plugins/computer_use/activation.py +75 -0
- code_puppy_core_plugins/computer_use/backend.py +584 -0
- code_puppy_core_plugins/computer_use/backend_types.py +5 -0
- code_puppy_core_plugins/computer_use/capture.py +110 -0
- code_puppy_core_plugins/computer_use/commands.py +62 -0
- code_puppy_core_plugins/computer_use/geometry.py +81 -0
- code_puppy_core_plugins/computer_use/inline_image.py +56 -0
- code_puppy_core_plugins/computer_use/keycodes.py +47 -0
- code_puppy_core_plugins/computer_use/policy.py +144 -0
- code_puppy_core_plugins/computer_use/register_callbacks.py +96 -0
- code_puppy_core_plugins/computer_use/safety.py +18 -0
- code_puppy_core_plugins/computer_use/settle.py +64 -0
- code_puppy_core_plugins/computer_use/state.py +86 -0
- code_puppy_core_plugins/computer_use/tools.py +469 -0
- code_puppy_core_plugins/context_indicator/__init__.py +14 -0
- code_puppy_core_plugins/context_indicator/register_callbacks.py +249 -0
- code_puppy_core_plugins/context_indicator/usage.py +40 -0
- code_puppy_core_plugins/copilot_auth/__init__.py +11 -0
- code_puppy_core_plugins/copilot_auth/config.py +93 -0
- code_puppy_core_plugins/copilot_auth/reasoning_client.py +409 -0
- code_puppy_core_plugins/copilot_auth/register_callbacks.py +460 -0
- code_puppy_core_plugins/copilot_auth/utils.py +587 -0
- code_puppy_core_plugins/customizable_commands/__init__.py +0 -0
- code_puppy_core_plugins/customizable_commands/register_callbacks.py +464 -0
- code_puppy_core_plugins/dbos_durable_exec/__init__.py +1 -0
- code_puppy_core_plugins/dbos_durable_exec/cancel.py +15 -0
- code_puppy_core_plugins/dbos_durable_exec/commands.py +31 -0
- code_puppy_core_plugins/dbos_durable_exec/config.py +31 -0
- code_puppy_core_plugins/dbos_durable_exec/lifecycle.py +83 -0
- code_puppy_core_plugins/dbos_durable_exec/register_callbacks.py +45 -0
- code_puppy_core_plugins/dbos_durable_exec/runtime.py +65 -0
- code_puppy_core_plugins/dbos_durable_exec/startup_lock.py +155 -0
- code_puppy_core_plugins/dbos_durable_exec/workflow_ids.py +16 -0
- code_puppy_core_plugins/dbos_durable_exec/wrapper.py +58 -0
- code_puppy_core_plugins/destructive_command_guard/AGENTS.md +79 -0
- code_puppy_core_plugins/destructive_command_guard/__init__.py +14 -0
- code_puppy_core_plugins/destructive_command_guard/detector.py +374 -0
- code_puppy_core_plugins/destructive_command_guard/register_callbacks.py +165 -0
- code_puppy_core_plugins/emoji_filter/__init__.py +12 -0
- code_puppy_core_plugins/emoji_filter/config.py +26 -0
- code_puppy_core_plugins/emoji_filter/register_callbacks.py +238 -0
- code_puppy_core_plugins/emoji_filter/stripper.py +45 -0
- code_puppy_core_plugins/empty_html_comment_filter/register_callbacks.py +116 -0
- code_puppy_core_plugins/example_custom_command/README.md +328 -0
- code_puppy_core_plugins/example_custom_command/register_callbacks.py +66 -0
- code_puppy_core_plugins/file_permission_handler/__init__.py +4 -0
- code_puppy_core_plugins/file_permission_handler/register_callbacks.py +575 -0
- code_puppy_core_plugins/flux_bootstrap/__init__.py +5 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/_docs/README.md +173 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/_docs/cheatsheet.md +86 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/_docs/pipeline.md +167 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/_docs/synopsis.md +392 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/about.md +51 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/address-feedback.md +129 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/ask.md +211 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/aug.md +181 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/auto-pilot.md +71 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/cheatsheet.md +16 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/commit.md +103 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/config.md +108 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/create-pr.md +195 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/exec.md +221 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/new.md +151 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/qa.md +208 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/rebase.md +180 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/review.md +304 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/split.md +120 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/squash-commits.md +179 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/status.md +46 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/commands/flux/tests.md +155 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/scripts/flux_about.py +154 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/scripts/flux_cheatsheet.py +248 -0
- code_puppy_core_plugins/flux_bootstrap/bundled/scripts/flux_status.py +345 -0
- code_puppy_core_plugins/flux_bootstrap/installer.py +256 -0
- code_puppy_core_plugins/flux_bootstrap/register_callbacks.py +71 -0
- code_puppy_core_plugins/force_push_guard/__init__.py +5 -0
- code_puppy_core_plugins/force_push_guard/detector.py +96 -0
- code_puppy_core_plugins/force_push_guard/register_callbacks.py +161 -0
- code_puppy_core_plugins/fork/__init__.py +7 -0
- code_puppy_core_plugins/fork/register_callbacks.py +445 -0
- code_puppy_core_plugins/frontend_emitter/__init__.py +25 -0
- code_puppy_core_plugins/frontend_emitter/emitter.py +249 -0
- code_puppy_core_plugins/frontend_emitter/register_callbacks.py +412 -0
- code_puppy_core_plugins/frontend_emitter/session_context.py +50 -0
- code_puppy_core_plugins/grok_oauth/__init__.py +6 -0
- code_puppy_core_plugins/grok_oauth/config.py +49 -0
- code_puppy_core_plugins/grok_oauth/oauth_flow.py +213 -0
- code_puppy_core_plugins/grok_oauth/register_callbacks.py +132 -0
- code_puppy_core_plugins/grok_oauth/utils.py +195 -0
- code_puppy_core_plugins/herdr/README.md +168 -0
- code_puppy_core_plugins/herdr/__init__.py +9 -0
- code_puppy_core_plugins/herdr/client.py +339 -0
- code_puppy_core_plugins/herdr/register_callbacks.py +140 -0
- code_puppy_core_plugins/herdr/reporter.py +212 -0
- code_puppy_core_plugins/herdr/smoke.py +143 -0
- code_puppy_core_plugins/herdr/sources.py +133 -0
- code_puppy_core_plugins/hook_creator/__init__.py +1 -0
- code_puppy_core_plugins/hook_creator/register_callbacks.py +33 -0
- code_puppy_core_plugins/hook_manager/__init__.py +1 -0
- code_puppy_core_plugins/hook_manager/config.py +290 -0
- code_puppy_core_plugins/hook_manager/hooks_menu.py +571 -0
- code_puppy_core_plugins/hook_manager/register_callbacks.py +227 -0
- code_puppy_core_plugins/meta_oauth/__init__.py +1 -0
- code_puppy_core_plugins/meta_oauth/config.py +55 -0
- code_puppy_core_plugins/meta_oauth/oauth_flow.py +109 -0
- code_puppy_core_plugins/meta_oauth/register_callbacks.py +154 -0
- code_puppy_core_plugins/meta_oauth/utils.py +252 -0
- code_puppy_core_plugins/namespace_skill_search/README.md +118 -0
- code_puppy_core_plugins/namespace_skill_search/__init__.py +15 -0
- code_puppy_core_plugins/namespace_skill_search/namespaces.py +125 -0
- code_puppy_core_plugins/namespace_skill_search/register_callbacks.py +99 -0
- code_puppy_core_plugins/namespace_skill_search/search_tool.py +158 -0
- code_puppy_core_plugins/no_tools/__init__.py +0 -0
- code_puppy_core_plugins/no_tools/register_callbacks.py +42 -0
- code_puppy_core_plugins/oauth_pasteback.py +110 -0
- code_puppy_core_plugins/oauth_puppy_html.py +194 -0
- code_puppy_core_plugins/obsidian_agent/README.md +52 -0
- code_puppy_core_plugins/obsidian_agent/__init__.py +8 -0
- code_puppy_core_plugins/obsidian_agent/agent_obsidian.py +147 -0
- code_puppy_core_plugins/obsidian_agent/register_callbacks.py +13 -0
- code_puppy_core_plugins/ollama/__init__.py +1 -0
- code_puppy_core_plugins/ollama/register_callbacks.py +127 -0
- code_puppy_core_plugins/ollama_setup/__init__.py +5 -0
- code_puppy_core_plugins/ollama_setup/completer.py +38 -0
- code_puppy_core_plugins/ollama_setup/register_callbacks.py +419 -0
- code_puppy_core_plugins/plugin_list/__init__.py +0 -0
- code_puppy_core_plugins/plugin_list/plugin_contributions.py +348 -0
- code_puppy_core_plugins/plugin_list/plugin_meta.py +67 -0
- code_puppy_core_plugins/plugin_list/plugin_text_utils.py +173 -0
- code_puppy_core_plugins/plugin_list/plugins_menu.py +455 -0
- code_puppy_core_plugins/plugin_list/plugins_menu_layout.py +194 -0
- code_puppy_core_plugins/plugin_list/plugins_menu_render.py +431 -0
- code_puppy_core_plugins/plugin_list/project_trust_flow.py +162 -0
- code_puppy_core_plugins/plugin_list/register_callbacks.py +281 -0
- code_puppy_core_plugins/pop_command/__init__.py +1 -0
- code_puppy_core_plugins/pop_command/register_callbacks.py +191 -0
- code_puppy_core_plugins/prompt_newline/__init__.py +13 -0
- code_puppy_core_plugins/prompt_newline/config.py +21 -0
- code_puppy_core_plugins/prompt_newline/register_callbacks.py +163 -0
- code_puppy_core_plugins/prune/__init__.py +1 -0
- code_puppy_core_plugins/prune/prune_menu.py +308 -0
- code_puppy_core_plugins/prune/prune_model.py +517 -0
- code_puppy_core_plugins/prune/prune_render.py +354 -0
- code_puppy_core_plugins/prune/register_callbacks.py +388 -0
- code_puppy_core_plugins/puppy_kennel/README.md +203 -0
- code_puppy_core_plugins/puppy_kennel/__init__.py +6 -0
- code_puppy_core_plugins/puppy_kennel/commands.py +206 -0
- code_puppy_core_plugins/puppy_kennel/config.py +36 -0
- code_puppy_core_plugins/puppy_kennel/kennel.py +368 -0
- code_puppy_core_plugins/puppy_kennel/packer.py +152 -0
- code_puppy_core_plugins/puppy_kennel/recorder.py +83 -0
- code_puppy_core_plugins/puppy_kennel/register_callbacks.py +109 -0
- code_puppy_core_plugins/puppy_kennel/retriever.py +28 -0
- code_puppy_core_plugins/puppy_kennel/schema.py +78 -0
- code_puppy_core_plugins/puppy_kennel/state.py +68 -0
- code_puppy_core_plugins/puppy_kennel/tools.py +449 -0
- code_puppy_core_plugins/puppy_kennel/wings.py +110 -0
- code_puppy_core_plugins/puppy_spinner/README.md +93 -0
- code_puppy_core_plugins/puppy_spinner/__init__.py +11 -0
- code_puppy_core_plugins/puppy_spinner/builtin_frames.py +172 -0
- code_puppy_core_plugins/puppy_spinner/commands.py +116 -0
- code_puppy_core_plugins/puppy_spinner/picker.py +379 -0
- code_puppy_core_plugins/puppy_spinner/register_callbacks.py +193 -0
- code_puppy_core_plugins/puppy_spinner/spinners.py +444 -0
- code_puppy_core_plugins/quick_resume/__init__.py +0 -0
- code_puppy_core_plugins/quick_resume/register_callbacks.py +77 -0
- code_puppy_core_plugins/review_pr/__init__.py +1 -0
- code_puppy_core_plugins/review_pr/register_callbacks.py +162 -0
- code_puppy_core_plugins/shell_safety/__init__.py +6 -0
- code_puppy_core_plugins/shell_safety/agent_shell_safety.py +69 -0
- code_puppy_core_plugins/shell_safety/command_cache.py +156 -0
- code_puppy_core_plugins/shell_safety/register_callbacks.py +203 -0
- code_puppy_core_plugins/stack_dump/__init__.py +1 -0
- code_puppy_core_plugins/stack_dump/register_callbacks.py +79 -0
- code_puppy_core_plugins/statusline/__init__.py +14 -0
- code_puppy_core_plugins/statusline/config.py +68 -0
- code_puppy_core_plugins/statusline/payload.py +138 -0
- code_puppy_core_plugins/statusline/prompt_patch.py +76 -0
- code_puppy_core_plugins/statusline/register_callbacks.py +45 -0
- code_puppy_core_plugins/statusline/runner.py +122 -0
- code_puppy_core_plugins/statusline/statusline_command.py +197 -0
- code_puppy_core_plugins/steer_queue/__init__.py +10 -0
- code_puppy_core_plugins/steer_queue/queue_menu.py +444 -0
- code_puppy_core_plugins/steer_queue/register_callbacks.py +138 -0
- code_puppy_core_plugins/subagent_panel/README.md +102 -0
- code_puppy_core_plugins/subagent_panel/__init__.py +24 -0
- code_puppy_core_plugins/subagent_panel/coalesce_patch.py +242 -0
- code_puppy_core_plugins/subagent_panel/panel_render.py +145 -0
- code_puppy_core_plugins/subagent_panel/register_callbacks.py +535 -0
- code_puppy_core_plugins/subagent_panel/resume_repaint.py +112 -0
- code_puppy_core_plugins/subagent_panel/state.py +231 -0
- code_puppy_core_plugins/switch_agent_resume/__init__.py +5 -0
- code_puppy_core_plugins/switch_agent_resume/register_callbacks.py +314 -0
- code_puppy_core_plugins/theme/README.md +86 -0
- code_puppy_core_plugins/theme/__init__.py +14 -0
- code_puppy_core_plugins/theme/bundled_palettes.py +346 -0
- code_puppy_core_plugins/theme/content_styles.py +146 -0
- code_puppy_core_plugins/theme/osc_palette.py +178 -0
- code_puppy_core_plugins/theme/picker.py +358 -0
- code_puppy_core_plugins/theme/prompt_toolkit_theme.py +113 -0
- code_puppy_core_plugins/theme/register_callbacks.py +348 -0
- code_puppy_core_plugins/theme/rich_themes.py +202 -0
- code_puppy_core_plugins/theme/themes.py +720 -0
- code_puppy_core_plugins/timestamp_heartbeat/__init__.py +1 -0
- code_puppy_core_plugins/timestamp_heartbeat/register_callbacks.py +114 -0
- code_puppy_core_plugins/token_ratio_learner/__init__.py +5 -0
- code_puppy_core_plugins/token_ratio_learner/ratios.py +208 -0
- code_puppy_core_plugins/token_ratio_learner/register_callbacks.py +213 -0
- code_puppy_core_plugins/universal_constructor/__init__.py +13 -0
- code_puppy_core_plugins/universal_constructor/models.py +138 -0
- code_puppy_core_plugins/universal_constructor/provider.py +62 -0
- code_puppy_core_plugins/universal_constructor/register_callbacks.py +75 -0
- code_puppy_core_plugins/universal_constructor/registry.py +302 -0
- code_puppy_core_plugins/universal_constructor/sandbox.py +584 -0
- code_puppy_core_plugins/wide_completion_menu/__init__.py +6 -0
- code_puppy_core_plugins/wide_completion_menu/register_callbacks.py +165 -0
- code_puppy_core_plugins/wiggum/__init__.py +1 -0
- code_puppy_core_plugins/wiggum/goal_runs.py +91 -0
- code_puppy_core_plugins/wiggum/judge.py +299 -0
- code_puppy_core_plugins/wiggum/judge_config.py +249 -0
- code_puppy_core_plugins/wiggum/judges_menu.py +814 -0
- code_puppy_core_plugins/wiggum/register_callbacks.py +569 -0
- code_puppy_core_plugins/wiggum/state.py +89 -0
- code_puppy_core_plugins/yolo_cli/__init__.py +1 -0
- code_puppy_core_plugins/yolo_cli/register_callbacks.py +41 -0
- code_puppy_core_plugins-0.0.2.dist-info/METADATA +64 -0
- code_puppy_core_plugins-0.0.2.dist-info/RECORD +313 -0
- code_puppy_core_plugins-0.0.2.dist-info/WHEEL +4 -0
- code_puppy_core_plugins-0.0.2.dist-info/entry_points.txt +55 -0
- code_puppy_core_plugins-0.0.2.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,517 @@
|
|
|
1
|
+
"""Data model and pydantic-ai introspection for /prune.
|
|
2
|
+
|
|
3
|
+
Kept separate from prune_menu.py so the TUI file stays focused on
|
|
4
|
+
prompt_toolkit wiring. Everything here is pure data-shape + parsing.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from dataclasses import dataclass, field
|
|
10
|
+
from typing import Any, List, Optional, Set
|
|
11
|
+
|
|
12
|
+
# ── tool-name → side-effect classification ─────────────────────────────────
|
|
13
|
+
|
|
14
|
+
_WRITE_TOOLS = {
|
|
15
|
+
"edit_file",
|
|
16
|
+
"create_file",
|
|
17
|
+
"replace_in_file",
|
|
18
|
+
"delete_snippet",
|
|
19
|
+
"delete_file",
|
|
20
|
+
}
|
|
21
|
+
_SHELL_TOOLS = {"agent_run_shell_command"}
|
|
22
|
+
_BROWSER_PREFIX = "browser_"
|
|
23
|
+
_TERMINAL_PREFIX = "terminal_"
|
|
24
|
+
|
|
25
|
+
SIDE_EFFECT_ICONS = {"⚡", "✎", "🌐", "▶"}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def classify_tool(tool_name: str) -> str:
|
|
29
|
+
"""Return a short single-char icon hinting at the side-effect kind."""
|
|
30
|
+
if tool_name in _WRITE_TOOLS:
|
|
31
|
+
return "✎"
|
|
32
|
+
if tool_name in _SHELL_TOOLS:
|
|
33
|
+
return "⚡"
|
|
34
|
+
if tool_name.startswith(_BROWSER_PREFIX):
|
|
35
|
+
return "🌐"
|
|
36
|
+
if tool_name.startswith(_TERMINAL_PREFIX):
|
|
37
|
+
return "▶"
|
|
38
|
+
return "·"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
# ── data classes ───────────────────────────────────────────────────────────
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@dataclass
|
|
45
|
+
class ToolCallInfo:
|
|
46
|
+
"""One tool call within a message."""
|
|
47
|
+
|
|
48
|
+
tool_call_id: str
|
|
49
|
+
name: str
|
|
50
|
+
args_preview: str # short single-line summary, for the list pane
|
|
51
|
+
full_args: dict = field(default_factory=dict) # full args, for detail pane
|
|
52
|
+
icon: str = "·"
|
|
53
|
+
has_return: bool = False
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@dataclass
|
|
57
|
+
class MessageEntry:
|
|
58
|
+
"""One displayable message in the prune menu."""
|
|
59
|
+
|
|
60
|
+
history_index: int
|
|
61
|
+
role: str # "system" | "user" | "assistant" | "tool-return" | "unknown"
|
|
62
|
+
preview: str
|
|
63
|
+
full_text: str
|
|
64
|
+
tool_calls: List[ToolCallInfo] = field(default_factory=list)
|
|
65
|
+
tool_return_ids: List[str] = field(default_factory=list)
|
|
66
|
+
# Keep ThinkingPart content separate so previews show the user-facing answer
|
|
67
|
+
# while detail panes can still expose the model's reasoning.
|
|
68
|
+
thinking_segments: List[str] = field(default_factory=list)
|
|
69
|
+
# Context-window annotations; None when no estimator is available.
|
|
70
|
+
tokens: Optional[int] = None
|
|
71
|
+
in_context: Optional[bool] = None
|
|
72
|
+
|
|
73
|
+
@property
|
|
74
|
+
def is_pure_tool_return(self) -> bool:
|
|
75
|
+
"""True for messages whose only content is tool returns.
|
|
76
|
+
|
|
77
|
+
These tag along with their parent tool-calling message and are
|
|
78
|
+
never shown as standalone rows in the menu.
|
|
79
|
+
"""
|
|
80
|
+
return self.role == "tool-return"
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
def is_locked(self) -> bool:
|
|
84
|
+
"""True when this entry carries a ``SystemPromptPart`` and so
|
|
85
|
+
must never be pruned.
|
|
86
|
+
|
|
87
|
+
``build_message_entries`` tags any request containing a
|
|
88
|
+
``SystemPromptPart`` with ``role == "system"``, which covers
|
|
89
|
+
both a standalone system message and pydantic-ai's bundled
|
|
90
|
+
``SystemPromptPart + UserPromptPart`` request.
|
|
91
|
+
"""
|
|
92
|
+
return self.role == "system"
|
|
93
|
+
|
|
94
|
+
@property
|
|
95
|
+
def role_color(self) -> str:
|
|
96
|
+
if self.role == "system":
|
|
97
|
+
return "class:tui.title"
|
|
98
|
+
if self.role == "user":
|
|
99
|
+
return "class:tui.success"
|
|
100
|
+
if self.role == "assistant":
|
|
101
|
+
return "class:tui.header"
|
|
102
|
+
if self.role == "tool-return":
|
|
103
|
+
return "class:tui.warning"
|
|
104
|
+
return "class:tui.muted"
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
@dataclass
|
|
108
|
+
class Row:
|
|
109
|
+
"""One visible row in the TUI list — always a whole-message header.
|
|
110
|
+
|
|
111
|
+
Thin named wrapper around ``message_idx`` so call sites read as
|
|
112
|
+
``row.message_idx`` rather than a bare int that needs context. The
|
|
113
|
+
menu operates on whole entries only; individual tool calls within a
|
|
114
|
+
message are not separately selectable.
|
|
115
|
+
"""
|
|
116
|
+
|
|
117
|
+
message_idx: int # index into MessageEntry list (not history_index)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
@dataclass
|
|
121
|
+
class PruneSelection:
|
|
122
|
+
"""Result of the menu — what the caller should remove.
|
|
123
|
+
|
|
124
|
+
Only whole messages can be selected. Their tool calls (and the
|
|
125
|
+
matching tool returns elsewhere in history) come along for the ride
|
|
126
|
+
via cascade logic in ``_perform_prune``.
|
|
127
|
+
"""
|
|
128
|
+
|
|
129
|
+
history_indices_to_drop: Set[int] = field(default_factory=set)
|
|
130
|
+
|
|
131
|
+
@property
|
|
132
|
+
def is_empty(self) -> bool:
|
|
133
|
+
return not self.history_indices_to_drop
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
@dataclass
|
|
137
|
+
class ContextBudget:
|
|
138
|
+
"""Snapshot of context-window math at menu open time.
|
|
139
|
+
|
|
140
|
+
``used_tokens`` represents what would actually be sent on the next
|
|
141
|
+
turn — i.e. the sum of in-context message tokens, NOT every message
|
|
142
|
+
in history. Messages older than the truncation point are silently
|
|
143
|
+
dropped by the model and accounted for separately in
|
|
144
|
+
``out_of_context_tokens`` so the budget percentage never exceeds 100%.
|
|
145
|
+
|
|
146
|
+
All fields default to None when the agent or its estimator is
|
|
147
|
+
unavailable — the menu degrades gracefully when this happens.
|
|
148
|
+
"""
|
|
149
|
+
|
|
150
|
+
used_tokens: Optional[int] = None # in-context message tokens (what fits)
|
|
151
|
+
overhead_tokens: Optional[int] = None # system prompt + tool defs
|
|
152
|
+
context_length: Optional[int] = None # model's max context size
|
|
153
|
+
out_of_context_tokens: int = 0 # tokens from messages that won't be sent
|
|
154
|
+
out_of_context_messages: int = 0 # count of those messages
|
|
155
|
+
available: bool = False # True if the rest of the fields are meaningful
|
|
156
|
+
|
|
157
|
+
@property
|
|
158
|
+
def total_used(self) -> Optional[int]:
|
|
159
|
+
if self.used_tokens is None or self.overhead_tokens is None:
|
|
160
|
+
return None
|
|
161
|
+
return self.used_tokens + self.overhead_tokens
|
|
162
|
+
|
|
163
|
+
@property
|
|
164
|
+
def percent_used(self) -> Optional[float]:
|
|
165
|
+
if not self.available or not self.context_length:
|
|
166
|
+
return None
|
|
167
|
+
total = self.total_used or 0
|
|
168
|
+
return 100.0 * total / self.context_length
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
# ── string helpers ─────────────────────────────────────────────────────────
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def short_str(value: Any, limit: int = 80) -> str:
|
|
175
|
+
if value is None:
|
|
176
|
+
return ""
|
|
177
|
+
s = str(value).replace("\n", " ").replace("\r", " ").strip()
|
|
178
|
+
if len(s) > limit:
|
|
179
|
+
return s[: limit - 1] + "…"
|
|
180
|
+
return s
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def short_args(args: dict, limit: int = 80) -> str:
|
|
184
|
+
if not args:
|
|
185
|
+
return ""
|
|
186
|
+
items: List[str] = []
|
|
187
|
+
for k, v in list(args.items())[:4]:
|
|
188
|
+
vs = short_str(v, limit=20)
|
|
189
|
+
items.append(f"{k}={vs}")
|
|
190
|
+
joined = ", ".join(items)
|
|
191
|
+
if len(joined) > limit:
|
|
192
|
+
return joined[: limit - 1] + "…"
|
|
193
|
+
return joined
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
# ── pydantic-ai introspection ──────────────────────────────────────────────
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def _extract_message(message: Any) -> Optional[MessageEntry]:
|
|
200
|
+
"""Inspect a pydantic-ai message and produce a MessageEntry, or None
|
|
201
|
+
if it's the system prompt / something we shouldn't show."""
|
|
202
|
+
try:
|
|
203
|
+
from pydantic_ai.messages import (
|
|
204
|
+
ModelRequest,
|
|
205
|
+
ModelResponse,
|
|
206
|
+
SystemPromptPart,
|
|
207
|
+
TextPart,
|
|
208
|
+
ToolCallPart,
|
|
209
|
+
ToolReturnPart,
|
|
210
|
+
UserPromptPart,
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
try:
|
|
214
|
+
from pydantic_ai.messages import ThinkingPart # type: ignore
|
|
215
|
+
except Exception: # pragma: no cover — older pydantic-ai
|
|
216
|
+
ThinkingPart = None # type: ignore[assignment]
|
|
217
|
+
|
|
218
|
+
try:
|
|
219
|
+
from pydantic_ai.messages import RetryPromptPart # type: ignore
|
|
220
|
+
except Exception: # pragma: no cover — older pydantic-ai
|
|
221
|
+
RetryPromptPart = None # type: ignore[assignment]
|
|
222
|
+
except Exception:
|
|
223
|
+
return MessageEntry(
|
|
224
|
+
history_index=-1,
|
|
225
|
+
role="unknown",
|
|
226
|
+
preview=short_str(message),
|
|
227
|
+
full_text=str(message),
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
if isinstance(message, ModelRequest):
|
|
231
|
+
parts = getattr(message, "parts", []) or []
|
|
232
|
+
text_fragments: List[str] = []
|
|
233
|
+
user_text_fragments: List[str] = []
|
|
234
|
+
saw_user = False
|
|
235
|
+
saw_tool_return = False
|
|
236
|
+
saw_system = False
|
|
237
|
+
tool_return_ids: List[str] = []
|
|
238
|
+
|
|
239
|
+
for part in parts:
|
|
240
|
+
if isinstance(part, SystemPromptPart):
|
|
241
|
+
saw_system = True
|
|
242
|
+
text_fragments.append(f"[system] {part.content}")
|
|
243
|
+
elif isinstance(part, UserPromptPart):
|
|
244
|
+
saw_user = True
|
|
245
|
+
content = part.content
|
|
246
|
+
if isinstance(content, list):
|
|
247
|
+
user_text = (
|
|
248
|
+
" ".join(str(item) for item in content if isinstance(item, str))
|
|
249
|
+
or "<non-text content>"
|
|
250
|
+
)
|
|
251
|
+
else:
|
|
252
|
+
user_text = str(content)
|
|
253
|
+
user_text_fragments.append(user_text)
|
|
254
|
+
text_fragments.append(user_text)
|
|
255
|
+
elif isinstance(part, ToolReturnPart):
|
|
256
|
+
saw_tool_return = True
|
|
257
|
+
tcid = getattr(part, "tool_call_id", None)
|
|
258
|
+
if tcid:
|
|
259
|
+
tool_return_ids.append(tcid)
|
|
260
|
+
# Keep the FULL content here so the detail pane can show
|
|
261
|
+
# everything. The list pane builds its own short preview.
|
|
262
|
+
content_str = str(part.content) if part.content is not None else ""
|
|
263
|
+
text_fragments.append(f"[tool-return: {part.tool_name}] {content_str}")
|
|
264
|
+
elif RetryPromptPart is not None and isinstance(part, RetryPromptPart):
|
|
265
|
+
# RetryPromptPart reports tool-argument validation failures; treat it
|
|
266
|
+
# like ToolReturnPart so the parent call pairs and the retry is visible.
|
|
267
|
+
saw_tool_return = True
|
|
268
|
+
tcid = getattr(part, "tool_call_id", None)
|
|
269
|
+
if tcid:
|
|
270
|
+
tool_return_ids.append(tcid)
|
|
271
|
+
content_str = str(part.content) if part.content is not None else ""
|
|
272
|
+
tool_name = getattr(part, "tool_name", "?")
|
|
273
|
+
text_fragments.append(f"[retry-prompt: {tool_name}] {content_str}")
|
|
274
|
+
|
|
275
|
+
if saw_system and not (saw_user or saw_tool_return):
|
|
276
|
+
return None # system-only prompt — never show, never prunable
|
|
277
|
+
|
|
278
|
+
# System > user > tool-return: bundled system+user requests stay locked
|
|
279
|
+
# because the system prompt is always in context.
|
|
280
|
+
if saw_system:
|
|
281
|
+
role = "system"
|
|
282
|
+
elif saw_user:
|
|
283
|
+
role = "user"
|
|
284
|
+
elif saw_tool_return:
|
|
285
|
+
role = "tool-return"
|
|
286
|
+
else:
|
|
287
|
+
role = "unknown"
|
|
288
|
+
|
|
289
|
+
text = "\n".join(text_fragments).strip() or "<empty request>"
|
|
290
|
+
# For system+user bundles, preview user text—the useful part when scanning
|
|
291
|
+
# old turns.
|
|
292
|
+
if saw_system and user_text_fragments:
|
|
293
|
+
preview_source = "\n".join(user_text_fragments)
|
|
294
|
+
else:
|
|
295
|
+
preview_source = text
|
|
296
|
+
return MessageEntry(
|
|
297
|
+
history_index=-1,
|
|
298
|
+
role=role,
|
|
299
|
+
preview=short_str(preview_source, limit=80),
|
|
300
|
+
full_text=text,
|
|
301
|
+
tool_calls=[],
|
|
302
|
+
tool_return_ids=tool_return_ids,
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
if isinstance(message, ModelResponse):
|
|
306
|
+
parts = getattr(message, "parts", []) or []
|
|
307
|
+
text_fragments: List[str] = []
|
|
308
|
+
thinking_segments: List[str] = []
|
|
309
|
+
tool_calls: List[ToolCallInfo] = []
|
|
310
|
+
for part in parts:
|
|
311
|
+
if isinstance(part, TextPart):
|
|
312
|
+
text_fragments.append(str(part.content))
|
|
313
|
+
elif ThinkingPart is not None and isinstance(part, ThinkingPart):
|
|
314
|
+
# Keep thinking content out of the preview line — it would
|
|
315
|
+
# bury the user-facing answer in chain-of-thought noise.
|
|
316
|
+
content = getattr(part, "content", None)
|
|
317
|
+
if content:
|
|
318
|
+
thinking_segments.append(str(content))
|
|
319
|
+
elif isinstance(part, ToolCallPart):
|
|
320
|
+
try:
|
|
321
|
+
args_dict = part.args_as_dict()
|
|
322
|
+
except Exception:
|
|
323
|
+
args_dict = {}
|
|
324
|
+
tool_calls.append(
|
|
325
|
+
ToolCallInfo(
|
|
326
|
+
tool_call_id=getattr(part, "tool_call_id", "") or "",
|
|
327
|
+
name=part.tool_name,
|
|
328
|
+
args_preview=short_args(args_dict),
|
|
329
|
+
full_args=args_dict if isinstance(args_dict, dict) else {},
|
|
330
|
+
icon=classify_tool(part.tool_name),
|
|
331
|
+
)
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
text = "\n".join(text_fragments).strip()
|
|
335
|
+
if not text and tool_calls:
|
|
336
|
+
text = f"<{len(tool_calls)} tool call(s)>"
|
|
337
|
+
elif not text:
|
|
338
|
+
text = "<empty response>"
|
|
339
|
+
|
|
340
|
+
# Compose the detail-pane body: response text first (what humans
|
|
341
|
+
# care about), thinking content below in a clearly fenced section.
|
|
342
|
+
if thinking_segments:
|
|
343
|
+
thinking_block = "\n".join(thinking_segments).strip()
|
|
344
|
+
full_text = f"{text}\n\n[thinking]\n{thinking_block}"
|
|
345
|
+
else:
|
|
346
|
+
full_text = text
|
|
347
|
+
|
|
348
|
+
return MessageEntry(
|
|
349
|
+
history_index=-1,
|
|
350
|
+
role="assistant",
|
|
351
|
+
preview=short_str(text, limit=80),
|
|
352
|
+
full_text=full_text,
|
|
353
|
+
tool_calls=tool_calls,
|
|
354
|
+
thinking_segments=thinking_segments,
|
|
355
|
+
)
|
|
356
|
+
|
|
357
|
+
return MessageEntry(
|
|
358
|
+
history_index=-1,
|
|
359
|
+
role="unknown",
|
|
360
|
+
preview=short_str(message),
|
|
361
|
+
full_text=str(message),
|
|
362
|
+
)
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
def build_message_entries(raw_history: List[Any]) -> List[MessageEntry]:
|
|
366
|
+
"""Turn pydantic-ai history into a list of MessageEntry, preserving order.
|
|
367
|
+
|
|
368
|
+
Pure-system messages in raw history are filtered out. Tool-return-only
|
|
369
|
+
messages stay in the list but are flagged so the menu can hide them
|
|
370
|
+
from the top level and surface them via the parent tool calls instead.
|
|
371
|
+
|
|
372
|
+
The sys row (when shown) comes exclusively from real history (e.g. a
|
|
373
|
+
``SystemPromptPart`` bundled in ``history[0]``); no synthetic sys row
|
|
374
|
+
is ever injected. This avoids duplicate-at-index-1 issues with
|
|
375
|
+
transports that fold the system prompt into the first user message
|
|
376
|
+
(e.g. claude-code OAuth).
|
|
377
|
+
"""
|
|
378
|
+
return_ids: Set[str] = set()
|
|
379
|
+
try:
|
|
380
|
+
from pydantic_ai.messages import ModelRequest, ToolReturnPart
|
|
381
|
+
|
|
382
|
+
try:
|
|
383
|
+
from pydantic_ai.messages import RetryPromptPart # type: ignore
|
|
384
|
+
except Exception: # pragma: no cover — older pydantic-ai
|
|
385
|
+
RetryPromptPart = None # type: ignore[assignment]
|
|
386
|
+
|
|
387
|
+
# ToolReturnPart and RetryPromptPart both satisfy a parent ToolCallPart.
|
|
388
|
+
tool_reply_kinds: tuple = (ToolReturnPart,)
|
|
389
|
+
if RetryPromptPart is not None:
|
|
390
|
+
tool_reply_kinds = (ToolReturnPart, RetryPromptPart)
|
|
391
|
+
|
|
392
|
+
for msg in raw_history:
|
|
393
|
+
if isinstance(msg, ModelRequest):
|
|
394
|
+
for part in getattr(msg, "parts", []) or []:
|
|
395
|
+
if isinstance(part, tool_reply_kinds):
|
|
396
|
+
tcid = getattr(part, "tool_call_id", None)
|
|
397
|
+
if tcid:
|
|
398
|
+
return_ids.add(tcid)
|
|
399
|
+
except Exception:
|
|
400
|
+
pass
|
|
401
|
+
|
|
402
|
+
entries: List[MessageEntry] = []
|
|
403
|
+
for hist_idx, msg in enumerate(raw_history):
|
|
404
|
+
entry = _extract_message(msg)
|
|
405
|
+
if entry is None:
|
|
406
|
+
continue
|
|
407
|
+
entry.history_index = hist_idx
|
|
408
|
+
for tc in entry.tool_calls:
|
|
409
|
+
tc.has_return = tc.tool_call_id in return_ids
|
|
410
|
+
entries.append(entry)
|
|
411
|
+
|
|
412
|
+
return entries
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
def annotate_context_window(
|
|
416
|
+
entries: List[MessageEntry],
|
|
417
|
+
raw_history: List[Any],
|
|
418
|
+
agent: Any,
|
|
419
|
+
) -> ContextBudget:
|
|
420
|
+
"""Mutate `entries` to set tokens + in_context, and return the budget.
|
|
421
|
+
|
|
422
|
+
Walks the entries newest → oldest, accumulating per-message token
|
|
423
|
+
estimates against ``context_length - overhead``. Each entry that fits
|
|
424
|
+
inside the remaining budget is marked in_context=True; once we blow
|
|
425
|
+
past the budget every older entry gets in_context=False.
|
|
426
|
+
|
|
427
|
+
Fails open: if the agent doesn't expose the expected helpers, all
|
|
428
|
+
entries get tokens=None / in_context=None and the returned budget
|
|
429
|
+
reports available=False.
|
|
430
|
+
"""
|
|
431
|
+
budget = ContextBudget()
|
|
432
|
+
|
|
433
|
+
estimate = getattr(agent, "estimate_tokens_for_message", None)
|
|
434
|
+
if not callable(estimate):
|
|
435
|
+
return budget
|
|
436
|
+
|
|
437
|
+
try:
|
|
438
|
+
context_length = int(agent._get_model_context_length())
|
|
439
|
+
except Exception:
|
|
440
|
+
context_length = 0
|
|
441
|
+
|
|
442
|
+
try:
|
|
443
|
+
overhead = int(agent._estimate_context_overhead())
|
|
444
|
+
except Exception:
|
|
445
|
+
overhead = 0
|
|
446
|
+
|
|
447
|
+
# Map history indices to raw messages for the estimator.
|
|
448
|
+
raw_by_idx = {i: msg for i, msg in enumerate(raw_history)}
|
|
449
|
+
|
|
450
|
+
# Per-entry token count
|
|
451
|
+
for entry in entries:
|
|
452
|
+
raw = raw_by_idx.get(entry.history_index)
|
|
453
|
+
if raw is None:
|
|
454
|
+
entry.tokens = None
|
|
455
|
+
continue
|
|
456
|
+
try:
|
|
457
|
+
entry.tokens = max(0, int(estimate(raw)))
|
|
458
|
+
except Exception:
|
|
459
|
+
entry.tokens = None
|
|
460
|
+
continue
|
|
461
|
+
|
|
462
|
+
# System messages are always sent; reserve their tokens before the
|
|
463
|
+
# contiguous non-system tail walk.
|
|
464
|
+
system_tokens = 0
|
|
465
|
+
for entry in entries:
|
|
466
|
+
if entry.role == "system" and entry.tokens is not None:
|
|
467
|
+
entry.in_context = True
|
|
468
|
+
system_tokens += entry.tokens
|
|
469
|
+
|
|
470
|
+
# Walk newest to oldest until the budget is exhausted; once one message
|
|
471
|
+
# overflows, all older messages are out of context.
|
|
472
|
+
available_budget = max(0, context_length - overhead - system_tokens)
|
|
473
|
+
non_system_cumulative = 0
|
|
474
|
+
out_of_context_total = 0
|
|
475
|
+
out_of_context_count = 0
|
|
476
|
+
overflowed = False
|
|
477
|
+
for entry in reversed(entries):
|
|
478
|
+
if entry.role == "system":
|
|
479
|
+
continue # already marked in_context=True above
|
|
480
|
+
if entry.tokens is None or context_length <= 0:
|
|
481
|
+
entry.in_context = None
|
|
482
|
+
continue
|
|
483
|
+
if not overflowed and non_system_cumulative + entry.tokens <= available_budget:
|
|
484
|
+
entry.in_context = True
|
|
485
|
+
non_system_cumulative += entry.tokens
|
|
486
|
+
else:
|
|
487
|
+
entry.in_context = False
|
|
488
|
+
overflowed = True
|
|
489
|
+
out_of_context_total += entry.tokens
|
|
490
|
+
out_of_context_count += 1
|
|
491
|
+
|
|
492
|
+
in_context_total = system_tokens + non_system_cumulative
|
|
493
|
+
|
|
494
|
+
# Report only the in-context tail in used_tokens; overflowed messages are
|
|
495
|
+
# separate so the percentage stays <=100%.
|
|
496
|
+
budget.used_tokens = in_context_total
|
|
497
|
+
budget.overhead_tokens = overhead
|
|
498
|
+
budget.context_length = context_length if context_length > 0 else None
|
|
499
|
+
budget.out_of_context_tokens = out_of_context_total
|
|
500
|
+
budget.out_of_context_messages = out_of_context_count
|
|
501
|
+
budget.available = context_length > 0
|
|
502
|
+
return budget
|
|
503
|
+
|
|
504
|
+
|
|
505
|
+
__all__ = [
|
|
506
|
+
"ContextBudget",
|
|
507
|
+
"MessageEntry",
|
|
508
|
+
"PruneSelection",
|
|
509
|
+
"Row",
|
|
510
|
+
"SIDE_EFFECT_ICONS",
|
|
511
|
+
"ToolCallInfo",
|
|
512
|
+
"annotate_context_window",
|
|
513
|
+
"build_message_entries",
|
|
514
|
+
"classify_tool",
|
|
515
|
+
"short_args",
|
|
516
|
+
"short_str",
|
|
517
|
+
]
|