echotools 2.3.29__tar.gz → 2.3.30__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 (188) hide show
  1. {echotools-2.3.29 → echotools-2.3.30}/PKG-INFO +1 -1
  2. {echotools-2.3.29 → echotools-2.3.30}/pyproject.toml +1 -1
  3. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/fncall/prompt/history_format.py +6 -2
  4. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/fncall/prompt/inject.py +10 -2
  5. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/fncall/prompt/prompt_helpers.py +38 -6
  6. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/fncall/protocols/entml_thinking_history.py +23 -0
  7. {echotools-2.3.29 → echotools-2.3.30}/src/echotools.egg-info/PKG-INFO +1 -1
  8. {echotools-2.3.29 → echotools-2.3.30}/src/tests/test_entml_protocol.py +40 -0
  9. {echotools-2.3.29 → echotools-2.3.30}/README.md +0 -0
  10. {echotools-2.3.29 → echotools-2.3.30}/docs/README.md +0 -0
  11. {echotools-2.3.29 → echotools-2.3.30}/setup.cfg +0 -0
  12. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/__init__.py +0 -0
  13. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/base/cache/__init__.py +0 -0
  14. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/base/cache/list_cache.py +0 -0
  15. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/base/cache/memory_cache.py +0 -0
  16. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/base/config/__init__.py +0 -0
  17. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/base/config/base.py +0 -0
  18. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/base/config/center.py +0 -0
  19. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/base/config/center_notify.py +0 -0
  20. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/base/config/center_template.py +0 -0
  21. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/base/config/loader.py +0 -0
  22. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/base/config/merge.py +0 -0
  23. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/base/errors/__init__.py +0 -0
  24. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/base/errors/base.py +0 -0
  25. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/base/errors/classify.py +0 -0
  26. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/base/errors/common.py +0 -0
  27. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/base/errors/http.py +0 -0
  28. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/base/ids/__init__.py +0 -0
  29. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/base/ids/generator.py +0 -0
  30. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/base/io/__init__.py +0 -0
  31. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/base/io/io_utils.py +0 -0
  32. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/base/io/printstream.py +0 -0
  33. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/base/logger/__init__.py +0 -0
  34. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/base/logger/manager.py +0 -0
  35. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/base/retry/__init__.py +0 -0
  36. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/base/retry/retry.py +0 -0
  37. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/compat.py +0 -0
  38. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/dispatch/__init__.py +0 -0
  39. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/dispatch/candidate.py +0 -0
  40. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/dispatch/dispatcher.py +0 -0
  41. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/dispatch/proxy_selector.py +0 -0
  42. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/dispatch/race.py +0 -0
  43. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/dispatch/selector.py +0 -0
  44. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/dispatch/usage.py +0 -0
  45. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/fncall/__init__.py +0 -0
  46. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/fncall/parsers/__init__.py +0 -0
  47. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/fncall/parsers/stream.py +0 -0
  48. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/fncall/parsers/xml_params.py +0 -0
  49. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/fncall/parsers/xml_parser.py +0 -0
  50. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/fncall/prompt/__init__.py +0 -0
  51. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/fncall/prompt/history.py +0 -0
  52. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/fncall/prompt/templates.py +0 -0
  53. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/fncall/protocols/__init__.py +0 -0
  54. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/fncall/protocols/entml.py +0 -0
  55. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/fncall/protocols/entml_invoke.py +0 -0
  56. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/fncall/protocols/entml_patterns.py +0 -0
  57. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/fncall/protocols/entml_thinking.py +0 -0
  58. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/fncall/protocols/entml_thinking_parse.py +0 -0
  59. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/fncall/protocols/entml_tools.py +0 -0
  60. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/fncall/protocols/entml_values.py +0 -0
  61. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/fncall/registry.py +0 -0
  62. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/fncall/shared/__init__.py +0 -0
  63. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/fncall/shared/coercion.py +0 -0
  64. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/fncall/shared/loop_detect.py +0 -0
  65. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/fncall/shared/normalization.py +0 -0
  66. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/fncall/shared/schema_render.py +0 -0
  67. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/fncall/shared/xml_helpers.py +0 -0
  68. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/keys.py +0 -0
  69. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/lifecycle/__init__.py +0 -0
  70. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/lifecycle/manager.py +0 -0
  71. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/lifecycle/updater.py +0 -0
  72. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/lifecycle/updater_pull.py +0 -0
  73. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/process/__init__.py +0 -0
  74. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/process/port.py +0 -0
  75. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/protocol/__init__.py +0 -0
  76. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/protocol/base.py +0 -0
  77. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/terminal/__init__.py +0 -0
  78. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/terminal/conpty.py +0 -0
  79. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/terminal/local/__init__.py +0 -0
  80. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/terminal/local/core.py +0 -0
  81. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/terminal/local/proc.py +0 -0
  82. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/terminal/local/unix.py +0 -0
  83. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/terminal/local/win.py +0 -0
  84. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/terminal/sanitize.py +0 -0
  85. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/terminal/session/__init__.py +0 -0
  86. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/terminal/session/base.py +0 -0
  87. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/terminal/session/client.py +0 -0
  88. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/terminal/ssh.py +0 -0
  89. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/exec/terminal/tmux.py +0 -0
  90. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/media/console/__init__.py +0 -0
  91. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/media/console/charmap.py +0 -0
  92. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/media/console/spinner.py +0 -0
  93. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/media/console/ui.py +0 -0
  94. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/media/events/__init__.py +0 -0
  95. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/media/events/bus.py +0 -0
  96. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/media/events/event.py +0 -0
  97. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/media/spinner/__init__.py +0 -0
  98. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/media/spinner/spinner.py +0 -0
  99. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/media/spinner/spinner_color.py +0 -0
  100. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/media/tracing/__init__.py +0 -0
  101. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/media/tracing/context.py +0 -0
  102. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/media/tracing/span.py +0 -0
  103. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/media/tracing/tracer.py +0 -0
  104. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/media/translate.py +0 -0
  105. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/media/watcher/__init__.py +0 -0
  106. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/media/watcher/file_watcher.py +0 -0
  107. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/media/web/__init__.py +0 -0
  108. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/media/web/application.py +0 -0
  109. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/media/web/broker.py +0 -0
  110. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/media/web/input_box/app.js +0 -0
  111. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/media/web/input_box/components/filezone.js +0 -0
  112. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/media/web/input_box/components/motionkit.js +0 -0
  113. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/media/web/input_box/components/sendbutton.js +0 -0
  114. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/media/web/input_box/components/sortablelist.css +0 -0
  115. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/media/web/input_box/components/sortablelist.js +0 -0
  116. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/media/web/input_box/components/textinput.js +0 -0
  117. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/media/web/input_box/components/voiceinput.js +0 -0
  118. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/media/web/input_box/fonts/inter-500.woff2 +0 -0
  119. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/media/web/input_box/fonts/inter-600.woff2 +0 -0
  120. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/media/web/input_box/fonts/inter400.woff2 +0 -0
  121. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/media/web/input_box/fonts/tailwind.css +0 -0
  122. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/media/web/input_box/inputbox.css +0 -0
  123. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/media/web/input_box/inputbox.js +0 -0
  124. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/media/web/input_box/style.css +0 -0
  125. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/media/web/input_box/voicegif.js +0 -0
  126. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/media/web/middleware.py +0 -0
  127. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/media/web/stats.py +0 -0
  128. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/media/web/utils.py +0 -0
  129. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/plat/files/__init__.py +0 -0
  130. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/plat/files/file_util.py +0 -0
  131. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/plat/network/__init__.py +0 -0
  132. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/plat/network/http_utils.py +0 -0
  133. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/plat/plugin/__init__.py +0 -0
  134. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/plat/plugin/base.py +0 -0
  135. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/plat/plugin/discovery.py +0 -0
  136. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/plat/plugin/registry.py +0 -0
  137. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/plat/plugin/registry_ops.py +0 -0
  138. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/plat/proxy/__init__.py +0 -0
  139. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/plat/proxy/manager.py +0 -0
  140. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/plat/runtime/__init__.py +0 -0
  141. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/plat/runtime/collector.py +0 -0
  142. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/plat/scheduler/__init__.py +0 -0
  143. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/plat/scheduler/scheduler.py +0 -0
  144. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/plat/sdk/__init__.py +0 -0
  145. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/plat/sdk/facade.py +0 -0
  146. {echotools-2.3.29 → echotools-2.3.30}/src/echotools/version.py +0 -0
  147. {echotools-2.3.29 → echotools-2.3.30}/src/echotools.egg-info/SOURCES.txt +0 -0
  148. {echotools-2.3.29 → echotools-2.3.30}/src/echotools.egg-info/dependency_links.txt +0 -0
  149. {echotools-2.3.29 → echotools-2.3.30}/src/echotools.egg-info/requires.txt +0 -0
  150. {echotools-2.3.29 → echotools-2.3.30}/src/echotools.egg-info/top_level.txt +0 -0
  151. {echotools-2.3.29 → echotools-2.3.30}/src/tests/bench_import.py +0 -0
  152. {echotools-2.3.29 → echotools-2.3.30}/src/tests/conftest.py +0 -0
  153. {echotools-2.3.29 → echotools-2.3.30}/src/tests/test_cache_retry.py +0 -0
  154. {echotools-2.3.29 → echotools-2.3.30}/src/tests/test_completion.py +0 -0
  155. {echotools-2.3.29 → echotools-2.3.30}/src/tests/test_config.py +0 -0
  156. {echotools-2.3.29 → echotools-2.3.30}/src/tests/test_config_extended.py +0 -0
  157. {echotools-2.3.29 → echotools-2.3.30}/src/tests/test_console.py +0 -0
  158. {echotools-2.3.29 → echotools-2.3.30}/src/tests/test_coverage_core.py +0 -0
  159. {echotools-2.3.29 → echotools-2.3.30}/src/tests/test_dispatch.py +0 -0
  160. {echotools-2.3.29 → echotools-2.3.30}/src/tests/test_dispatch_extended.py +0 -0
  161. {echotools-2.3.29 → echotools-2.3.30}/src/tests/test_dispatch_race.py +0 -0
  162. {echotools-2.3.29 → echotools-2.3.30}/src/tests/test_entml_thinking_history.py +0 -0
  163. {echotools-2.3.29 → echotools-2.3.30}/src/tests/test_entml_thinking_parse.py +0 -0
  164. {echotools-2.3.29 → echotools-2.3.30}/src/tests/test_entml_tools.py +0 -0
  165. {echotools-2.3.29 → echotools-2.3.30}/src/tests/test_errors.py +0 -0
  166. {echotools-2.3.29 → echotools-2.3.30}/src/tests/test_errors_common.py +0 -0
  167. {echotools-2.3.29 → echotools-2.3.30}/src/tests/test_events.py +0 -0
  168. {echotools-2.3.29 → echotools-2.3.30}/src/tests/test_events_event.py +0 -0
  169. {echotools-2.3.29 → echotools-2.3.30}/src/tests/test_facade.py +0 -0
  170. {echotools-2.3.29 → echotools-2.3.30}/src/tests/test_fncall.py +0 -0
  171. {echotools-2.3.29 → echotools-2.3.30}/src/tests/test_ids.py +0 -0
  172. {echotools-2.3.29 → echotools-2.3.30}/src/tests/test_imports.py +0 -0
  173. {echotools-2.3.29 → echotools-2.3.30}/src/tests/test_io.py +0 -0
  174. {echotools-2.3.29 → echotools-2.3.30}/src/tests/test_keys.py +0 -0
  175. {echotools-2.3.29 → echotools-2.3.30}/src/tests/test_lifecycle.py +0 -0
  176. {echotools-2.3.29 → echotools-2.3.30}/src/tests/test_logger.py +0 -0
  177. {echotools-2.3.29 → echotools-2.3.30}/src/tests/test_merge.py +0 -0
  178. {echotools-2.3.29 → echotools-2.3.30}/src/tests/test_plugin.py +0 -0
  179. {echotools-2.3.29 → echotools-2.3.30}/src/tests/test_printstream.py +0 -0
  180. {echotools-2.3.29 → echotools-2.3.30}/src/tests/test_protocols.py +0 -0
  181. {echotools-2.3.29 → echotools-2.3.30}/src/tests/test_proxy.py +0 -0
  182. {echotools-2.3.29 → echotools-2.3.30}/src/tests/test_proxy_selector.py +0 -0
  183. {echotools-2.3.29 → echotools-2.3.30}/src/tests/test_runtime.py +0 -0
  184. {echotools-2.3.29 → echotools-2.3.30}/src/tests/test_scheduler.py +0 -0
  185. {echotools-2.3.29 → echotools-2.3.30}/src/tests/test_tracing.py +0 -0
  186. {echotools-2.3.29 → echotools-2.3.30}/src/tests/test_usage.py +0 -0
  187. {echotools-2.3.29 → echotools-2.3.30}/src/tests/test_web.py +0 -0
  188. {echotools-2.3.29 → echotools-2.3.30}/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.29
3
+ Version: 2.3.30
4
4
  Summary: 通用基础设施 SDK:配置、日志、事件、调度、插件、协议、调用链
5
5
  Author: nichengfuben
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "echotools"
7
- version = "2.3.29"
7
+ version = "2.3.30"
8
8
  description = "通用基础设施 SDK:配置、日志、事件、调度、插件、协议、调用链"
9
9
  readme = "docs/README.md"
10
10
  requires-python = ">=3.8"
@@ -18,6 +18,8 @@ from .prompt_helpers import (
18
18
  def _format_conversation_history(
19
19
  messages: List[Dict[str, Any]],
20
20
  protocol: Optional[Any] = None,
21
+ *,
22
+ include_thinking_in_history: bool = False,
21
23
  ) -> str:
22
24
  if not messages:
23
25
  return ""
@@ -48,14 +50,16 @@ def _format_conversation_history(
48
50
  tool_msgs.append(messages[j])
49
51
  j += 1
50
52
  block = format_assistant_block_with_results(
51
- m, tool_msgs, protocol, call_id_to_name, seen_assistant_keys
53
+ m, tool_msgs, protocol, call_id_to_name, seen_assistant_keys,
54
+ include_thinking_in_history=include_thinking_in_history,
52
55
  )
53
56
  if block:
54
57
  parts.append((block, False))
55
58
  i = j
56
59
  else:
57
60
  block = format_assistant_block(
58
- m, content_str, protocol, call_id_to_name, seen_assistant_keys
61
+ m, content_str, protocol, call_id_to_name, seen_assistant_keys,
62
+ include_thinking_in_history=include_thinking_in_history,
59
63
  )
60
64
  if block:
61
65
  parts.append((block, False))
@@ -22,6 +22,10 @@ from echotools.exec.fncall.protocols.entml import (
22
22
  format_entml_current_user_message,
23
23
  )
24
24
  from echotools.exec.fncall.protocols.entml_thinking import build_entml_thinking_section
25
+ from echotools.exec.fncall.protocols.entml_thinking_history import (
26
+ apply_thinking_history_policy,
27
+ parse_include_thinking_in_history,
28
+ )
25
29
  from echotools.exec.fncall.shared.loop_detect import detect_tool_loop
26
30
  from echotools.exec.fncall.shared.normalization import format_tool_descs
27
31
  from echotools.exec.protocol.base import ToolProtocol
@@ -96,14 +100,18 @@ def inject_fncall(
96
100
  protocol_options: Optional[Dict[str, Any]] = None,
97
101
  ) -> List[Dict[str, Any]]:
98
102
  """注入工具定义,返回单条 user 消息(含历史)。"""
99
- normalized = _normalize_messages(list(messages))
103
+ include_history = parse_include_thinking_in_history(protocol_options)
104
+ prepared = apply_thinking_history_policy(list(messages), include_history)
105
+ normalized = _normalize_messages(prepared)
100
106
  history_messages, current_user_message = split_last_user_message(normalized)
101
107
 
102
108
  if hasattr(protocol, 'clean_tags'):
103
109
  current_user_message = protocol.clean_tags(current_user_message)
104
110
 
105
111
  history_text = _format_conversation_history(
106
- history_messages, protocol=protocol
112
+ history_messages,
113
+ protocol=protocol,
114
+ include_thinking_in_history=include_history,
107
115
  ).strip()
108
116
 
109
117
  if not tools:
@@ -15,9 +15,37 @@ from .history import (
15
15
  _try_convert_user_to_tool,
16
16
  )
17
17
 
18
+ from echotools.exec.fncall.protocols.entml_thinking_history import (
19
+ extract_reasoning_text,
20
+ format_entml_thinking_history_block,
21
+ )
22
+
18
23
  logger = get_logger(__name__)
19
24
 
20
25
 
26
+ def _assistant_history_content_blocks(
27
+ m: Dict[str, Any],
28
+ content_str: str,
29
+ protocol: Optional[Any],
30
+ include_thinking_in_history: bool,
31
+ ) -> List[str]:
32
+ """构建 assistant 历史块正文(可选前置 entml:thinking)。"""
33
+ blocks: List[str] = []
34
+ if (
35
+ include_thinking_in_history
36
+ and protocol is not None
37
+ and getattr(protocol, "id", None) == "entml"
38
+ ):
39
+ reasoning = extract_reasoning_text(m)
40
+ if reasoning:
41
+ thinking_block = format_entml_thinking_history_block(reasoning)
42
+ if thinking_block:
43
+ blocks.append(thinking_block)
44
+ if content_str:
45
+ blocks.append(content_str)
46
+ return blocks
47
+
48
+
21
49
  def split_last_user_message(
22
50
  normalized: List[Dict[str, Any]],
23
51
  ) -> Tuple[List[Dict[str, Any]], str]:
@@ -52,11 +80,13 @@ def format_assistant_block(
52
80
  protocol: Optional[Any],
53
81
  call_id_to_name: Dict[str, str],
54
82
  seen_assistant_keys: Set[Tuple[str, Tuple[Tuple[str, str], ...]]],
83
+ *,
84
+ include_thinking_in_history: bool = False,
55
85
  ) -> Optional[str]:
56
86
  tcs: List[Dict[str, Any]] = m.get("tool_calls") or []
57
- blocks: List[str] = []
58
- if content_str:
59
- blocks.append(content_str)
87
+ blocks = _assistant_history_content_blocks(
88
+ m, content_str, protocol, include_thinking_in_history
89
+ )
60
90
  for tc in tcs:
61
91
  cid = tc.get("id") or ""
62
92
  fn_name = (tc.get("function") or {}).get("name") or ""
@@ -87,6 +117,8 @@ def format_assistant_block_with_results(
87
117
  protocol: Optional[Any],
88
118
  call_id_to_name: Dict[str, str],
89
119
  seen_assistant_keys: Set[Tuple[str, Tuple[Tuple[str, str], ...]]],
120
+ *,
121
+ include_thinking_in_history: bool = False,
90
122
  ) -> Optional[str]:
91
123
  tcs: List[Dict[str, Any]] = m.get("tool_calls") or []
92
124
  content_str = normalize_content(m.get("content", ""))
@@ -102,9 +134,9 @@ def format_assistant_block_with_results(
102
134
  for tmsg in tool_msgs
103
135
  }
104
136
 
105
- blocks: List[str] = []
106
- if content_str:
107
- blocks.append(content_str)
137
+ blocks = _assistant_history_content_blocks(
138
+ m, content_str, protocol, include_thinking_in_history
139
+ )
108
140
 
109
141
  for tc in tcs:
110
142
  if protocol is not None and hasattr(protocol, "format_assistant_tool_calls"):
@@ -11,6 +11,29 @@ HISTORY_FLAG_KEYS = (
11
11
  )
12
12
  _THINKING_BLOCK_TYPES = frozenset({"thinking", "reasoning", "redacted_thinking"})
13
13
 
14
+ _THINKING_BLOCK_OPEN = "<entml:thinking>"
15
+ _THINKING_BLOCK_CLOSE = "</entml:thinking>"
16
+
17
+
18
+ def format_entml_thinking_history_block(text: str) -> str:
19
+ """将历史 assistant 思考链格式化为 entml 块(供 conversation_history 使用)。"""
20
+ stripped = (text or "").strip()
21
+ if not stripped:
22
+ return ""
23
+ return f"{_THINKING_BLOCK_OPEN}\n{stripped}\n{_THINKING_BLOCK_CLOSE}"
24
+
25
+
26
+ def parse_include_thinking_in_history(
27
+ protocol_options: Optional[Mapping[str, Any]],
28
+ ) -> bool:
29
+ """从 protocol_options 解析是否在历史中渲染 assistant 思考链。"""
30
+ if not protocol_options:
31
+ return False
32
+ for key in HISTORY_FLAG_KEYS:
33
+ if key in protocol_options:
34
+ return bool(protocol_options[key])
35
+ return False
36
+
14
37
 
15
38
  def parse_interleaved_history(
16
39
  body: Mapping[str, Any],
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: echotools
3
- Version: 2.3.29
3
+ Version: 2.3.30
4
4
  Summary: 通用基础设施 SDK:配置、日志、事件、调度、插件、协议、调用链
5
5
  Author: nichengfuben
6
6
  License: MIT
@@ -426,3 +426,43 @@ def test_entml_parse_schema_coercion() -> None:
426
426
  calls = parse_entml_tool_calls(sample, tools, schema_index)
427
427
  args = json.loads(calls[0]["function"]["arguments"])
428
428
  assert args == {"count": 7, "enabled": True, "tags": ["x", "y"]}
429
+
430
+
431
+ def test_inject_include_thinking_in_history() -> None:
432
+ """protocol_options.include_thinking_in_history 应在历史中渲染 entml:thinking。"""
433
+ proto = get_protocol("entml")
434
+ tools = [
435
+ {
436
+ "type": "function",
437
+ "function": {
438
+ "name": "get_weather",
439
+ "description": "weather",
440
+ "parameters": {
441
+ "type": "object",
442
+ "properties": {"city": {"type": "string"}},
443
+ "required": ["city"],
444
+ },
445
+ },
446
+ }
447
+ ]
448
+ msgs = [
449
+ {"role": "user", "content": "查北京天气"},
450
+ {
451
+ "role": "assistant",
452
+ "reasoning": "应先调用 get_weather 获取实时数据。",
453
+ "content": "我来查一下。",
454
+ },
455
+ {"role": "user", "content": "那上海呢?"},
456
+ ]
457
+ plain = inject_fncall(msgs, tools, proto)[0]["content"]
458
+ assert "应先调用 get_weather" not in plain
459
+
460
+ with_history = inject_fncall(
461
+ msgs,
462
+ tools,
463
+ proto,
464
+ protocol_options={"include_thinking_in_history": True},
465
+ )[0]["content"]
466
+ assert "<entml:thinking>" in with_history
467
+ assert "应先调用 get_weather 获取实时数据。" in with_history
468
+ assert "那上海呢?" in with_history
File without changes
File without changes
File without changes