micro-cc 0.2.78__tar.gz → 0.2.79__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.
- micro_cc-0.2.79/LICENSE +21 -0
- {micro_cc-0.2.78/src/micro_cc.egg-info → micro_cc-0.2.79}/PKG-INFO +20 -17
- {micro_cc-0.2.78 → micro_cc-0.2.79}/README.md +1 -1
- {micro_cc-0.2.78 → micro_cc-0.2.79}/pyproject.toml +2 -2
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/browser/_md_convert.py +12 -19
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/claude_loop_.py +17 -52
- micro_cc-0.2.79/src/micro_cc/models/__init__.py +6 -0
- micro_cc-0.2.79/src/micro_cc/models/adapters/__init__.py +1 -0
- micro_cc-0.2.79/src/micro_cc/models/adapters/anthropic.py +91 -0
- micro_cc-0.2.79/src/micro_cc/models/adapters/chat.py +108 -0
- micro_cc-0.2.79/src/micro_cc/models/adapters/responses.py +74 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/models/anthropic.py +42 -119
- micro_cc-0.2.79/src/micro_cc/models/client.py +65 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/models/foundry.py +2 -87
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/models/litellm.py +20 -236
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/models/ollama.py +9 -166
- micro_cc-0.2.79/src/micro_cc/models/openai.py +564 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/models/registry.py +17 -10
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/models/schema.py +22 -0
- micro_cc-0.2.79/src/micro_cc/models/types.py +53 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/graph-orchestration/SKILL.md +12 -1
- micro_cc-0.2.79/src/micro_cc/skills/system-design-review/REFERENCE.md +174 -0
- micro_cc-0.2.79/src/micro_cc/skills/system-design-review/SKILL.md +161 -0
- micro_cc-0.2.79/src/micro_cc/skills/system-design-review/scripts/design_graph.py +290 -0
- micro_cc-0.2.79/src/micro_cc/skills/system-design-review/scripts/design_review.py +528 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/start_headless_.py +6 -1
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/start_live_tui_.py +51 -20
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tools/bash_tool.py +76 -1
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tools/file_tools_.py +2 -2
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tools/monitor_.py +34 -5
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tools/monitor_watch_.py +7 -10
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tools/vision_tools_.py +6 -28
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/alt_screen_.py +16 -6
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/detect_images_.py +29 -40
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/diff_viewer_.py +2 -3
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/etype_handler_.py +2 -3
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/keys_.py +27 -33
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/kill_ring_.py +6 -10
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/list_picker_.py +3 -7
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/message_row_.py +31 -43
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/prompt_input_.py +7 -9
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/screen_cmds_.py +1 -1
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/stack_.py +23 -30
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/stdin_buffer_.py +16 -21
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/terminal_.py +16 -30
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/text_.py +28 -32
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/text_utils_.py +10 -12
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/theme_.py +3 -4
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/truncated_text_.py +7 -9
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/undo_stack_.py +7 -10
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/word_navigation_.py +10 -28
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/claude_subscription.py +10 -12
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/helpers.py +22 -7
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/msg_store_.py +29 -58
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/pg_store_.py +53 -5
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/subagent_tracker_.py +29 -3
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/tokenization_simple.py +81 -13
- {micro_cc-0.2.78 → micro_cc-0.2.79/src/micro_cc.egg-info}/PKG-INFO +20 -17
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc.egg-info/SOURCES.txt +14 -6
- micro_cc-0.2.79/tests/test_model_consumers.py +168 -0
- micro_cc-0.2.79/tests/test_models.py +412 -0
- micro_cc-0.2.78/LICENSE +0 -18
- micro_cc-0.2.78/src/micro_cc/code_test/run_token_cutter.py +0 -61
- micro_cc-0.2.78/src/micro_cc/code_test/test_messages.py +0 -127
- micro_cc-0.2.78/src/micro_cc/skills/autoresearch/SKILL.md +0 -69
- micro_cc-0.2.78/src/micro_cc/start_watch_.py +0 -104
- micro_cc-0.2.78/src/micro_cc/utils/__init__.py +0 -0
- micro_cc-0.2.78/src/micro_cc/webui/__init__.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/setup.cfg +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/__init__.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/browser/__init__.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/browser/_cookies.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/browser/browser_manager.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/browser/simpletextbrowser.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/cache/__init__.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/cache/redis_cache.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/execute_tool.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/SKILL.md +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/ArsenalSC-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/ArsenalSC-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/BigShoulders-Bold.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/BigShoulders-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/BigShoulders-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Boldonse-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Boldonse-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/BricolageGrotesque-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/CrimsonPro-Bold.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/CrimsonPro-Italic.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/CrimsonPro-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/CrimsonPro-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/DMMono-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/DMMono-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/EricaOne-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/EricaOne-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/GeistMono-Bold.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/GeistMono-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/GeistMono-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Gloock-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Gloock-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/IBMPlexMono-Bold.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/IBMPlexMono-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/IBMPlexMono-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/IBMPlexSerif-Bold.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/IBMPlexSerif-BoldItalic.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/IBMPlexSerif-Italic.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/IBMPlexSerif-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/InstrumentSans-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Italiana-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Italiana-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/JetBrainsMono-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Jura-Light.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Jura-Medium.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Jura-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/LibreBaskerville-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/LibreBaskerville-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Lora-Bold.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Lora-BoldItalic.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Lora-Italic.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Lora-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Lora-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/NationalPark-Bold.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/NationalPark-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/NationalPark-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/NothingYouCouldDo-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Outfit-Bold.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Outfit-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Outfit-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/PixelifySans-Medium.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/PixelifySans-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/PoiretOne-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/PoiretOne-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/RedHatMono-Bold.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/RedHatMono-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/RedHatMono-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Silkscreen-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Silkscreen-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/SmoochSans-Medium.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/SmoochSans-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Tektur-Medium.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Tektur-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Tektur-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/WorkSans-Bold.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/WorkSans-BoldItalic.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/WorkSans-Italic.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/WorkSans-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/WorkSans-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/YoungSerif-OFL.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/YoungSerif-Regular.ttf +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/references/blueprint-tokens.md +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/github/SKILL.md +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/pptx/SKILL.md +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/pptx/brief.md +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/pptx/scripts/build_deck.js +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/pptx/scripts/deck_to_images.py +0 -0
- {micro_cc-0.2.78/src/micro_cc/code_test → micro_cc-0.2.79/src/micro_cc/skills/pptx/scripts/office}/__init__.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/pptx/scripts/office/soffice.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/pptx/scripts/render_svg.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/pptx/svg-slides.md +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/skill_loader.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/xlsx/SKILL.md +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/start_batch_.py +0 -0
- {micro_cc-0.2.78/src/micro_cc/models → micro_cc-0.2.79/src/micro_cc/tools}/__init__.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tools/ask_user_tool.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tools/browser_tool_.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tools/computer_tool_.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tools/mcp_client_.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tools/memory_tool_.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tools/message_session_.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tools/search_history_tool_.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tools/search_tool_.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tools/skill_tools_.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tools/todo_tools_.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tools/web_tools_.py +0 -0
- {micro_cc-0.2.78/src/micro_cc/skills/pptx/scripts/office → micro_cc-0.2.79/src/micro_cc/tui_native}/__init__.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/md_render_.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/multi_select_list_.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/question_panel_.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/scroll_view_.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/self_terminal_setup_.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/self_update_.py +0 -0
- {micro_cc-0.2.78/src/micro_cc/tools → micro_cc-0.2.79/src/micro_cc/utils}/__init__.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/annotate_.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/banner_.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/claude_md_loader.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/command_registry.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/default_status_sh.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/hidden_prompts.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/hints.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/history_mount_.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/inbox_store_.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/memory_store_.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/msg_normalize_.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/project_files_.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/session_ipc_.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/settings_store_.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/status_marker.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/terminal_setup.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/tool_limits.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/tool_result_storage.py +0 -0
- {micro_cc-0.2.78/src/micro_cc/tui_native → micro_cc-0.2.79/src/micro_cc/webui}/__init__.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/webui/bridge.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/webui/dist/assets/index-9B5FcRm2.css +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/webui/dist/assets/index-CDG9HO3B.js +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/webui/dist/index.html +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/webui/history.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/webui/launch.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/webui/server.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/webui/session.py +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc.egg-info/dependency_links.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc.egg-info/entry_points.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc.egg-info/requires.txt +0 -0
- {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc.egg-info/top_level.txt +0 -0
micro_cc-0.2.79/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 George Salapa
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -1,28 +1,31 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: micro-cc
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.79
|
|
4
4
|
Summary: Harness that gives frontier models full system access — shell, filesystem, browser, MCP — running directly on the metal.
|
|
5
5
|
Author: George Salapa
|
|
6
|
-
License:
|
|
6
|
+
License: MIT License
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
confidential. No license, express or implied, is granted to any person
|
|
10
|
-
obtaining a copy of the Software.
|
|
8
|
+
Copyright (c) 2026 George Salapa
|
|
11
9
|
|
|
12
|
-
Permission
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
18
16
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
OTHER LIABILITY ARISING FROM THE USE OF THE SOFTWARE.
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
22
19
|
|
|
23
|
-
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
24
27
|
|
|
25
|
-
Classifier: License ::
|
|
28
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
26
29
|
Requires-Python: >=3.12
|
|
27
30
|
Description-Content-Type: text/markdown
|
|
28
31
|
License-File: LICENSE
|
|
@@ -197,4 +200,4 @@ Relative paths resolve to `project_dir`. Absolute paths work anywhere.
|
|
|
197
200
|
|
|
198
201
|
## License
|
|
199
202
|
|
|
200
|
-
|
|
203
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -4,13 +4,13 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "micro-cc"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.79"
|
|
8
8
|
description = "Harness that gives frontier models full system access — shell, filesystem, browser, MCP — running directly on the metal."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.12"
|
|
11
11
|
license = {file = "LICENSE"}
|
|
12
12
|
authors = [{name = "George Salapa"}]
|
|
13
|
-
classifiers = ["License ::
|
|
13
|
+
classifiers = ["License :: OSI Approved :: MIT License"]
|
|
14
14
|
|
|
15
15
|
dependencies = [
|
|
16
16
|
"anthropic>=0.76.0",
|
|
@@ -24,7 +24,8 @@ import os
|
|
|
24
24
|
import re
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
from micro_cc.
|
|
27
|
+
from micro_cc.models import model_call
|
|
28
|
+
from micro_cc.utils import settings_store_
|
|
28
29
|
|
|
29
30
|
|
|
30
31
|
class _CustomMarkdownify(markdownify.MarkdownConverter):
|
|
@@ -639,26 +640,18 @@ class ImageConverter(MediaConverter):
|
|
|
639
640
|
def _get_image_description(self, local_path, extension):
|
|
640
641
|
prompt = "Write a detailed caption for this image."
|
|
641
642
|
|
|
642
|
-
data_uri = ""
|
|
643
643
|
with open(local_path, "rb") as image_file:
|
|
644
|
-
content_type, encoding = mimetypes.guess_type("_dummy" + extension)
|
|
645
|
-
if content_type is None:
|
|
646
|
-
content_type = "image/jpeg"
|
|
647
644
|
image_base64 = base64.b64encode(image_file.read()).decode("utf-8")
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
else:
|
|
659
|
-
from micro_cc.models.anthropic import a_model_call
|
|
660
|
-
response = asyncio.run(a_model_call(input=prompt, encoded_image=data_uri))
|
|
661
|
-
return response.content[0].text
|
|
645
|
+
|
|
646
|
+
# Providers add their own image envelope; encoded_image is bare base64.
|
|
647
|
+
# Use the selected model rather than a Claude default on OpenAI/Ollama.
|
|
648
|
+
response = asyncio.run(model_call(
|
|
649
|
+
input=prompt, encoded_image=image_base64,
|
|
650
|
+
model=settings_store_.get_setting("model"),
|
|
651
|
+
))
|
|
652
|
+
if response is None:
|
|
653
|
+
return ""
|
|
654
|
+
return "\n".join(block.text for block in response.content if block.type == "text")
|
|
662
655
|
|
|
663
656
|
|
|
664
657
|
class FileConversionException(BaseException):
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import datetime
|
|
3
|
-
import json
|
|
4
3
|
import os
|
|
5
4
|
from functools import partial
|
|
6
5
|
|
|
@@ -8,6 +7,7 @@ from dotenv import load_dotenv
|
|
|
8
7
|
|
|
9
8
|
from micro_cc.cache.redis_cache import RedisStateManager
|
|
10
9
|
from micro_cc.execute_tool import execute_tool_call
|
|
10
|
+
from micro_cc.models import model_call
|
|
11
11
|
from micro_cc.models.registry import DEFAULT_MODEL, DEFAULT_TRIM_BUDGET
|
|
12
12
|
from micro_cc.utils.tool_limits import cap_for, MAX_TOOL_RESULTS_PER_MESSAGE
|
|
13
13
|
from micro_cc.utils.tool_result_storage import persist_and_preview
|
|
@@ -490,49 +490,14 @@ whole conversation history, including compacted turns.
|
|
|
490
490
|
)
|
|
491
491
|
|
|
492
492
|
try:
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
from micro_cc.models.ollama import o_model_call
|
|
502
|
-
stream = await o_model_call(
|
|
503
|
-
input=trimmed_loop_msgs,
|
|
504
|
-
model=model,
|
|
505
|
-
tools=tool_schemas,
|
|
506
|
-
thinking=True,
|
|
507
|
-
stream=True,
|
|
508
|
-
)
|
|
509
|
-
elif end_resp == "LiteLLM":
|
|
510
|
-
from micro_cc.models.litellm import l_model_call
|
|
511
|
-
stream = await l_model_call(
|
|
512
|
-
input=trimmed_loop_msgs,
|
|
513
|
-
model=model,
|
|
514
|
-
tools=tool_schemas,
|
|
515
|
-
thinking=True,
|
|
516
|
-
stream=True,
|
|
517
|
-
)
|
|
518
|
-
elif end_resp == "Foundry":
|
|
519
|
-
from micro_cc.models.foundry import f_model_call
|
|
520
|
-
stream = await f_model_call(
|
|
521
|
-
input=trimmed_loop_msgs,
|
|
522
|
-
model=model,
|
|
523
|
-
tools=tool_schemas,
|
|
524
|
-
thinking=True,
|
|
525
|
-
stream=True,
|
|
526
|
-
)
|
|
527
|
-
else:
|
|
528
|
-
from micro_cc.models.anthropic import a_model_call
|
|
529
|
-
stream = await a_model_call(
|
|
530
|
-
input=trimmed_loop_msgs,
|
|
531
|
-
model=model,
|
|
532
|
-
tools=tool_schemas,
|
|
533
|
-
thinking=True,
|
|
534
|
-
stream=True,
|
|
535
|
-
)
|
|
493
|
+
stream = await model_call(
|
|
494
|
+
input=trimmed_loop_msgs,
|
|
495
|
+
model=model,
|
|
496
|
+
endpoint=end_resp,
|
|
497
|
+
tools=tool_schemas,
|
|
498
|
+
thinking=True,
|
|
499
|
+
stream=True,
|
|
500
|
+
)
|
|
536
501
|
|
|
537
502
|
if stream is None:
|
|
538
503
|
yield {"type": "error", "message": "model call failed after retries"}
|
|
@@ -550,7 +515,15 @@ whole conversation history, including compacted turns.
|
|
|
550
515
|
api_usage = event.get("usage", {})
|
|
551
516
|
|
|
552
517
|
if api_usage.get("input"):
|
|
518
|
+
# "input": last call's context size (live ctx% readout —
|
|
519
|
+
# same snapshot semantics as real Claude Code's
|
|
520
|
+
# calculateContextPercentages). "total_input": running sum
|
|
521
|
+
# across every call this session (same as real Claude
|
|
522
|
+
# Code's cost-tracker.ts addToTotalModelUsage) — each turn
|
|
523
|
+
# is its own billed API request, so real spend is this
|
|
524
|
+
# sum, not the size of the most recent one alone.
|
|
553
525
|
token_stats["input"] = api_usage["input"]
|
|
526
|
+
token_stats["total_input"] += api_usage["input"]
|
|
554
527
|
if api_usage.get("output"):
|
|
555
528
|
token_stats["output"] += api_usage["output"]
|
|
556
529
|
if api_usage:
|
|
@@ -870,14 +843,6 @@ whole conversation history, including compacted turns.
|
|
|
870
843
|
# for this whole turn (final_text/done) to finish.
|
|
871
844
|
yield {"type": "turn_boundary"}
|
|
872
845
|
|
|
873
|
-
# # Post-tool nudge (lightweight user reminder, not full context)
|
|
874
|
-
# plan_data_post = redis_state.get_plan(project_dir)
|
|
875
|
-
# if plan_data_post:
|
|
876
|
-
# post_reminder = get_post_tool_plan_reminder(plan_data_post, all_blocks[0].name)
|
|
877
|
-
# msgs.append({"role": "user", "content": f"<system-reminder>{post_reminder}</system-reminder>"})
|
|
878
|
-
# else:
|
|
879
|
-
# msgs.append({"role": "user", "content": "<system-reminder>You just used a tool. Note what you found, then continue working silently — no narration needed.</system-reminder>"})
|
|
880
|
-
|
|
881
846
|
# No tool use = final response (text already streamed as deltas)
|
|
882
847
|
if not tool_use_blocks and text_block:
|
|
883
848
|
msgs.append({"role": "assistant", "content": text_block.text})
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"""Application model API. Provider SDKs are loaded only when called."""
|
|
2
|
+
|
|
3
|
+
from micro_cc.models.client import model_call
|
|
4
|
+
from micro_cc.models.types import ContentBlock, Response, ResponseStream, StreamEvent, Usage
|
|
5
|
+
|
|
6
|
+
__all__ = ["model_call", "ContentBlock", "Response", "ResponseStream", "StreamEvent", "Usage"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""SDK-output adapters. No credentials, requests, retries, or SDK imports here."""
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"""Anthropic Messages output (direct API and Foundry)."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
|
|
5
|
+
from micro_cc.models.types import ContentBlock, Response, ResponseStream
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def response(raw) -> Response:
|
|
9
|
+
"""Normalize usage while retaining SDK content blocks and their extra fields.
|
|
10
|
+
|
|
11
|
+
Content blocks already implement the application's attribute interface;
|
|
12
|
+
keeping them also preserves signed/redacted thinking without a lossy copy.
|
|
13
|
+
"""
|
|
14
|
+
usage = {}
|
|
15
|
+
u = getattr(raw, "usage", None)
|
|
16
|
+
if u:
|
|
17
|
+
usage = {
|
|
18
|
+
"input": (getattr(u, "input_tokens", 0)
|
|
19
|
+
+ getattr(u, "cache_read_input_tokens", 0)
|
|
20
|
+
+ getattr(u, "cache_creation_input_tokens", 0)),
|
|
21
|
+
"output": getattr(u, "output_tokens", 0),
|
|
22
|
+
}
|
|
23
|
+
return Response(content=raw.content, usage=usage)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
async def stream_response(raw_stream, unstealth=None) -> ResponseStream:
|
|
27
|
+
"""Iterate Anthropic SDK stream, yield standardized deltas + final Response.
|
|
28
|
+
|
|
29
|
+
unstealth: optional str->str applied to each tool_use block's name —
|
|
30
|
+
supplied by the direct provider for OAuth tool-name mapping. Foundry
|
|
31
|
+
and API-key calls leave it unset."""
|
|
32
|
+
text = ""
|
|
33
|
+
thinking = ""
|
|
34
|
+
thinking_signature = ""
|
|
35
|
+
tool_blocks = []
|
|
36
|
+
current_tool = None
|
|
37
|
+
usage = {}
|
|
38
|
+
|
|
39
|
+
async for event in raw_stream:
|
|
40
|
+
if event.type == "message_start":
|
|
41
|
+
u = getattr(event.message, "usage", None)
|
|
42
|
+
if u:
|
|
43
|
+
# input_tokens alone is only the NEW (uncached) tokens for this
|
|
44
|
+
# turn — with the rolling cache breakpoint above, most of the
|
|
45
|
+
# transcript is cache_read/cache_creation instead, so input_tokens
|
|
46
|
+
# drops to near-zero after turn 1. The true context size sent to
|
|
47
|
+
# the API is the sum of all three.
|
|
48
|
+
usage["input"] = (
|
|
49
|
+
getattr(u, "input_tokens", 0)
|
|
50
|
+
+ getattr(u, "cache_read_input_tokens", 0)
|
|
51
|
+
+ getattr(u, "cache_creation_input_tokens", 0)
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
elif event.type == "content_block_start":
|
|
55
|
+
if event.content_block.type == "tool_use":
|
|
56
|
+
current_tool = {"id": event.content_block.id, "name": event.content_block.name, "input_json": ""}
|
|
57
|
+
|
|
58
|
+
elif event.type == "content_block_delta":
|
|
59
|
+
if event.delta.type == "text_delta":
|
|
60
|
+
text += event.delta.text
|
|
61
|
+
yield {"type": "text_delta", "text": event.delta.text}
|
|
62
|
+
elif event.delta.type == "thinking_delta":
|
|
63
|
+
thinking += event.delta.thinking
|
|
64
|
+
yield {"type": "thinking_delta", "thinking": event.delta.thinking}
|
|
65
|
+
elif event.delta.type == "signature_delta":
|
|
66
|
+
thinking_signature += event.delta.signature or ""
|
|
67
|
+
elif event.delta.type == "input_json_delta":
|
|
68
|
+
if current_tool:
|
|
69
|
+
current_tool["input_json"] += event.delta.partial_json
|
|
70
|
+
|
|
71
|
+
elif event.type == "content_block_stop":
|
|
72
|
+
if current_tool:
|
|
73
|
+
args = json.loads(current_tool["input_json"]) if current_tool["input_json"] else {}
|
|
74
|
+
tool_blocks.append(current_tool | {"input": args})
|
|
75
|
+
current_tool = None
|
|
76
|
+
|
|
77
|
+
elif event.type == "message_delta":
|
|
78
|
+
u = getattr(event, "usage", None)
|
|
79
|
+
if u:
|
|
80
|
+
usage["output"] = getattr(u, "output_tokens", 0)
|
|
81
|
+
|
|
82
|
+
blocks = []
|
|
83
|
+
if thinking:
|
|
84
|
+
blocks.append(ContentBlock(type="thinking", thinking=thinking, signature=thinking_signature))
|
|
85
|
+
if text:
|
|
86
|
+
blocks.append(ContentBlock(type="text", text=text))
|
|
87
|
+
for tb in tool_blocks:
|
|
88
|
+
name = unstealth(tb["name"]) if unstealth else tb["name"]
|
|
89
|
+
blocks.append(ContentBlock(type="tool_use", name=name, input=tb["input"], id=tb["id"]))
|
|
90
|
+
|
|
91
|
+
yield {"type": "response", "response": Response(content=blocks, usage=usage), "usage": usage}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"""OpenAI Chat Completions output, including LiteLLM/Ollama reasoning.
|
|
2
|
+
|
|
3
|
+
The wire protocol is shared; only reasoning extraction varies by provider.
|
|
4
|
+
These functions consume streams in the caller's task without prefetch/retry.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
from typing import Literal
|
|
9
|
+
|
|
10
|
+
from micro_cc.models.types import ContentBlock, Response, ResponseStream, Usage
|
|
11
|
+
|
|
12
|
+
Reasoning = Literal["none", "litellm", "ollama"]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _reasoning_text(obj, reasoning: Reasoning) -> str:
|
|
16
|
+
if reasoning == "litellm":
|
|
17
|
+
return getattr(obj, "reasoning_content", None) or ""
|
|
18
|
+
if reasoning == "ollama":
|
|
19
|
+
text = getattr(obj, "reasoning", None)
|
|
20
|
+
if text:
|
|
21
|
+
return text
|
|
22
|
+
try:
|
|
23
|
+
return obj.model_dump().get("reasoning") or ""
|
|
24
|
+
except Exception:
|
|
25
|
+
return ""
|
|
26
|
+
return ""
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _usage(raw) -> Usage:
|
|
30
|
+
u = getattr(raw, "usage", None)
|
|
31
|
+
if not u:
|
|
32
|
+
return {}
|
|
33
|
+
return {
|
|
34
|
+
"input": getattr(u, "prompt_tokens", 0),
|
|
35
|
+
"output": getattr(u, "completion_tokens", 0),
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def response(raw, *, reasoning: Reasoning = "none") -> Response:
|
|
40
|
+
"""Normalize a completion, preserving LiteLLM's signed thinking block."""
|
|
41
|
+
msg = raw.choices[0].message
|
|
42
|
+
blocks = []
|
|
43
|
+
thinking_blocks = getattr(msg, "thinking_blocks", None) if reasoning == "litellm" else None
|
|
44
|
+
if thinking_blocks:
|
|
45
|
+
tb = thinking_blocks[0]
|
|
46
|
+
blocks.append(ContentBlock(
|
|
47
|
+
type="thinking",
|
|
48
|
+
thinking=tb.get("thinking", "") if isinstance(tb, dict) else getattr(tb, "thinking", ""),
|
|
49
|
+
signature=tb.get("signature", "") if isinstance(tb, dict) else getattr(tb, "signature", ""),
|
|
50
|
+
))
|
|
51
|
+
else:
|
|
52
|
+
text = _reasoning_text(msg, reasoning)
|
|
53
|
+
if text:
|
|
54
|
+
blocks.append(ContentBlock(type="thinking", thinking=text))
|
|
55
|
+
|
|
56
|
+
if msg.content:
|
|
57
|
+
blocks.append(ContentBlock(type="text", text=msg.content))
|
|
58
|
+
for tc in msg.tool_calls or []:
|
|
59
|
+
try:
|
|
60
|
+
args = json.loads(tc.function.arguments)
|
|
61
|
+
except (json.JSONDecodeError, TypeError):
|
|
62
|
+
args = {}
|
|
63
|
+
blocks.append(ContentBlock(type="tool_use", name=tc.function.name, input=args, id=tc.id))
|
|
64
|
+
return Response(content=blocks, usage=_usage(raw))
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
async def stream_response(raw_stream, *, reasoning: Reasoning = "none") -> ResponseStream:
|
|
68
|
+
"""Yield deltas as received, then one response with assembled tool calls."""
|
|
69
|
+
text = ""
|
|
70
|
+
thinking = ""
|
|
71
|
+
tool_calls = {} # index -> {id, name, args}; insertion order is call order
|
|
72
|
+
usage = {}
|
|
73
|
+
|
|
74
|
+
async for chunk in raw_stream:
|
|
75
|
+
# include_usage may produce a choices=[] trailer on any chat backend.
|
|
76
|
+
usage.update(_usage(chunk))
|
|
77
|
+
if not chunk.choices:
|
|
78
|
+
continue
|
|
79
|
+
delta = chunk.choices[0].delta
|
|
80
|
+
if delta.content:
|
|
81
|
+
text += delta.content
|
|
82
|
+
yield {"type": "text_delta", "text": delta.content}
|
|
83
|
+
rc = _reasoning_text(delta, reasoning)
|
|
84
|
+
if rc:
|
|
85
|
+
thinking += rc
|
|
86
|
+
yield {"type": "thinking_delta", "thinking": rc}
|
|
87
|
+
for tc in delta.tool_calls or []:
|
|
88
|
+
if tc.index not in tool_calls:
|
|
89
|
+
tool_calls[tc.index] = {
|
|
90
|
+
"id": tc.id or "",
|
|
91
|
+
"name": tc.function.name if tc.function else "",
|
|
92
|
+
"args": "",
|
|
93
|
+
}
|
|
94
|
+
if tc.function and tc.function.arguments:
|
|
95
|
+
tool_calls[tc.index]["args"] += tc.function.arguments
|
|
96
|
+
|
|
97
|
+
blocks = []
|
|
98
|
+
if thinking:
|
|
99
|
+
blocks.append(ContentBlock(type="thinking", thinking=thinking))
|
|
100
|
+
if text:
|
|
101
|
+
blocks.append(ContentBlock(type="text", text=text))
|
|
102
|
+
for tc in tool_calls.values():
|
|
103
|
+
# As before, malformed streamed arguments fail rather than execute a
|
|
104
|
+
# partial call with invented arguments. No retry after visible deltas.
|
|
105
|
+
args = json.loads(tc["args"]) if tc["args"] else {}
|
|
106
|
+
blocks.append(ContentBlock(type="tool_use", name=tc["name"], input=args, id=tc["id"]))
|
|
107
|
+
result = Response(content=blocks, usage=usage)
|
|
108
|
+
yield {"type": "response", "response": result, "usage": usage}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"""OpenAI Responses output (direct API and LiteLLM)."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
|
|
5
|
+
from micro_cc.models.types import ContentBlock, Response, ResponseStream
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def response(resp) -> Response:
|
|
9
|
+
"""Normalize a Responses API result, including non-stream usage."""
|
|
10
|
+
blocks = []
|
|
11
|
+
for item in resp.output:
|
|
12
|
+
if item.type == "reasoning":
|
|
13
|
+
summary = getattr(item, "summary", None) or []
|
|
14
|
+
text = "\n".join(getattr(s, "text", "") for s in summary)
|
|
15
|
+
if text:
|
|
16
|
+
blocks.append(ContentBlock(type="thinking", thinking=text))
|
|
17
|
+
elif item.type == "message":
|
|
18
|
+
for part in item.content:
|
|
19
|
+
if getattr(part, "type", None) == "output_text":
|
|
20
|
+
blocks.append(ContentBlock(type="text", text=part.text))
|
|
21
|
+
elif item.type == "function_call":
|
|
22
|
+
try:
|
|
23
|
+
args = json.loads(item.arguments)
|
|
24
|
+
except (json.JSONDecodeError, TypeError):
|
|
25
|
+
args = {}
|
|
26
|
+
blocks.append(ContentBlock(
|
|
27
|
+
type="tool_use", name=item.name, input=args, id=item.call_id,
|
|
28
|
+
))
|
|
29
|
+
|
|
30
|
+
usage = {}
|
|
31
|
+
u = getattr(resp, "usage", None)
|
|
32
|
+
if u:
|
|
33
|
+
usage["input"] = getattr(u, "input_tokens", 0)
|
|
34
|
+
usage["output"] = getattr(u, "output_tokens", 0)
|
|
35
|
+
return Response(content=blocks, usage=usage)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
async def stream_response(resp_stream) -> ResponseStream:
|
|
39
|
+
"""Accumulate Responses API stream events, yield Anthropic-shaped
|
|
40
|
+
events, return final Response with ContentBlocks."""
|
|
41
|
+
text = ""
|
|
42
|
+
thinking = ""
|
|
43
|
+
tool_calls = []
|
|
44
|
+
usage = {}
|
|
45
|
+
|
|
46
|
+
async for ev in resp_stream:
|
|
47
|
+
et = ev.type
|
|
48
|
+
if et == "response.output_text.delta":
|
|
49
|
+
text += ev.delta
|
|
50
|
+
yield {"type": "text_delta", "text": ev.delta}
|
|
51
|
+
elif et == "response.reasoning_summary_text.delta":
|
|
52
|
+
thinking += ev.delta
|
|
53
|
+
yield {"type": "thinking_delta", "thinking": ev.delta}
|
|
54
|
+
elif et == "response.output_item.done" and getattr(ev.item, "type", None) == "function_call":
|
|
55
|
+
tool_calls.append(ev.item)
|
|
56
|
+
elif et == "response.completed":
|
|
57
|
+
u = ev.response.usage
|
|
58
|
+
if u:
|
|
59
|
+
usage["input"] = getattr(u, "input_tokens", 0)
|
|
60
|
+
usage["output"] = getattr(u, "output_tokens", 0)
|
|
61
|
+
|
|
62
|
+
blocks = []
|
|
63
|
+
if thinking:
|
|
64
|
+
blocks.append(ContentBlock(type="thinking", thinking=thinking))
|
|
65
|
+
if text:
|
|
66
|
+
blocks.append(ContentBlock(type="text", text=text))
|
|
67
|
+
for tc in tool_calls:
|
|
68
|
+
try:
|
|
69
|
+
args = json.loads(tc.arguments)
|
|
70
|
+
except (json.JSONDecodeError, TypeError):
|
|
71
|
+
args = {}
|
|
72
|
+
blocks.append(ContentBlock(type="tool_use", name=tc.name, input=args, id=tc.call_id))
|
|
73
|
+
|
|
74
|
+
yield {"type": "response", "response": Response(content=blocks, usage=usage), "usage": usage}
|