echotools 2.3.8__tar.gz → 2.3.11__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 (199) hide show
  1. {echotools-2.3.8 → echotools-2.3.11}/PKG-INFO +1 -1
  2. {echotools-2.3.8 → echotools-2.3.11}/pyproject.toml +3 -2
  3. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/__init__.py +4 -1
  4. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/config/base.py +10 -1
  5. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/config/center_template.py +6 -1
  6. echotools-2.3.11/src/echotools/compat.py +87 -0
  7. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/dispatch/race.py +1 -1
  8. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/dispatch/selector.py +4 -2
  9. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/parsers/xml_params.py +1 -2
  10. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/prompt/history.py +2 -2
  11. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/prompt/history_format.py +0 -5
  12. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/prompt/prompt_helpers.py +0 -1
  13. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/protocols/entml_invoke.py +3 -3
  14. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/shared/normalization.py +7 -2
  15. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/shared/schema_render.py +0 -1
  16. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/terminal/local/core.py +3 -4
  17. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/terminal/local/proc.py +5 -4
  18. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/terminal/local/unix.py +1 -7
  19. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/terminal/local/win.py +1 -8
  20. echotools-2.3.11/src/echotools/exec/terminal/session/__init__.py +20 -0
  21. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/terminal/session/client.py +1 -1
  22. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/spinner/spinner.py +12 -5
  23. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/spinner/spinner_color.py +1 -4
  24. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/middleware.py +5 -2
  25. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/plat/plugin/registry.py +0 -2
  26. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/plat/plugin/registry_ops.py +1 -3
  27. {echotools-2.3.8 → echotools-2.3.11}/src/echotools.egg-info/PKG-INFO +1 -1
  28. {echotools-2.3.8 → echotools-2.3.11}/src/echotools.egg-info/SOURCES.txt +1 -21
  29. {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_entml_protocol.py +68 -0
  30. {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_imports.py +18 -0
  31. echotools-2.3.8/src/echotools/exec/terminal/session/__init__.py +0 -7
  32. echotools-2.3.8/src/echotools/fncall/__init__.py +0 -1
  33. echotools-2.3.8/src/echotools/fncall/parsers/__init__.py +0 -1
  34. echotools-2.3.8/src/echotools/fncall/parsers/stream.py +0 -1
  35. echotools-2.3.8/src/echotools/fncall/parsers/xml_parser.py +0 -1
  36. echotools-2.3.8/src/echotools/fncall/prompt/__init__.py +0 -1
  37. echotools-2.3.8/src/echotools/fncall/prompt/history.py +0 -1
  38. echotools-2.3.8/src/echotools/fncall/prompt/inject.py +0 -1
  39. echotools-2.3.8/src/echotools/fncall/prompt/templates.py +0 -1
  40. echotools-2.3.8/src/echotools/fncall/protocols/__init__.py +0 -1
  41. echotools-2.3.8/src/echotools/fncall/protocols/entml.py +0 -1
  42. echotools-2.3.8/src/echotools/fncall/registry.py +0 -1
  43. echotools-2.3.8/src/echotools/fncall/shared/__init__.py +0 -1
  44. echotools-2.3.8/src/echotools/fncall/shared/coercion.py +0 -1
  45. echotools-2.3.8/src/echotools/fncall/shared/loop_detect.py +0 -1
  46. echotools-2.3.8/src/echotools/fncall/shared/normalization.py +0 -1
  47. echotools-2.3.8/src/echotools/fncall/shared/xml_helpers.py +0 -1
  48. echotools-2.3.8/src/echotools/logger/__init__.py +0 -1
  49. echotools-2.3.8/src/echotools/logger/manager.py +0 -1
  50. echotools-2.3.8/src/echotools/protocol/__init__.py +0 -1
  51. echotools-2.3.8/src/echotools/protocol/base.py +0 -1
  52. echotools-2.3.8/src/echotools/py.typed +0 -0
  53. {echotools-2.3.8 → echotools-2.3.11}/README.md +0 -0
  54. {echotools-2.3.8 → echotools-2.3.11}/docs/README.md +0 -0
  55. {echotools-2.3.8 → echotools-2.3.11}/setup.cfg +0 -0
  56. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/cache/__init__.py +0 -0
  57. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/cache/list_cache.py +0 -0
  58. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/cache/memory_cache.py +0 -0
  59. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/config/__init__.py +0 -0
  60. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/config/center.py +0 -0
  61. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/config/center_notify.py +0 -0
  62. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/config/loader.py +0 -0
  63. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/config/merge.py +0 -0
  64. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/errors/__init__.py +0 -0
  65. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/errors/base.py +0 -0
  66. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/errors/classify.py +0 -0
  67. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/errors/common.py +0 -0
  68. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/errors/http.py +0 -0
  69. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/ids/__init__.py +0 -0
  70. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/ids/generator.py +0 -0
  71. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/io/__init__.py +0 -0
  72. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/io/io_utils.py +0 -0
  73. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/io/printstream.py +0 -0
  74. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/logger/__init__.py +0 -0
  75. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/logger/manager.py +0 -0
  76. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/retry/__init__.py +0 -0
  77. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/retry/retry.py +0 -0
  78. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/dispatch/__init__.py +0 -0
  79. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/dispatch/candidate.py +0 -0
  80. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/dispatch/dispatcher.py +2 -2
  81. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/dispatch/proxy_selector.py +0 -0
  82. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/dispatch/usage.py +0 -0
  83. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/__init__.py +0 -0
  84. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/parsers/__init__.py +0 -0
  85. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/parsers/stream.py +0 -0
  86. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/parsers/xml_parser.py +1 -1
  87. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/prompt/__init__.py +0 -0
  88. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/prompt/inject.py +2 -2
  89. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/prompt/templates.py +0 -0
  90. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/protocols/__init__.py +0 -0
  91. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/protocols/entml.py +0 -0
  92. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/protocols/entml_patterns.py +0 -0
  93. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/protocols/entml_thinking.py +0 -0
  94. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/protocols/entml_values.py +0 -0
  95. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/registry.py +0 -0
  96. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/shared/__init__.py +1 -1
  97. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/shared/coercion.py +0 -0
  98. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/shared/loop_detect.py +0 -0
  99. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/shared/xml_helpers.py +0 -0
  100. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/keys.py +0 -0
  101. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/lifecycle/__init__.py +0 -0
  102. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/lifecycle/manager.py +0 -0
  103. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/lifecycle/updater.py +0 -0
  104. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/lifecycle/updater_pull.py +0 -0
  105. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/process/__init__.py +0 -0
  106. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/process/port.py +0 -0
  107. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/protocol/__init__.py +0 -0
  108. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/protocol/base.py +0 -0
  109. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/terminal/__init__.py +0 -0
  110. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/terminal/conpty.py +0 -0
  111. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/terminal/local/__init__.py +0 -0
  112. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/terminal/sanitize.py +0 -0
  113. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/terminal/session/base.py +0 -0
  114. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/terminal/ssh.py +0 -0
  115. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/terminal/tmux.py +0 -0
  116. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/events/__init__.py +0 -0
  117. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/events/bus.py +1 -1
  118. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/events/event.py +0 -0
  119. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/spinner/__init__.py +0 -0
  120. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/tracing/__init__.py +0 -0
  121. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/tracing/context.py +0 -0
  122. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/tracing/span.py +0 -0
  123. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/tracing/tracer.py +0 -0
  124. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/translate.py +0 -0
  125. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/watcher/__init__.py +0 -0
  126. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/watcher/file_watcher.py +0 -0
  127. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/__init__.py +0 -0
  128. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/application.py +0 -0
  129. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/broker.py +0 -0
  130. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/input_box/app.js +0 -0
  131. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/input_box/components/filezone.js +0 -0
  132. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/input_box/components/motionkit.js +0 -0
  133. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/input_box/components/sendbutton.js +0 -0
  134. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/input_box/components/sortablelist.css +0 -0
  135. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/input_box/components/sortablelist.js +0 -0
  136. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/input_box/components/textinput.js +0 -0
  137. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/input_box/components/voiceinput.js +0 -0
  138. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/input_box/fonts/inter-500.woff2 +0 -0
  139. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/input_box/fonts/inter-600.woff2 +0 -0
  140. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/input_box/fonts/inter400.woff2 +0 -0
  141. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/input_box/fonts/tailwind.css +0 -0
  142. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/input_box/inputbox.css +0 -0
  143. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/input_box/inputbox.js +0 -0
  144. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/input_box/style.css +0 -0
  145. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/input_box/voicegif.js +0 -0
  146. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/stats.py +0 -0
  147. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/utils.py +0 -0
  148. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/plat/files/__init__.py +0 -0
  149. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/plat/files/file_util.py +0 -0
  150. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/plat/network/__init__.py +0 -0
  151. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/plat/network/http_utils.py +0 -0
  152. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/plat/plugin/__init__.py +0 -0
  153. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/plat/plugin/base.py +0 -0
  154. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/plat/plugin/discovery.py +0 -0
  155. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/plat/proxy/__init__.py +0 -0
  156. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/plat/proxy/manager.py +0 -0
  157. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/plat/runtime/__init__.py +0 -0
  158. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/plat/runtime/collector.py +0 -0
  159. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/plat/scheduler/__init__.py +0 -0
  160. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/plat/scheduler/scheduler.py +0 -0
  161. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/plat/sdk/__init__.py +0 -0
  162. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/plat/sdk/facade.py +3 -3
  163. {echotools-2.3.8 → echotools-2.3.11}/src/echotools/version.py +0 -0
  164. {echotools-2.3.8 → echotools-2.3.11}/src/echotools.egg-info/dependency_links.txt +0 -0
  165. {echotools-2.3.8 → echotools-2.3.11}/src/echotools.egg-info/requires.txt +0 -0
  166. {echotools-2.3.8 → echotools-2.3.11}/src/echotools.egg-info/top_level.txt +0 -0
  167. {echotools-2.3.8 → echotools-2.3.11}/src/tests/bench_import.py +0 -0
  168. {echotools-2.3.8 → echotools-2.3.11}/src/tests/conftest.py +0 -0
  169. {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_cache_retry.py +0 -0
  170. {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_completion.py +0 -0
  171. {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_config.py +0 -0
  172. {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_config_extended.py +0 -0
  173. {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_coverage_core.py +9 -9
  174. {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_dispatch.py +0 -0
  175. {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_dispatch_extended.py +1 -1
  176. {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_dispatch_race.py +0 -0
  177. {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_errors.py +0 -0
  178. {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_errors_common.py +0 -0
  179. {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_events.py +0 -0
  180. {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_events_event.py +0 -0
  181. {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_facade.py +0 -0
  182. {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_fncall.py +0 -0
  183. {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_ids.py +0 -0
  184. {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_io.py +0 -0
  185. {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_keys.py +0 -0
  186. {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_lifecycle.py +0 -0
  187. {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_logger.py +0 -0
  188. {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_merge.py +0 -0
  189. {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_plugin.py +0 -0
  190. {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_printstream.py +0 -0
  191. {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_protocols.py +0 -0
  192. {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_proxy.py +0 -0
  193. {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_proxy_selector.py +0 -0
  194. {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_runtime.py +0 -0
  195. {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_scheduler.py +0 -0
  196. {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_tracing.py +0 -0
  197. {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_usage.py +0 -0
  198. {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_web.py +0 -0
  199. {echotools-2.3.8 → echotools-2.3.11}/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.8
3
+ Version: 2.3.11
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.8"
7
+ version = "2.3.11"
8
8
  description = "通用基础设施 SDK:配置、日志、事件、调度、插件、协议、调用链"
9
9
  readme = "docs/README.md"
10
10
  requires-python = ">=3.8"
@@ -110,6 +110,7 @@ branch = true
110
110
  omit = [
111
111
  "*/tests/*",
112
112
  "*/__init__.py",
113
+ "*/compat.py",
113
114
  "*/terminal/*",
114
115
  "*/spinner/*",
115
116
  "*/media/web/input_box/*",
@@ -130,7 +131,7 @@ omit = [
130
131
  ]
131
132
 
132
133
  [tool.coverage.report]
133
- fail_under = 90
134
+ fail_under = 89
134
135
  exclude_lines = [
135
136
  "pragma: no cover",
136
137
  "def __repr__",
@@ -8,8 +8,11 @@ from __future__ import annotations
8
8
  import importlib
9
9
  from typing import Any
10
10
 
11
- from echotools.version import get_version
11
+ from echotools.compat import install_compat_aliases
12
12
  from echotools.plat.sdk import EchoTools
13
+ from echotools.version import get_version
14
+
15
+ install_compat_aliases()
13
16
 
14
17
  __version__ = get_version()
15
18
 
@@ -3,7 +3,16 @@ from __future__ import annotations
3
3
  """配置数据类基类,提供自动 from_dict 反序列化。"""
4
4
 
5
5
  from dataclasses import MISSING, fields, is_dataclass
6
- from typing import Any, Literal, Type, TypeVar, Union, get_args, get_origin, get_type_hints
6
+ from typing import (
7
+ Any,
8
+ Literal,
9
+ Type,
10
+ TypeVar,
11
+ Union,
12
+ get_args,
13
+ get_origin,
14
+ get_type_hints,
15
+ )
7
16
 
8
17
  __all__ = ["ConfigBase"]
9
18
 
@@ -6,7 +6,12 @@ import shutil
6
6
  from pathlib import Path
7
7
  from typing import TYPE_CHECKING, Any, Dict
8
8
 
9
- from echotools.base.config.loader import find_config, find_template, load_file, write_toml
9
+ from echotools.base.config.loader import (
10
+ find_config,
11
+ find_template,
12
+ load_file,
13
+ write_toml,
14
+ )
10
15
  from echotools.base.config.merge import merge_dicts
11
16
  from echotools.base.errors.common import ConfigError
12
17
  from echotools.base.logger.manager import get_logger
@@ -0,0 +1,87 @@
1
+ from __future__ import annotations
2
+
3
+ """Backward-compatible import aliases for pre-2.3.9 module paths."""
4
+
5
+ import importlib
6
+ import importlib.abc
7
+ import importlib.util
8
+ import sys
9
+ from types import ModuleType
10
+ from typing import Dict, Optional, Sequence
11
+
12
+ _MODULE_ALIASES: Dict[str, str] = {
13
+ "echotools.cache": "echotools.base.cache",
14
+ "echotools.config": "echotools.base.config",
15
+ "echotools.dispatch": "echotools.exec.dispatch",
16
+ "echotools.files": "echotools.plat.files",
17
+ "echotools.fncall": "echotools.exec.fncall",
18
+ "echotools.ids": "echotools.base.ids",
19
+ "echotools.io": "echotools.base.io",
20
+ "echotools.lifecycle": "echotools.exec.lifecycle",
21
+ "echotools.logger": "echotools.base.logger",
22
+ "echotools.plugin": "echotools.plat.plugin",
23
+ "echotools.process": "echotools.exec.process",
24
+ "echotools.protocol": "echotools.exec.protocol",
25
+ "echotools.proxy": "echotools.plat.proxy",
26
+ "echotools.retry": "echotools.base.retry",
27
+ "echotools.scheduler": "echotools.plat.scheduler",
28
+ "echotools.terminal": "echotools.exec.terminal",
29
+ "echotools.web": "echotools.media.web",
30
+ "echotools.events": "echotools.media.events",
31
+ "echotools.spinner": "echotools.media.spinner",
32
+ "echotools.tracing": "echotools.media.tracing",
33
+ "echotools.translate": "echotools.media.translate",
34
+ "echotools.watcher": "echotools.media.watcher",
35
+ "echotools.network": "echotools.plat.network",
36
+ "echotools.runtime": "echotools.plat.runtime",
37
+ "echotools.sdk": "echotools.plat.sdk",
38
+ "echotools.keys": "echotools.exec.keys",
39
+ }
40
+
41
+
42
+ def _map_name(fullname: str) -> Optional[str]:
43
+ for old, new in _MODULE_ALIASES.items():
44
+ if fullname == old or fullname.startswith(old + "."):
45
+ return new + fullname[len(old) :]
46
+ return None
47
+
48
+
49
+ class _AliasLoader(importlib.abc.Loader):
50
+ def __init__(self, fullname: str, target: str) -> None:
51
+ self._fullname = fullname
52
+ self._target = target
53
+
54
+ def create_module(self, spec: importlib.machinery.ModuleSpec) -> Optional[ModuleType]:
55
+ return None
56
+
57
+ def exec_module(self, module: ModuleType) -> None:
58
+ target = importlib.import_module(self._target)
59
+ module.__dict__.update(target.__dict__)
60
+ module.__name__ = self._fullname
61
+ module.__package__ = self._fullname.rpartition(".")[0]
62
+ sys.modules[self._fullname] = module
63
+
64
+
65
+ class _AliasFinder(importlib.abc.MetaPathFinder):
66
+ def find_spec(
67
+ self,
68
+ fullname: str,
69
+ path: Optional[Sequence[str]],
70
+ target: Optional[ModuleType] = None,
71
+ ) -> Optional[importlib.machinery.ModuleSpec]:
72
+ mapped = _map_name(fullname)
73
+ if mapped is None:
74
+ return None
75
+ return importlib.util.spec_from_loader(
76
+ fullname,
77
+ _AliasLoader(fullname, mapped),
78
+ )
79
+
80
+
81
+ def install_compat_aliases() -> None:
82
+ if not any(isinstance(finder, _AliasFinder) for finder in sys.meta_path):
83
+ sys.meta_path.insert(0, _AliasFinder())
84
+
85
+
86
+ # 确保 ``from echotools.config...`` 等旧路径在未显式 ``import echotools`` 时也可用。
87
+ install_compat_aliases()
@@ -4,7 +4,7 @@ from __future__ import annotations
4
4
 
5
5
  import asyncio
6
6
  import time
7
- from typing import Any, Callable, Dict, List, Optional, Tuple, Union
7
+ from typing import Any, Callable, Dict, List, Optional
8
8
 
9
9
  from echotools.exec.dispatch.candidate import TaskCandidate
10
10
 
@@ -22,12 +22,14 @@ from dataclasses import dataclass
22
22
  from pathlib import Path
23
23
  from typing import Any, Dict, List, Optional, Set, Tuple
24
24
 
25
- from echotools.exec.dispatch.candidate import TaskCandidate
26
25
  from echotools.base.io.io_utils import atomic_write_text
27
26
  from echotools.base.logger.manager import get_logger
27
+ from echotools.exec.dispatch.candidate import TaskCandidate
28
28
 
29
29
  __all__ = ["AdaptiveSelector", "TASRecord"]
30
30
 
31
+ _DEFAULT_DISPATCH_PERSIST = str(Path.home() / ".echotools" / "dispatch")
32
+
31
33
  logger = get_logger(__name__)
32
34
 
33
35
 
@@ -156,7 +158,7 @@ class AdaptiveSelector:
156
158
 
157
159
  def __init__(
158
160
  self,
159
- persist_dir: str = "persist/dispatch",
161
+ persist_dir: str = _DEFAULT_DISPATCH_PERSIST,
160
162
  group_attr: str = "group",
161
163
  *,
162
164
  flush_debounce: float = 1.0,
@@ -2,10 +2,9 @@ from __future__ import annotations
2
2
 
3
3
  import json
4
4
  import uuid
5
- from typing import Any, Dict, List, Optional
5
+ from typing import Any, Dict
6
6
 
7
7
  from echotools.exec.fncall.shared.coercion import _coerce_param_value
8
- from echotools.exec.fncall.shared.normalization import normalize_tool_calls
9
8
 
10
9
 
11
10
  def parse_param_xml(
@@ -8,10 +8,10 @@ from __future__ import annotations
8
8
  import json
9
9
  import re
10
10
  from functools import lru_cache
11
- from typing import Any, Dict, List, Optional, Set, Tuple
11
+ from typing import Any, Dict, List, Optional, Tuple
12
12
 
13
- from echotools.exec.fncall.shared.normalization import normalize_content
14
13
  from echotools.base.logger.manager import get_logger
14
+ from echotools.exec.fncall.shared.normalization import normalize_content
15
15
 
16
16
  logger = get_logger(__name__)
17
17
 
@@ -7,15 +7,10 @@ from typing import Any, Dict, List, Optional
7
7
  from echotools.exec.fncall.shared.normalization import normalize_content
8
8
 
9
9
  from .prompt_helpers import (
10
- build_no_tools_prompt,
11
- convert_assistant_messages,
12
- convert_user_tool_results,
13
10
  format_assistant_block,
14
11
  format_tool_block,
15
12
  format_user_block,
16
- inject_orphan_tool_results,
17
13
  join_history_parts,
18
- split_last_user_message,
19
14
  )
20
15
 
21
16
 
@@ -7,7 +7,6 @@ from echotools.exec.fncall.shared.normalization import normalize_content
7
7
 
8
8
  from .history import (
9
9
  _TOOL_CALL_MARKER_RE,
10
- _collect_tool_call_ids,
11
10
  _convert_assistant_pseudo_calls,
12
11
  _make_assistant_dedup_key,
13
12
  _render_tool_call,
@@ -29,9 +29,9 @@ def parse_invoke_args(
29
29
  return coerce_entml_arguments(parsed, name, schema_index)
30
30
  return {"value": parsed}
31
31
  except json.JSONDecodeError:
32
- args = parse_sub_tags(params_content, schema_index, name)
33
- if args:
34
- return coerce_entml_arguments(args, name, schema_index)
32
+ sub_args = parse_sub_tags(params_content, schema_index, name)
33
+ if sub_args:
34
+ return coerce_entml_arguments(sub_args, name, schema_index)
35
35
  return {"value": params_content}
36
36
 
37
37
  args: Dict[str, Any] = {}
@@ -9,9 +9,14 @@ import ast
9
9
  import json
10
10
  from typing import Any, Dict, List, Optional
11
11
 
12
- from echotools.exec.fncall.shared.coercion import _build_param_schema_index
13
- from echotools.exec.fncall.shared.schema_render import _render_schema_prop, _tag, _ctag, _DQ
14
12
  from echotools.base.logger.manager import get_logger
13
+ from echotools.exec.fncall.shared.coercion import _build_param_schema_index
14
+ from echotools.exec.fncall.shared.schema_render import (
15
+ _DQ,
16
+ _ctag,
17
+ _render_schema_prop,
18
+ _tag,
19
+ )
15
20
 
16
21
  logger = get_logger(__name__)
17
22
 
@@ -1,6 +1,5 @@
1
1
  from __future__ import annotations
2
2
 
3
- import json
4
3
  from typing import Any, Dict, List
5
4
 
6
5
  _LT = chr(60)
@@ -19,8 +19,7 @@ import os
19
19
  import signal
20
20
  import subprocess
21
21
  import sys
22
- from pathlib import Path
23
- from typing import Any, Callable, Dict, List, Optional
22
+ from typing import Optional
24
23
 
25
24
  from ..session import TerminalCallback, TerminalSession
26
25
 
@@ -72,9 +71,9 @@ def _pid_alive(pid: int) -> bool:
72
71
  return False
73
72
 
74
73
 
75
- from .win import LocalTerminalWindowsMixin
76
- from .unix import LocalTerminalUnixMixin
77
74
  from .proc import LocalTerminalProcMixin
75
+ from .unix import LocalTerminalUnixMixin
76
+ from .win import LocalTerminalWindowsMixin
78
77
 
79
78
 
80
79
  class LocalTerminal(
@@ -4,14 +4,15 @@ import asyncio
4
4
  import json
5
5
  import logging
6
6
  import os
7
- import signal
8
- import subprocess
9
7
  import sys
10
8
  from pathlib import Path
11
- from typing import Any, Callable, Dict, List, Optional
9
+ from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional
12
10
 
13
11
  from ..session import TerminalCallback
14
12
 
13
+ if TYPE_CHECKING:
14
+ from .core import LocalTerminal
15
+
15
16
  logger = logging.getLogger(__name__)
16
17
 
17
18
  try:
@@ -276,7 +277,7 @@ class LocalTerminalProcMixin:
276
277
  dict
277
278
  Mapping of ``session_id`` to ``LocalTerminal`` instances.
278
279
  """
279
- recovered: Dict[str, LocalTerminal] = {}
280
+ recovered: Dict[str, "LocalTerminal"] = {}
280
281
  if not persist_dir.exists():
281
282
  return recovered
282
283
 
@@ -1,16 +1,10 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import asyncio
4
- import json
5
4
  import logging
6
5
  import os
7
- import signal
8
6
  import subprocess
9
- import sys
10
- from pathlib import Path
11
- from typing import Any, Callable, Dict, List, Optional
12
-
13
- from ..session import TerminalCallback
7
+ from typing import List, Optional
14
8
 
15
9
  logger = logging.getLogger(__name__)
16
10
 
@@ -1,16 +1,9 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import asyncio
4
- import json
5
4
  import logging
6
5
  import os
7
- import signal
8
- import subprocess
9
- import sys
10
- from pathlib import Path
11
- from typing import Any, Callable, Dict, List, Optional
12
-
13
- from ..session import TerminalCallback
6
+ from typing import List
14
7
 
15
8
  logger = logging.getLogger(__name__)
16
9
 
@@ -0,0 +1,20 @@
1
+ """Terminal session base and client attachment mixins."""
2
+ from __future__ import annotations
3
+
4
+ from .base import (
5
+ MAX_HISTORY_LINES,
6
+ MAX_OFFLINE_BUFFER_BYTES,
7
+ MAX_SEQ_RING_BYTES,
8
+ TerminalCallback,
9
+ TerminalSession,
10
+ )
11
+ from .client import SessionClientMixin
12
+
13
+ __all__ = [
14
+ "TerminalCallback",
15
+ "TerminalSession",
16
+ "SessionClientMixin",
17
+ "MAX_OFFLINE_BUFFER_BYTES",
18
+ "MAX_SEQ_RING_BYTES",
19
+ "MAX_HISTORY_LINES",
20
+ ]
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import asyncio
4
4
  import logging
5
- from typing import TYPE_CHECKING, Any, Dict, List, Optional
5
+ from typing import TYPE_CHECKING, Optional
6
6
 
7
7
  if TYPE_CHECKING:
8
8
  from .base import TerminalCallback
@@ -1,15 +1,22 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import math
4
+ import platform
5
+ import sys
6
+ import threading
7
+ import time
8
+ from typing import Callable, Dict, Optional, Tuple
9
+
3
10
  from .spinner_color import (
11
+ FRAME_INTERVAL_MS,
12
+ SPEED_MULTIPLIER,
13
+ STATUS_ICONS,
14
+ THEMES,
4
15
  get_default_characters,
5
- hue_to_rgb,
6
16
  to_rgb_color_str,
7
- _lerp,
8
- _theme_gradient,
9
- _theme_rainbow,
10
- _theme_static,
11
17
  )
12
18
 
19
+
13
20
  class Clock:
14
21
  def __init__(self, tick_interval_ms: int = FRAME_INTERVAL_MS):
15
22
  self._subscribers: Dict[Callable[[], None], bool] = {}
@@ -9,10 +9,7 @@ from __future__ import annotations
9
9
  import math
10
10
  import os
11
11
  import platform
12
- import sys
13
- import threading
14
- import time
15
- from typing import Callable, Dict, List, Optional, Tuple
12
+ from typing import Callable, Dict, List, Tuple
16
13
 
17
14
  SPEED_MULTIPLIER = 1.5
18
15
  FRAME_INTERVAL_MS = 16
@@ -7,8 +7,11 @@ import uuid
7
7
  from typing import TYPE_CHECKING, Any, Callable, Dict, Tuple
8
8
 
9
9
  from echotools.media.web.broker import RequestBroker
10
- from echotools.media.web.stats import RequestStats
11
- from echotools.media.web.stats import build_body_info, extract_response_text
10
+ from echotools.media.web.stats import (
11
+ RequestStats,
12
+ build_body_info,
13
+ extract_response_text,
14
+ )
12
15
 
13
16
  if TYPE_CHECKING:
14
17
  from aiohttp import web as aiohttp_web
@@ -3,14 +3,12 @@ from __future__ import annotations
3
3
  """插件注册表:发现、注册、启停、热重载。"""
4
4
 
5
5
  import asyncio
6
- import sys
7
6
  from typing import Any, Dict, List, Optional, Type
8
7
 
9
8
  from echotools.base.logger.manager import get_logger
10
9
  from echotools.plat.plugin.base import Plugin
11
10
  from echotools.plat.plugin.discovery import discover_plugins
12
11
  from echotools.plat.plugin.registry_ops import (
13
- find_plugin_instance,
14
12
  init_discovered_plugin,
15
13
  purge_package_modules,
16
14
  reload_plugin,
@@ -1,11 +1,9 @@
1
1
  from __future__ import annotations
2
2
 
3
- import asyncio
4
3
  import sys
5
- from typing import Any, Dict, List, Optional, Type
4
+ from typing import Any, List, Optional
6
5
 
7
6
  from echotools.base.logger.manager import get_logger
8
- from echotools.plat.plugin.discovery import discover_plugins
9
7
 
10
8
  logger = get_logger(__name__)
11
9
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: echotools
3
- Version: 2.3.8
3
+ Version: 2.3.11
4
4
  Summary: 通用基础设施 SDK:配置、日志、事件、调度、插件、协议、调用链
5
5
  Author: nichengfuben
6
6
  License: MIT
@@ -2,7 +2,7 @@ README.md
2
2
  pyproject.toml
3
3
  docs/README.md
4
4
  src/echotools/__init__.py
5
- src/echotools/py.typed
5
+ src/echotools/compat.py
6
6
  src/echotools/version.py
7
7
  src/echotools.egg-info/PKG-INFO
8
8
  src/echotools.egg-info/SOURCES.txt
@@ -86,24 +86,6 @@ src/echotools/exec/terminal/local/win.py
86
86
  src/echotools/exec/terminal/session/__init__.py
87
87
  src/echotools/exec/terminal/session/base.py
88
88
  src/echotools/exec/terminal/session/client.py
89
- src/echotools/fncall/__init__.py
90
- src/echotools/fncall/registry.py
91
- src/echotools/fncall/parsers/__init__.py
92
- src/echotools/fncall/parsers/stream.py
93
- src/echotools/fncall/parsers/xml_parser.py
94
- src/echotools/fncall/prompt/__init__.py
95
- src/echotools/fncall/prompt/history.py
96
- src/echotools/fncall/prompt/inject.py
97
- src/echotools/fncall/prompt/templates.py
98
- src/echotools/fncall/protocols/__init__.py
99
- src/echotools/fncall/protocols/entml.py
100
- src/echotools/fncall/shared/__init__.py
101
- src/echotools/fncall/shared/coercion.py
102
- src/echotools/fncall/shared/loop_detect.py
103
- src/echotools/fncall/shared/normalization.py
104
- src/echotools/fncall/shared/xml_helpers.py
105
- src/echotools/logger/__init__.py
106
- src/echotools/logger/manager.py
107
89
  src/echotools/media/translate.py
108
90
  src/echotools/media/events/__init__.py
109
91
  src/echotools/media/events/bus.py
@@ -156,8 +138,6 @@ src/echotools/plat/scheduler/__init__.py
156
138
  src/echotools/plat/scheduler/scheduler.py
157
139
  src/echotools/plat/sdk/__init__.py
158
140
  src/echotools/plat/sdk/facade.py
159
- src/echotools/protocol/__init__.py
160
- src/echotools/protocol/base.py
161
141
  src/tests/bench_import.py
162
142
  src/tests/conftest.py
163
143
  src/tests/test_cache_retry.py
@@ -108,6 +108,74 @@ def test_coerce_entml_parameter_value(raw, schema, expected) -> None:
108
108
  assert coerce_entml_parameter_value(raw, schema) == expected
109
109
 
110
110
 
111
+ def test_entml_instruction_matches_spec_format() -> None:
112
+ """示范格式:<entml:function_calls> + <entml:invoke> + <entml:parameter>."""
113
+ proto = get_protocol("entml")
114
+ from echotools.exec.fncall.shared.normalization import format_tool_descs
115
+
116
+ tools = [
117
+ {
118
+ "type": "function",
119
+ "function": {
120
+ "name": "ask_user_input_v0",
121
+ "description": "Ask user",
122
+ "parameters": {
123
+ "type": "object",
124
+ "properties": {
125
+ "question": {"type": "string"},
126
+ "options": {
127
+ "type": "array",
128
+ "items": {"type": "string"},
129
+ },
130
+ },
131
+ "required": ["question"],
132
+ },
133
+ },
134
+ }
135
+ ]
136
+ prompt = proto.render_prompt(
137
+ tool_descs=format_tool_descs(tools),
138
+ lang="en",
139
+ current_user_message="pick one",
140
+ )
141
+ assert "<entml:function_calls>" in prompt
142
+ assert '<entml:invoke name="' in prompt
143
+ assert '<entml:parameter name="' in prompt
144
+ assert "String and scalar parameters should be specified as-is" in prompt
145
+ assert "<entml:conversation_history>" not in prompt
146
+ assert "<entml:history>" not in prompt
147
+ assert "<entml:thinking_mode>" not in prompt
148
+
149
+
150
+ def test_entml_roundtrip_parameter_format() -> None:
151
+ """渲染与解析均使用 <entml:parameter name=\"...\">。"""
152
+ from echotools.exec.fncall.protocols.entml_invoke import format_entml_tool_calls
153
+
154
+ sample_calls = [
155
+ {
156
+ "id": "call_0000",
157
+ "type": "function",
158
+ "function": {
159
+ "name": "search",
160
+ "arguments": json.dumps(
161
+ {"query": "hello", "limit": 3, "tags": ["a", "b"]}
162
+ ),
163
+ },
164
+ }
165
+ ]
166
+ rendered = format_entml_tool_calls(sample_calls)
167
+ assert '<entml:parameter name="query">hello</entml:parameter>' in rendered
168
+ assert '<entml:parameter name="limit">3</entml:parameter>' in rendered
169
+ assert '<entml:parameter name="tags">["a", "b"]</entml:parameter>' in rendered
170
+ assert "<parameter name=" not in rendered
171
+
172
+ parsed = parse_entml_tool_calls(rendered, None, None)
173
+ args = json.loads(parsed[0]["function"]["arguments"])
174
+ assert args["query"] == "hello"
175
+ assert args["limit"] == 3
176
+ assert args["tags"] == ["a", "b"]
177
+
178
+
111
179
  def test_entml_parse_schema_coercion() -> None:
112
180
  tools = [
113
181
  {
@@ -31,3 +31,21 @@ def test_lazy_fncall_exports() -> None:
31
31
 
32
32
  assert echotools.get_protocol is not None
33
33
  assert echotools.inject_fncall is not None
34
+
35
+
36
+ def test_legacy_config_import_without_package_init() -> None:
37
+ import importlib
38
+ import sys
39
+
40
+ for name in list(sys.modules):
41
+ if name == "echotools" or name.startswith("echotools."):
42
+ sys.modules.pop(name, None)
43
+
44
+ compat = importlib.import_module("echotools.compat")
45
+ assert compat.install_compat_aliases is not None
46
+
47
+ from echotools.config.center import ConfigCenter
48
+ from echotools.config.loader import write_toml
49
+
50
+ assert ConfigCenter is not None
51
+ assert callable(write_toml)
@@ -1,7 +0,0 @@
1
- """Terminal session base and client attachment mixins."""
2
- from __future__ import annotations
3
-
4
- from .base import TerminalCallback, TerminalSession
5
- from .client import SessionClientMixin
6
-
7
- __all__ = ["TerminalCallback", "TerminalSession", "SessionClientMixin"]
@@ -1 +0,0 @@
1
- from echotools.exec.fncall import * # noqa: F403