echotools 2.3.10__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.
- {echotools-2.3.10 → echotools-2.3.12}/PKG-INFO +1 -1
- {echotools-2.3.10 → echotools-2.3.12}/pyproject.toml +3 -2
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/base/config/base.py +10 -1
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/base/config/center_template.py +6 -1
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/compat.py +6 -2
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/dispatch/race.py +1 -1
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/fncall/parsers/xml_params.py +1 -2
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/fncall/prompt/history.py +2 -2
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/fncall/prompt/history_format.py +0 -5
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/fncall/prompt/prompt_helpers.py +0 -1
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/fncall/protocols/entml.py +19 -25
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/fncall/protocols/entml_invoke.py +3 -3
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/fncall/protocols/entml_thinking.py +16 -4
- echotools-2.3.12/src/echotools/exec/fncall/protocols/entml_tools.py +26 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/fncall/shared/normalization.py +7 -2
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/fncall/shared/schema_render.py +0 -1
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/terminal/local/core.py +3 -4
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/terminal/local/proc.py +5 -4
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/terminal/local/unix.py +1 -7
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/terminal/local/win.py +1 -8
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/terminal/session/client.py +1 -1
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/media/spinner/spinner.py +12 -5
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/media/spinner/spinner_color.py +1 -4
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/media/web/middleware.py +5 -2
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/plat/plugin/registry.py +0 -2
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/plat/plugin/registry_ops.py +1 -3
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools.egg-info/PKG-INFO +1 -1
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools.egg-info/SOURCES.txt +1 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/tests/test_entml_protocol.py +39 -8
- {echotools-2.3.10 → echotools-2.3.12}/src/tests/test_imports.py +18 -0
- {echotools-2.3.10 → echotools-2.3.12}/README.md +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/docs/README.md +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/setup.cfg +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/__init__.py +2 -2
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/base/cache/__init__.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/base/cache/list_cache.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/base/cache/memory_cache.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/base/config/__init__.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/base/config/center.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/base/config/center_notify.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/base/config/loader.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/base/config/merge.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/base/errors/__init__.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/base/errors/base.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/base/errors/classify.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/base/errors/common.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/base/errors/http.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/base/ids/__init__.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/base/ids/generator.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/base/io/__init__.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/base/io/io_utils.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/base/io/printstream.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/base/logger/__init__.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/base/logger/manager.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/base/retry/__init__.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/base/retry/retry.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/dispatch/__init__.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/dispatch/candidate.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/dispatch/dispatcher.py +2 -2
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/dispatch/proxy_selector.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/dispatch/selector.py +1 -1
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/dispatch/usage.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/fncall/__init__.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/fncall/parsers/__init__.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/fncall/parsers/stream.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/fncall/parsers/xml_parser.py +1 -1
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/fncall/prompt/__init__.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/fncall/prompt/inject.py +2 -2
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/fncall/prompt/templates.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/fncall/protocols/__init__.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/fncall/protocols/entml_patterns.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/fncall/protocols/entml_values.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/fncall/registry.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/fncall/shared/__init__.py +1 -1
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/fncall/shared/coercion.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/fncall/shared/loop_detect.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/fncall/shared/xml_helpers.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/keys.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/lifecycle/__init__.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/lifecycle/manager.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/lifecycle/updater.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/lifecycle/updater_pull.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/process/__init__.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/process/port.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/protocol/__init__.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/protocol/base.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/terminal/__init__.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/terminal/conpty.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/terminal/local/__init__.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/terminal/sanitize.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/terminal/session/__init__.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/terminal/session/base.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/terminal/ssh.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/exec/terminal/tmux.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/media/events/__init__.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/media/events/bus.py +1 -1
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/media/events/event.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/media/spinner/__init__.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/media/tracing/__init__.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/media/tracing/context.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/media/tracing/span.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/media/tracing/tracer.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/media/translate.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/media/watcher/__init__.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/media/watcher/file_watcher.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/media/web/__init__.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/media/web/application.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/media/web/broker.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/media/web/input_box/app.js +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/media/web/input_box/components/filezone.js +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/media/web/input_box/components/motionkit.js +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/media/web/input_box/components/sendbutton.js +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/media/web/input_box/components/sortablelist.css +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/media/web/input_box/components/sortablelist.js +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/media/web/input_box/components/textinput.js +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/media/web/input_box/components/voiceinput.js +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/media/web/input_box/fonts/inter-500.woff2 +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/media/web/input_box/fonts/inter-600.woff2 +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/media/web/input_box/fonts/inter400.woff2 +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/media/web/input_box/fonts/tailwind.css +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/media/web/input_box/inputbox.css +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/media/web/input_box/inputbox.js +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/media/web/input_box/style.css +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/media/web/input_box/voicegif.js +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/media/web/stats.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/media/web/utils.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/plat/files/__init__.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/plat/files/file_util.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/plat/network/__init__.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/plat/network/http_utils.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/plat/plugin/__init__.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/plat/plugin/base.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/plat/plugin/discovery.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/plat/proxy/__init__.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/plat/proxy/manager.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/plat/runtime/__init__.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/plat/runtime/collector.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/plat/scheduler/__init__.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/plat/scheduler/scheduler.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/plat/sdk/__init__.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/plat/sdk/facade.py +3 -3
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools/version.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools.egg-info/dependency_links.txt +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools.egg-info/requires.txt +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/echotools.egg-info/top_level.txt +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/tests/bench_import.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/tests/conftest.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/tests/test_cache_retry.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/tests/test_completion.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/tests/test_config.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/tests/test_config_extended.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/tests/test_coverage_core.py +9 -9
- {echotools-2.3.10 → echotools-2.3.12}/src/tests/test_dispatch.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/tests/test_dispatch_extended.py +1 -1
- {echotools-2.3.10 → echotools-2.3.12}/src/tests/test_dispatch_race.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/tests/test_errors.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/tests/test_errors_common.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/tests/test_events.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/tests/test_events_event.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/tests/test_facade.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/tests/test_fncall.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/tests/test_ids.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/tests/test_io.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/tests/test_keys.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/tests/test_lifecycle.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/tests/test_logger.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/tests/test_merge.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/tests/test_plugin.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/tests/test_printstream.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/tests/test_protocols.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/tests/test_proxy.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/tests/test_proxy_selector.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/tests/test_runtime.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/tests/test_scheduler.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/tests/test_tracing.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/tests/test_usage.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/tests/test_web.py +0 -0
- {echotools-2.3.10 → echotools-2.3.12}/src/tests/test_web_broker.py +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "echotools"
|
|
7
|
-
version = "2.3.
|
|
7
|
+
version = "2.3.12"
|
|
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 =
|
|
134
|
+
fail_under = 89
|
|
134
135
|
exclude_lines = [
|
|
135
136
|
"pragma: no cover",
|
|
136
137
|
"def __repr__",
|
|
@@ -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
|
|
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
|
|
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
|
|
@@ -7,7 +7,7 @@ import importlib.abc
|
|
|
7
7
|
import importlib.util
|
|
8
8
|
import sys
|
|
9
9
|
from types import ModuleType
|
|
10
|
-
from typing import Dict, Optional
|
|
10
|
+
from typing import Dict, Optional, Sequence
|
|
11
11
|
|
|
12
12
|
_MODULE_ALIASES: Dict[str, str] = {
|
|
13
13
|
"echotools.cache": "echotools.base.cache",
|
|
@@ -66,7 +66,7 @@ class _AliasFinder(importlib.abc.MetaPathFinder):
|
|
|
66
66
|
def find_spec(
|
|
67
67
|
self,
|
|
68
68
|
fullname: str,
|
|
69
|
-
path: Optional[
|
|
69
|
+
path: Optional[Sequence[str]],
|
|
70
70
|
target: Optional[ModuleType] = None,
|
|
71
71
|
) -> Optional[importlib.machinery.ModuleSpec]:
|
|
72
72
|
mapped = _map_name(fullname)
|
|
@@ -81,3 +81,7 @@ class _AliasFinder(importlib.abc.MetaPathFinder):
|
|
|
81
81
|
def install_compat_aliases() -> None:
|
|
82
82
|
if not any(isinstance(finder, _AliasFinder) for finder in sys.meta_path):
|
|
83
83
|
sys.meta_path.insert(0, _AliasFinder())
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
# 确保 ``from echotools.config...`` 等旧路径在未显式 ``import echotools`` 时也可用。
|
|
87
|
+
install_compat_aliases()
|
|
@@ -2,10 +2,9 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
4
|
import uuid
|
|
5
|
-
from typing import Any, Dict
|
|
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,
|
|
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
|
|
|
@@ -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
|
-
|
|
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="
|
|
37
|
-
<entml:parameter name="
|
|
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
|
|
38
|
+
String and scalar parameters should be specified as is, while lists and objects should use JSON format.
|
|
42
39
|
|
|
43
|
-
|
|
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,
|
|
105
|
+
format_entml_conversation_history(history_text, _HISTORY_CLARIFY_EN)
|
|
112
106
|
)
|
|
113
107
|
|
|
114
108
|
if loop_warning:
|
|
@@ -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
|
-
|
|
33
|
-
if
|
|
34
|
-
return coerce_entml_arguments(
|
|
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] = {}
|
|
@@ -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 = [
|
|
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
|
-
"
|
|
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)
|
|
@@ -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
|
|
|
@@ -19,8 +19,7 @@ import os
|
|
|
19
19
|
import signal
|
|
20
20
|
import subprocess
|
|
21
21
|
import sys
|
|
22
|
-
from
|
|
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
|
|
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
|
|
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
|
|
|
@@ -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
|
|
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
|
|
11
|
-
|
|
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,
|
|
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
|
|
|
@@ -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
|
-
"""
|
|
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
|
|
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 "<
|
|
178
|
+
assert "<functions>" not in prompt
|
|
148
179
|
|
|
149
180
|
|
|
150
181
|
def test_entml_roundtrip_parameter_format() -> None:
|
|
@@ -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)
|
|
File without changes
|
|
File without changes
|