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.
Files changed (223) hide show
  1. micro_cc-0.2.79/LICENSE +21 -0
  2. {micro_cc-0.2.78/src/micro_cc.egg-info → micro_cc-0.2.79}/PKG-INFO +20 -17
  3. {micro_cc-0.2.78 → micro_cc-0.2.79}/README.md +1 -1
  4. {micro_cc-0.2.78 → micro_cc-0.2.79}/pyproject.toml +2 -2
  5. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/browser/_md_convert.py +12 -19
  6. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/claude_loop_.py +17 -52
  7. micro_cc-0.2.79/src/micro_cc/models/__init__.py +6 -0
  8. micro_cc-0.2.79/src/micro_cc/models/adapters/__init__.py +1 -0
  9. micro_cc-0.2.79/src/micro_cc/models/adapters/anthropic.py +91 -0
  10. micro_cc-0.2.79/src/micro_cc/models/adapters/chat.py +108 -0
  11. micro_cc-0.2.79/src/micro_cc/models/adapters/responses.py +74 -0
  12. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/models/anthropic.py +42 -119
  13. micro_cc-0.2.79/src/micro_cc/models/client.py +65 -0
  14. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/models/foundry.py +2 -87
  15. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/models/litellm.py +20 -236
  16. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/models/ollama.py +9 -166
  17. micro_cc-0.2.79/src/micro_cc/models/openai.py +564 -0
  18. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/models/registry.py +17 -10
  19. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/models/schema.py +22 -0
  20. micro_cc-0.2.79/src/micro_cc/models/types.py +53 -0
  21. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/graph-orchestration/SKILL.md +12 -1
  22. micro_cc-0.2.79/src/micro_cc/skills/system-design-review/REFERENCE.md +174 -0
  23. micro_cc-0.2.79/src/micro_cc/skills/system-design-review/SKILL.md +161 -0
  24. micro_cc-0.2.79/src/micro_cc/skills/system-design-review/scripts/design_graph.py +290 -0
  25. micro_cc-0.2.79/src/micro_cc/skills/system-design-review/scripts/design_review.py +528 -0
  26. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/start_headless_.py +6 -1
  27. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/start_live_tui_.py +51 -20
  28. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tools/bash_tool.py +76 -1
  29. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tools/file_tools_.py +2 -2
  30. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tools/monitor_.py +34 -5
  31. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tools/monitor_watch_.py +7 -10
  32. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tools/vision_tools_.py +6 -28
  33. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/alt_screen_.py +16 -6
  34. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/detect_images_.py +29 -40
  35. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/diff_viewer_.py +2 -3
  36. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/etype_handler_.py +2 -3
  37. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/keys_.py +27 -33
  38. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/kill_ring_.py +6 -10
  39. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/list_picker_.py +3 -7
  40. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/message_row_.py +31 -43
  41. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/prompt_input_.py +7 -9
  42. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/screen_cmds_.py +1 -1
  43. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/stack_.py +23 -30
  44. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/stdin_buffer_.py +16 -21
  45. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/terminal_.py +16 -30
  46. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/text_.py +28 -32
  47. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/text_utils_.py +10 -12
  48. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/theme_.py +3 -4
  49. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/truncated_text_.py +7 -9
  50. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/undo_stack_.py +7 -10
  51. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/word_navigation_.py +10 -28
  52. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/claude_subscription.py +10 -12
  53. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/helpers.py +22 -7
  54. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/msg_store_.py +29 -58
  55. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/pg_store_.py +53 -5
  56. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/subagent_tracker_.py +29 -3
  57. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/tokenization_simple.py +81 -13
  58. {micro_cc-0.2.78 → micro_cc-0.2.79/src/micro_cc.egg-info}/PKG-INFO +20 -17
  59. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc.egg-info/SOURCES.txt +14 -6
  60. micro_cc-0.2.79/tests/test_model_consumers.py +168 -0
  61. micro_cc-0.2.79/tests/test_models.py +412 -0
  62. micro_cc-0.2.78/LICENSE +0 -18
  63. micro_cc-0.2.78/src/micro_cc/code_test/run_token_cutter.py +0 -61
  64. micro_cc-0.2.78/src/micro_cc/code_test/test_messages.py +0 -127
  65. micro_cc-0.2.78/src/micro_cc/skills/autoresearch/SKILL.md +0 -69
  66. micro_cc-0.2.78/src/micro_cc/start_watch_.py +0 -104
  67. micro_cc-0.2.78/src/micro_cc/utils/__init__.py +0 -0
  68. micro_cc-0.2.78/src/micro_cc/webui/__init__.py +0 -0
  69. {micro_cc-0.2.78 → micro_cc-0.2.79}/setup.cfg +0 -0
  70. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/__init__.py +0 -0
  71. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/browser/__init__.py +0 -0
  72. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/browser/_cookies.py +0 -0
  73. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/browser/browser_manager.py +0 -0
  74. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/browser/simpletextbrowser.py +0 -0
  75. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/cache/__init__.py +0 -0
  76. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/cache/redis_cache.py +0 -0
  77. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/execute_tool.py +0 -0
  78. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/SKILL.md +0 -0
  79. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/ArsenalSC-OFL.txt +0 -0
  80. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/ArsenalSC-Regular.ttf +0 -0
  81. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/BigShoulders-Bold.ttf +0 -0
  82. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/BigShoulders-OFL.txt +0 -0
  83. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/BigShoulders-Regular.ttf +0 -0
  84. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Boldonse-OFL.txt +0 -0
  85. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Boldonse-Regular.ttf +0 -0
  86. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
  87. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/BricolageGrotesque-OFL.txt +0 -0
  88. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
  89. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/CrimsonPro-Bold.ttf +0 -0
  90. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/CrimsonPro-Italic.ttf +0 -0
  91. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/CrimsonPro-OFL.txt +0 -0
  92. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/CrimsonPro-Regular.ttf +0 -0
  93. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/DMMono-OFL.txt +0 -0
  94. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/DMMono-Regular.ttf +0 -0
  95. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/EricaOne-OFL.txt +0 -0
  96. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/EricaOne-Regular.ttf +0 -0
  97. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/GeistMono-Bold.ttf +0 -0
  98. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/GeistMono-OFL.txt +0 -0
  99. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/GeistMono-Regular.ttf +0 -0
  100. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Gloock-OFL.txt +0 -0
  101. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Gloock-Regular.ttf +0 -0
  102. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/IBMPlexMono-Bold.ttf +0 -0
  103. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/IBMPlexMono-OFL.txt +0 -0
  104. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/IBMPlexMono-Regular.ttf +0 -0
  105. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/IBMPlexSerif-Bold.ttf +0 -0
  106. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/IBMPlexSerif-BoldItalic.ttf +0 -0
  107. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/IBMPlexSerif-Italic.ttf +0 -0
  108. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/IBMPlexSerif-Regular.ttf +0 -0
  109. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
  110. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
  111. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
  112. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/InstrumentSans-OFL.txt +0 -0
  113. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
  114. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
  115. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
  116. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Italiana-OFL.txt +0 -0
  117. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Italiana-Regular.ttf +0 -0
  118. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
  119. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/JetBrainsMono-OFL.txt +0 -0
  120. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
  121. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Jura-Light.ttf +0 -0
  122. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Jura-Medium.ttf +0 -0
  123. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Jura-OFL.txt +0 -0
  124. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/LibreBaskerville-OFL.txt +0 -0
  125. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/LibreBaskerville-Regular.ttf +0 -0
  126. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Lora-Bold.ttf +0 -0
  127. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Lora-BoldItalic.ttf +0 -0
  128. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Lora-Italic.ttf +0 -0
  129. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Lora-OFL.txt +0 -0
  130. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Lora-Regular.ttf +0 -0
  131. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/NationalPark-Bold.ttf +0 -0
  132. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/NationalPark-OFL.txt +0 -0
  133. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/NationalPark-Regular.ttf +0 -0
  134. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/NothingYouCouldDo-OFL.txt +0 -0
  135. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
  136. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Outfit-Bold.ttf +0 -0
  137. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Outfit-OFL.txt +0 -0
  138. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Outfit-Regular.ttf +0 -0
  139. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/PixelifySans-Medium.ttf +0 -0
  140. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/PixelifySans-OFL.txt +0 -0
  141. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/PoiretOne-OFL.txt +0 -0
  142. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/PoiretOne-Regular.ttf +0 -0
  143. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/RedHatMono-Bold.ttf +0 -0
  144. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/RedHatMono-OFL.txt +0 -0
  145. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/RedHatMono-Regular.ttf +0 -0
  146. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Silkscreen-OFL.txt +0 -0
  147. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Silkscreen-Regular.ttf +0 -0
  148. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/SmoochSans-Medium.ttf +0 -0
  149. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/SmoochSans-OFL.txt +0 -0
  150. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Tektur-Medium.ttf +0 -0
  151. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Tektur-OFL.txt +0 -0
  152. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/Tektur-Regular.ttf +0 -0
  153. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/WorkSans-Bold.ttf +0 -0
  154. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/WorkSans-BoldItalic.ttf +0 -0
  155. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/WorkSans-Italic.ttf +0 -0
  156. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/WorkSans-OFL.txt +0 -0
  157. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/WorkSans-Regular.ttf +0 -0
  158. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/YoungSerif-OFL.txt +0 -0
  159. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/canvas-fonts/YoungSerif-Regular.ttf +0 -0
  160. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/design/references/blueprint-tokens.md +0 -0
  161. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/github/SKILL.md +0 -0
  162. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/pptx/SKILL.md +0 -0
  163. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/pptx/brief.md +0 -0
  164. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/pptx/scripts/build_deck.js +0 -0
  165. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/pptx/scripts/deck_to_images.py +0 -0
  166. {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
  167. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/pptx/scripts/office/soffice.py +0 -0
  168. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/pptx/scripts/render_svg.py +0 -0
  169. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/pptx/svg-slides.md +0 -0
  170. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/skill_loader.py +0 -0
  171. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/skills/xlsx/SKILL.md +0 -0
  172. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/start_batch_.py +0 -0
  173. {micro_cc-0.2.78/src/micro_cc/models → micro_cc-0.2.79/src/micro_cc/tools}/__init__.py +0 -0
  174. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tools/ask_user_tool.py +0 -0
  175. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tools/browser_tool_.py +0 -0
  176. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tools/computer_tool_.py +0 -0
  177. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tools/mcp_client_.py +0 -0
  178. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tools/memory_tool_.py +0 -0
  179. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tools/message_session_.py +0 -0
  180. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tools/search_history_tool_.py +0 -0
  181. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tools/search_tool_.py +0 -0
  182. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tools/skill_tools_.py +0 -0
  183. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tools/todo_tools_.py +0 -0
  184. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tools/web_tools_.py +0 -0
  185. {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
  186. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/md_render_.py +0 -0
  187. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/multi_select_list_.py +0 -0
  188. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/question_panel_.py +0 -0
  189. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/scroll_view_.py +0 -0
  190. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/self_terminal_setup_.py +0 -0
  191. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/tui_native/self_update_.py +0 -0
  192. {micro_cc-0.2.78/src/micro_cc/tools → micro_cc-0.2.79/src/micro_cc/utils}/__init__.py +0 -0
  193. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/annotate_.py +0 -0
  194. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/banner_.py +0 -0
  195. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/claude_md_loader.py +0 -0
  196. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/command_registry.py +0 -0
  197. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/default_status_sh.py +0 -0
  198. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/hidden_prompts.py +0 -0
  199. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/hints.py +0 -0
  200. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/history_mount_.py +0 -0
  201. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/inbox_store_.py +0 -0
  202. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/memory_store_.py +0 -0
  203. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/msg_normalize_.py +0 -0
  204. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/project_files_.py +0 -0
  205. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/session_ipc_.py +0 -0
  206. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/settings_store_.py +0 -0
  207. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/status_marker.py +0 -0
  208. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/terminal_setup.py +0 -0
  209. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/tool_limits.py +0 -0
  210. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/utils/tool_result_storage.py +0 -0
  211. {micro_cc-0.2.78/src/micro_cc/tui_native → micro_cc-0.2.79/src/micro_cc/webui}/__init__.py +0 -0
  212. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/webui/bridge.py +0 -0
  213. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/webui/dist/assets/index-9B5FcRm2.css +0 -0
  214. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/webui/dist/assets/index-CDG9HO3B.js +0 -0
  215. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/webui/dist/index.html +0 -0
  216. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/webui/history.py +0 -0
  217. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/webui/launch.py +0 -0
  218. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/webui/server.py +0 -0
  219. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc/webui/session.py +0 -0
  220. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc.egg-info/dependency_links.txt +0 -0
  221. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc.egg-info/entry_points.txt +0 -0
  222. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc.egg-info/requires.txt +0 -0
  223. {micro_cc-0.2.78 → micro_cc-0.2.79}/src/micro_cc.egg-info/top_level.txt +0 -0
@@ -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.78
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: Copyright (c) 2026 George Salapa. All rights reserved.
6
+ License: MIT License
7
7
 
8
- This software and associated source code ("Software") are proprietary and
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 to install and run the Software via its published package
13
- (e.g. from PyPI) for personal or internal business use is granted, provided
14
- that this permission does not extend to copying, modifying, merging,
15
- publishing, distributing, sublicensing, forking, decompiling, reverse
16
- engineering, or creating derivative works of the Software, in whole or in
17
- part, without prior written permission from the copyright holder.
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
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
- IMPLIED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES, OR
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
- Interested in collaborating? george@salapa.xyz
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 :: Other/Proprietary 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
- Proprietary — all rights reserved.
203
+ MIT — see [LICENSE](LICENSE).
@@ -133,4 +133,4 @@ Relative paths resolve to `project_dir`. Absolute paths work anywhere.
133
133
 
134
134
  ## License
135
135
 
136
- Proprietary — all rights reserved.
136
+ 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.78"
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 :: Other/Proprietary 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.utils.helpers import get_endpoint
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
- data_uri = f"data:{content_type};base64,{image_base64}"
649
-
650
- endpoint = get_endpoint()
651
- # Lazy-imported per-branch — see claude_loop_.py's dispatch for why.
652
- if endpoint == "LiteLLM":
653
- from micro_cc.models.litellm import l_model_call
654
- response = asyncio.run(l_model_call(input=prompt, encoded_image=data_uri))
655
- elif endpoint == "Foundry":
656
- from micro_cc.models.foundry import f_model_call
657
- response = asyncio.run(f_model_call(input=prompt, encoded_image=data_uri))
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
- # Imported lazily, per-branch: anthropic/openai are the two
494
- # heaviest imports in the whole app (pydantic building hundreds
495
- # of response-type models — see search_tool_.py's own lazy
496
- # AsyncOpenAI import for the same reason). Only one backend is
497
- # ever active per session, so eagerly importing all four at
498
- # module load (as this used to) paid for both SDKs on every
499
- # startup no matter which endpoint was actually configured.
500
- if end_resp == "Ollama":
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}