tau-coding-agent 0.3.5__tar.gz → 0.3.9__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {tau_coding_agent-0.3.5/tau_coding_agent.egg-info → tau_coding_agent-0.3.9}/PKG-INFO +3 -1
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/docs/auth.md +1 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/docs/extensions.md +0 -24
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/docs/inference-providers.md +42 -1
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/docs/settings.md +13 -5
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/docs/usage.md +2 -2
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/pyproject.toml +4 -1
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/agent/prompt/builder.py +15 -8
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/agent/service.py +153 -75
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/auth/manager.py +6 -2
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/builtins/extensions/footer/__init__.py +14 -9
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/builtins/extensions/header/__init__.py +7 -2
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/builtins/models/text.py +340 -3
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/builtins/providers/text.py +39 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/builtins/tools/glob.py +22 -3
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/builtins/tools/grep.py +48 -18
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/builtins/tools/read.py +4 -2
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/console/commands/auth.py +14 -3
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/core/registry.py +1 -1
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/engine/service.py +29 -5
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/engine/types.py +2 -1
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/extensions/__init__.py +0 -2
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/extensions/api.py +0 -14
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/extensions/context.py +10 -2
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/extensions/loader.py +11 -11
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/extensions/runtime.py +15 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/hooks/engine.py +14 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/hooks/service.py +3 -3
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/__init__.py +3 -3
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/audio/gemini_audio.py +2 -2
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/audio/service.py +25 -2
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/image/gemini_image.py +2 -2
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/image/service.py +14 -1
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/text/anthropic_claude_code.py +26 -12
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/text/anthropic_messages.py +32 -13
- tau_coding_agent-0.3.9/tau/inference/api/text/anthropic_vertex.py +269 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/text/builtins.py +3 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/text/gemini_generate.py +26 -22
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/text/github_copilot_chat.py +5 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/text/google_antigravity.py +26 -8
- tau_coding_agent-0.3.9/tau/inference/api/text/google_vertex.py +366 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/text/mistral_chat.py +4 -1
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/text/ollama_chat.py +4 -1
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/text/openai_codex_responses.py +11 -11
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/text/openai_completions.py +5 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/text/openai_responses.py +16 -12
- tau_coding_agent-0.3.9/tau/inference/api/text/openai_vertex.py +309 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/text/service.py +105 -27
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/video/service.py +14 -1
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/model/types.py +6 -1
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/provider/oauth/utils.py +4 -1
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/provider/registry.py +5 -9
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/types.py +1 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/utils.py +49 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/message/types.py +9 -21
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/message/utils.py +3 -2
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/packages/manager.py +5 -2
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/rpc/mode.py +8 -4
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/runtime/service.py +30 -20
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/runtime/types.py +8 -5
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/session/compaction.py +47 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/session/manager.py +36 -8
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/session/utils.py +55 -3
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/settings/manager.py +19 -8
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/trust/manager.py +7 -1
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/agent_hooks.py +4 -1
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/ansi.py +23 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/app.py +11 -1
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/commands/auth.py +24 -18
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/commands/context.py +3 -3
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/commands/session.py +34 -9
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/components/autocomplete_manager.py +5 -2
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/components/image.py +9 -2
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/components/layout.py +12 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/components/message_list.py +12 -4
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/components/settings_modal.py +3 -1
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/components/text_input.py +61 -39
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/input.py +5 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/input_handler.py +49 -22
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/markdown.py +52 -13
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/renderer.py +24 -19
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/terminal.py +9 -10
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/tui.py +15 -4
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/utils/image_processing.py +2 -2
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/utils/secrets.py +16 -3
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9/tau_coding_agent.egg-info}/PKG-INFO +3 -1
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau_coding_agent.egg-info/SOURCES.txt +6 -1
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau_coding_agent.egg-info/requires.txt +3 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_ansi.py +145 -0
- tau_coding_agent-0.3.9/tests/test_auth_storage.py +106 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_builtin_tools.py +43 -0
- tau_coding_agent-0.3.9/tests/test_compaction.py +433 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_image_processing.py +69 -0
- tau_coding_agent-0.3.9/tests/test_inference_api_text_utils.py +127 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_markdown.py +42 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_message_types.py +83 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_message_utils.py +27 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_packages_utils.py +48 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_rpc_mode.py +125 -4
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_secrets.py +6 -1
- tau_coding_agent-0.3.9/tests/test_session_trust_persist.py +154 -0
- tau_coding_agent-0.3.9/tests/test_session_utils.py +443 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_settings_paths.py +29 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_settings_storage.py +42 -0
- tau_coding_agent-0.3.9/tests/test_text_llm_invoke.py +308 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_tool_registry.py +27 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_trust_utils.py +29 -0
- tau_coding_agent-0.3.9/tests/test_tui_input.py +401 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_tui_utils.py +9 -2
- tau_coding_agent-0.3.5/tau/extensions/events.py +0 -71
- tau_coding_agent-0.3.5/tests/test_auth_storage.py +0 -43
- tau_coding_agent-0.3.5/tests/test_compaction.py +0 -214
- tau_coding_agent-0.3.5/tests/test_session_utils.py +0 -169
- tau_coding_agent-0.3.5/tests/test_tui_input.py +0 -211
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/LICENSE +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/MANIFEST.in +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/README.md +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/docs/IMPLEMENTATION_SUMMARY.md +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/docs/architecture.md +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/docs/cli-reference.md +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/docs/development.md +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/docs/docs.json +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/docs/extension-settings.md +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/docs/http-proxy.md +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/docs/index.md +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/docs/installation.md +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/docs/keybindings.md +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/docs/messages.md +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/docs/project-context.md +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/docs/project-structure.md +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/docs/prompts.md +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/docs/python-api.md +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/docs/quickstart.md +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/docs/sessions.md +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/docs/skills.md +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/docs/themes.md +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/docs/tools.md +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/setup.cfg +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/__init__.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/agent/__init__.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/agent/prompt/__init__.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/agent/prompt/types.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/agent/types.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/auth/storage.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/auth/types.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/builtins/__init__.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/builtins/commands/__init__.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/builtins/commands/clear.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/builtins/commands/compact.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/builtins/commands/reload.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/builtins/commands/session.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/builtins/extensions/footer/git.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/builtins/extensions/footer/model.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/builtins/extensions/footer/utils.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/builtins/models/__init__.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/builtins/models/audio.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/builtins/models/image.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/builtins/models/video.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/builtins/prompts/commit.md +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/builtins/prompts/docs.md +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/builtins/prompts/explain.md +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/builtins/prompts/fix.md +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/builtins/prompts/refactor.md +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/builtins/prompts/review.md +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/builtins/prompts/test.md +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/builtins/providers/__init__.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/builtins/providers/audio.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/builtins/providers/image.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/builtins/providers/video.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/builtins/skills/code-review/SKILL.md +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/builtins/skills/debug/SKILL.md +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/builtins/skills/git-commit/SKILL.md +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/builtins/themes/dark.yaml +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/builtins/themes/light.yaml +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/builtins/tools/__init__.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/builtins/tools/edit.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/builtins/tools/ls.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/builtins/tools/terminal.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/builtins/tools/write.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/commands/__init__.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/commands/registry.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/commands/types.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/console/__init__.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/console/cli.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/console/commands/__init__.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/console/commands/packages.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/console/commands/update.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/core/__init__.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/engine/__init__.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/extensions/settings.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/hooks/__init__.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/hooks/inference.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/hooks/runtime.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/hooks/session.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/hooks/tui.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/hooks/types.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/__init__.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/audio/__init__.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/audio/base.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/audio/builtins.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/audio/elevenlabs_audio.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/audio/openai_audio.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/audio/registry.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/audio/sarvam_audio.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/audio/utils.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/image/__init__.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/image/base.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/image/builtins.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/image/openai_image.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/image/openrouter.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/image/registry.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/registry.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/text/__init__.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/text/base.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/text/registry.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/text/types.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/text/utils.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/video/__init__.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/video/base.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/video/builtins.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/video/fal_video.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/video/openrouter_video.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/api/video/registry.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/model/__init__.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/model/registry.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/provider/__init__.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/provider/oauth/__init__.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/provider/oauth/anthropic_claude_code.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/provider/oauth/github_copilot.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/provider/oauth/google_antigravity.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/provider/oauth/openai_codex.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/provider/oauth/pkce.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/provider/oauth/types.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/inference/provider/types.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/message/__init__.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/packages/__init__.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/packages/types.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/packages/utils.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/prompts/expand.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/prompts/loader.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/prompts/registry.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/prompts/types.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/rpc/__init__.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/rpc/types.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/session/branch_summarization.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/session/types.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/settings/paths.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/settings/storage.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/settings/types.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/settings/utils.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/skills/loader.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/skills/registry.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/skills/types.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/themes/loader.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/themes/registry.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/themes/types.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tool/__init__.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tool/registry.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tool/render.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tool/types.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/trust/__init__.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/trust/types.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/trust/utils.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/__init__.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/autocomplete.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/capabilities.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/commands/__init__.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/commands/appearance.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/commands/misc.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/commands/model.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/component.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/components/__init__.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/components/autocomplete_picker.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/components/box.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/components/command_palette.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/components/dynamic_border.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/components/file_picker.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/components/inline_selector.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/components/modal.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/components/model_palette.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/components/picker_overlay.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/components/prompt_overlay.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/components/resume_modal.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/components/select_list.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/components/settings_schema.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/components/spinner.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/components/text_prompt.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/components/tree_select_list.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/components/trust_screen.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/diff.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/fuzzy.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/keybindings.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/message_renderers.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/overlay.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/theme.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/ui_context.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/tui/utils.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/utils/__init__.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/utils/http_proxy.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau/utils/version_check.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau_coding_agent.egg-info/dependency_links.txt +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau_coding_agent.egg-info/entry_points.txt +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tau_coding_agent.egg-info/top_level.txt +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_agent_prompt.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_agent_types.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_auth_manager.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_branch_summarization.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_command_registry.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_diff.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_engine_types.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_footer_utils.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_fuzzy.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_http_proxy.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_inference_error_utils.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_inference_types.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_inference_utils.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_keybindings.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_model_registry.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_model_types.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_oauth_utils.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_pkce.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_prompts_expand.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_prompts_loader.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_prompts_registry.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_provider_registry.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_session_types.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_settings_manager.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_settings_utils.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_skills_loader.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_skills_registry.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_theme_loader.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_themes_registry.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_tool_render.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_trust_manager.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_tui_capabilities.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_tui_theme.py +0 -0
- {tau_coding_agent-0.3.5 → tau_coding_agent-0.3.9}/tests/test_version_check.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tau-coding-agent
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.9
|
|
4
4
|
Summary: A self-extensible agent CLI with terminal UI, multi-provider LLM support, session management with branching, and a plugin system for tools and commands
|
|
5
5
|
Requires-Python: >=3.12
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
@@ -26,6 +26,8 @@ Requires-Dist: pygments==2.20.0
|
|
|
26
26
|
Requires-Dist: pathspec==1.1.1
|
|
27
27
|
Requires-Dist: gitpython==3.1.50
|
|
28
28
|
Requires-Dist: grapheme==0.6.0
|
|
29
|
+
Provides-Extra: tools
|
|
30
|
+
Requires-Dist: ripgrep>=14.0.0; extra == "tools"
|
|
29
31
|
Dynamic: license-file
|
|
30
32
|
|
|
31
33
|
# Tau (τ)
|
|
@@ -143,6 +143,7 @@ The provider ID used as the key in `auth.json` and the `{PROVIDER}_API_KEY` env
|
|
|
143
143
|
| OpenAI | `openai` | `OPENAI_API_KEY` |
|
|
144
144
|
| Google | `google` | `GOOGLE_API_KEY` |
|
|
145
145
|
| Mistral | `mistral` | `MISTRAL_API_KEY` |
|
|
146
|
+
| Fireworks AI | `fireworks` | `FIREWORKS_API_KEY` |
|
|
146
147
|
| Ollama | `ollama` | `OLLAMA_API_KEY` |
|
|
147
148
|
|
|
148
149
|
## Next Steps
|
|
@@ -627,29 +627,6 @@ session working directory; pass an explicit `cwd=` to override.
|
|
|
627
627
|
|
|
628
628
|
---
|
|
629
629
|
|
|
630
|
-
## Cross-extension event bus
|
|
631
|
-
|
|
632
|
-
Extensions can communicate with each other via `tau.events`:
|
|
633
|
-
|
|
634
|
-
```python
|
|
635
|
-
# producer.py
|
|
636
|
-
def register(tau):
|
|
637
|
-
@tau.on("session_start")
|
|
638
|
-
async def on_start(event, ctx):
|
|
639
|
-
await tau.events.emit("producer:ready", {"version": "1.0"})
|
|
640
|
-
|
|
641
|
-
# consumer.py
|
|
642
|
-
def register(tau):
|
|
643
|
-
@tau.events.on("producer:ready")
|
|
644
|
-
async def on_ready(data):
|
|
645
|
-
print(f"producer ready — version {data['version']}")
|
|
646
|
-
```
|
|
647
|
-
|
|
648
|
-
This is separate from the hooks bus: `tau.events` is for extension-to-extension
|
|
649
|
-
messages; `tau.on(...)` is for system lifecycle events.
|
|
650
|
-
|
|
651
|
-
---
|
|
652
|
-
|
|
653
630
|
## Editor autocomplete providers
|
|
654
631
|
|
|
655
632
|
Extensions can inject custom autocomplete suggestions into the editor. When the user
|
|
@@ -742,7 +719,6 @@ def register(tau):
|
|
|
742
719
|
| `tau.register_flag(name, type, env, default)` | Declare an env-backed flag |
|
|
743
720
|
| `tau.get_flag(name)` | Read a registered flag's value |
|
|
744
721
|
| `await tau.exec(cmd, args, cwd)` | Run a shell command |
|
|
745
|
-
| `tau.events` | Cross-extension `EventBus` |
|
|
746
722
|
| `tau.config` | Per-extension settings dict from `settings.json` |
|
|
747
723
|
| `tau.cwd` | `Path` — working directory at session start |
|
|
748
724
|
| `tau.model_id` | Active model identifier |
|
|
@@ -12,6 +12,7 @@ Tau supports the following inference providers:
|
|
|
12
12
|
| OpenAI | API Key | No | [Link](#openai) |
|
|
13
13
|
| Google Gemini | API Key | Yes | [Link](#google-gemini) |
|
|
14
14
|
| Mistral AI | API Key | Limited | [Link](#mistral-ai) |
|
|
15
|
+
| Fireworks AI | API Key | No | [Link](#fireworks-ai) |
|
|
15
16
|
| Ollama | None | Yes | [Link](#ollama-local) |
|
|
16
17
|
| Azure OpenAI | API Key | No | [Link](#azure-openai) |
|
|
17
18
|
|
|
@@ -103,11 +104,51 @@ export MISTRAL_API_KEY=...
|
|
|
103
104
|
tau --model mistral/mistral-large -p "Say hello"
|
|
104
105
|
```
|
|
105
106
|
|
|
107
|
+
## Fireworks AI
|
|
108
|
+
|
|
109
|
+
Fireworks AI provides fast, cost-efficient inference for open-source models including Llama, DeepSeek, Qwen, and Mixtral — with OpenAI-compatible APIs.
|
|
110
|
+
|
|
111
|
+
**Text models**:
|
|
112
|
+
|
|
113
|
+
| Model | Context | Pricing (in/out per M tokens) |
|
|
114
|
+
|-------|---------|-------------------------------|
|
|
115
|
+
| `accounts/fireworks/models/llama-v3p3-70b-instruct` | 131K | $0.90 / $0.90 |
|
|
116
|
+
| `accounts/fireworks/models/llama-v3p1-405b-instruct` | 131K | $3.00 / $3.00 |
|
|
117
|
+
| `accounts/fireworks/models/deepseek-r1` *(thinking)* | 160K | $3.00 / $7.00 |
|
|
118
|
+
| `accounts/fireworks/models/deepseek-v3` | 131K | $0.90 / $0.90 |
|
|
119
|
+
| `accounts/fireworks/models/qwen3-235b-a22b` *(thinking)* | 131K | $0.22 / $0.88 |
|
|
120
|
+
| `accounts/fireworks/models/qwen3-30b-a3b` *(thinking)* | 131K | $0.15 / $0.60 |
|
|
121
|
+
| `accounts/fireworks/models/mixtral-8x22b-instruct` | 65K | $0.90 / $0.90 |
|
|
122
|
+
| `accounts/fireworks/models/gemma2-9b-it` | 8K | $0.20 / $0.20 |
|
|
123
|
+
|
|
124
|
+
**Image models**: Flux 1 Schnell FP8, Flux 1 Dev FP8
|
|
125
|
+
|
|
126
|
+
### Setup
|
|
127
|
+
|
|
128
|
+
1. Create an account at [Fireworks AI](https://fireworks.ai)
|
|
129
|
+
2. Generate an API key in your account settings
|
|
130
|
+
3. Set the environment variable:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
export FIREWORKS_API_KEY=fw_...
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Verify
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
tau --model fireworks/accounts/fireworks/models/llama-v3p3-70b-instruct -p "Say hello"
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Notes
|
|
143
|
+
|
|
144
|
+
- Uses the OpenAI-compatible completions API under the hood
|
|
145
|
+
- Session affinity is maintained automatically via a per-request `x-session-affinity` header
|
|
146
|
+
|
|
106
147
|
## Ollama (Local)
|
|
107
148
|
|
|
108
149
|
Run open-source models locally without API keys or internet.
|
|
109
150
|
|
|
110
|
-
**Models**: `llama2`, `mistral`, `neural-chat`, and [others](https://ollama.ai/library)
|
|
151
|
+
**Models**: `llama2`, `mistral`, `neural-chat`, `qwen3.5:cloud` (262K context, thinking), and [others](https://ollama.ai/library)
|
|
111
152
|
|
|
112
153
|
### Setup
|
|
113
154
|
|
|
@@ -187,6 +187,10 @@ When your conversation grows long, tau automatically summarizes older messages t
|
|
|
187
187
|
- **`reserve_tokens`**: How many tokens to keep available for the LLM's response (default 16,384 ≈ 4K-5K words)
|
|
188
188
|
- **`keep_recent_tokens`**: How many recent message tokens to preserve word-for-word before summarization kicks in (default 20,000 ≈ 5K-6K words)
|
|
189
189
|
|
|
190
|
+
#### Mid-turn (threshold) compaction
|
|
191
|
+
|
|
192
|
+
In addition to compaction triggered at the start of a turn, tau can compact **mid-turn** when the context hits the configured limit while the agent is already running. When this happens the engine stops cleanly so you can review the compacted context and continue — no partial output is lost. Tool output lines are truncated before sending to the LLM to help prevent hitting the threshold in the first place.
|
|
193
|
+
|
|
190
194
|
Example configurations:
|
|
191
195
|
|
|
192
196
|
```json
|
|
@@ -284,6 +288,10 @@ These settings are applied to the LLM client at startup:
|
|
|
284
288
|
|
|
285
289
|
Changes take effect on the next session start or after `/reload`.
|
|
286
290
|
|
|
291
|
+
#### Adaptive retry delay
|
|
292
|
+
|
|
293
|
+
When a provider responds with a `Retry-After` or `Retry-After-Ms` header (common on rate-limit responses), tau uses that value as the retry delay instead of the configured `base_delay_ms`. The delay is capped at **60 seconds** so a provider that returns an extreme value (e.g. "retry in 16 days") doesn't stall the agent indefinitely. When no header is present, `base_delay_ms` is used.
|
|
294
|
+
|
|
287
295
|
```json
|
|
288
296
|
{
|
|
289
297
|
"retry": {
|
|
@@ -442,11 +450,11 @@ All retry settings are **fully implemented and wired to the LLM client at startu
|
|
|
442
450
|
All thinking budget settings are **fully implemented and configurable**:
|
|
443
451
|
|
|
444
452
|
- **`thinking_budgets.minimal`**: Token budget for "minimal" level (default: `1024`)
|
|
445
|
-
- **`thinking_budgets.low`**: Token budget for "low" level (default: `
|
|
446
|
-
- **`thinking_budgets.medium`**: Token budget for "medium" level (default: `
|
|
447
|
-
- **`thinking_budgets.high`**: Token budget for "high" level (default: `
|
|
448
|
-
- **`thinking_budgets.xhigh`**: Token budget for "xhigh" level (default: `
|
|
449
|
-
- **`thinking_budgets.max`**: Token budget for "max" level (default: `
|
|
453
|
+
- **`thinking_budgets.low`**: Token budget for "low" level (default: `4096`)
|
|
454
|
+
- **`thinking_budgets.medium`**: Token budget for "medium" level (default: `8192`)
|
|
455
|
+
- **`thinking_budgets.high`**: Token budget for "high" level (default: `16384`)
|
|
456
|
+
- **`thinking_budgets.xhigh`**: Token budget for "xhigh" level (default: `32768`)
|
|
457
|
+
- **`thinking_budgets.max`**: Token budget for "max" level (default: `65536`)
|
|
450
458
|
|
|
451
459
|
Override these to customize extended thinking token allocations for your workflow.
|
|
452
460
|
|
|
@@ -102,8 +102,8 @@ Prints session info inline in the chat. Shows:
|
|
|
102
102
|
|
|
103
103
|
- **Session Info** — Name (if set), File path, ID
|
|
104
104
|
- **Messages** — User, Assistant, Tool calls, Tool results, Total
|
|
105
|
-
- **Tokens** — Input, Output, Cache read (if any), Cache write (if any), Total
|
|
106
|
-
- **Cost** — Total USD cost (only shown if non-zero)
|
|
105
|
+
- **Tokens** — Input, Output, Cache read (if any), Cache write (if any), Total — counts use human-readable suffixes (e.g. `1.2K`, `3.4M`); each line shows an inline cost estimate in USD
|
|
106
|
+
- **Cost** — Total USD cost with inline estimate (only shown if non-zero)
|
|
107
107
|
|
|
108
108
|
### `/copy`
|
|
109
109
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "tau-coding-agent"
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.9"
|
|
8
8
|
description = "A self-extensible agent CLI with terminal UI, multi-provider LLM support, session management with branching, and a plugin system for tools and commands"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.12"
|
|
@@ -68,6 +68,9 @@ tau = [
|
|
|
68
68
|
[tool.pytest.ini_options]
|
|
69
69
|
testpaths = ["tests"]
|
|
70
70
|
|
|
71
|
+
[project.optional-dependencies]
|
|
72
|
+
tools = ["ripgrep>=14.0.0"]
|
|
73
|
+
|
|
71
74
|
[dependency-groups]
|
|
72
75
|
dev = [
|
|
73
76
|
"pytest>=9.1.1",
|
|
@@ -93,7 +93,8 @@ def load_project_context_files(cwd: Path) -> list[tuple[str, Path]]:
|
|
|
93
93
|
|
|
94
94
|
|
|
95
95
|
_DEFAULT_IDENTITY = """\
|
|
96
|
-
You are a coding agent operating inside Tau, a coding agent harness. You help users by
|
|
96
|
+
You are a coding agent operating inside Tau, a coding agent harness. You help users by
|
|
97
|
+
reading files, executing commands, editing code, and writing new files.
|
|
97
98
|
|
|
98
99
|
You have strong software engineering skills. You think carefully before making changes,
|
|
99
100
|
and follow the existing style and conventions of the project.
|
|
@@ -101,10 +102,13 @@ and follow the existing style and conventions of the project.
|
|
|
101
102
|
|
|
102
103
|
_GENERAL_GUIDELINES = [
|
|
103
104
|
"If a task is ambiguous, ask a precise, clarifying question before proceeding.",
|
|
104
|
-
"Do only what the task asks; don't add features, refactors, or abstractions beyond scope.",
|
|
105
|
+
("Do only what the task asks; don't add features, refactors, or abstractions beyond scope."),
|
|
105
106
|
"Write comments when the *why* is non-obvious — well-named code explains itself.",
|
|
106
107
|
"Keep responses short, concise, and direct; don't summarize what you just did.",
|
|
107
|
-
|
|
108
|
+
(
|
|
109
|
+
"Prioritize accuracy over agreement — investigate before confirming, and "
|
|
110
|
+
"disagree when the evidence calls for it."
|
|
111
|
+
),
|
|
108
112
|
]
|
|
109
113
|
|
|
110
114
|
|
|
@@ -231,7 +235,9 @@ class PromptBuilder:
|
|
|
231
235
|
append = self._append()
|
|
232
236
|
git = self._git_section()
|
|
233
237
|
footer = self._footer()
|
|
234
|
-
return
|
|
238
|
+
return (
|
|
239
|
+
identity + guidelines + tools + docs + project_context + skills + append + git + footer
|
|
240
|
+
)
|
|
235
241
|
|
|
236
242
|
# ------------------------------------------------------------------
|
|
237
243
|
# Layers
|
|
@@ -267,7 +273,10 @@ class PromptBuilder:
|
|
|
267
273
|
if guideline:
|
|
268
274
|
guidelines.append(f"- **{t.name}**: {guideline.strip()}")
|
|
269
275
|
section = "\n\n# Available Tools\n\n" + "\n".join(lines)
|
|
270
|
-
section+=
|
|
276
|
+
section += (
|
|
277
|
+
"\nIn addition to the tools above, you may have access to other custom "
|
|
278
|
+
"tools depending on the project."
|
|
279
|
+
)
|
|
271
280
|
if guidelines:
|
|
272
281
|
section += "\n\n## Tool Guidelines\n\n" + "\n".join(guidelines)
|
|
273
282
|
return section
|
|
@@ -297,9 +306,7 @@ class PromptBuilder:
|
|
|
297
306
|
return (
|
|
298
307
|
"\n\n# Project Instructions\n\n"
|
|
299
308
|
"Project-specific guidelines (follow before general Tau guidelines):\n\n"
|
|
300
|
-
"<project_context>\n\n"
|
|
301
|
-
+ blocks
|
|
302
|
-
+ "</project_context>"
|
|
309
|
+
"<project_context>\n\n" + blocks + "</project_context>"
|
|
303
310
|
)
|
|
304
311
|
|
|
305
312
|
def _docs_section(self) -> str:
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
|
+
import logging
|
|
4
5
|
from pathlib import Path
|
|
5
6
|
from typing import TYPE_CHECKING
|
|
6
7
|
|
|
@@ -8,17 +9,33 @@ from tau.agent.types import AgentConfig, AgentContext, AgentPhase, ContextUsage,
|
|
|
8
9
|
from tau.hooks.engine import MessageEndEvent, MessageRollbackEvent, SavePointEvent, SettledEvent
|
|
9
10
|
from tau.hooks.service import Hooks
|
|
10
11
|
from tau.message.types import (
|
|
11
|
-
AgentMessage,
|
|
12
12
|
AssistantMessage,
|
|
13
13
|
LLMMessage,
|
|
14
|
-
TerminalExecutionMessage,
|
|
15
|
-
TextContent,
|
|
16
14
|
ToolMessage,
|
|
17
15
|
UserMessage,
|
|
18
16
|
)
|
|
19
17
|
from tau.message.utils import strip_unusable_trailing_assistant
|
|
18
|
+
from tau.session.utils import to_llm_messages as _to_llm_messages
|
|
20
19
|
from tau.tool.types import ToolInvocation, ToolResult
|
|
21
20
|
|
|
21
|
+
_log = logging.getLogger(__name__)
|
|
22
|
+
|
|
23
|
+
_TOOL_CAP_BYTES = 50 * 1024 # 50 KB — DEFAULT_MAX_BYTES
|
|
24
|
+
_TOOL_CAP_LINES = 2000 # DEFAULT_MAX_LINES
|
|
25
|
+
_TOOL_LINE_CAP_BYTES = 2 * 1024 # 2 KB — max bytes for a single line
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
from tau.hooks.engine import CompactionReason as _CompactionReason
|
|
29
|
+
from tau.session.compaction import ThresholdCompactionStop as _ThresholdCompactionStop
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _fmt_size(n: int) -> str:
|
|
33
|
+
if n < 1024:
|
|
34
|
+
return f"{n}B"
|
|
35
|
+
if n < 1024 * 1024:
|
|
36
|
+
return f"{n / 1024:.1f}KB"
|
|
37
|
+
return f"{n / (1024 * 1024):.1f}MB"
|
|
38
|
+
|
|
22
39
|
if TYPE_CHECKING:
|
|
23
40
|
from tau.engine.service import Engine
|
|
24
41
|
from tau.runtime.service import Runtime
|
|
@@ -26,37 +43,6 @@ if TYPE_CHECKING:
|
|
|
26
43
|
from tau.session.manager import SessionManager
|
|
27
44
|
|
|
28
45
|
|
|
29
|
-
def _to_llm_messages(messages: list[AgentMessage]) -> list[LLMMessage]:
|
|
30
|
-
"""Convert AgentMessages to LLM-compatible messages.
|
|
31
|
-
|
|
32
|
-
TerminalExecutionMessage → UserMessage (Ran `cmd`\n```output```)
|
|
33
|
-
CompactionSummaryMessage → UserMessage with summary wrapped in XML tags
|
|
34
|
-
CustomMessage and other non-LLM types → skipped
|
|
35
|
-
Empty AssistantMessages are visual-only markers (aborts, persisted API/credit
|
|
36
|
-
errors) and are skipped — an assistant turn with neither content nor tool
|
|
37
|
-
calls is invalid to send back and triggers provider 400s.
|
|
38
|
-
"""
|
|
39
|
-
from tau.message.types import CompactionSummaryMessage, ThinkingContent, ToolCallContent
|
|
40
|
-
|
|
41
|
-
result: list[LLMMessage] = []
|
|
42
|
-
for msg in messages:
|
|
43
|
-
if isinstance(msg, CompactionSummaryMessage):
|
|
44
|
-
text = f"<context-summary>\n{msg.summary}\n</context-summary>"
|
|
45
|
-
result.append(UserMessage.from_text(text))
|
|
46
|
-
elif isinstance(msg, TerminalExecutionMessage):
|
|
47
|
-
if not msg.exclude:
|
|
48
|
-
result.append(msg.to_user_message())
|
|
49
|
-
elif isinstance(msg, AssistantMessage):
|
|
50
|
-
has_usable = any(
|
|
51
|
-
isinstance(c, (TextContent, ToolCallContent, ThinkingContent)) for c in msg.contents
|
|
52
|
-
)
|
|
53
|
-
if has_usable:
|
|
54
|
-
result.append(msg)
|
|
55
|
-
elif isinstance(msg, (UserMessage, ToolMessage)):
|
|
56
|
-
result.append(msg)
|
|
57
|
-
return result
|
|
58
|
-
|
|
59
|
-
|
|
60
46
|
class Agent:
|
|
61
47
|
"""
|
|
62
48
|
High-level agent session tying together Engine and SessionManager.
|
|
@@ -87,6 +73,7 @@ class Agent:
|
|
|
87
73
|
self._overflow_recovery_attempted: bool = False
|
|
88
74
|
self._engine.options.before_tool_call = self._before_tool_call
|
|
89
75
|
self._engine.options.after_tool_call = self._after_tool_call
|
|
76
|
+
self._engine.options.transform_context = self._transform_context
|
|
90
77
|
|
|
91
78
|
# -------------------------------------------------------------------------
|
|
92
79
|
# Public interface
|
|
@@ -179,6 +166,79 @@ class Agent:
|
|
|
179
166
|
result: ToolResult,
|
|
180
167
|
signal: asyncio.Event | None,
|
|
181
168
|
) -> ToolResult | None:
|
|
169
|
+
"""Cap oversized tool output before it enters the context window.
|
|
170
|
+
|
|
171
|
+
Hard cap on tool output size 50 KB / 2000-line
|
|
172
|
+
Head-truncation keeps the first N lines/bytes; a trailing marker
|
|
173
|
+
reports how much was omitted and the total size.
|
|
174
|
+
"""
|
|
175
|
+
content = result.content
|
|
176
|
+
raw = content.encode("utf-8", errors="replace")
|
|
177
|
+
total_bytes = len(raw)
|
|
178
|
+
lines = content.split("\n")
|
|
179
|
+
total_lines = len(lines)
|
|
180
|
+
|
|
181
|
+
if total_bytes <= _TOOL_CAP_BYTES and total_lines <= _TOOL_CAP_LINES:
|
|
182
|
+
return result
|
|
183
|
+
|
|
184
|
+
# Cap individual lines that would consume the entire budget on their own
|
|
185
|
+
# (e.g. minified JS). Truncate each line to _TOOL_LINE_CAP_BYTES.
|
|
186
|
+
capped_lines: list[str] = []
|
|
187
|
+
for line in lines:
|
|
188
|
+
lb = len(line.encode("utf-8", errors="replace"))
|
|
189
|
+
if lb > _TOOL_LINE_CAP_BYTES:
|
|
190
|
+
buf = line.encode("utf-8", errors="replace")[:_TOOL_LINE_CAP_BYTES]
|
|
191
|
+
# Walk back to a valid UTF-8 boundary
|
|
192
|
+
while buf and (buf[-1] & 0xC0) == 0x80:
|
|
193
|
+
buf = buf[:-1]
|
|
194
|
+
capped_lines.append(buf.decode("utf-8", errors="replace") + f" …[line truncated: {_fmt_size(lb)} → {_fmt_size(_TOOL_LINE_CAP_BYTES)}]")
|
|
195
|
+
else:
|
|
196
|
+
capped_lines.append(line)
|
|
197
|
+
lines = capped_lines
|
|
198
|
+
|
|
199
|
+
kept: list[str] = []
|
|
200
|
+
byte_count = 0
|
|
201
|
+
for i, line in enumerate(lines):
|
|
202
|
+
if i >= _TOOL_CAP_LINES:
|
|
203
|
+
break
|
|
204
|
+
enc = len(line.encode("utf-8", errors="replace")) + (1 if i > 0 else 0)
|
|
205
|
+
if byte_count + enc > _TOOL_CAP_BYTES:
|
|
206
|
+
break
|
|
207
|
+
kept.append(line)
|
|
208
|
+
byte_count += enc
|
|
209
|
+
|
|
210
|
+
omitted = total_bytes - byte_count
|
|
211
|
+
kept.append(
|
|
212
|
+
f"[truncated: {_fmt_size(omitted)} omitted"
|
|
213
|
+
f" — {_fmt_size(total_bytes)} total, showing first {len(kept)} lines / {_fmt_size(byte_count)}]"
|
|
214
|
+
)
|
|
215
|
+
return ToolResult(
|
|
216
|
+
id=result.id,
|
|
217
|
+
content="\n".join(kept),
|
|
218
|
+
is_error=result.is_error,
|
|
219
|
+
metadata=result.metadata,
|
|
220
|
+
terminate=result.terminate,
|
|
221
|
+
terminate_message=result.terminate_message,
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
async def _transform_context(
|
|
225
|
+
self,
|
|
226
|
+
messages: list[LLMMessage],
|
|
227
|
+
signal: asyncio.Event | None,
|
|
228
|
+
) -> list[LLMMessage]:
|
|
229
|
+
"""Called before every LLM inference in the engine loop.
|
|
230
|
+
|
|
231
|
+
Runs a compaction check so it can fire between tool iterations
|
|
232
|
+
(not only at invoke() boundaries), then rebuilds the message list
|
|
233
|
+
from the current session so the engine always sees up-to-date
|
|
234
|
+
compacted history.
|
|
235
|
+
"""
|
|
236
|
+
threshold_stop = await self._check_compaction()
|
|
237
|
+
session_ctx = self._session_manager.build_session_context()
|
|
238
|
+
llm_messages = _to_llm_messages(session_ctx.messages)
|
|
239
|
+
result = strip_unusable_trailing_assistant(llm_messages, self._session_manager)
|
|
240
|
+
if threshold_stop:
|
|
241
|
+
raise _ThresholdCompactionStop()
|
|
182
242
|
return result
|
|
183
243
|
|
|
184
244
|
# -------------------------------------------------------------------------
|
|
@@ -225,7 +285,8 @@ class Agent:
|
|
|
225
285
|
if preparation is None:
|
|
226
286
|
return False
|
|
227
287
|
await self._apply_compaction(
|
|
228
|
-
preparation, entries, manual=True, custom_instructions=custom_instructions
|
|
288
|
+
preparation, entries, manual=True, custom_instructions=custom_instructions,
|
|
289
|
+
reason=_CompactionReason.Manual,
|
|
229
290
|
)
|
|
230
291
|
return True
|
|
231
292
|
|
|
@@ -235,12 +296,15 @@ class Agent:
|
|
|
235
296
|
entries: list,
|
|
236
297
|
manual: bool,
|
|
237
298
|
custom_instructions: str | None = None,
|
|
299
|
+
reason: _CompactionReason = _CompactionReason.Manual,
|
|
238
300
|
) -> None:
|
|
239
301
|
"""Run a prepared compaction, persist the summary, and emit the end event."""
|
|
240
302
|
from tau.hooks.engine import CompactionEndEvent
|
|
241
303
|
|
|
304
|
+
will_retry = reason == _CompactionReason.Overflow
|
|
242
305
|
result, from_extension = await self._run_compaction(
|
|
243
|
-
preparation, entries, manual=manual, custom_instructions=custom_instructions
|
|
306
|
+
preparation, entries, manual=manual, custom_instructions=custom_instructions,
|
|
307
|
+
reason=reason, will_retry=will_retry,
|
|
244
308
|
)
|
|
245
309
|
self._session_manager.append_compaction(
|
|
246
310
|
summary=result.summary,
|
|
@@ -254,32 +318,40 @@ class Agent:
|
|
|
254
318
|
tokens_before=result.tokens_before,
|
|
255
319
|
summary_length=len(result.summary),
|
|
256
320
|
from_extension=from_extension,
|
|
321
|
+
reason=reason,
|
|
322
|
+
will_retry=will_retry,
|
|
257
323
|
)
|
|
258
324
|
)
|
|
259
325
|
|
|
260
|
-
def
|
|
261
|
-
"""Timestamp of the most recent
|
|
262
|
-
from tau.session.types import
|
|
326
|
+
def _latest_model_change_timestamp(self) -> float | None:
|
|
327
|
+
"""Timestamp of the most recent model-change entry in the active branch, if any."""
|
|
328
|
+
from tau.session.types import ModelChangeEntry
|
|
263
329
|
|
|
264
330
|
for entry in reversed(self._session_manager.get_branch()):
|
|
265
|
-
if isinstance(entry,
|
|
331
|
+
if isinstance(entry, ModelChangeEntry):
|
|
266
332
|
return entry.timestamp
|
|
267
333
|
return None
|
|
268
334
|
|
|
269
|
-
async def _check_compaction(self) ->
|
|
270
|
-
"""Auto-compact if context usage exceeds the threshold. Circuit-breaks after 3 failures.
|
|
335
|
+
async def _check_compaction(self) -> bool:
|
|
336
|
+
"""Auto-compact if context usage exceeds the threshold. Circuit-breaks after 3 failures.
|
|
337
|
+
|
|
338
|
+
Returns True if threshold compaction ran (caller should stop the current turn),
|
|
339
|
+
False otherwise (overflow-forced compaction or no compaction needed).
|
|
340
|
+
"""
|
|
271
341
|
from tau.session.compaction import (
|
|
272
342
|
estimate_context_tokens,
|
|
343
|
+
is_silent_overflow,
|
|
344
|
+
latest_compaction_timestamp,
|
|
273
345
|
prepare_compaction,
|
|
274
346
|
should_compact,
|
|
275
347
|
)
|
|
276
348
|
|
|
277
349
|
if self._compaction_failures >= 3:
|
|
278
|
-
return
|
|
350
|
+
return False
|
|
279
351
|
|
|
280
352
|
settings = self._config.compaction
|
|
281
353
|
if not settings.enabled:
|
|
282
|
-
return
|
|
354
|
+
return False
|
|
283
355
|
|
|
284
356
|
entries = self._session_manager.get_branch()
|
|
285
357
|
session_ctx = self._session_manager.build_session_context()
|
|
@@ -292,48 +364,46 @@ class Agent:
|
|
|
292
364
|
# (Xiaomi MiMo) instead of erroring. The threshold check can miss these, so
|
|
293
365
|
# force compaction when the last response shows the symptom.
|
|
294
366
|
last = self._session_manager.find_last_assistant_message()
|
|
295
|
-
|
|
367
|
+
|
|
368
|
+
# Model-switch guard: if the last assistant message is older than the most recent
|
|
369
|
+
# model change, it came from a different model. Treating its usage/overflow data as
|
|
370
|
+
# a signal for the new model is unreliable (context windows differ), so skip.
|
|
371
|
+
model_change_ts = self._latest_model_change_timestamp()
|
|
372
|
+
if model_change_ts is not None and last is not None:
|
|
373
|
+
if last.timestamp <= model_change_ts:
|
|
374
|
+
return False
|
|
375
|
+
|
|
376
|
+
forced = last is not None and is_silent_overflow(last, self._context_window)
|
|
296
377
|
|
|
297
378
|
if not forced:
|
|
298
379
|
if not should_compact(usage.tokens, self._context_window, settings):
|
|
299
|
-
return
|
|
380
|
+
return False
|
|
300
381
|
# Stale-anchor guard: right after a compaction the kept messages still carry
|
|
301
382
|
# pre-compaction usage on their anchor, which would re-trigger compaction every
|
|
302
383
|
# turn. Skip if the usage anchor predates the latest compaction boundary.
|
|
303
384
|
if usage.last_usage_index is not None:
|
|
304
385
|
anchor = llm_messages[usage.last_usage_index]
|
|
305
|
-
comp_ts =
|
|
386
|
+
comp_ts = latest_compaction_timestamp(entries)
|
|
306
387
|
if comp_ts is not None and getattr(anchor, "timestamp", 0.0) <= comp_ts:
|
|
307
|
-
return
|
|
388
|
+
return False
|
|
308
389
|
|
|
309
390
|
preparation = prepare_compaction(entries, settings)
|
|
310
391
|
if preparation is None:
|
|
311
|
-
return
|
|
392
|
+
return False
|
|
312
393
|
|
|
313
394
|
try:
|
|
314
|
-
await self._apply_compaction(
|
|
395
|
+
await self._apply_compaction(
|
|
396
|
+
preparation, entries, manual=False,
|
|
397
|
+
reason=_CompactionReason.Overflow if forced else _CompactionReason.Threshold,
|
|
398
|
+
)
|
|
399
|
+
# Threshold compaction: caller should stop the turn; user resumes manually.
|
|
400
|
+
# Forced (silent overflow) compaction: caller should continue — the LLM
|
|
401
|
+
# never got a usable response, so there's nothing for the user to resume from.
|
|
402
|
+
return not forced
|
|
315
403
|
except Exception:
|
|
316
404
|
self._compaction_failures += 1
|
|
317
|
-
|
|
318
|
-
def _is_silent_overflow(self, message: AssistantMessage) -> bool:
|
|
319
|
-
"""Detect overflow on a *successful* response (no error was raised).
|
|
320
|
-
|
|
321
|
-
- Silent (z.ai): a normal stop whose input tokens exceed the window.
|
|
322
|
-
- Length-stop (Xiaomi MiMo): server truncated the input to fill the window,
|
|
323
|
-
leaving no room to generate, so it stops with zero output.
|
|
324
|
-
"""
|
|
325
|
-
from tau.inference.types import StopReason
|
|
326
|
-
|
|
327
|
-
cw = self._context_window
|
|
328
|
-
if cw <= 0:
|
|
405
|
+
_log.exception("Auto-compaction failed")
|
|
329
406
|
return False
|
|
330
|
-
u = message.usage
|
|
331
|
-
inp = u.input_tokens + u.cache_read_tokens
|
|
332
|
-
if message.stop_reason == StopReason.Stop and inp > cw:
|
|
333
|
-
return True
|
|
334
|
-
return bool(
|
|
335
|
-
message.stop_reason == StopReason.Length and u.output_tokens == 0 and inp >= cw * 0.99
|
|
336
|
-
)
|
|
337
407
|
|
|
338
408
|
async def _try_overflow_recovery(self) -> bool:
|
|
339
409
|
"""If the last turn died with a context-overflow error, compact once and signal a retry.
|
|
@@ -349,6 +419,13 @@ class Agent:
|
|
|
349
419
|
if last is None or last.error_kind != ErrorKind.CONTEXT_OVERFLOW:
|
|
350
420
|
return False
|
|
351
421
|
|
|
422
|
+
# Model-switch guard: the overflow error is from a different model if it predates
|
|
423
|
+
# the most recent model-change entry. Skip recovery — the new model may handle the
|
|
424
|
+
# context fine, and compacting based on a stale signal wastes history.
|
|
425
|
+
model_change_ts = self._latest_model_change_timestamp()
|
|
426
|
+
if model_change_ts is not None and last.timestamp <= model_change_ts:
|
|
427
|
+
return False
|
|
428
|
+
|
|
352
429
|
if self._overflow_recovery_attempted:
|
|
353
430
|
self._notify(
|
|
354
431
|
"Context overflow recovery failed after compaction. "
|
|
@@ -366,9 +443,10 @@ class Agent:
|
|
|
366
443
|
if preparation is None:
|
|
367
444
|
return False
|
|
368
445
|
try:
|
|
369
|
-
await self._apply_compaction(preparation, entries, manual=False)
|
|
446
|
+
await self._apply_compaction(preparation, entries, manual=False, reason=_CompactionReason.Overflow)
|
|
370
447
|
except Exception:
|
|
371
448
|
self._compaction_failures += 1
|
|
449
|
+
_log.exception("Overflow-triggered compaction failed")
|
|
372
450
|
return False
|
|
373
451
|
return True
|
|
374
452
|
|
|
@@ -388,6 +466,8 @@ class Agent:
|
|
|
388
466
|
entries: list,
|
|
389
467
|
manual: bool,
|
|
390
468
|
custom_instructions: str | None = None,
|
|
469
|
+
reason: _CompactionReason = _CompactionReason.Manual,
|
|
470
|
+
will_retry: bool = False,
|
|
391
471
|
) -> tuple:
|
|
392
472
|
"""Emit before_compaction (allowing interception), then run the default algorithm.
|
|
393
473
|
|
|
@@ -408,6 +488,8 @@ class Agent:
|
|
|
408
488
|
preparation=preparation,
|
|
409
489
|
entries=entries,
|
|
410
490
|
manual=manual,
|
|
491
|
+
reason=reason,
|
|
492
|
+
will_retry=will_retry,
|
|
411
493
|
)
|
|
412
494
|
)
|
|
413
495
|
|
|
@@ -419,7 +501,7 @@ class Agent:
|
|
|
419
501
|
if res.compaction is not None:
|
|
420
502
|
return res.compaction, True
|
|
421
503
|
|
|
422
|
-
await self.hooks.emit(CompactionStartEvent(manual=manual))
|
|
504
|
+
await self.hooks.emit(CompactionStartEvent(manual=manual, reason=reason, will_retry=will_retry))
|
|
423
505
|
result = await _compact(
|
|
424
506
|
preparation, self._engine.llm, custom_instructions=custom_instructions
|
|
425
507
|
) # type: ignore[arg-type]
|
|
@@ -438,10 +520,6 @@ class Agent:
|
|
|
438
520
|
|
|
439
521
|
opts = options or PromptOptions()
|
|
440
522
|
|
|
441
|
-
# Pre-flight: a resumed or already-oversized session can exceed the window on the
|
|
442
|
-
# very first send. Compact before appending and shipping the new turn.
|
|
443
|
-
await self._check_compaction()
|
|
444
|
-
|
|
445
523
|
user_message = UserMessage.with_media(
|
|
446
524
|
text,
|
|
447
525
|
list(opts.images) if opts.images else None,
|
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import builtins
|
|
4
4
|
import json
|
|
5
|
+
import logging
|
|
5
6
|
import os
|
|
6
7
|
from pathlib import Path
|
|
7
8
|
|
|
@@ -19,6 +20,8 @@ from tau.inference.provider.registry import ProviderRegistry
|
|
|
19
20
|
from tau.settings.paths import get_auth_path
|
|
20
21
|
from tau.utils.secrets import resolve_secret
|
|
21
22
|
|
|
23
|
+
_log = logging.getLogger(__name__)
|
|
24
|
+
|
|
22
25
|
|
|
23
26
|
def _get_env_api_key(provider: str) -> str | None:
|
|
24
27
|
"""Get API key for a provider from environment variables."""
|
|
@@ -79,12 +82,12 @@ class AuthManager:
|
|
|
79
82
|
return AuthManager(registry, storage)
|
|
80
83
|
|
|
81
84
|
@staticmethod
|
|
82
|
-
def in_memory(registry: ProviderRegistry, initial: dict = None) -> AuthManager:
|
|
85
|
+
def in_memory(registry: ProviderRegistry, initial: dict | None = None) -> AuthManager:
|
|
83
86
|
"""Create AuthManager with in-memory storage for testing."""
|
|
84
87
|
if initial is None:
|
|
85
88
|
initial = {}
|
|
86
89
|
storage = InMemoryAuthStorage()
|
|
87
|
-
storage.with_lock(lambda _: LockResult(result=
|
|
90
|
+
storage.with_lock(lambda _: LockResult(result=initial, next=json.dumps(initial, indent=2))) # type: ignore[arg-type]
|
|
88
91
|
return AuthManager.from_storage(registry, storage)
|
|
89
92
|
|
|
90
93
|
def _record_error(self, error: Exception) -> None:
|
|
@@ -274,6 +277,7 @@ class AuthManager:
|
|
|
274
277
|
result=refreshed_credential, next=json.dumps(serialized, indent=2)
|
|
275
278
|
)
|
|
276
279
|
except Exception as e:
|
|
280
|
+
_log.error("oauth token refresh failed for %s: %s", provider, e, exc_info=True)
|
|
277
281
|
self._record_error(e)
|
|
278
282
|
return LockResult(result=None)
|
|
279
283
|
|