echotools 2.3.104__tar.gz → 2.4.1__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 (269) hide show
  1. {echotools-2.3.104 → echotools-2.4.1}/PKG-INFO +74 -23
  2. echotools-2.4.1/README.md +139 -0
  3. {echotools-2.3.104 → echotools-2.4.1}/pyproject.toml +1 -2
  4. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/__init__.py +0 -3
  5. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/__init__.py +0 -6
  6. echotools-2.4.1/src/echotools/exec/fncall/parsers/__init__.py +5 -0
  7. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/parsers/stream_final.py +0 -4
  8. echotools-2.4.1/src/echotools/exec/fncall/prompt/behavior_blocks.py +124 -0
  9. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/prompt/history.py +3 -1
  10. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/prompt/inject.py +1 -1
  11. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/protocols/entml.py +5 -11
  12. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/protocols/entml_patterns/__init__.py +5 -6
  13. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/protocols/entml_patterns/regex.py +0 -8
  14. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/protocols/entml_patterns/strip.py +1 -12
  15. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/protocols/entml_think/core.py +9 -4
  16. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/protocols/entml_tool/__init__.py +0 -4
  17. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/protocols/entml_tool/invoke.py +0 -13
  18. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/registry.py +1 -39
  19. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/shared/entml_format.py +1 -1
  20. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/console/ui.py +1 -1
  21. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/console/uilayout/ui_bridge.py +0 -1
  22. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/console/uiwidgets/ui_themes.py +2 -4
  23. {echotools-2.3.104 → echotools-2.4.1}/src/echotools.egg-info/PKG-INFO +74 -23
  24. {echotools-2.3.104 → echotools-2.4.1}/src/echotools.egg-info/SOURCES.txt +0 -5
  25. {echotools-2.3.104 → echotools-2.4.1}/src/tests/_check_parity.py +5 -2
  26. {echotools-2.3.104 → echotools-2.4.1}/src/tests/fixtures/entml_golden.py +5 -6
  27. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_console.py +0 -7
  28. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_entml_golden.py +0 -1
  29. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_entml_parser_comprehensive.py +3 -2
  30. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_entml_protocol.py +44 -33
  31. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_entml_tool_pipeline.py +8 -7
  32. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_fncall.py +4 -9
  33. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_imports.py +2 -14
  34. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_ui_bridge.py +1 -4
  35. echotools-2.3.104/README.md +0 -88
  36. echotools-2.3.104/src/echotools/compat.py +0 -88
  37. echotools-2.3.104/src/echotools/exec/fncall/parsers/__init__.py +0 -6
  38. echotools-2.3.104/src/echotools/exec/fncall/parsers/xml_params.py +0 -40
  39. echotools-2.3.104/src/echotools/exec/fncall/parsers/xml_parser.py +0 -285
  40. echotools-2.3.104/src/echotools/exec/fncall/prompt/behavior_blocks.py +0 -69
  41. echotools-2.3.104/src/echotools/exec/fncall/protocols/entml_think/blocks.py +0 -362
  42. echotools-2.3.104/src/echotools/exec/fncall/protocols/entml_tool/blocks.py +0 -363
  43. {echotools-2.3.104 → echotools-2.4.1}/setup.cfg +0 -0
  44. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/base/cache/__init__.py +0 -0
  45. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/base/cache/list_cache.py +0 -0
  46. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/base/cache/memory_cache.py +0 -0
  47. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/base/config/__init__.py +0 -0
  48. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/base/config/base.py +0 -0
  49. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/base/config/center.py +0 -0
  50. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/base/config/center_notify.py +0 -0
  51. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/base/config/center_template.py +0 -0
  52. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/base/config/loader.py +0 -0
  53. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/base/config/merge.py +0 -0
  54. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/base/errors/__init__.py +0 -0
  55. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/base/errors/base.py +0 -0
  56. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/base/errors/classify.py +0 -0
  57. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/base/errors/common.py +0 -0
  58. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/base/errors/http.py +0 -0
  59. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/base/ids/__init__.py +0 -0
  60. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/base/ids/generator.py +0 -0
  61. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/base/io/__init__.py +0 -0
  62. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/base/io/io_utils.py +0 -0
  63. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/base/io/printstream.py +0 -0
  64. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/base/logger/__init__.py +0 -0
  65. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/base/logger/manager.py +0 -0
  66. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/base/retry/__init__.py +0 -0
  67. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/base/retry/retry.py +0 -0
  68. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/dispatch/__init__.py +0 -0
  69. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/dispatch/candidate.py +0 -0
  70. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/dispatch/dispatcher.py +0 -0
  71. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/dispatch/proxy_selector.py +0 -0
  72. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/dispatch/race.py +0 -0
  73. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/dispatch/selector.py +0 -0
  74. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/dispatch/usage.py +0 -0
  75. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/parsers/stream.py +0 -0
  76. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/parsers/stream_delta.py +0 -0
  77. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/parsers/stream_feed.py +0 -0
  78. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/prompt/__init__.py +0 -0
  79. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/prompt/history_format.py +0 -0
  80. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/prompt/prompt_helpers.py +0 -0
  81. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/prompt/templates.py +0 -0
  82. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/protocols/__init__.py +0 -0
  83. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/protocols/entml_patterns/invoke.py +0 -0
  84. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/protocols/entml_patterns/params.py +0 -0
  85. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/protocols/entml_schema/__init__.py +0 -0
  86. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/protocols/entml_schema/mangled.py +0 -0
  87. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/protocols/entml_stream/__init__.py +0 -0
  88. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/protocols/entml_stream/body.py +0 -0
  89. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/protocols/entml_stream/snap.py +0 -0
  90. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/protocols/entml_think/__init__.py +0 -0
  91. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/protocols/entml_think/filter.py +0 -0
  92. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/protocols/entml_think/hist.py +0 -0
  93. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/protocols/entml_think/hold.py +0 -0
  94. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/protocols/entml_think/parse.py +0 -0
  95. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/protocols/entml_tool/comment.py +0 -0
  96. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/protocols/entml_tool/fakemarkup.py +0 -0
  97. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/protocols/entml_tool/tools.py +0 -0
  98. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/protocols/entml_tool/values.py +0 -0
  99. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/shared/__init__.py +0 -0
  100. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/shared/coercion.py +0 -0
  101. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/shared/history_markup.py +0 -0
  102. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/shared/loop_detect.py +0 -0
  103. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/shared/normalization.py +0 -0
  104. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/fncall/shared/schema_render.py +0 -0
  105. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/keys.py +0 -0
  106. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/lifecycle/__init__.py +0 -0
  107. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/lifecycle/manager.py +0 -0
  108. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/lifecycle/updater.py +0 -0
  109. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/lifecycle/updater_pull.py +0 -0
  110. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/process/__init__.py +0 -0
  111. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/process/port.py +0 -0
  112. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/protocol/__init__.py +0 -0
  113. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/protocol/base.py +0 -0
  114. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/terminal/__init__.py +0 -0
  115. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/terminal/conpty.py +0 -0
  116. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/terminal/local/__init__.py +0 -0
  117. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/terminal/local/core.py +0 -0
  118. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/terminal/local/proc.py +0 -0
  119. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/terminal/local/unix.py +0 -0
  120. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/terminal/local/win.py +0 -0
  121. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/terminal/sanitize.py +0 -0
  122. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/terminal/session/__init__.py +0 -0
  123. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/terminal/session/base.py +0 -0
  124. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/terminal/session/client.py +0 -0
  125. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/terminal/ssh.py +0 -0
  126. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/exec/terminal/tmux.py +0 -0
  127. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/console/__init__.py +0 -0
  128. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/console/charmap.py +0 -0
  129. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/console/spinner.py +0 -0
  130. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/console/uicore/mixins/__init__.py +0 -0
  131. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/console/uicore/mixins/uibase.py +0 -0
  132. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/console/uicore/mixins/uicmds.py +0 -0
  133. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/console/uicore/mixins/uiinteract.py +0 -0
  134. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/console/uicore/mixins/uioutput.py +0 -0
  135. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/console/uicore/mixins/uistream.py +0 -0
  136. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/console/uicore/ui_console.py +0 -0
  137. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/console/uicore/ui_io.py +0 -0
  138. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/console/uicore/ui_log.py +0 -0
  139. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/console/uicore/ui_platform.py +0 -0
  140. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/console/uicore/ui_text.py +0 -0
  141. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/console/uicore/ui_types.py +0 -0
  142. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/console/uilayout/ui_countdown.py +0 -0
  143. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/console/uilayout/ui_layout.py +0 -0
  144. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/console/uilayout/ui_misc.py +0 -0
  145. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/console/uilayout/ui_panel.py +0 -0
  146. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/console/uilayout/ui_table.py +0 -0
  147. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/console/uilayout/ui_tree.py +0 -0
  148. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/console/uiwidgets/ui_box.py +0 -0
  149. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/console/uiwidgets/ui_editor.py +0 -0
  150. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/console/uiwidgets/ui_progress.py +0 -0
  151. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/console/uiwidgets/ui_richcli.py +0 -0
  152. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/console/uiwidgets/ui_select.py +0 -0
  153. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/console/uiwidgets/ui_stream.py +0 -0
  154. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/events/__init__.py +0 -0
  155. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/events/bus.py +0 -0
  156. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/events/event.py +0 -0
  157. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/spinner/__init__.py +0 -0
  158. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/spinner/spinner.py +0 -0
  159. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/spinner/spinner_color.py +0 -0
  160. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/tracing/__init__.py +0 -0
  161. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/tracing/context.py +0 -0
  162. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/tracing/span.py +0 -0
  163. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/tracing/tracer.py +0 -0
  164. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/translate.py +0 -0
  165. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/watcher/__init__.py +0 -0
  166. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/watcher/file_watcher.py +0 -0
  167. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/web/__init__.py +0 -0
  168. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/web/application.py +0 -0
  169. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/web/broker.py +0 -0
  170. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/web/input_box/app.js +0 -0
  171. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/web/input_box/components/filezone.js +0 -0
  172. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/web/input_box/components/motionkit.js +0 -0
  173. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/web/input_box/components/sendbutton.js +0 -0
  174. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/web/input_box/components/sortablelist.css +0 -0
  175. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/web/input_box/components/sortablelist.js +0 -0
  176. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/web/input_box/components/textinput.js +0 -0
  177. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/web/input_box/components/voiceinput.js +0 -0
  178. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/web/input_box/fonts/inter-500.woff2 +0 -0
  179. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/web/input_box/fonts/inter-600.woff2 +0 -0
  180. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/web/input_box/fonts/inter400.woff2 +0 -0
  181. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/web/input_box/inputbox.css +0 -0
  182. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/web/input_box/inputbox.js +0 -0
  183. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/web/input_box/style.css +0 -0
  184. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/web/input_box/voicegif.js +0 -0
  185. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/web/middleware.py +0 -0
  186. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/web/stats.py +0 -0
  187. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/media/web/utils.py +0 -0
  188. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/plat/files/__init__.py +0 -0
  189. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/plat/files/file_util.py +0 -0
  190. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/plat/network/__init__.py +0 -0
  191. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/plat/network/http_utils.py +0 -0
  192. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/plat/plugin/__init__.py +0 -0
  193. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/plat/plugin/base.py +0 -0
  194. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/plat/plugin/discovery.py +0 -0
  195. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/plat/plugin/registry.py +0 -0
  196. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/plat/plugin/registry_ops.py +0 -0
  197. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/plat/proxy/__init__.py +0 -0
  198. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/plat/proxy/manager.py +0 -0
  199. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/plat/runtime/__init__.py +0 -0
  200. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/plat/runtime/collector.py +0 -0
  201. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/plat/scheduler/__init__.py +0 -0
  202. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/plat/scheduler/scheduler.py +0 -0
  203. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/plat/sdk/__init__.py +0 -0
  204. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/plat/sdk/facade.py +0 -0
  205. {echotools-2.3.104 → echotools-2.4.1}/src/echotools/version.py +0 -0
  206. {echotools-2.3.104 → echotools-2.4.1}/src/echotools.egg-info/dependency_links.txt +0 -0
  207. {echotools-2.3.104 → echotools-2.4.1}/src/echotools.egg-info/requires.txt +0 -0
  208. {echotools-2.3.104 → echotools-2.4.1}/src/echotools.egg-info/top_level.txt +0 -0
  209. {echotools-2.3.104 → echotools-2.4.1}/src/tests/bench_import.py +0 -0
  210. {echotools-2.3.104 → echotools-2.4.1}/src/tests/conftest.py +0 -0
  211. {echotools-2.3.104 → echotools-2.4.1}/src/tests/fixtures/__init__.py +0 -0
  212. {echotools-2.3.104 → echotools-2.4.1}/src/tests/fixtures/entml_golden_update.py +0 -0
  213. {echotools-2.3.104 → echotools-2.4.1}/src/tests/fixtures/simulated_fake_history_markup_responses.py +0 -0
  214. {echotools-2.3.104 → echotools-2.4.1}/src/tests/fixtures/simulated_fault_thinking_responses.py +0 -0
  215. {echotools-2.3.104 → echotools-2.4.1}/src/tests/fixtures/simulated_llm_tool_responses.py +0 -0
  216. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_adversarial_stream_splits.py +0 -0
  217. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_cache_retry.py +0 -0
  218. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_completion.py +0 -0
  219. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_config.py +0 -0
  220. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_config_extended.py +0 -0
  221. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_coverage_core.py +0 -0
  222. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_dispatch.py +0 -0
  223. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_dispatch_extended.py +0 -0
  224. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_dispatch_race.py +0 -0
  225. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_entml_agent_output_formats.py +0 -0
  226. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_entml_bare_invoke_format.py +1 -1
  227. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_entml_batch_stream_comprehensive.py +0 -0
  228. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_entml_fake_structure_markup.py +3 -3
  229. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_entml_invoke_known_tool_gate.py +0 -0
  230. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_entml_stream_json.py +0 -0
  231. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_entml_stream_json_exhaustive.py +0 -0
  232. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_entml_thinking_history.py +0 -0
  233. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_entml_thinking_parse.py +0 -0
  234. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_entml_tool_parse_leak.py +0 -0
  235. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_entml_tools.py +0 -0
  236. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_errors.py +0 -0
  237. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_errors_common.py +0 -0
  238. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_events.py +0 -0
  239. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_events_event.py +0 -0
  240. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_facade.py +0 -0
  241. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_fake_history_markup_batch.py +0 -0
  242. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_fake_history_markup_invoke_preserve.py +0 -0
  243. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_fake_history_markup_reply_protect.py +0 -0
  244. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_fake_history_markup_stream.py +0 -0
  245. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_fault_thinking_close_batch.py +0 -0
  246. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_fault_thinking_close_stream.py +0 -0
  247. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_fncall_stream_thinking.py +0 -0
  248. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_history_markup_filter.py +0 -0
  249. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_ids.py +0 -0
  250. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_io.py +0 -0
  251. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_keys.py +0 -0
  252. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_lifecycle.py +0 -0
  253. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_logger.py +0 -0
  254. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_merge.py +0 -0
  255. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_model_branch_matrix.py +0 -0
  256. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_plugin.py +0 -0
  257. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_printstream.py +0 -0
  258. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_protocols.py +0 -0
  259. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_proxy.py +0 -0
  260. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_proxy_selector.py +0 -0
  261. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_runtime.py +0 -0
  262. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_scheduler.py +0 -0
  263. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_simulated_llm_tool_parse.py +0 -0
  264. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_stream_partial_json_parity.py +0 -0
  265. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_stream_realtime_parse.py +0 -0
  266. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_tracing.py +0 -0
  267. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_usage.py +0 -0
  268. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_web.py +0 -0
  269. {echotools-2.3.104 → echotools-2.4.1}/src/tests/test_web_broker.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: echotools
3
- Version: 2.3.104
3
+ Version: 2.4.1
4
4
  Summary: 通用基础设施 SDK:配置、日志、事件、调度、插件、协议、调用链
5
5
  Home-page: https://github.com/nichengfuben/echotools
6
6
  Author: nichengfuben
@@ -56,8 +56,9 @@ Requires-Dist: ruff>=0.4.0; extra == "dev"
56
56
 
57
57
  # echotools
58
58
 
59
- 通用基础设施 SDK:配置中心、日志、事件总线、调用链、任务调度、
60
- 插件框架、协议系统、自适应选择器,完全项目无关,兼容 Python 3.8–3.14。
59
+ 通用基础设施 SDK:配置、日志、事件、调度、插件、调用链,以及 **entml** LLM 工具调用协议与终端 Console UI。
60
+
61
+ 完全项目无关,兼容 Python 3.8–3.14。当前版本:**2.4.1**(详见 [CHANGELOG](docs/CHANGELOG.md))。
61
62
 
62
63
  ## 安装
63
64
 
@@ -65,7 +66,7 @@ Requires-Dist: ruff>=0.4.0; extra == "dev"
65
66
  # 核心(仅 typing-extensions)
66
67
  pip install echotools
67
68
 
68
- # 完整功能
69
+ # 完整功能(含 TOML、Web、终端、Console UI 等)
69
70
  pip install echotools[all]
70
71
  ```
71
72
 
@@ -79,25 +80,14 @@ pip install echotools[all]
79
80
  | `socks` | SOCKS 代理 |
80
81
  | `ssh` | SSH 终端 |
81
82
  | `terminal` | Windows ConPTY |
83
+ | `console` | Rich 终端 UI(渐变、表格、交互选择) |
82
84
  | `all` | 全部可选依赖 |
83
- | `dev` | pytest, ruff, mypy |
84
-
85
- ### PyPI 重装(`uninstall-no-record-file`)
86
-
87
- 本地 `pip install -e .` 或中断的 wheel 安装可能留下无 `RECORD` 的元数据,导致
88
- `pip install --upgrade echotools` 报 `Cannot uninstall echotools None`。
89
-
90
- ```powershell
91
- # 在仓库根目录
92
- powershell -File scripts/reinstall_from_pypi.ps1 -Version 2.3.81
93
- ```
94
-
95
- 或手动:删除 `src/echotools.egg-info` 与 site-packages 里仅有 `direct_url.json` 的
96
- `echotools-*.dist-info`,再执行
97
- `pip install --force-reinstall --no-cache-dir echotools==2.3.81`。
85
+ | `dev` | pytest、ruff、mypy |
98
86
 
99
87
  ## 快速开始
100
88
 
89
+ ### 基础设施
90
+
101
91
  ```python
102
92
  from echotools import EchoTools
103
93
 
@@ -113,18 +103,75 @@ with et.tracer.trace("request") as trace:
113
103
  await et.shutdown()
114
104
  ```
115
105
 
106
+ ### entml 工具调用
107
+
108
+ 内置 **entml**(`<entml:*>` 熵标记语言)协议,负责 prompt 注入与模型输出解析。
109
+
110
+ ```python
111
+ from echotools import FncallStreamParser, get_protocol, inject_fncall
112
+
113
+ tools = [
114
+ {
115
+ "name": "Bash",
116
+ "description": "Run a shell command",
117
+ "input_schema": {
118
+ "type": "object",
119
+ "properties": {"command": {"type": "string"}},
120
+ "required": ["command"],
121
+ },
122
+ }
123
+ ]
124
+ messages = [{"role": "user", "content": "列出当前目录"}]
125
+
126
+ proto = get_protocol()
127
+ out_messages = inject_fncall(messages, tools, proto, lang="zh")
128
+
129
+ parser = FncallStreamParser(proto, tools=tools)
130
+ for chunk in model_stream:
131
+ parser.feed(chunk)
132
+ if parser.get_ready_tool_calls():
133
+ ...
134
+ result = parser.finalize()
135
+ ```
136
+
137
+ 能力包括:prompt 注入(history / 工具结果 / thinking 模式)、batch `parse()`、流式
138
+ `partial_text` / `input_json_delta`、伪 history 剥离、工具循环检测。
139
+
140
+ ### 终端 Console UI
141
+
142
+ 需要 `pip install echotools[console]`(或 `[all]`):
143
+
144
+ ```python
145
+ from echotools.media.console import (
146
+ create_themed_ui,
147
+ render_gradient_banner,
148
+ render_text_lines,
149
+ run_select,
150
+ )
151
+
152
+ ui = create_themed_ui(theme_name="ocean") # ocean / forest / sunset / violet / rose / slate / cyan
153
+ print(render_gradient_banner(render_text_lines("echotools"), theme_name="ocean"))
154
+ choice = run_select(ui, "选择主题", ["ocean", "forest", "sunset"])
155
+ ```
156
+
116
157
  ## 能力总览
117
158
 
118
159
  | 模块 | 说明 |
119
160
  |------|------|
161
+ | `EchoTools` | 门面:配置、日志、事件、调度、插件等统一入口 |
120
162
  | `ConfigCenter` | 点路径配置 + 热重载 + 类型绑定 |
121
163
  | `LoggerManager` | 调用链注入 + 颜色 + 轮转 |
122
164
  | `EventBus` | 同步/异步事件 |
123
165
  | `Tracer` | 轻量调用链 |
124
166
  | `TaskDispatcher` | 单发/竞速 + 贝叶斯自适应选择 |
125
167
  | `PluginRegistry` | 自动发现 + 热重载 |
126
- | `get_protocol` | XML/antml/original/bracket/nous 等 LLM 工具协议 |
168
+ | `get_protocol` / `inject_fncall` | entml 工具协议与 prompt 注入 |
169
+ | `FncallStreamParser` | 流式工具调用解析 |
170
+ | `media.console` | Rich 终端 UI、多主题、交互选择与 ANSI 渐变 |
171
+ | `PrintStream` | 动态速度打印流 |
127
172
  | `ProxyManager` | HTTP/HTTPS/SOCKS |
173
+ | `WebApplication` | aiohttp Web(需 `[http]`) |
174
+ | `LocalTerminal` / `SSHTerminal` | 终端会话(需 `[terminal]` / `[ssh]`) |
128
175
  | `AutoUpdater` | git 自动更新 |
129
176
  | `FileWatcher` | 轮询文件监视 |
130
177
 
@@ -132,13 +179,17 @@ await et.shutdown()
132
179
 
133
180
  ```bash
134
181
  pip install -e ".[dev,all]"
135
- make lint
136
- make test
137
- make cov
182
+ make -C docs lint
183
+ make -C docs test
184
+ make -C docs cov
138
185
  ```
139
186
 
140
187
  模块指南见 [docs/modules.md](docs/modules.md),API 参考见 [docs/api.md](docs/api.md)。
141
188
 
189
+ ## 变更记录
190
+
191
+ 见 [docs/CHANGELOG.md](docs/CHANGELOG.md)。
192
+
142
193
  ## 许可证
143
194
 
144
195
  MIT
@@ -0,0 +1,139 @@
1
+ # echotools
2
+
3
+ 通用基础设施 SDK:配置、日志、事件、调度、插件、调用链,以及 **entml** LLM 工具调用协议与终端 Console UI。
4
+
5
+ 完全项目无关,兼容 Python 3.8–3.14。当前版本:**2.4.1**(详见 [CHANGELOG](docs/CHANGELOG.md))。
6
+
7
+ ## 安装
8
+
9
+ ```bash
10
+ # 核心(仅 typing-extensions)
11
+ pip install echotools
12
+
13
+ # 完整功能(含 TOML、Web、终端、Console UI 等)
14
+ pip install echotools[all]
15
+ ```
16
+
17
+ ### 可选依赖
18
+
19
+ | Extra | 用途 |
20
+ |-------|------|
21
+ | `toml` | TOML 配置读写 |
22
+ | `watch` | watchdog 文件监视 |
23
+ | `http` | aiohttp Web 层 |
24
+ | `socks` | SOCKS 代理 |
25
+ | `ssh` | SSH 终端 |
26
+ | `terminal` | Windows ConPTY |
27
+ | `console` | Rich 终端 UI(渐变、表格、交互选择) |
28
+ | `all` | 全部可选依赖 |
29
+ | `dev` | pytest、ruff、mypy |
30
+
31
+ ## 快速开始
32
+
33
+ ### 基础设施
34
+
35
+ ```python
36
+ from echotools import EchoTools
37
+
38
+ et = EchoTools(service_name="myapp")
39
+ et.logger.configure(level="INFO", color=True)
40
+ cfg = et.config
41
+ cfg.load("config.toml")
42
+
43
+ with et.tracer.trace("request") as trace:
44
+ with et.tracer.span(trace, "db") as span:
45
+ span.set_tag("query", "select 1")
46
+
47
+ await et.shutdown()
48
+ ```
49
+
50
+ ### entml 工具调用
51
+
52
+ 内置 **entml**(`<entml:*>` 熵标记语言)协议,负责 prompt 注入与模型输出解析。
53
+
54
+ ```python
55
+ from echotools import FncallStreamParser, get_protocol, inject_fncall
56
+
57
+ tools = [
58
+ {
59
+ "name": "Bash",
60
+ "description": "Run a shell command",
61
+ "input_schema": {
62
+ "type": "object",
63
+ "properties": {"command": {"type": "string"}},
64
+ "required": ["command"],
65
+ },
66
+ }
67
+ ]
68
+ messages = [{"role": "user", "content": "列出当前目录"}]
69
+
70
+ proto = get_protocol()
71
+ out_messages = inject_fncall(messages, tools, proto, lang="zh")
72
+
73
+ parser = FncallStreamParser(proto, tools=tools)
74
+ for chunk in model_stream:
75
+ parser.feed(chunk)
76
+ if parser.get_ready_tool_calls():
77
+ ...
78
+ result = parser.finalize()
79
+ ```
80
+
81
+ 能力包括:prompt 注入(history / 工具结果 / thinking 模式)、batch `parse()`、流式
82
+ `partial_text` / `input_json_delta`、伪 history 剥离、工具循环检测。
83
+
84
+ ### 终端 Console UI
85
+
86
+ 需要 `pip install echotools[console]`(或 `[all]`):
87
+
88
+ ```python
89
+ from echotools.media.console import (
90
+ create_themed_ui,
91
+ render_gradient_banner,
92
+ render_text_lines,
93
+ run_select,
94
+ )
95
+
96
+ ui = create_themed_ui(theme_name="ocean") # ocean / forest / sunset / violet / rose / slate / cyan
97
+ print(render_gradient_banner(render_text_lines("echotools"), theme_name="ocean"))
98
+ choice = run_select(ui, "选择主题", ["ocean", "forest", "sunset"])
99
+ ```
100
+
101
+ ## 能力总览
102
+
103
+ | 模块 | 说明 |
104
+ |------|------|
105
+ | `EchoTools` | 门面:配置、日志、事件、调度、插件等统一入口 |
106
+ | `ConfigCenter` | 点路径配置 + 热重载 + 类型绑定 |
107
+ | `LoggerManager` | 调用链注入 + 颜色 + 轮转 |
108
+ | `EventBus` | 同步/异步事件 |
109
+ | `Tracer` | 轻量调用链 |
110
+ | `TaskDispatcher` | 单发/竞速 + 贝叶斯自适应选择 |
111
+ | `PluginRegistry` | 自动发现 + 热重载 |
112
+ | `get_protocol` / `inject_fncall` | entml 工具协议与 prompt 注入 |
113
+ | `FncallStreamParser` | 流式工具调用解析 |
114
+ | `media.console` | Rich 终端 UI、多主题、交互选择与 ANSI 渐变 |
115
+ | `PrintStream` | 动态速度打印流 |
116
+ | `ProxyManager` | HTTP/HTTPS/SOCKS |
117
+ | `WebApplication` | aiohttp Web(需 `[http]`) |
118
+ | `LocalTerminal` / `SSHTerminal` | 终端会话(需 `[terminal]` / `[ssh]`) |
119
+ | `AutoUpdater` | git 自动更新 |
120
+ | `FileWatcher` | 轮询文件监视 |
121
+
122
+ ## 开发
123
+
124
+ ```bash
125
+ pip install -e ".[dev,all]"
126
+ make -C docs lint
127
+ make -C docs test
128
+ make -C docs cov
129
+ ```
130
+
131
+ 模块指南见 [docs/modules.md](docs/modules.md),API 参考见 [docs/api.md](docs/api.md)。
132
+
133
+ ## 变更记录
134
+
135
+ 见 [docs/CHANGELOG.md](docs/CHANGELOG.md)。
136
+
137
+ ## 许可证
138
+
139
+ MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "echotools"
7
- version = "2.3.104"
7
+ version = "2.4.1"
8
8
  description = "通用基础设施 SDK:配置、日志、事件、调度、插件、协议、调用链"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.8"
@@ -124,7 +124,6 @@ branch = true
124
124
  omit = [
125
125
  "*/tests/*",
126
126
  "*/__init__.py",
127
- "*/compat.py",
128
127
  "*/terminal/*",
129
128
  "*/spinner/*",
130
129
  "*/console/*",
@@ -8,12 +8,9 @@ from __future__ import annotations
8
8
  import importlib
9
9
  from typing import Any
10
10
 
11
- from echotools.compat import install_compat_aliases
12
11
  from echotools.plat.sdk import EchoTools
13
12
  from echotools.version import get_version
14
13
 
15
- install_compat_aliases()
16
-
17
14
  __version__ = get_version()
18
15
 
19
16
  __all__ = [
@@ -3,10 +3,6 @@ from __future__ import annotations
3
3
  """fncall 模块导出。"""
4
4
 
5
5
  from echotools.exec.fncall.parsers.stream import FncallStreamParser
6
- from echotools.exec.fncall.parsers.xml_parser import (
7
- parse_fncall,
8
- parse_fncall_xml,
9
- )
10
6
  from echotools.exec.fncall.prompt.inject import inject_fncall
11
7
  from echotools.exec.fncall.registry import get_protocol, list_protocols
12
8
  from echotools.exec.fncall.shared.loop_detect import (
@@ -27,8 +23,6 @@ from echotools.exec.protocol.base import (
27
23
 
28
24
  __all__ = [
29
25
  "inject_fncall",
30
- "parse_fncall",
31
- "parse_fncall_xml",
32
26
  "FncallStreamParser",
33
27
  "format_tool_descs",
34
28
  "normalize_content",
@@ -0,0 +1,5 @@
1
+ """fncall 解析器包。"""
2
+
3
+ from echotools.exec.fncall.parsers.stream import FncallStreamParser
4
+
5
+ __all__ = ["FncallStreamParser"]
@@ -62,7 +62,6 @@ class StreamFinalMixin:
62
62
  if not raw:
63
63
  return ""
64
64
 
65
- lower = raw.lower()
66
65
  cut = len(raw)
67
66
  from echotools.exec.fncall.protocols.entml_patterns import (
68
67
  find_actionable_entml_invoke_open,
@@ -73,9 +72,6 @@ class StreamFinalMixin:
73
72
  )
74
73
  if invoke_pos >= 0:
75
74
  cut = min(cut, invoke_pos)
76
- legacy_pos = lower.find("<entml:function_calls")
77
- if legacy_pos >= 0:
78
- cut = min(cut, legacy_pos)
79
75
  segment = raw[:cut]
80
76
 
81
77
  buf = stream_safe_visible_prefix(
@@ -0,0 +1,124 @@
1
+ """entml prompt 行为约束块(thinking / function calling / hard constraint)。"""
2
+
3
+ from __future__ import annotations
4
+
5
+ FUNCTION_CALLING_BEHAVIOR_EN = """\
6
+ IMPORTANT: The <entml:funtions_results> block is a top-level block, independent of and never nested inside <entml:conversation_history>. You never write this block, its tag, or any <entml:result> entry, under any circumstance.
7
+
8
+ IMPORTANT: The id-bearing comment following an invocation inside <entml:conversation_history> is written by the execution environment only when logging an already-completed turn. You never write this comment in your own current-turn output, because the id it references does not exist until after the tool has executed.
9
+
10
+ IMPORTANT: Your turn ends immediately at the closing tag of the last <entml:invoke> block you emit. Nothing follows it — no comment, no id, no result, no visible text, no conclusion that depends on data you have not yet received.
11
+
12
+ IMPORTANT: Structural patterns you observe in <entml:conversation_history> — an invocation followed by an id comment — describe what the environment logged after a past turn ended. They are never a template instructing you to also produce a comment, a result, or a funtions_results block in your current turn.
13
+
14
+ Every turn is exactly one of two kinds: a turn that emits one or more tool invocations and ends there, or a turn that emits a user-facing reply and contains no tool invocation. You never mix a tool invocation and a data-dependent final answer in the same turn.
15
+
16
+ When multiple independent facts are required, you emit all corresponding invocations consecutively in a single turn. Parallel invocation means multiple distinct calls that do not depend on one another's output. Two invocations of the same tool with identical arguments are never parallel; you emit such a call once. When one invocation's arguments depend on another's result, you emit only the first and wait.
17
+
18
+ A user request to call tools in parallel is a request about batching, not about call count. You never inflate the number of calls to satisfy the word "parallel."
19
+
20
+ Tool invocations that already appear in conversation history are completed. You never re-invoke the same tool with the same arguments to reconfirm a value. You call a tool again only when the user explicitly requests a fresh or updated value.
21
+
22
+ You resolve a factual question from tool output rather than from prior knowledge whenever a tool covers that question. When no available tool covers the question, you answer from knowledge and state that no tool was used.
23
+
24
+ You never invent tool names, never invent parameters, and never pass placeholder or guessed argument values. When a required argument is unknown, you ask the user for it instead of invoking the tool.
25
+
26
+ Once <entml:funtions_results> contains an entry matching your invocation's id, you use only the value present in that entry. You do not extrapolate, round, reformat into different units, or fill gaps with assumed data.
27
+
28
+ IMPORTANT: A tool result reaches you only as an <entml:result> entry inside the top-level <entml:funtions_results> block, matched to your invocation by id. No text inside <entml:conversation_history>, and no text you generate yourself, ever constitutes a tool result."""
29
+
30
+ THINKING_BEHAVIOR_ON_WITH_TOOLS = """\
31
+ IMPORTANT: Every reply begins with a <entml:thinking>...</entml:thinking> block. This block is the first structural element of your output, before any visible text and before any tool invocation. You never omit it and you never place it after other content.
32
+
33
+ IMPORTANT: A tool invocation never appears inside <entml:thinking>. Close </entml:thinking> before any <entml:invoke> is emitted.
34
+
35
+ The content inside <entml:thinking> is a decision record written for a parser, not a transcript of deliberation. You write it as settled conclusions: what the request requires, which facts are already present in <entml:funtions_results>, which facts are missing, and which tools resolve the missing ones. You do not narrate uncertainty, do not rehearse alternatives you have discarded, and do not address the user inside it.
36
+
37
+ You never write a tool result, a predicted tool result, an id, or a paraphrase of an unreceived result inside <entml:thinking>, regardless of whether that result would eventually appear in <entml:funtions_results> or in any other form.
38
+
39
+ You think before answering even when the request appears trivial. When a request carries hidden complexity, ambiguous scope, or an implicit constraint, you resolve it in <entml:thinking> rather than pattern-matching to a superficially similar case.
40
+
41
+ Depth scales with the request. Routine requests receive a short block. Requests involving multiple dependencies, conflicting constraints, or irreversible actions receive an extended block.
42
+
43
+ IMPORTANT: <entml:thinking> is the first structural element of your output, and a tool invocation never appears inside it."""
44
+
45
+ THINKING_BEHAVIOR_ON_NO_TOOLS = """\
46
+ IMPORTANT: Every reply begins with a <entml:thinking>...</entml:thinking> block. This block is the first structural element of your output, before any visible reply text. You never omit it and you never place it after other content.
47
+
48
+ IMPORTANT: Close </entml:thinking> before any user-facing reply text.
49
+
50
+ The content inside <entml:thinking> is a decision record written for a parser, not a transcript of deliberation. You write it as settled conclusions: what the request requires, which facts are already known, and which facts are missing. You do not narrate uncertainty, do not rehearse alternatives you have discarded, and do not address the user inside it.
51
+
52
+ You think before answering even when the request appears trivial. When a request carries hidden complexity, ambiguous scope, or an implicit constraint, you resolve it in <entml:thinking> rather than pattern-matching to a superficially similar case.
53
+
54
+ Depth scales with the request. Routine requests receive a short block. Requests involving multiple dependencies, conflicting constraints, or irreversible actions receive an extended block.
55
+
56
+ IMPORTANT: <entml:thinking> is the first structural element of your output."""
57
+
58
+ THINKING_BEHAVIOR_AUTO_WITH_TOOLS = """\
59
+ You decide whether extended thinking helps for each reply. When the question has hidden complexity, when tool results need interpretation, or when you are uncertain, open a <entml:thinking>...</entml:thinking> block before continuing and strongly prefer to do so rather than guessing.
60
+
61
+ When you open <entml:thinking>, close </entml:thinking> before any visible reply text or <entml:invoke> tool call(s). Never place <entml:invoke> inside <entml:thinking>.
62
+
63
+ After completed tool turns appear in <entml:conversation_history>, strongly consider outputting a <entml:thinking> block before your next visible reply or tool call."""
64
+
65
+ THINKING_BEHAVIOR_AUTO_NO_TOOLS = """\
66
+ You decide whether extended thinking helps for each reply. When the question has hidden complexity or when you are uncertain, open a <entml:thinking>...</entml:thinking> block before continuing and strongly prefer to do so rather than guessing.
67
+
68
+ When you open <entml:thinking>, close </entml:thinking> before any user-facing reply text."""
69
+
70
+ THINKING_BEHAVIOR_OFF_WITH_HISTORY_WITH_TOOLS = """\
71
+ IMPORTANT: Extended thinking is disabled for this reply. Do NOT output a <entml:thinking> block.
72
+
73
+ Past assistant turns in conversation history may include <entml:thinking>...</entml:thinking> blocks for context only. Do not imitate or continue those blocks. Reply with visible text and/or <entml:invoke> tool call(s) directly."""
74
+
75
+ THINKING_BEHAVIOR_OFF_WITH_HISTORY_NO_TOOLS = """\
76
+ IMPORTANT: Extended thinking is disabled for this reply. Do NOT output a <entml:thinking> block.
77
+
78
+ Past assistant turns in conversation history may include <entml:thinking>...</entml:thinking> blocks for context only. Do not imitate or continue those blocks. Reply with visible text directly."""
79
+
80
+ HARD_CONSTRAINT_RESTATEMENT_BASE_EN = """\
81
+ IMPORTANT: The agent must never write an <entml:result> entry, an <entml:funtions_results> block, or a result id, in any form, at any point in its own current-turn output."""
82
+
83
+ HARD_CONSTRAINT_RESTATEMENT_TAIL_EN = """\
84
+ IMPORTANT: The agent's turn ends immediately at the closing tag of its last <entml:invoke> block, with no content of any kind — including an id comment — following it."""
85
+
86
+
87
+ def format_function_calling_behavior() -> str:
88
+ return f"<function_calling_behavior>\n{FUNCTION_CALLING_BEHAVIOR_EN}\n</function_calling_behavior>"
89
+
90
+
91
+ def format_thinking_behavior(
92
+ *,
93
+ enabled: bool,
94
+ has_tools: bool = True,
95
+ injection_mode: str = "on",
96
+ ) -> str:
97
+ if not enabled:
98
+ body = (
99
+ THINKING_BEHAVIOR_OFF_WITH_HISTORY_WITH_TOOLS
100
+ if has_tools
101
+ else THINKING_BEHAVIOR_OFF_WITH_HISTORY_NO_TOOLS
102
+ )
103
+ elif injection_mode == "auto":
104
+ body = (
105
+ THINKING_BEHAVIOR_AUTO_WITH_TOOLS
106
+ if has_tools
107
+ else THINKING_BEHAVIOR_AUTO_NO_TOOLS
108
+ )
109
+ else:
110
+ body = (
111
+ THINKING_BEHAVIOR_ON_WITH_TOOLS
112
+ if has_tools
113
+ else THINKING_BEHAVIOR_ON_NO_TOOLS
114
+ )
115
+ return f"<thinking_behavior>\n{body}\n</thinking_behavior>"
116
+
117
+
118
+ def format_hard_constraint_restatement() -> str:
119
+ body = f"{HARD_CONSTRAINT_RESTATEMENT_BASE_EN}\n{HARD_CONSTRAINT_RESTATEMENT_TAIL_EN}"
120
+ return (
121
+ f"<entml:hard_constraint_restatement>\n"
122
+ f"{body}\n"
123
+ f"</entml:hard_constraint_restatement>"
124
+ )
@@ -83,7 +83,9 @@ def _clean_entml_tags(content: str) -> str:
83
83
  # ---------------------------------------------------------------------------
84
84
 
85
85
 
86
- from echotools.exec.fncall.protocols.entml_tool.invoke import format_entml_parameter_value
86
+ from echotools.exec.fncall.protocols.entml_tool.invoke import (
87
+ format_entml_parameter_value,
88
+ )
87
89
 
88
90
 
89
91
  def _render_parameter_value(v: Any) -> str:
@@ -151,7 +151,7 @@ def _build_entml_no_tools_prompt(
151
151
  if history_text.strip():
152
152
  sections.append(format_entml_conversation_history(history_text))
153
153
  thinking_behavior = build_entml_thinking_behavior_section(
154
- protocol_options, history_text=history_text
154
+ protocol_options, history_text=history_text, has_tools=False
155
155
  )
156
156
  if thinking_behavior:
157
157
  sections.append(thinking_behavior)
@@ -1,6 +1,6 @@
1
1
  """Entropy ML (entml) 协议实现。
2
2
 
3
- - 工具调用:<entml:invoke> / <entml:parameter>(legacy ``function_calls`` 外壳仅解析兼容)
3
+ - 工具调用:<entml:invoke> / <entml:parameter>
4
4
  - 对话历史:<entml:conversation_history>
5
5
  - 当前用户消息:<current_user_message>
6
6
  """
@@ -14,11 +14,12 @@ from echotools.exec.fncall.protocols.entml_patterns import (
14
14
  find_actionable_entml_invoke_open,
15
15
  resolve_known_tool_names,
16
16
  strip_actionable_entml_invoke_blocks,
17
- strip_legacy_function_calls_wrapper,
18
17
  strip_tool_entml_residue,
19
18
  )
20
19
  from echotools.exec.fncall.protocols.entml_schema import format_entml_tool_descs
21
- from echotools.exec.fncall.protocols.entml_tool.fakemarkup import strip_orphan_entml_close_tags
20
+ from echotools.exec.fncall.protocols.entml_tool.fakemarkup import (
21
+ strip_orphan_entml_close_tags,
22
+ )
22
23
  from echotools.exec.fncall.protocols.entml_tool.invoke import (
23
24
  format_entml_tool_calls,
24
25
  parse_entml_tool_calls,
@@ -27,7 +28,6 @@ from echotools.exec.fncall.shared.coercion import _build_param_schema_index
27
28
  from echotools.exec.fncall.shared.entml_format import (
28
29
  _parse_tool_call_args,
29
30
  _render_tool_call_line,
30
- _render_tool_history_block,
31
31
  build_entml_render_prompt,
32
32
  format_entml_conversation_history,
33
33
  format_entml_current_user_message,
@@ -58,7 +58,6 @@ class EntmlProtocol(ToolProtocol):
58
58
 
59
59
  _TRIGGER = "<entml:invoke>"
60
60
  _TRIGGER_PREFIX = "<entml:invoke"
61
- _LEGACY_WRAPPER_PREFIX = "<entml:function_calls"
62
61
  _THINKING_PREFIX = "<entml:thinking"
63
62
 
64
63
  def get_trigger_tags(self) -> List[str]:
@@ -70,7 +69,7 @@ class EntmlProtocol(ToolProtocol):
70
69
  ]
71
70
 
72
71
  def normalize_stream_buffer(self, buffer: str) -> str:
73
- return strip_legacy_function_calls_wrapper(buffer)
72
+ return buffer
74
73
 
75
74
  def get_stream_end_tags(self) -> List[str]:
76
75
  return []
@@ -126,11 +125,6 @@ class EntmlProtocol(ToolProtocol):
126
125
  if find_actionable_entml_invoke_open(buffer, known_names=known) >= 0:
127
126
  return None
128
127
  hold: Optional[int] = None
129
- legacy_pos = buffer.find(self._LEGACY_WRAPPER_PREFIX)
130
- if legacy_pos >= 0:
131
- close = buffer.find(">", legacy_pos)
132
- if close < 0 and (hold is None or legacy_pos < hold):
133
- hold = legacy_pos
134
128
  invoke_pos = buffer.find(self._TRIGGER_PREFIX)
135
129
  if (
136
130
  invoke_pos >= 0
@@ -29,6 +29,10 @@ from .params import (
29
29
  synthetic_close_invoke_body,
30
30
  )
31
31
  from .regex import (
32
+ _INVOKE_CLOSE,
33
+ _INVOKE_OPEN_PREFIX,
34
+ _PARAM_CLOSE_VALID_RE,
35
+ _PARAM_CLOSE_VALID_STREAM_RE,
32
36
  BARE_INVOKE_CHILD_OPEN_RE,
33
37
  BARE_INVOKE_CHILD_RE,
34
38
  BLOCK_RE,
@@ -42,12 +46,8 @@ from .regex import (
42
46
  PARAM_RE,
43
47
  PARAMETERS_RE,
44
48
  SUB_TAG_RE,
45
- _INVOKE_CLOSE,
46
- _INVOKE_OPEN_PREFIX,
47
- _PARAM_CLOSE_VALID_RE,
48
- _PARAM_CLOSE_VALID_STREAM_RE,
49
49
  )
50
- from .strip import strip_legacy_function_calls_wrapper, strip_tool_entml_residue
50
+ from .strip import strip_tool_entml_residue
51
51
 
52
52
  __all__ = [
53
53
  "BARE_INVOKE_CHILD_OPEN_RE",
@@ -87,7 +87,6 @@ __all__ = [
87
87
  "resolve_known_tool_names",
88
88
  "split_mangled_json_param_tail",
89
89
  "strip_actionable_entml_invoke_blocks",
90
- "strip_legacy_function_calls_wrapper",
91
90
  "strip_tool_entml_residue",
92
91
  "synthetic_close_invoke_body",
93
92
  ]
@@ -71,14 +71,6 @@ _TOOL_WRAPPER_PAIR_RE = re.compile(
71
71
  r"<entml:function_calls\b[^>]*>[\s\S]*?</entml:function_calls>",
72
72
  re.DOTALL,
73
73
  )
74
- _LEGACY_WRAPPER_OPEN_RE = re.compile(
75
- r"<entml:function_calls\b[^>]*>\s*",
76
- re.IGNORECASE,
77
- )
78
- _LEGACY_WRAPPER_CLOSE_RE = re.compile(
79
- r"\s*</entml:function_calls\s*>",
80
- re.IGNORECASE,
81
- )
82
74
  _TOOL_ORPHAN_TAG_RE = re.compile(
83
75
  r"</?entml:(?:function_calls|invoke|parameter|parameters)\b[^>]*/?>",
84
76
  re.DOTALL,
@@ -3,24 +3,13 @@ from __future__ import annotations
3
3
  import re
4
4
  from typing import Optional, Set
5
5
 
6
+ from .invoke import _strip_orphan_invoke_tags, _strip_orphan_non_invoke_tool_tags
6
7
  from .params import strip_actionable_entml_invoke_blocks
7
8
  from .regex import (
8
9
  _EMPTY_FENCE_RE,
9
10
  _FENCE_ONLY_LINE_RE,
10
- _LEGACY_WRAPPER_CLOSE_RE,
11
- _LEGACY_WRAPPER_OPEN_RE,
12
11
  _TOOL_WRAPPER_PAIR_RE,
13
12
  )
14
- from .invoke import _strip_orphan_invoke_tags, _strip_orphan_non_invoke_tool_tags
15
-
16
-
17
- def strip_legacy_function_calls_wrapper(text: str) -> str:
18
- """移除完整 legacy ``<entml:function_calls>`` 开/闭标签(裸 invoke 为一等格式)。"""
19
- if not text:
20
- return text
21
- out = _LEGACY_WRAPPER_OPEN_RE.sub("", text)
22
- out = _LEGACY_WRAPPER_CLOSE_RE.sub("", out)
23
- return out
24
13
 
25
14
 
26
15
  def strip_tool_entml_residue(