echotools 2.3.11__tar.gz → 2.3.12__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 (178) hide show
  1. {echotools-2.3.11 → echotools-2.3.12}/PKG-INFO +1 -1
  2. {echotools-2.3.11 → echotools-2.3.12}/pyproject.toml +1 -1
  3. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/fncall/protocols/entml.py +19 -25
  4. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/fncall/protocols/entml_thinking.py +16 -4
  5. echotools-2.3.12/src/echotools/exec/fncall/protocols/entml_tools.py +26 -0
  6. {echotools-2.3.11 → echotools-2.3.12}/src/echotools.egg-info/PKG-INFO +1 -1
  7. {echotools-2.3.11 → echotools-2.3.12}/src/echotools.egg-info/SOURCES.txt +1 -0
  8. {echotools-2.3.11 → echotools-2.3.12}/src/tests/test_entml_protocol.py +39 -8
  9. {echotools-2.3.11 → echotools-2.3.12}/README.md +0 -0
  10. {echotools-2.3.11 → echotools-2.3.12}/docs/README.md +0 -0
  11. {echotools-2.3.11 → echotools-2.3.12}/setup.cfg +0 -0
  12. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/__init__.py +0 -0
  13. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/base/cache/__init__.py +0 -0
  14. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/base/cache/list_cache.py +0 -0
  15. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/base/cache/memory_cache.py +0 -0
  16. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/base/config/__init__.py +0 -0
  17. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/base/config/base.py +0 -0
  18. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/base/config/center.py +0 -0
  19. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/base/config/center_notify.py +0 -0
  20. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/base/config/center_template.py +0 -0
  21. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/base/config/loader.py +0 -0
  22. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/base/config/merge.py +0 -0
  23. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/base/errors/__init__.py +0 -0
  24. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/base/errors/base.py +0 -0
  25. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/base/errors/classify.py +0 -0
  26. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/base/errors/common.py +0 -0
  27. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/base/errors/http.py +0 -0
  28. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/base/ids/__init__.py +0 -0
  29. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/base/ids/generator.py +0 -0
  30. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/base/io/__init__.py +0 -0
  31. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/base/io/io_utils.py +0 -0
  32. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/base/io/printstream.py +0 -0
  33. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/base/logger/__init__.py +0 -0
  34. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/base/logger/manager.py +0 -0
  35. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/base/retry/__init__.py +0 -0
  36. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/base/retry/retry.py +0 -0
  37. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/compat.py +0 -0
  38. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/dispatch/__init__.py +0 -0
  39. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/dispatch/candidate.py +0 -0
  40. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/dispatch/dispatcher.py +0 -0
  41. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/dispatch/proxy_selector.py +0 -0
  42. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/dispatch/race.py +0 -0
  43. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/dispatch/selector.py +0 -0
  44. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/dispatch/usage.py +0 -0
  45. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/fncall/__init__.py +0 -0
  46. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/fncall/parsers/__init__.py +0 -0
  47. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/fncall/parsers/stream.py +0 -0
  48. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/fncall/parsers/xml_params.py +0 -0
  49. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/fncall/parsers/xml_parser.py +0 -0
  50. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/fncall/prompt/__init__.py +0 -0
  51. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/fncall/prompt/history.py +0 -0
  52. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/fncall/prompt/history_format.py +0 -0
  53. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/fncall/prompt/inject.py +0 -0
  54. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/fncall/prompt/prompt_helpers.py +0 -0
  55. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/fncall/prompt/templates.py +0 -0
  56. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/fncall/protocols/__init__.py +0 -0
  57. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/fncall/protocols/entml_invoke.py +0 -0
  58. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/fncall/protocols/entml_patterns.py +0 -0
  59. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/fncall/protocols/entml_values.py +0 -0
  60. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/fncall/registry.py +0 -0
  61. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/fncall/shared/__init__.py +0 -0
  62. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/fncall/shared/coercion.py +0 -0
  63. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/fncall/shared/loop_detect.py +0 -0
  64. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/fncall/shared/normalization.py +0 -0
  65. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/fncall/shared/schema_render.py +0 -0
  66. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/fncall/shared/xml_helpers.py +0 -0
  67. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/keys.py +0 -0
  68. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/lifecycle/__init__.py +0 -0
  69. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/lifecycle/manager.py +0 -0
  70. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/lifecycle/updater.py +0 -0
  71. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/lifecycle/updater_pull.py +0 -0
  72. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/process/__init__.py +0 -0
  73. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/process/port.py +0 -0
  74. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/protocol/__init__.py +0 -0
  75. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/protocol/base.py +0 -0
  76. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/terminal/__init__.py +0 -0
  77. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/terminal/conpty.py +0 -0
  78. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/terminal/local/__init__.py +0 -0
  79. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/terminal/local/core.py +0 -0
  80. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/terminal/local/proc.py +0 -0
  81. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/terminal/local/unix.py +0 -0
  82. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/terminal/local/win.py +0 -0
  83. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/terminal/sanitize.py +0 -0
  84. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/terminal/session/__init__.py +0 -0
  85. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/terminal/session/base.py +0 -0
  86. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/terminal/session/client.py +0 -0
  87. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/terminal/ssh.py +0 -0
  88. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/exec/terminal/tmux.py +0 -0
  89. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/media/events/__init__.py +0 -0
  90. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/media/events/bus.py +0 -0
  91. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/media/events/event.py +0 -0
  92. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/media/spinner/__init__.py +0 -0
  93. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/media/spinner/spinner.py +0 -0
  94. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/media/spinner/spinner_color.py +0 -0
  95. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/media/tracing/__init__.py +0 -0
  96. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/media/tracing/context.py +0 -0
  97. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/media/tracing/span.py +0 -0
  98. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/media/tracing/tracer.py +0 -0
  99. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/media/translate.py +0 -0
  100. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/media/watcher/__init__.py +0 -0
  101. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/media/watcher/file_watcher.py +0 -0
  102. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/media/web/__init__.py +0 -0
  103. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/media/web/application.py +0 -0
  104. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/media/web/broker.py +0 -0
  105. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/media/web/input_box/app.js +0 -0
  106. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/media/web/input_box/components/filezone.js +0 -0
  107. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/media/web/input_box/components/motionkit.js +0 -0
  108. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/media/web/input_box/components/sendbutton.js +0 -0
  109. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/media/web/input_box/components/sortablelist.css +0 -0
  110. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/media/web/input_box/components/sortablelist.js +0 -0
  111. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/media/web/input_box/components/textinput.js +0 -0
  112. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/media/web/input_box/components/voiceinput.js +0 -0
  113. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/media/web/input_box/fonts/inter-500.woff2 +0 -0
  114. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/media/web/input_box/fonts/inter-600.woff2 +0 -0
  115. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/media/web/input_box/fonts/inter400.woff2 +0 -0
  116. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/media/web/input_box/fonts/tailwind.css +0 -0
  117. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/media/web/input_box/inputbox.css +0 -0
  118. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/media/web/input_box/inputbox.js +0 -0
  119. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/media/web/input_box/style.css +0 -0
  120. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/media/web/input_box/voicegif.js +0 -0
  121. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/media/web/middleware.py +0 -0
  122. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/media/web/stats.py +0 -0
  123. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/media/web/utils.py +0 -0
  124. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/plat/files/__init__.py +0 -0
  125. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/plat/files/file_util.py +0 -0
  126. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/plat/network/__init__.py +0 -0
  127. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/plat/network/http_utils.py +0 -0
  128. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/plat/plugin/__init__.py +0 -0
  129. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/plat/plugin/base.py +0 -0
  130. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/plat/plugin/discovery.py +0 -0
  131. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/plat/plugin/registry.py +0 -0
  132. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/plat/plugin/registry_ops.py +0 -0
  133. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/plat/proxy/__init__.py +0 -0
  134. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/plat/proxy/manager.py +0 -0
  135. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/plat/runtime/__init__.py +0 -0
  136. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/plat/runtime/collector.py +0 -0
  137. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/plat/scheduler/__init__.py +0 -0
  138. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/plat/scheduler/scheduler.py +0 -0
  139. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/plat/sdk/__init__.py +0 -0
  140. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/plat/sdk/facade.py +0 -0
  141. {echotools-2.3.11 → echotools-2.3.12}/src/echotools/version.py +0 -0
  142. {echotools-2.3.11 → echotools-2.3.12}/src/echotools.egg-info/dependency_links.txt +0 -0
  143. {echotools-2.3.11 → echotools-2.3.12}/src/echotools.egg-info/requires.txt +0 -0
  144. {echotools-2.3.11 → echotools-2.3.12}/src/echotools.egg-info/top_level.txt +0 -0
  145. {echotools-2.3.11 → echotools-2.3.12}/src/tests/bench_import.py +0 -0
  146. {echotools-2.3.11 → echotools-2.3.12}/src/tests/conftest.py +0 -0
  147. {echotools-2.3.11 → echotools-2.3.12}/src/tests/test_cache_retry.py +0 -0
  148. {echotools-2.3.11 → echotools-2.3.12}/src/tests/test_completion.py +0 -0
  149. {echotools-2.3.11 → echotools-2.3.12}/src/tests/test_config.py +0 -0
  150. {echotools-2.3.11 → echotools-2.3.12}/src/tests/test_config_extended.py +0 -0
  151. {echotools-2.3.11 → echotools-2.3.12}/src/tests/test_coverage_core.py +0 -0
  152. {echotools-2.3.11 → echotools-2.3.12}/src/tests/test_dispatch.py +0 -0
  153. {echotools-2.3.11 → echotools-2.3.12}/src/tests/test_dispatch_extended.py +0 -0
  154. {echotools-2.3.11 → echotools-2.3.12}/src/tests/test_dispatch_race.py +0 -0
  155. {echotools-2.3.11 → echotools-2.3.12}/src/tests/test_errors.py +0 -0
  156. {echotools-2.3.11 → echotools-2.3.12}/src/tests/test_errors_common.py +0 -0
  157. {echotools-2.3.11 → echotools-2.3.12}/src/tests/test_events.py +0 -0
  158. {echotools-2.3.11 → echotools-2.3.12}/src/tests/test_events_event.py +0 -0
  159. {echotools-2.3.11 → echotools-2.3.12}/src/tests/test_facade.py +0 -0
  160. {echotools-2.3.11 → echotools-2.3.12}/src/tests/test_fncall.py +0 -0
  161. {echotools-2.3.11 → echotools-2.3.12}/src/tests/test_ids.py +0 -0
  162. {echotools-2.3.11 → echotools-2.3.12}/src/tests/test_imports.py +0 -0
  163. {echotools-2.3.11 → echotools-2.3.12}/src/tests/test_io.py +0 -0
  164. {echotools-2.3.11 → echotools-2.3.12}/src/tests/test_keys.py +0 -0
  165. {echotools-2.3.11 → echotools-2.3.12}/src/tests/test_lifecycle.py +0 -0
  166. {echotools-2.3.11 → echotools-2.3.12}/src/tests/test_logger.py +0 -0
  167. {echotools-2.3.11 → echotools-2.3.12}/src/tests/test_merge.py +0 -0
  168. {echotools-2.3.11 → echotools-2.3.12}/src/tests/test_plugin.py +0 -0
  169. {echotools-2.3.11 → echotools-2.3.12}/src/tests/test_printstream.py +0 -0
  170. {echotools-2.3.11 → echotools-2.3.12}/src/tests/test_protocols.py +0 -0
  171. {echotools-2.3.11 → echotools-2.3.12}/src/tests/test_proxy.py +0 -0
  172. {echotools-2.3.11 → echotools-2.3.12}/src/tests/test_proxy_selector.py +0 -0
  173. {echotools-2.3.11 → echotools-2.3.12}/src/tests/test_runtime.py +0 -0
  174. {echotools-2.3.11 → echotools-2.3.12}/src/tests/test_scheduler.py +0 -0
  175. {echotools-2.3.11 → echotools-2.3.12}/src/tests/test_tracing.py +0 -0
  176. {echotools-2.3.11 → echotools-2.3.12}/src/tests/test_usage.py +0 -0
  177. {echotools-2.3.11 → echotools-2.3.12}/src/tests/test_web.py +0 -0
  178. {echotools-2.3.11 → echotools-2.3.12}/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.11
3
+ Version: 2.3.12
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.11"
7
+ version = "2.3.12"
8
8
  description = "通用基础设施 SDK:配置、日志、事件、调度、插件、协议、调用链"
9
9
  readme = "docs/README.md"
10
10
  requires-python = ">=3.8"
@@ -9,44 +9,35 @@ from __future__ import annotations
9
9
 
10
10
  from typing import Any, Dict, List, Optional, Tuple
11
11
 
12
- from echotools.exec.fncall.prompt.templates import (
13
- _HISTORY_CLARIFY_EN,
14
- _HISTORY_CLARIFY_ZH,
15
- )
12
+ from echotools.exec.fncall.prompt.templates import _HISTORY_CLARIFY_EN
16
13
  from echotools.exec.fncall.protocols.entml_invoke import (
17
14
  format_entml_tool_calls,
18
15
  parse_entml_tool_calls,
19
16
  )
20
17
  from echotools.exec.fncall.protocols.entml_patterns import BLOCK_RE
21
18
  from echotools.exec.fncall.protocols.entml_thinking import build_entml_thinking_section
19
+ from echotools.exec.fncall.protocols.entml_tools import format_entml_tool_descs
22
20
  from echotools.exec.fncall.shared.coercion import _build_param_schema_index
23
21
  from echotools.exec.fncall.shared.normalization import normalize_tool_calls
24
22
  from echotools.exec.protocol.base import ToolProtocol
25
23
 
26
24
  _ENTML_INSTRUCTION = """\
27
- ## Function Definitions
28
-
29
- All functions are defined inside a `<functions>` wrapper block. Each function is a JSON object inside a `<function>` tag containing `description`, `name`, and `parameters` (JSON Schema).
30
-
31
- **Function Invocation Syntax:**
32
-
33
- When calling tools, respond with ONLY the following XML block format:
25
+ In this environment you have access to a set of tools you can use to answer the user's question.
26
+ You can invoke functions by writing a "<entml:function_calls>" block like the following as part of your reply to the user:
34
27
 
35
28
  <entml:function_calls>
36
- <entml:invoke name="tool_name">
37
- <entml:parameter name="param_name">value</entml:parameter>
29
+ <entml:invoke name="$FUNCTION_NAME">
30
+ <entml:parameter name="$PARAMETER_NAME">$PARAMETER_VALUE</entml:parameter>
31
+ ...
32
+ </entml:invoke>
33
+ <entml:invoke name="$FUNCTION_NAME2">
34
+ ...
38
35
  </entml:invoke>
39
36
  </entml:function_calls>
40
37
 
41
- String and scalar parameters should be specified as-is, while lists and objects should use JSON format.
38
+ String and scalar parameters should be specified as is, while lists and objects should use JSON format.
42
39
 
43
- Multiple invocations can be stacked inside one `<entml:function_calls>` block for parallel execution.
44
-
45
- ## Function Call Instructions
46
-
47
- Answer the user's request using the relevant tool(s), if they are available. Check that all required parameters are provided or can reasonably be inferred from context. If there are no relevant tools or missing required parameter values, ask the user. If the user provides a specific value for a parameter (e.g., in quotes), use that value EXACTLY. Do NOT make up values for or ask about optional parameters.
48
-
49
- If you intend to call multiple tools and there are no dependencies between the calls, make all independent calls in the same function_calls block. Otherwise, wait for previous calls to finish to determine dependent values (do NOT use placeholders or guess missing parameters).
40
+ Here are the functions available in JSONSchema format:
50
41
  """
51
42
 
52
43
 
@@ -84,6 +75,10 @@ class EntmlProtocol(ToolProtocol):
84
75
  def get_trigger_tags(self) -> List[str]:
85
76
  return [self._TRIGGER]
86
77
 
78
+ @staticmethod
79
+ def format_tool_descs(tools: List[Dict[str, Any]]) -> str:
80
+ return format_entml_tool_descs(tools)
81
+
87
82
  def render_prompt(
88
83
  self,
89
84
  tool_descs: str,
@@ -94,11 +89,11 @@ class EntmlProtocol(ToolProtocol):
94
89
  current_user_message: str = "",
95
90
  protocol_options: Optional[Dict[str, Any]] = None,
96
91
  ) -> str:
97
- sections: List[str] = [_ENTML_INSTRUCTION]
92
+ sections: List[str] = [_ENTML_INSTRUCTION + tool_descs]
93
+
98
94
  thinking_section = build_entml_thinking_section(protocol_options)
99
95
  if thinking_section:
100
96
  sections.append(thinking_section)
101
- sections.append("<functions>\n" + tool_descs + "\n</functions>")
102
97
 
103
98
  if user_system_prompt and user_system_prompt.strip():
104
99
  sections.append(
@@ -106,9 +101,8 @@ class EntmlProtocol(ToolProtocol):
106
101
  )
107
102
 
108
103
  if history_text:
109
- clarify = _HISTORY_CLARIFY_ZH if lang == "zh" else _HISTORY_CLARIFY_EN
110
104
  sections.append(
111
- format_entml_conversation_history(history_text, clarify)
105
+ format_entml_conversation_history(history_text, _HISTORY_CLARIFY_EN)
112
106
  )
113
107
 
114
108
  if loop_warning:
@@ -14,7 +14,7 @@ def build_entml_thinking_section(
14
14
  if thinking_mode is None and max_thinking_length is None:
15
15
  return ""
16
16
 
17
- lines = ["## Thinking", ""]
17
+ lines: list[str] = []
18
18
  if thinking_mode is not None:
19
19
  mode = str(thinking_mode).strip()
20
20
  if mode:
@@ -30,12 +30,24 @@ def build_entml_thinking_section(
30
30
  [
31
31
  "",
32
32
  "If the thinking_mode is interleaved or auto, then after function "
33
- "results you should strongly consider outputting a thinking block "
34
- "before continuing:",
33
+ "results you should strongly consider outputting a thinking block. "
34
+ "Here is an example:",
35
+ "",
36
+ "<entml:function_calls>",
37
+ "...",
38
+ "</entml:function_calls>",
39
+ "",
40
+ "<function_results>",
41
+ "...",
42
+ "</function_results>",
35
43
  "",
36
44
  "<entml:thinking>",
37
- "...thinking about results...",
45
+ "...thinking about results",
38
46
  "</entml:thinking>",
47
+ "Whenever you have the result of a function call, think carefully "
48
+ "about whether an `<entml:thinking>` `</entml:thinking>` block "
49
+ "would be appropriate and strongly prefer to output a thinking "
50
+ "block if you are uncertain.",
39
51
  ]
40
52
  )
41
53
 
@@ -0,0 +1,26 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from typing import Any, Dict, List
5
+
6
+ __all__ = ["format_entml_tool_descs"]
7
+
8
+
9
+ def format_entml_tool_descs(tools: List[Dict[str, Any]]) -> str:
10
+ """将工具列表格式化为 **name** + JSON Schema 代码块(对齐 entml/antml 示范)。"""
11
+ if not tools:
12
+ return ""
13
+
14
+ blocks: List[str] = []
15
+ for tool in tools:
16
+ fn = tool.get("function", tool)
17
+ name = str(fn.get("name") or "unknown")
18
+ payload = {
19
+ "description": fn.get("description") or "",
20
+ "name": name,
21
+ "parameters": fn.get("parameters")
22
+ or {"type": "object", "properties": {}},
23
+ }
24
+ body = json.dumps(payload, ensure_ascii=False, indent=2)
25
+ blocks.append(f"**{name}**\n\n```json\n{body}\n```")
26
+ return "\n\n".join(blocks)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: echotools
3
- Version: 2.3.11
3
+ Version: 2.3.12
4
4
  Summary: 通用基础设施 SDK:配置、日志、事件、调度、插件、协议、调用链
5
5
  Author: nichengfuben
6
6
  License: MIT
@@ -58,6 +58,7 @@ src/echotools/exec/fncall/protocols/entml.py
58
58
  src/echotools/exec/fncall/protocols/entml_invoke.py
59
59
  src/echotools/exec/fncall/protocols/entml_patterns.py
60
60
  src/echotools/exec/fncall/protocols/entml_thinking.py
61
+ src/echotools/exec/fncall/protocols/entml_tools.py
61
62
  src/echotools/exec/fncall/protocols/entml_values.py
62
63
  src/echotools/exec/fncall/shared/__init__.py
63
64
  src/echotools/exec/fncall/shared/coercion.py
@@ -91,6 +91,28 @@ def test_inject_with_history_entml_tags() -> None:
91
91
  assert "<entml:current_user_message>\nnew\n</entml:current_user_message>" in content
92
92
 
93
93
 
94
+ def test_entml_history_clarify_always_english() -> None:
95
+ proto = get_protocol("entml")
96
+ tools = [
97
+ {
98
+ "type": "function",
99
+ "function": {
100
+ "name": "search",
101
+ "description": "Search",
102
+ "parameters": {"type": "object", "properties": {}},
103
+ },
104
+ }
105
+ ]
106
+ msgs = [
107
+ {"role": "user", "content": "old"},
108
+ {"role": "assistant", "content": "ok"},
109
+ {"role": "user", "content": "new"},
110
+ ]
111
+ content = inject_fncall(msgs, tools, proto, lang="zh")[0]["content"]
112
+ assert "The following is a transcript of completed interactions." in content
113
+ assert "以下是已完成的交互记录" not in content
114
+
115
+
94
116
  @pytest.mark.parametrize(
95
117
  "raw,schema,expected",
96
118
  [
@@ -109,10 +131,8 @@ def test_coerce_entml_parameter_value(raw, schema, expected) -> None:
109
131
 
110
132
 
111
133
  def test_entml_instruction_matches_spec_format() -> None:
112
- """示范格式:<entml:function_calls> + <entml:invoke> + <entml:parameter>."""
134
+ """示范格式:环境说明 + JSONSchema 工具块 + entml 调用标签。"""
113
135
  proto = get_protocol("entml")
114
- from echotools.exec.fncall.shared.normalization import format_tool_descs
115
-
116
136
  tools = [
117
137
  {
118
138
  "type": "function",
@@ -134,17 +154,28 @@ def test_entml_instruction_matches_spec_format() -> None:
134
154
  }
135
155
  ]
136
156
  prompt = proto.render_prompt(
137
- tool_descs=format_tool_descs(tools),
157
+ tool_descs=proto.format_tool_descs(tools),
138
158
  lang="en",
139
159
  current_user_message="pick one",
160
+ protocol_options={
161
+ "thinking_mode": "interleaved",
162
+ "max_thinking_length": 22000,
163
+ },
140
164
  )
165
+ assert "In this environment you have access to a set of tools" in prompt
166
+ assert "Here are the functions available in JSONSchema format:" in prompt
167
+ assert "**ask_user_input_v0**" in prompt
168
+ assert '"name": "ask_user_input_v0"' in prompt
141
169
  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
170
+ assert '<entml:invoke name="$FUNCTION_NAME">' in prompt
171
+ assert '<entml:parameter name="$PARAMETER_NAME">' in prompt
172
+ assert "String and scalar parameters should be specified as is" in prompt
173
+ assert "<entml:thinking_mode>interleaved</entml:thinking_mode>" in prompt
174
+ assert "<entml:max_thinking_length>22000</entml:max_thinking_length>" in prompt
175
+ assert "<function_results>" in prompt
145
176
  assert "<entml:conversation_history>" not in prompt
146
177
  assert "<entml:history>" not in prompt
147
- assert "<entml:thinking_mode>" not in prompt
178
+ assert "<functions>" not in prompt
148
179
 
149
180
 
150
181
  def test_entml_roundtrip_parameter_format() -> None:
File without changes
File without changes
File without changes