echotools 2.3.7__tar.gz → 2.3.8__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 (213) hide show
  1. {echotools-2.3.7 → echotools-2.3.8}/PKG-INFO +1 -1
  2. echotools-2.3.8/README.md +3 -0
  3. {echotools-2.3.7 → echotools-2.3.8}/pyproject.toml +6 -6
  4. echotools-2.3.8/src/echotools/__init__.py +212 -0
  5. echotools-2.3.8/src/echotools/base/cache/__init__.py +8 -0
  6. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/base}/cache/list_cache.py +1 -1
  7. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/base}/config/__init__.py +4 -4
  8. echotools-2.3.8/src/echotools/base/config/base.py +146 -0
  9. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/base}/config/center.py +17 -175
  10. echotools-2.3.8/src/echotools/base/config/center_notify.py +39 -0
  11. echotools-2.3.8/src/echotools/base/config/center_template.py +137 -0
  12. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/base}/config/loader.py +1 -1
  13. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/base}/errors/__init__.py +4 -4
  14. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/base}/errors/classify.py +3 -3
  15. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/base}/errors/common.py +1 -1
  16. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/base}/errors/http.py +1 -1
  17. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/base}/ids/__init__.py +1 -1
  18. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/base}/io/__init__.py +2 -2
  19. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/base}/io/io_utils.py +1 -1
  20. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/base}/io/printstream.py +17 -31
  21. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/base}/logger/__init__.py +1 -1
  22. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/base}/retry/__init__.py +1 -1
  23. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/base}/retry/retry.py +12 -26
  24. echotools-2.3.8/src/echotools/exec/dispatch/__init__.py +21 -0
  25. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/exec}/dispatch/dispatcher.py +56 -126
  26. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/exec}/dispatch/proxy_selector.py +2 -2
  27. echotools-2.3.8/src/echotools/exec/dispatch/race.py +119 -0
  28. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/exec}/dispatch/selector.py +3 -3
  29. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/exec}/fncall/__init__.py +7 -7
  30. echotools-2.3.8/src/echotools/exec/fncall/parsers/__init__.py +6 -0
  31. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/exec}/fncall/parsers/stream.py +1 -1
  32. echotools-2.3.8/src/echotools/exec/fncall/parsers/xml_params.py +41 -0
  33. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/exec}/fncall/parsers/xml_parser.py +48 -86
  34. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/exec}/fncall/prompt/__init__.py +1 -1
  35. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/exec}/fncall/prompt/history.py +13 -145
  36. echotools-2.3.8/src/echotools/exec/fncall/prompt/history_format.py +56 -0
  37. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/exec}/fncall/prompt/inject.py +67 -70
  38. echotools-2.3.8/src/echotools/exec/fncall/prompt/prompt_helpers.py +153 -0
  39. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/exec}/fncall/protocols/__init__.py +2 -2
  40. echotools-2.3.8/src/echotools/exec/fncall/protocols/entml.py +159 -0
  41. echotools-2.3.8/src/echotools/exec/fncall/protocols/entml_invoke.py +109 -0
  42. echotools-2.3.8/src/echotools/exec/fncall/protocols/entml_patterns.py +42 -0
  43. echotools-2.3.8/src/echotools/exec/fncall/protocols/entml_thinking.py +42 -0
  44. echotools-2.3.8/src/echotools/exec/fncall/protocols/entml_values.py +74 -0
  45. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/exec}/fncall/registry.py +3 -3
  46. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/exec}/fncall/shared/__init__.py +4 -4
  47. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/exec}/fncall/shared/coercion.py +43 -54
  48. echotools-2.3.8/src/echotools/exec/fncall/shared/normalization.py +172 -0
  49. echotools-2.3.8/src/echotools/exec/fncall/shared/schema_render.py +127 -0
  50. echotools-2.3.8/src/echotools/exec/lifecycle/__init__.py +8 -0
  51. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/exec}/lifecycle/manager.py +1 -1
  52. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/exec}/lifecycle/updater.py +11 -38
  53. echotools-2.3.8/src/echotools/exec/lifecycle/updater_pull.py +33 -0
  54. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/exec}/process/__init__.py +1 -1
  55. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/exec}/process/port.py +1 -1
  56. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/exec}/protocol/__init__.py +1 -1
  57. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/exec}/protocol/base.py +2 -1
  58. echotools-2.3.8/src/echotools/exec/terminal/local/__init__.py +6 -0
  59. echotools-2.3.8/src/echotools/exec/terminal/local/core.py +319 -0
  60. echotools-2.3.8/src/echotools/exec/terminal/local/proc.py +330 -0
  61. echotools-2.3.8/src/echotools/exec/terminal/local/unix.py +201 -0
  62. echotools-2.3.8/src/echotools/exec/terminal/local/win.py +206 -0
  63. echotools-2.3.8/src/echotools/exec/terminal/session/__init__.py +7 -0
  64. echotools-2.3.7/src/echotools/terminal/session.py → echotools-2.3.8/src/echotools/exec/terminal/session/base.py +5 -145
  65. echotools-2.3.8/src/echotools/exec/terminal/session/client.py +155 -0
  66. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/exec}/terminal/ssh.py +40 -24
  67. echotools-2.3.8/src/echotools/fncall/__init__.py +1 -0
  68. echotools-2.3.8/src/echotools/fncall/parsers/__init__.py +1 -0
  69. echotools-2.3.8/src/echotools/fncall/parsers/stream.py +1 -0
  70. echotools-2.3.8/src/echotools/fncall/parsers/xml_parser.py +1 -0
  71. echotools-2.3.8/src/echotools/fncall/prompt/__init__.py +1 -0
  72. echotools-2.3.8/src/echotools/fncall/prompt/history.py +1 -0
  73. echotools-2.3.8/src/echotools/fncall/prompt/inject.py +1 -0
  74. echotools-2.3.8/src/echotools/fncall/prompt/templates.py +1 -0
  75. echotools-2.3.8/src/echotools/fncall/protocols/__init__.py +1 -0
  76. echotools-2.3.8/src/echotools/fncall/protocols/entml.py +1 -0
  77. echotools-2.3.8/src/echotools/fncall/registry.py +1 -0
  78. echotools-2.3.8/src/echotools/fncall/shared/__init__.py +1 -0
  79. echotools-2.3.8/src/echotools/fncall/shared/coercion.py +1 -0
  80. echotools-2.3.8/src/echotools/fncall/shared/loop_detect.py +1 -0
  81. echotools-2.3.8/src/echotools/fncall/shared/normalization.py +1 -0
  82. echotools-2.3.8/src/echotools/fncall/shared/xml_helpers.py +1 -0
  83. echotools-2.3.8/src/echotools/logger/__init__.py +1 -0
  84. echotools-2.3.8/src/echotools/logger/manager.py +1 -0
  85. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/media}/events/__init__.py +2 -2
  86. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/media}/events/bus.py +2 -2
  87. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/media}/spinner/__init__.py +2 -2
  88. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/media}/spinner/spinner.py +9 -114
  89. echotools-2.3.8/src/echotools/media/spinner/spinner_color.py +101 -0
  90. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/media}/tracing/__init__.py +3 -3
  91. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/media}/tracing/span.py +2 -2
  92. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/media}/tracing/tracer.py +2 -2
  93. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/media}/translate.py +24 -35
  94. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/media}/watcher/__init__.py +1 -1
  95. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/media}/watcher/file_watcher.py +1 -1
  96. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/media}/web/__init__.py +6 -6
  97. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/media}/web/application.py +1 -1
  98. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/media}/web/input_box/app.js +8 -7
  99. echotools-2.3.8/src/echotools/media/web/input_box/components/filezone.js +277 -0
  100. echotools-2.3.8/src/echotools/media/web/input_box/components/motionkit.js +154 -0
  101. echotools-2.3.8/src/echotools/media/web/input_box/components/sendbutton.js +64 -0
  102. echotools-2.3.8/src/echotools/media/web/input_box/components/voiceinput.js +76 -0
  103. echotools-2.3.7/src/echotools/web/input_box/input-box.js → echotools-2.3.8/src/echotools/media/web/input_box/inputbox.js +7 -8
  104. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/media}/web/input_box/style.css +1 -1
  105. echotools-2.3.7/src/echotools/web/input_box/voice_input/voice-input.js → echotools-2.3.8/src/echotools/media/web/input_box/voicegif.js +2 -102
  106. echotools-2.3.8/src/echotools/media/web/middleware.py +126 -0
  107. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/media}/web/stats.py +37 -0
  108. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/media}/web/utils.py +1 -1
  109. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/plat}/files/__init__.py +1 -1
  110. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/plat}/files/file_util.py +1 -1
  111. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/plat}/network/__init__.py +1 -1
  112. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/plat}/network/http_utils.py +2 -2
  113. echotools-2.3.8/src/echotools/plat/plugin/__init__.py +9 -0
  114. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/plat}/plugin/discovery.py +2 -2
  115. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/plat}/plugin/registry.py +23 -76
  116. echotools-2.3.8/src/echotools/plat/plugin/registry_ops.py +101 -0
  117. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/plat}/proxy/__init__.py +1 -1
  118. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/plat}/proxy/manager.py +1 -1
  119. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/plat}/runtime/__init__.py +1 -1
  120. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/plat}/runtime/collector.py +1 -1
  121. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/plat}/scheduler/__init__.py +1 -1
  122. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/plat}/scheduler/scheduler.py +1 -1
  123. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/plat}/sdk/__init__.py +1 -1
  124. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/plat}/sdk/facade.py +12 -12
  125. echotools-2.3.8/src/echotools/protocol/__init__.py +1 -0
  126. echotools-2.3.8/src/echotools/protocol/base.py +1 -0
  127. {echotools-2.3.7 → echotools-2.3.8}/src/echotools.egg-info/PKG-INFO +1 -1
  128. echotools-2.3.8/src/echotools.egg-info/SOURCES.txt +195 -0
  129. echotools-2.3.8/src/echotools.egg-info/top_level.txt +3 -0
  130. echotools-2.3.8/src/tests/bench_import.py +14 -0
  131. echotools-2.3.8/src/tests/conftest.py +19 -0
  132. {echotools-2.3.7 → echotools-2.3.8/src}/tests/test_cache_retry.py +2 -2
  133. {echotools-2.3.7 → echotools-2.3.8/src}/tests/test_completion.py +2 -2
  134. {echotools-2.3.7 → echotools-2.3.8/src}/tests/test_config.py +3 -3
  135. {echotools-2.3.7 → echotools-2.3.8/src}/tests/test_config_extended.py +1 -1
  136. {echotools-2.3.7 → echotools-2.3.8/src}/tests/test_coverage_core.py +23 -23
  137. {echotools-2.3.7 → echotools-2.3.8/src}/tests/test_dispatch.py +2 -2
  138. {echotools-2.3.7 → echotools-2.3.8/src}/tests/test_dispatch_extended.py +3 -3
  139. {echotools-2.3.7 → echotools-2.3.8/src}/tests/test_dispatch_race.py +2 -2
  140. echotools-2.3.8/src/tests/test_entml_protocol.py +141 -0
  141. {echotools-2.3.7 → echotools-2.3.8/src}/tests/test_errors.py +2 -2
  142. {echotools-2.3.7 → echotools-2.3.8/src}/tests/test_errors_common.py +1 -1
  143. {echotools-2.3.7 → echotools-2.3.8/src}/tests/test_events.py +1 -1
  144. {echotools-2.3.7 → echotools-2.3.8/src}/tests/test_events_event.py +1 -1
  145. {echotools-2.3.7 → echotools-2.3.8/src}/tests/test_facade.py +1 -1
  146. {echotools-2.3.7 → echotools-2.3.8/src}/tests/test_fncall.py +2 -2
  147. {echotools-2.3.7 → echotools-2.3.8/src}/tests/test_ids.py +1 -1
  148. {echotools-2.3.7 → echotools-2.3.8/src}/tests/test_io.py +1 -1
  149. {echotools-2.3.7 → echotools-2.3.8/src}/tests/test_keys.py +1 -1
  150. {echotools-2.3.7 → echotools-2.3.8/src}/tests/test_lifecycle.py +1 -1
  151. {echotools-2.3.7 → echotools-2.3.8/src}/tests/test_logger.py +1 -1
  152. {echotools-2.3.7 → echotools-2.3.8/src}/tests/test_merge.py +2 -2
  153. {echotools-2.3.7 → echotools-2.3.8/src}/tests/test_plugin.py +1 -1
  154. {echotools-2.3.7 → echotools-2.3.8/src}/tests/test_printstream.py +1 -1
  155. {echotools-2.3.7 → echotools-2.3.8/src}/tests/test_protocols.py +2 -2
  156. {echotools-2.3.7 → echotools-2.3.8/src}/tests/test_proxy.py +1 -1
  157. {echotools-2.3.7 → echotools-2.3.8/src}/tests/test_proxy_selector.py +1 -1
  158. {echotools-2.3.7 → echotools-2.3.8/src}/tests/test_runtime.py +1 -1
  159. {echotools-2.3.7 → echotools-2.3.8/src}/tests/test_scheduler.py +1 -1
  160. {echotools-2.3.7 → echotools-2.3.8/src}/tests/test_tracing.py +1 -1
  161. {echotools-2.3.7 → echotools-2.3.8/src}/tests/test_usage.py +1 -1
  162. {echotools-2.3.7 → echotools-2.3.8/src}/tests/test_web.py +6 -6
  163. {echotools-2.3.7 → echotools-2.3.8/src}/tests/test_web_broker.py +2 -2
  164. echotools-2.3.7/src/echotools/__init__.py +0 -212
  165. echotools-2.3.7/src/echotools/cache/__init__.py +0 -8
  166. echotools-2.3.7/src/echotools/config/base.py +0 -144
  167. echotools-2.3.7/src/echotools/dispatch/__init__.py +0 -21
  168. echotools-2.3.7/src/echotools/fncall/parsers/__init__.py +0 -6
  169. echotools-2.3.7/src/echotools/fncall/protocols/entml.py +0 -286
  170. echotools-2.3.7/src/echotools/fncall/shared/normalization.py +0 -257
  171. echotools-2.3.7/src/echotools/lifecycle/__init__.py +0 -8
  172. echotools-2.3.7/src/echotools/plugin/__init__.py +0 -9
  173. echotools-2.3.7/src/echotools/terminal/local.py +0 -964
  174. echotools-2.3.7/src/echotools/web/input_box/file_zone/file-zone.js +0 -268
  175. echotools-2.3.7/src/echotools/web/input_box/motion_kit/motion-kit.js +0 -139
  176. echotools-2.3.7/src/echotools/web/input_box/send_button/send-button.js +0 -64
  177. echotools-2.3.7/src/echotools/web/middleware.py +0 -161
  178. echotools-2.3.7/src/echotools.egg-info/SOURCES.txt +0 -150
  179. echotools-2.3.7/src/echotools.egg-info/top_level.txt +0 -1
  180. {echotools-2.3.7 → echotools-2.3.8/docs}/README.md +0 -0
  181. {echotools-2.3.7 → echotools-2.3.8}/setup.cfg +0 -0
  182. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/base}/cache/memory_cache.py +0 -0
  183. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/base}/config/merge.py +0 -0
  184. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/base}/errors/base.py +0 -0
  185. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/base}/ids/generator.py +0 -0
  186. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/base}/logger/manager.py +0 -0
  187. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/exec}/dispatch/candidate.py +0 -0
  188. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/exec}/dispatch/usage.py +0 -0
  189. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/exec}/fncall/prompt/templates.py +0 -0
  190. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/exec}/fncall/shared/loop_detect.py +0 -0
  191. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/exec}/fncall/shared/xml_helpers.py +0 -0
  192. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/exec}/keys.py +0 -0
  193. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/exec}/terminal/__init__.py +0 -0
  194. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/exec}/terminal/conpty.py +0 -0
  195. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/exec}/terminal/sanitize.py +0 -0
  196. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/exec}/terminal/tmux.py +0 -0
  197. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/media}/events/event.py +0 -0
  198. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/media}/tracing/context.py +0 -0
  199. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/media}/web/broker.py +0 -0
  200. /echotools-2.3.7/src/echotools/web/input_box/sortable_list/sortable-list.css → /echotools-2.3.8/src/echotools/media/web/input_box/components/sortablelist.css +0 -0
  201. /echotools-2.3.7/src/echotools/web/input_box/sortable_list/sortable-list.js → /echotools-2.3.8/src/echotools/media/web/input_box/components/sortablelist.js +0 -0
  202. /echotools-2.3.7/src/echotools/web/input_box/text_input/text-input.js → /echotools-2.3.8/src/echotools/media/web/input_box/components/textinput.js +0 -0
  203. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/media}/web/input_box/fonts/inter-500.woff2 +0 -0
  204. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/media}/web/input_box/fonts/inter-600.woff2 +0 -0
  205. /echotools-2.3.7/src/echotools/web/input_box/fonts/inter-400.woff2 → /echotools-2.3.8/src/echotools/media/web/input_box/fonts/inter400.woff2 +0 -0
  206. /echotools-2.3.7/src/echotools/web/input_box/fonts/tailwind.min.css → /echotools-2.3.8/src/echotools/media/web/input_box/fonts/tailwind.css +0 -0
  207. /echotools-2.3.7/src/echotools/web/input_box/input-box.css → /echotools-2.3.8/src/echotools/media/web/input_box/inputbox.css +0 -0
  208. {echotools-2.3.7/src/echotools → echotools-2.3.8/src/echotools/plat}/plugin/base.py +0 -0
  209. {echotools-2.3.7 → echotools-2.3.8}/src/echotools/py.typed +0 -0
  210. /echotools-2.3.7/src/echotools/_version.py → /echotools-2.3.8/src/echotools/version.py +0 -0
  211. {echotools-2.3.7 → echotools-2.3.8}/src/echotools.egg-info/dependency_links.txt +0 -0
  212. {echotools-2.3.7 → echotools-2.3.8}/src/echotools.egg-info/requires.txt +0 -0
  213. {echotools-2.3.7 → echotools-2.3.8/src}/tests/test_imports.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: echotools
3
- Version: 2.3.7
3
+ Version: 2.3.8
4
4
  Summary: 通用基础设施 SDK:配置、日志、事件、调度、插件、协议、调用链
5
5
  Author: nichengfuben
6
6
  License: MIT
@@ -0,0 +1,3 @@
1
+ # echotools
2
+
3
+ Documentation: [docs/README.md](docs/README.md)
@@ -4,9 +4,9 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "echotools"
7
- version = "2.3.7"
7
+ version = "2.3.8"
8
8
  description = "通用基础设施 SDK:配置、日志、事件、调度、插件、协议、调用链"
9
- readme = "README.md"
9
+ readme = "docs/README.md"
10
10
  requires-python = ">=3.8"
11
11
  license = { text = "MIT" }
12
12
  authors = [{ name = "nichengfuben" }]
@@ -59,7 +59,7 @@ Issues = "https://github.com/nichengfuben/echotools/issues"
59
59
  where = ["src"]
60
60
 
61
61
  [tool.setuptools.package-data]
62
- echotools = ["py.typed", "web/input_box/**/*"]
62
+ echotools = ["py.typed", "media/web/input_box/**/*"]
63
63
 
64
64
  [tool.ruff]
65
65
  line-length = 88
@@ -91,11 +91,11 @@ disable_error_code = [
91
91
  ]
92
92
 
93
93
  [[tool.mypy.overrides]]
94
- module = "echotools.terminal.*"
94
+ module = "echotools.exec.terminal.*"
95
95
  ignore_errors = true
96
96
 
97
97
  [tool.pytest.ini_options]
98
- testpaths = ["tests"]
98
+ testpaths = ["src/tests"]
99
99
  asyncio_mode = "auto"
100
100
  addopts = ["--strict-markers", "--tb=short"]
101
101
  markers = [
@@ -112,7 +112,7 @@ omit = [
112
112
  "*/__init__.py",
113
113
  "*/terminal/*",
114
114
  "*/spinner/*",
115
- "*/web/input_box/*",
115
+ "*/media/web/input_box/*",
116
116
  "*/lifecycle/updater.py",
117
117
  "*/watcher/*",
118
118
  "*/process/*",
@@ -0,0 +1,212 @@
1
+ from __future__ import annotations
2
+
3
+ """echotools:通用基础设施 SDK。
4
+
5
+ 完全项目无关,支持调用链,覆盖 Python 3.8-3.14。
6
+ """
7
+
8
+ import importlib
9
+ from typing import Any
10
+
11
+ from echotools.version import get_version
12
+ from echotools.plat.sdk import EchoTools
13
+
14
+ __version__ = get_version()
15
+
16
+ __all__ = [
17
+ "__version__",
18
+ "EchoTools",
19
+ "ConfigBase",
20
+ "ConfigCenter",
21
+ "LoggerManager",
22
+ "get_logger",
23
+ "set_color",
24
+ "configure",
25
+ "Event",
26
+ "EventBus",
27
+ "Tracer",
28
+ "Trace",
29
+ "Span",
30
+ "get_current_trace_id",
31
+ "set_current_trace_id",
32
+ "get_current_span_id",
33
+ "set_current_span_id",
34
+ "get_request_id",
35
+ "set_request_id",
36
+ "ListCache",
37
+ "MemoryCache",
38
+ "TaskCandidate",
39
+ "make_id",
40
+ "AdaptiveSelector",
41
+ "TaskDispatcher",
42
+ "TaskScheduler",
43
+ "ProxySelector",
44
+ "ProxyRecord",
45
+ "Plugin",
46
+ "PluginRegistry",
47
+ "discover_plugins",
48
+ "ToolProtocol",
49
+ "register_protocol",
50
+ "get_protocol_by_id",
51
+ "get_protocol",
52
+ "list_protocols",
53
+ "LifecycleManager",
54
+ "AutoUpdater",
55
+ "ProxyManager",
56
+ "PortReleaseResult",
57
+ "ensure_port_available",
58
+ "RuntimeCollector",
59
+ "WebApplication",
60
+ "json_body",
61
+ "safe_flush",
62
+ "FileUtil",
63
+ "uuid7",
64
+ "short_id",
65
+ "trace_id",
66
+ "span_id",
67
+ "atomic_write_text",
68
+ "ensure_directory",
69
+ "read_text_if_exists",
70
+ "retry_with_backoff",
71
+ "retry_on_empty",
72
+ "retry_on_exception",
73
+ "retry_async_generator",
74
+ "KeyState",
75
+ "KeyPool",
76
+ "extract_text_from_messages",
77
+ "split_text_chunks",
78
+ "format_translation_response",
79
+ "TerminalSession",
80
+ "TerminalCallback",
81
+ "LocalTerminal",
82
+ "SSHTerminal",
83
+ "PrintStream",
84
+ "print_stream",
85
+ "start_print_stream",
86
+ "stop_print_stream",
87
+ "flush_print_stream",
88
+ "get_buffer_size",
89
+ "get_queue_length",
90
+ "is_print_stream_running",
91
+ "set_print_speed",
92
+ "configure_print_stream",
93
+ "inject_fncall",
94
+ "FncallStreamParser",
95
+ "detect_tool_loop",
96
+ "LoopDetectionResult",
97
+ "EchoError",
98
+ "ConfigError",
99
+ "ValidationError",
100
+ "NetworkError",
101
+ "TimeoutError",
102
+ "NotSupportedError",
103
+ "NoCandidateError",
104
+ "PluginError",
105
+ "ProtocolError",
106
+ "classify_http_error",
107
+ "Spinner",
108
+ ]
109
+
110
+ _EXPORTS: dict[str, tuple[str, str]] = {
111
+ "ConfigBase": ("echotools.base.config", "ConfigBase"),
112
+ "ConfigCenter": ("echotools.base.config", "ConfigCenter"),
113
+ "LoggerManager": ("echotools.base.logger", "LoggerManager"),
114
+ "get_logger": ("echotools.base.logger", "get_logger"),
115
+ "set_color": ("echotools.base.logger", "set_color"),
116
+ "configure": ("echotools.base.logger", "configure"),
117
+ "Event": ("echotools.media.events", "Event"),
118
+ "EventBus": ("echotools.media.events", "EventBus"),
119
+ "Tracer": ("echotools.media.tracing", "Tracer"),
120
+ "Trace": ("echotools.media.tracing", "Trace"),
121
+ "Span": ("echotools.media.tracing", "Span"),
122
+ "get_current_trace_id": ("echotools.media.tracing", "get_current_trace_id"),
123
+ "set_current_trace_id": ("echotools.media.tracing", "set_current_trace_id"),
124
+ "get_current_span_id": ("echotools.media.tracing", "get_current_span_id"),
125
+ "set_current_span_id": ("echotools.media.tracing", "set_current_span_id"),
126
+ "get_request_id": ("echotools.media.tracing", "get_request_id"),
127
+ "set_request_id": ("echotools.media.tracing", "set_request_id"),
128
+ "ListCache": ("echotools.base.cache", "ListCache"),
129
+ "MemoryCache": ("echotools.base.cache", "MemoryCache"),
130
+ "TaskCandidate": ("echotools.exec.dispatch", "TaskCandidate"),
131
+ "make_id": ("echotools.exec.dispatch", "make_id"),
132
+ "AdaptiveSelector": ("echotools.exec.dispatch", "AdaptiveSelector"),
133
+ "TaskDispatcher": ("echotools.exec.dispatch", "TaskDispatcher"),
134
+ "TaskScheduler": ("echotools.plat.scheduler", "TaskScheduler"),
135
+ "ProxySelector": ("echotools.exec.dispatch", "ProxySelector"),
136
+ "ProxyRecord": ("echotools.exec.dispatch", "ProxyRecord"),
137
+ "Plugin": ("echotools.plat.plugin", "Plugin"),
138
+ "PluginRegistry": ("echotools.plat.plugin", "PluginRegistry"),
139
+ "discover_plugins": ("echotools.plat.plugin", "discover_plugins"),
140
+ "ToolProtocol": ("echotools.exec.protocol.base", "ToolProtocol"),
141
+ "register_protocol": ("echotools.exec.protocol.base", "register_protocol"),
142
+ "get_protocol_by_id": ("echotools.exec.protocol.base", "get_protocol_by_id"),
143
+ "get_protocol": ("echotools.exec.fncall.registry", "get_protocol"),
144
+ "list_protocols": ("echotools.exec.fncall.registry", "list_protocols"),
145
+ "LifecycleManager": ("echotools.exec.lifecycle", "LifecycleManager"),
146
+ "AutoUpdater": ("echotools.exec.lifecycle", "AutoUpdater"),
147
+ "ProxyManager": ("echotools.plat.proxy", "ProxyManager"),
148
+ "PortReleaseResult": ("echotools.exec.process", "PortReleaseResult"),
149
+ "ensure_port_available": ("echotools.exec.process", "ensure_port_available"),
150
+ "RuntimeCollector": ("echotools.plat.runtime", "RuntimeCollector"),
151
+ "WebApplication": ("echotools.media.web.application", "WebApplication"),
152
+ "json_body": ("echotools.media.web.utils", "json_body"),
153
+ "safe_flush": ("echotools.media.web.utils", "safe_flush"),
154
+ "FileUtil": ("echotools.plat.files", "FileUtil"),
155
+ "uuid7": ("echotools.base.ids", "uuid7"),
156
+ "short_id": ("echotools.base.ids", "short_id"),
157
+ "trace_id": ("echotools.base.ids", "trace_id"),
158
+ "span_id": ("echotools.base.ids", "span_id"),
159
+ "atomic_write_text": ("echotools.base.io", "atomic_write_text"),
160
+ "ensure_directory": ("echotools.base.io", "ensure_directory"),
161
+ "read_text_if_exists": ("echotools.base.io", "read_text_if_exists"),
162
+ "retry_with_backoff": ("echotools.base.retry", "retry_with_backoff"),
163
+ "retry_on_empty": ("echotools.base.retry", "retry_on_empty"),
164
+ "retry_on_exception": ("echotools.base.retry", "retry_on_exception"),
165
+ "retry_async_generator": ("echotools.base.retry", "retry_async_generator"),
166
+ "KeyState": ("echotools.exec.keys", "KeyState"),
167
+ "KeyPool": ("echotools.exec.keys", "KeyPool"),
168
+ "extract_text_from_messages": ("echotools.media.translate", "extract_text_from_messages"),
169
+ "split_text_chunks": ("echotools.media.translate", "split_text_chunks"),
170
+ "format_translation_response": ("echotools.media.translate", "format_translation_response"),
171
+ "TerminalSession": ("echotools.exec.terminal.session", "TerminalSession"),
172
+ "TerminalCallback": ("echotools.exec.terminal.session", "TerminalCallback"),
173
+ "LocalTerminal": ("echotools.exec.terminal.local", "LocalTerminal"),
174
+ "SSHTerminal": ("echotools.exec.terminal.ssh", "SSHTerminal"),
175
+ "PrintStream": ("echotools.base.io.printstream", "PrintStream"),
176
+ "print_stream": ("echotools.base.io.printstream", "print_stream"),
177
+ "start_print_stream": ("echotools.base.io.printstream", "start_print_stream"),
178
+ "stop_print_stream": ("echotools.base.io.printstream", "stop_print_stream"),
179
+ "flush_print_stream": ("echotools.base.io.printstream", "flush_print_stream"),
180
+ "get_buffer_size": ("echotools.base.io.printstream", "get_buffer_size"),
181
+ "get_queue_length": ("echotools.base.io.printstream", "get_queue_length"),
182
+ "is_print_stream_running": ("echotools.base.io.printstream", "is_print_stream_running"),
183
+ "set_print_speed": ("echotools.base.io.printstream", "set_print_speed"),
184
+ "configure_print_stream": ("echotools.base.io.printstream", "configure_print_stream"),
185
+ "inject_fncall": ("echotools.exec.fncall.prompt.inject", "inject_fncall"),
186
+ "FncallStreamParser": ("echotools.exec.fncall.parsers.stream", "FncallStreamParser"),
187
+ "detect_tool_loop": ("echotools.exec.fncall.shared.loop_detect", "detect_tool_loop"),
188
+ "LoopDetectionResult": ("echotools.exec.fncall.shared.loop_detect", "LoopDetectionResult"),
189
+ "EchoError": ("echotools.base.errors", "EchoError"),
190
+ "ConfigError": ("echotools.base.errors", "ConfigError"),
191
+ "ValidationError": ("echotools.base.errors", "ValidationError"),
192
+ "NetworkError": ("echotools.base.errors", "NetworkError"),
193
+ "TimeoutError": ("echotools.base.errors", "TimeoutError"),
194
+ "NotSupportedError": ("echotools.base.errors", "NotSupportedError"),
195
+ "NoCandidateError": ("echotools.base.errors", "NoCandidateError"),
196
+ "PluginError": ("echotools.base.errors", "PluginError"),
197
+ "ProtocolError": ("echotools.base.errors", "ProtocolError"),
198
+ "classify_http_error": ("echotools.base.errors", "classify_http_error"),
199
+ "Spinner": ("echotools.media.spinner", "Spinner"),
200
+ }
201
+
202
+
203
+ def __getattr__(name: str) -> Any:
204
+ if name in _EXPORTS:
205
+ module_path, attr = _EXPORTS[name]
206
+ module = importlib.import_module(module_path)
207
+ return getattr(module, attr)
208
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
209
+
210
+
211
+ def __dir__() -> list[str]:
212
+ return sorted(__all__)
@@ -0,0 +1,8 @@
1
+ from __future__ import annotations
2
+
3
+ """cache 模块导出。"""
4
+
5
+ from echotools.base.cache.list_cache import ListCache
6
+ from echotools.base.cache.memory_cache import MemoryCache
7
+
8
+ __all__ = ["ListCache", "MemoryCache"]
@@ -11,7 +11,7 @@ import time
11
11
  from pathlib import Path
12
12
  from typing import Awaitable, Callable, List, Optional
13
13
 
14
- from echotools.logger.manager import get_logger
14
+ from echotools.base.logger.manager import get_logger
15
15
 
16
16
  __all__ = ["ListCache"]
17
17
 
@@ -2,15 +2,15 @@ from __future__ import annotations
2
2
 
3
3
  """config 模块导出。"""
4
4
 
5
- from echotools.config.base import ConfigBase
6
- from echotools.config.center import ConfigCenter
7
- from echotools.config.loader import (
5
+ from echotools.base.config.base import ConfigBase
6
+ from echotools.base.config.center import ConfigCenter
7
+ from echotools.base.config.loader import (
8
8
  find_config,
9
9
  find_template,
10
10
  load_file,
11
11
  write_toml,
12
12
  )
13
- from echotools.config.merge import merge_dicts
13
+ from echotools.base.config.merge import merge_dicts
14
14
 
15
15
  __all__ = [
16
16
  "ConfigBase",
@@ -0,0 +1,146 @@
1
+ from __future__ import annotations
2
+
3
+ """配置数据类基类,提供自动 from_dict 反序列化。"""
4
+
5
+ from dataclasses import MISSING, fields, is_dataclass
6
+ from typing import Any, Literal, Type, TypeVar, Union, get_args, get_origin, get_type_hints
7
+
8
+ __all__ = ["ConfigBase"]
9
+
10
+ T = TypeVar("T", bound="ConfigBase")
11
+
12
+ _type_hints_cache: dict[type, dict[str, Any]] = {}
13
+
14
+
15
+ class ConfigBase:
16
+ """配置类基类,提供 from_dict 自动反序列化。"""
17
+
18
+ @classmethod
19
+ def from_dict(cls: Type[T], data: dict[str, Any]) -> T:
20
+ """从字典构造实例。"""
21
+ if not isinstance(data, dict):
22
+ raise TypeError(
23
+ "Expected a dict, got {}".format(type(data).__name__)
24
+ )
25
+ init_args: dict[str, Any] = {}
26
+ type_hints = _get_type_hints(cls)
27
+ for f in fields(cls): # type: ignore[arg-type]
28
+ field_name = f.name
29
+ field_type = type_hints.get(field_name, f.type)
30
+ if field_name.startswith("_"):
31
+ continue
32
+ if not f.init:
33
+ continue
34
+ if field_name not in data:
35
+ if f.default is not MISSING:
36
+ init_args[field_name] = f.default
37
+ continue
38
+ if f.default_factory is not MISSING: # type: ignore[misc]
39
+ init_args[field_name] = f.default_factory() # type: ignore[misc]
40
+ continue
41
+ raise ValueError(
42
+ "Missing required field: '{}'".format(field_name)
43
+ )
44
+ value = data[field_name]
45
+ init_args[field_name] = cls._convert_field(value, field_type)
46
+ return cls(**init_args)
47
+
48
+ @classmethod
49
+ def _convert_field(cls, value: Any, field_type: Any) -> Any:
50
+ """转换单个字段。"""
51
+ if isinstance(field_type, type) and is_dataclass(field_type):
52
+ return field_type.from_dict(value) # type: ignore[attr-defined]
53
+ origin = get_origin(field_type)
54
+ args = get_args(field_type)
55
+ if origin is list:
56
+ item_type = args[0] if args else Any
57
+ return _convert_list_field(cls, value, item_type)
58
+ if origin is set:
59
+ item_type = args[0] if args else Any
60
+ return _convert_set_field(cls, value, item_type)
61
+ if origin is tuple:
62
+ return _convert_tuple_field(cls, value, args)
63
+ if origin is dict:
64
+ key_type, val_type = args if len(args) == 2 else (Any, Any)
65
+ return _convert_dict_field(cls, value, key_type, val_type)
66
+ if origin is Union:
67
+ return _convert_union_field(cls, value, args)
68
+ if origin is Literal:
69
+ return _convert_literal_field(value, field_type)
70
+ if isinstance(field_type, type):
71
+ return _convert_scalar_field(value, field_type)
72
+ return value
73
+
74
+ def __str__(self) -> str:
75
+ field_strs = [
76
+ "{}={!r}".format(f.name, getattr(self, f.name))
77
+ for f in fields(self) # type: ignore[arg-type]
78
+ ]
79
+ return "{}({})".format(
80
+ self.__class__.__name__, ", ".join(field_strs)
81
+ )
82
+
83
+
84
+ def _get_type_hints(cls: type) -> dict[str, Any]:
85
+ """带缓存的 get_type_hints。"""
86
+ if cls not in _type_hints_cache:
87
+ try:
88
+ _type_hints_cache[cls] = get_type_hints(cls)
89
+ except Exception:
90
+ _type_hints_cache[cls] = {}
91
+ return _type_hints_cache[cls]
92
+
93
+
94
+ def _convert_list_field(cls: type, value: Any, item_type: Any) -> list:
95
+ if not isinstance(value, list):
96
+ raise TypeError("Expected list, got {}".format(type(value).__name__))
97
+ return [cls._convert_field(i, item_type) for i in value]
98
+
99
+
100
+ def _convert_set_field(cls: type, value: Any, item_type: Any) -> set:
101
+ if not isinstance(value, list):
102
+ raise TypeError("Expected list, got {}".format(type(value).__name__))
103
+ return {cls._convert_field(i, item_type) for i in value}
104
+
105
+
106
+ def _convert_tuple_field(cls: type, value: Any, args: tuple) -> tuple:
107
+ return tuple(cls._convert_field(i, a) for i, a in zip(value, args))
108
+
109
+
110
+ def _convert_dict_field(cls: type, value: Any, key_type: Any, val_type: Any) -> dict:
111
+ if not isinstance(value, dict):
112
+ raise TypeError("Expected dict, got {}".format(type(value).__name__))
113
+ result = {}
114
+ for k, v in value.items():
115
+ ck = cls._convert_field(k, key_type)
116
+ try:
117
+ cv = cls._convert_field(v, val_type)
118
+ except (TypeError, ValueError):
119
+ cv = v
120
+ result[ck] = cv
121
+ return result
122
+
123
+
124
+ def _convert_union_field(cls: type, value: Any, args: tuple) -> Any:
125
+ if value is None:
126
+ return None
127
+ real_type = next((a for a in args if a is not type(None)), Any)
128
+ return cls._convert_field(value, real_type)
129
+
130
+
131
+ def _convert_literal_field(value: Any, field_type: Any) -> Any:
132
+ allowed = get_args(field_type)
133
+ if value not in allowed:
134
+ raise TypeError("Value '{}' not in allowed values {}".format(value, allowed))
135
+ return value
136
+
137
+
138
+ def _convert_scalar_field(value: Any, field_type: type) -> Any:
139
+ if isinstance(value, field_type):
140
+ return value
141
+ try:
142
+ return field_type(value)
143
+ except (ValueError, TypeError) as e:
144
+ raise TypeError(
145
+ "Cannot convert {} to {}".format(type(value).__name__, field_type.__name__)
146
+ ) from e