echotools 2.3.8__tar.gz → 2.3.11__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {echotools-2.3.8 → echotools-2.3.11}/PKG-INFO +1 -1
- {echotools-2.3.8 → echotools-2.3.11}/pyproject.toml +3 -2
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/__init__.py +4 -1
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/config/base.py +10 -1
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/config/center_template.py +6 -1
- echotools-2.3.11/src/echotools/compat.py +87 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/dispatch/race.py +1 -1
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/dispatch/selector.py +4 -2
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/parsers/xml_params.py +1 -2
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/prompt/history.py +2 -2
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/prompt/history_format.py +0 -5
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/prompt/prompt_helpers.py +0 -1
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/protocols/entml_invoke.py +3 -3
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/shared/normalization.py +7 -2
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/shared/schema_render.py +0 -1
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/terminal/local/core.py +3 -4
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/terminal/local/proc.py +5 -4
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/terminal/local/unix.py +1 -7
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/terminal/local/win.py +1 -8
- echotools-2.3.11/src/echotools/exec/terminal/session/__init__.py +20 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/terminal/session/client.py +1 -1
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/spinner/spinner.py +12 -5
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/spinner/spinner_color.py +1 -4
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/middleware.py +5 -2
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/plat/plugin/registry.py +0 -2
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/plat/plugin/registry_ops.py +1 -3
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools.egg-info/PKG-INFO +1 -1
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools.egg-info/SOURCES.txt +1 -21
- {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_entml_protocol.py +68 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_imports.py +18 -0
- echotools-2.3.8/src/echotools/exec/terminal/session/__init__.py +0 -7
- echotools-2.3.8/src/echotools/fncall/__init__.py +0 -1
- echotools-2.3.8/src/echotools/fncall/parsers/__init__.py +0 -1
- echotools-2.3.8/src/echotools/fncall/parsers/stream.py +0 -1
- echotools-2.3.8/src/echotools/fncall/parsers/xml_parser.py +0 -1
- echotools-2.3.8/src/echotools/fncall/prompt/__init__.py +0 -1
- echotools-2.3.8/src/echotools/fncall/prompt/history.py +0 -1
- echotools-2.3.8/src/echotools/fncall/prompt/inject.py +0 -1
- echotools-2.3.8/src/echotools/fncall/prompt/templates.py +0 -1
- echotools-2.3.8/src/echotools/fncall/protocols/__init__.py +0 -1
- echotools-2.3.8/src/echotools/fncall/protocols/entml.py +0 -1
- echotools-2.3.8/src/echotools/fncall/registry.py +0 -1
- echotools-2.3.8/src/echotools/fncall/shared/__init__.py +0 -1
- echotools-2.3.8/src/echotools/fncall/shared/coercion.py +0 -1
- echotools-2.3.8/src/echotools/fncall/shared/loop_detect.py +0 -1
- echotools-2.3.8/src/echotools/fncall/shared/normalization.py +0 -1
- echotools-2.3.8/src/echotools/fncall/shared/xml_helpers.py +0 -1
- echotools-2.3.8/src/echotools/logger/__init__.py +0 -1
- echotools-2.3.8/src/echotools/logger/manager.py +0 -1
- echotools-2.3.8/src/echotools/protocol/__init__.py +0 -1
- echotools-2.3.8/src/echotools/protocol/base.py +0 -1
- echotools-2.3.8/src/echotools/py.typed +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/README.md +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/docs/README.md +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/setup.cfg +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/cache/__init__.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/cache/list_cache.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/cache/memory_cache.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/config/__init__.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/config/center.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/config/center_notify.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/config/loader.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/config/merge.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/errors/__init__.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/errors/base.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/errors/classify.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/errors/common.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/errors/http.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/ids/__init__.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/ids/generator.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/io/__init__.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/io/io_utils.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/io/printstream.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/logger/__init__.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/logger/manager.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/retry/__init__.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/base/retry/retry.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/dispatch/__init__.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/dispatch/candidate.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/dispatch/dispatcher.py +2 -2
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/dispatch/proxy_selector.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/dispatch/usage.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/__init__.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/parsers/__init__.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/parsers/stream.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/parsers/xml_parser.py +1 -1
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/prompt/__init__.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/prompt/inject.py +2 -2
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/prompt/templates.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/protocols/__init__.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/protocols/entml.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/protocols/entml_patterns.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/protocols/entml_thinking.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/protocols/entml_values.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/registry.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/shared/__init__.py +1 -1
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/shared/coercion.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/shared/loop_detect.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/fncall/shared/xml_helpers.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/keys.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/lifecycle/__init__.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/lifecycle/manager.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/lifecycle/updater.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/lifecycle/updater_pull.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/process/__init__.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/process/port.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/protocol/__init__.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/protocol/base.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/terminal/__init__.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/terminal/conpty.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/terminal/local/__init__.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/terminal/sanitize.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/terminal/session/base.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/terminal/ssh.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/exec/terminal/tmux.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/events/__init__.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/events/bus.py +1 -1
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/events/event.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/spinner/__init__.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/tracing/__init__.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/tracing/context.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/tracing/span.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/tracing/tracer.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/translate.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/watcher/__init__.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/watcher/file_watcher.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/__init__.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/application.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/broker.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/input_box/app.js +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/input_box/components/filezone.js +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/input_box/components/motionkit.js +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/input_box/components/sendbutton.js +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/input_box/components/sortablelist.css +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/input_box/components/sortablelist.js +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/input_box/components/textinput.js +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/input_box/components/voiceinput.js +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/input_box/fonts/inter-500.woff2 +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/input_box/fonts/inter-600.woff2 +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/input_box/fonts/inter400.woff2 +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/input_box/fonts/tailwind.css +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/input_box/inputbox.css +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/input_box/inputbox.js +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/input_box/style.css +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/input_box/voicegif.js +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/stats.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/media/web/utils.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/plat/files/__init__.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/plat/files/file_util.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/plat/network/__init__.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/plat/network/http_utils.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/plat/plugin/__init__.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/plat/plugin/base.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/plat/plugin/discovery.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/plat/proxy/__init__.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/plat/proxy/manager.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/plat/runtime/__init__.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/plat/runtime/collector.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/plat/scheduler/__init__.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/plat/scheduler/scheduler.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/plat/sdk/__init__.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/plat/sdk/facade.py +3 -3
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools/version.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools.egg-info/dependency_links.txt +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools.egg-info/requires.txt +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/echotools.egg-info/top_level.txt +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/tests/bench_import.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/tests/conftest.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_cache_retry.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_completion.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_config.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_config_extended.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_coverage_core.py +9 -9
- {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_dispatch.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_dispatch_extended.py +1 -1
- {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_dispatch_race.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_errors.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_errors_common.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_events.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_events_event.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_facade.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_fncall.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_ids.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_io.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_keys.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_lifecycle.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_logger.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_merge.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_plugin.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_printstream.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_protocols.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_proxy.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_proxy_selector.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_runtime.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_scheduler.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_tracing.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_usage.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/src/tests/test_web.py +0 -0
- {echotools-2.3.8 → echotools-2.3.11}/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.11"
|
|
8
8
|
description = "通用基础设施 SDK:配置、日志、事件、调度、插件、协议、调用链"
|
|
9
9
|
readme = "docs/README.md"
|
|
10
10
|
requires-python = ">=3.8"
|
|
@@ -110,6 +110,7 @@ branch = true
|
|
|
110
110
|
omit = [
|
|
111
111
|
"*/tests/*",
|
|
112
112
|
"*/__init__.py",
|
|
113
|
+
"*/compat.py",
|
|
113
114
|
"*/terminal/*",
|
|
114
115
|
"*/spinner/*",
|
|
115
116
|
"*/media/web/input_box/*",
|
|
@@ -130,7 +131,7 @@ omit = [
|
|
|
130
131
|
]
|
|
131
132
|
|
|
132
133
|
[tool.coverage.report]
|
|
133
|
-
fail_under =
|
|
134
|
+
fail_under = 89
|
|
134
135
|
exclude_lines = [
|
|
135
136
|
"pragma: no cover",
|
|
136
137
|
"def __repr__",
|
|
@@ -8,8 +8,11 @@ from __future__ import annotations
|
|
|
8
8
|
import importlib
|
|
9
9
|
from typing import Any
|
|
10
10
|
|
|
11
|
-
from echotools.
|
|
11
|
+
from echotools.compat import install_compat_aliases
|
|
12
12
|
from echotools.plat.sdk import EchoTools
|
|
13
|
+
from echotools.version import get_version
|
|
14
|
+
|
|
15
|
+
install_compat_aliases()
|
|
13
16
|
|
|
14
17
|
__version__ = get_version()
|
|
15
18
|
|
|
@@ -3,7 +3,16 @@ from __future__ import annotations
|
|
|
3
3
|
"""配置数据类基类,提供自动 from_dict 反序列化。"""
|
|
4
4
|
|
|
5
5
|
from dataclasses import MISSING, fields, is_dataclass
|
|
6
|
-
from typing import
|
|
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
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
"""Backward-compatible import aliases for pre-2.3.9 module paths."""
|
|
4
|
+
|
|
5
|
+
import importlib
|
|
6
|
+
import importlib.abc
|
|
7
|
+
import importlib.util
|
|
8
|
+
import sys
|
|
9
|
+
from types import ModuleType
|
|
10
|
+
from typing import Dict, Optional, Sequence
|
|
11
|
+
|
|
12
|
+
_MODULE_ALIASES: Dict[str, str] = {
|
|
13
|
+
"echotools.cache": "echotools.base.cache",
|
|
14
|
+
"echotools.config": "echotools.base.config",
|
|
15
|
+
"echotools.dispatch": "echotools.exec.dispatch",
|
|
16
|
+
"echotools.files": "echotools.plat.files",
|
|
17
|
+
"echotools.fncall": "echotools.exec.fncall",
|
|
18
|
+
"echotools.ids": "echotools.base.ids",
|
|
19
|
+
"echotools.io": "echotools.base.io",
|
|
20
|
+
"echotools.lifecycle": "echotools.exec.lifecycle",
|
|
21
|
+
"echotools.logger": "echotools.base.logger",
|
|
22
|
+
"echotools.plugin": "echotools.plat.plugin",
|
|
23
|
+
"echotools.process": "echotools.exec.process",
|
|
24
|
+
"echotools.protocol": "echotools.exec.protocol",
|
|
25
|
+
"echotools.proxy": "echotools.plat.proxy",
|
|
26
|
+
"echotools.retry": "echotools.base.retry",
|
|
27
|
+
"echotools.scheduler": "echotools.plat.scheduler",
|
|
28
|
+
"echotools.terminal": "echotools.exec.terminal",
|
|
29
|
+
"echotools.web": "echotools.media.web",
|
|
30
|
+
"echotools.events": "echotools.media.events",
|
|
31
|
+
"echotools.spinner": "echotools.media.spinner",
|
|
32
|
+
"echotools.tracing": "echotools.media.tracing",
|
|
33
|
+
"echotools.translate": "echotools.media.translate",
|
|
34
|
+
"echotools.watcher": "echotools.media.watcher",
|
|
35
|
+
"echotools.network": "echotools.plat.network",
|
|
36
|
+
"echotools.runtime": "echotools.plat.runtime",
|
|
37
|
+
"echotools.sdk": "echotools.plat.sdk",
|
|
38
|
+
"echotools.keys": "echotools.exec.keys",
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _map_name(fullname: str) -> Optional[str]:
|
|
43
|
+
for old, new in _MODULE_ALIASES.items():
|
|
44
|
+
if fullname == old or fullname.startswith(old + "."):
|
|
45
|
+
return new + fullname[len(old) :]
|
|
46
|
+
return None
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class _AliasLoader(importlib.abc.Loader):
|
|
50
|
+
def __init__(self, fullname: str, target: str) -> None:
|
|
51
|
+
self._fullname = fullname
|
|
52
|
+
self._target = target
|
|
53
|
+
|
|
54
|
+
def create_module(self, spec: importlib.machinery.ModuleSpec) -> Optional[ModuleType]:
|
|
55
|
+
return None
|
|
56
|
+
|
|
57
|
+
def exec_module(self, module: ModuleType) -> None:
|
|
58
|
+
target = importlib.import_module(self._target)
|
|
59
|
+
module.__dict__.update(target.__dict__)
|
|
60
|
+
module.__name__ = self._fullname
|
|
61
|
+
module.__package__ = self._fullname.rpartition(".")[0]
|
|
62
|
+
sys.modules[self._fullname] = module
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class _AliasFinder(importlib.abc.MetaPathFinder):
|
|
66
|
+
def find_spec(
|
|
67
|
+
self,
|
|
68
|
+
fullname: str,
|
|
69
|
+
path: Optional[Sequence[str]],
|
|
70
|
+
target: Optional[ModuleType] = None,
|
|
71
|
+
) -> Optional[importlib.machinery.ModuleSpec]:
|
|
72
|
+
mapped = _map_name(fullname)
|
|
73
|
+
if mapped is None:
|
|
74
|
+
return None
|
|
75
|
+
return importlib.util.spec_from_loader(
|
|
76
|
+
fullname,
|
|
77
|
+
_AliasLoader(fullname, mapped),
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def install_compat_aliases() -> None:
|
|
82
|
+
if not any(isinstance(finder, _AliasFinder) for finder in sys.meta_path):
|
|
83
|
+
sys.meta_path.insert(0, _AliasFinder())
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
# 确保 ``from echotools.config...`` 等旧路径在未显式 ``import echotools`` 时也可用。
|
|
87
|
+
install_compat_aliases()
|
|
@@ -22,12 +22,14 @@ from dataclasses import dataclass
|
|
|
22
22
|
from pathlib import Path
|
|
23
23
|
from typing import Any, Dict, List, Optional, Set, Tuple
|
|
24
24
|
|
|
25
|
-
from echotools.exec.dispatch.candidate import TaskCandidate
|
|
26
25
|
from echotools.base.io.io_utils import atomic_write_text
|
|
27
26
|
from echotools.base.logger.manager import get_logger
|
|
27
|
+
from echotools.exec.dispatch.candidate import TaskCandidate
|
|
28
28
|
|
|
29
29
|
__all__ = ["AdaptiveSelector", "TASRecord"]
|
|
30
30
|
|
|
31
|
+
_DEFAULT_DISPATCH_PERSIST = str(Path.home() / ".echotools" / "dispatch")
|
|
32
|
+
|
|
31
33
|
logger = get_logger(__name__)
|
|
32
34
|
|
|
33
35
|
|
|
@@ -156,7 +158,7 @@ class AdaptiveSelector:
|
|
|
156
158
|
|
|
157
159
|
def __init__(
|
|
158
160
|
self,
|
|
159
|
-
persist_dir: str =
|
|
161
|
+
persist_dir: str = _DEFAULT_DISPATCH_PERSIST,
|
|
160
162
|
group_attr: str = "group",
|
|
161
163
|
*,
|
|
162
164
|
flush_debounce: float = 1.0,
|
|
@@ -2,10 +2,9 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
4
|
import uuid
|
|
5
|
-
from typing import Any, Dict
|
|
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
|
|
|
@@ -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] = {}
|
|
@@ -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
|
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""Terminal session base and client attachment mixins."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from .base import (
|
|
5
|
+
MAX_HISTORY_LINES,
|
|
6
|
+
MAX_OFFLINE_BUFFER_BYTES,
|
|
7
|
+
MAX_SEQ_RING_BYTES,
|
|
8
|
+
TerminalCallback,
|
|
9
|
+
TerminalSession,
|
|
10
|
+
)
|
|
11
|
+
from .client import SessionClientMixin
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"TerminalCallback",
|
|
15
|
+
"TerminalSession",
|
|
16
|
+
"SessionClientMixin",
|
|
17
|
+
"MAX_OFFLINE_BUFFER_BYTES",
|
|
18
|
+
"MAX_SEQ_RING_BYTES",
|
|
19
|
+
"MAX_HISTORY_LINES",
|
|
20
|
+
]
|
|
@@ -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
|
|
|
@@ -2,7 +2,7 @@ README.md
|
|
|
2
2
|
pyproject.toml
|
|
3
3
|
docs/README.md
|
|
4
4
|
src/echotools/__init__.py
|
|
5
|
-
src/echotools/py
|
|
5
|
+
src/echotools/compat.py
|
|
6
6
|
src/echotools/version.py
|
|
7
7
|
src/echotools.egg-info/PKG-INFO
|
|
8
8
|
src/echotools.egg-info/SOURCES.txt
|
|
@@ -86,24 +86,6 @@ src/echotools/exec/terminal/local/win.py
|
|
|
86
86
|
src/echotools/exec/terminal/session/__init__.py
|
|
87
87
|
src/echotools/exec/terminal/session/base.py
|
|
88
88
|
src/echotools/exec/terminal/session/client.py
|
|
89
|
-
src/echotools/fncall/__init__.py
|
|
90
|
-
src/echotools/fncall/registry.py
|
|
91
|
-
src/echotools/fncall/parsers/__init__.py
|
|
92
|
-
src/echotools/fncall/parsers/stream.py
|
|
93
|
-
src/echotools/fncall/parsers/xml_parser.py
|
|
94
|
-
src/echotools/fncall/prompt/__init__.py
|
|
95
|
-
src/echotools/fncall/prompt/history.py
|
|
96
|
-
src/echotools/fncall/prompt/inject.py
|
|
97
|
-
src/echotools/fncall/prompt/templates.py
|
|
98
|
-
src/echotools/fncall/protocols/__init__.py
|
|
99
|
-
src/echotools/fncall/protocols/entml.py
|
|
100
|
-
src/echotools/fncall/shared/__init__.py
|
|
101
|
-
src/echotools/fncall/shared/coercion.py
|
|
102
|
-
src/echotools/fncall/shared/loop_detect.py
|
|
103
|
-
src/echotools/fncall/shared/normalization.py
|
|
104
|
-
src/echotools/fncall/shared/xml_helpers.py
|
|
105
|
-
src/echotools/logger/__init__.py
|
|
106
|
-
src/echotools/logger/manager.py
|
|
107
89
|
src/echotools/media/translate.py
|
|
108
90
|
src/echotools/media/events/__init__.py
|
|
109
91
|
src/echotools/media/events/bus.py
|
|
@@ -156,8 +138,6 @@ src/echotools/plat/scheduler/__init__.py
|
|
|
156
138
|
src/echotools/plat/scheduler/scheduler.py
|
|
157
139
|
src/echotools/plat/sdk/__init__.py
|
|
158
140
|
src/echotools/plat/sdk/facade.py
|
|
159
|
-
src/echotools/protocol/__init__.py
|
|
160
|
-
src/echotools/protocol/base.py
|
|
161
141
|
src/tests/bench_import.py
|
|
162
142
|
src/tests/conftest.py
|
|
163
143
|
src/tests/test_cache_retry.py
|
|
@@ -108,6 +108,74 @@ def test_coerce_entml_parameter_value(raw, schema, expected) -> None:
|
|
|
108
108
|
assert coerce_entml_parameter_value(raw, schema) == expected
|
|
109
109
|
|
|
110
110
|
|
|
111
|
+
def test_entml_instruction_matches_spec_format() -> None:
|
|
112
|
+
"""示范格式:<entml:function_calls> + <entml:invoke> + <entml:parameter>."""
|
|
113
|
+
proto = get_protocol("entml")
|
|
114
|
+
from echotools.exec.fncall.shared.normalization import format_tool_descs
|
|
115
|
+
|
|
116
|
+
tools = [
|
|
117
|
+
{
|
|
118
|
+
"type": "function",
|
|
119
|
+
"function": {
|
|
120
|
+
"name": "ask_user_input_v0",
|
|
121
|
+
"description": "Ask user",
|
|
122
|
+
"parameters": {
|
|
123
|
+
"type": "object",
|
|
124
|
+
"properties": {
|
|
125
|
+
"question": {"type": "string"},
|
|
126
|
+
"options": {
|
|
127
|
+
"type": "array",
|
|
128
|
+
"items": {"type": "string"},
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
"required": ["question"],
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
}
|
|
135
|
+
]
|
|
136
|
+
prompt = proto.render_prompt(
|
|
137
|
+
tool_descs=format_tool_descs(tools),
|
|
138
|
+
lang="en",
|
|
139
|
+
current_user_message="pick one",
|
|
140
|
+
)
|
|
141
|
+
assert "<entml:function_calls>" in prompt
|
|
142
|
+
assert '<entml:invoke name="' in prompt
|
|
143
|
+
assert '<entml:parameter name="' in prompt
|
|
144
|
+
assert "String and scalar parameters should be specified as-is" in prompt
|
|
145
|
+
assert "<entml:conversation_history>" not in prompt
|
|
146
|
+
assert "<entml:history>" not in prompt
|
|
147
|
+
assert "<entml:thinking_mode>" not in prompt
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def test_entml_roundtrip_parameter_format() -> None:
|
|
151
|
+
"""渲染与解析均使用 <entml:parameter name=\"...\">。"""
|
|
152
|
+
from echotools.exec.fncall.protocols.entml_invoke import format_entml_tool_calls
|
|
153
|
+
|
|
154
|
+
sample_calls = [
|
|
155
|
+
{
|
|
156
|
+
"id": "call_0000",
|
|
157
|
+
"type": "function",
|
|
158
|
+
"function": {
|
|
159
|
+
"name": "search",
|
|
160
|
+
"arguments": json.dumps(
|
|
161
|
+
{"query": "hello", "limit": 3, "tags": ["a", "b"]}
|
|
162
|
+
),
|
|
163
|
+
},
|
|
164
|
+
}
|
|
165
|
+
]
|
|
166
|
+
rendered = format_entml_tool_calls(sample_calls)
|
|
167
|
+
assert '<entml:parameter name="query">hello</entml:parameter>' in rendered
|
|
168
|
+
assert '<entml:parameter name="limit">3</entml:parameter>' in rendered
|
|
169
|
+
assert '<entml:parameter name="tags">["a", "b"]</entml:parameter>' in rendered
|
|
170
|
+
assert "<parameter name=" not in rendered
|
|
171
|
+
|
|
172
|
+
parsed = parse_entml_tool_calls(rendered, None, None)
|
|
173
|
+
args = json.loads(parsed[0]["function"]["arguments"])
|
|
174
|
+
assert args["query"] == "hello"
|
|
175
|
+
assert args["limit"] == 3
|
|
176
|
+
assert args["tags"] == ["a", "b"]
|
|
177
|
+
|
|
178
|
+
|
|
111
179
|
def test_entml_parse_schema_coercion() -> None:
|
|
112
180
|
tools = [
|
|
113
181
|
{
|
|
@@ -31,3 +31,21 @@ def test_lazy_fncall_exports() -> None:
|
|
|
31
31
|
|
|
32
32
|
assert echotools.get_protocol is not None
|
|
33
33
|
assert echotools.inject_fncall is not None
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_legacy_config_import_without_package_init() -> None:
|
|
37
|
+
import importlib
|
|
38
|
+
import sys
|
|
39
|
+
|
|
40
|
+
for name in list(sys.modules):
|
|
41
|
+
if name == "echotools" or name.startswith("echotools."):
|
|
42
|
+
sys.modules.pop(name, None)
|
|
43
|
+
|
|
44
|
+
compat = importlib.import_module("echotools.compat")
|
|
45
|
+
assert compat.install_compat_aliases is not None
|
|
46
|
+
|
|
47
|
+
from echotools.config.center import ConfigCenter
|
|
48
|
+
from echotools.config.loader import write_toml
|
|
49
|
+
|
|
50
|
+
assert ConfigCenter is not None
|
|
51
|
+
assert callable(write_toml)
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
from echotools.exec.fncall import * # noqa: F403
|