echotools 2.3.87__tar.gz → 2.3.89__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.87 → echotools-2.3.89}/PKG-INFO +1 -1
- {echotools-2.3.87 → echotools-2.3.89}/pyproject.toml +1 -1
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/fncall/parsers/stream.py +5 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/fncall/parsers/stream_delta.py +5 -5
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/fncall/parsers/stream_feed.py +5 -5
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/fncall/parsers/stream_final.py +27 -6
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/fncall/protocols/entml.py +43 -26
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/fncall/protocols/entml_invoke.py +11 -4
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/fncall/protocols/entml_patterns.py +190 -30
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/fncall/protocols/entml_stream/body.py +18 -33
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/fncall/protocols/entml_think/hold.py +17 -23
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/fncall/protocols/entml_think/parse.py +29 -13
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/protocol/base.py +5 -1
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools.egg-info/PKG-INFO +1 -1
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools.egg-info/SOURCES.txt +1 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_entml_bare_invoke_format.py +30 -9
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_entml_batch_stream_comprehensive.py +2 -1
- echotools-2.3.89/src/tests/test_entml_invoke_known_tool_gate.py +220 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_entml_protocol.py +104 -0
- {echotools-2.3.87 → echotools-2.3.89}/README.md +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/setup.cfg +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/__init__.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/base/cache/__init__.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/base/cache/list_cache.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/base/cache/memory_cache.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/base/config/__init__.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/base/config/base.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/base/config/center.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/base/config/center_notify.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/base/config/center_template.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/base/config/loader.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/base/config/merge.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/base/errors/__init__.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/base/errors/base.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/base/errors/classify.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/base/errors/common.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/base/errors/http.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/base/ids/__init__.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/base/ids/generator.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/base/io/__init__.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/base/io/io_utils.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/base/io/printstream.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/base/logger/__init__.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/base/logger/manager.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/base/retry/__init__.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/base/retry/retry.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/compat.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/dispatch/__init__.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/dispatch/candidate.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/dispatch/dispatcher.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/dispatch/proxy_selector.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/dispatch/race.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/dispatch/selector.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/dispatch/usage.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/fncall/__init__.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/fncall/parsers/__init__.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/fncall/parsers/xml_params.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/fncall/parsers/xml_parser.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/fncall/prompt/__init__.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/fncall/prompt/history.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/fncall/prompt/history_format.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/fncall/prompt/inject.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/fncall/prompt/prompt_helpers.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/fncall/prompt/templates.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/fncall/protocols/__init__.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/fncall/protocols/entml_schema.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/fncall/protocols/entml_stream/__init__.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/fncall/protocols/entml_stream/snap.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/fncall/protocols/entml_think/__init__.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/fncall/protocols/entml_think/blocks.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/fncall/protocols/entml_think/core.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/fncall/protocols/entml_think/filter.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/fncall/protocols/entml_think/hist.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/fncall/registry.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/fncall/shared/__init__.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/fncall/shared/coercion.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/fncall/shared/history_markup.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/fncall/shared/loop_detect.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/fncall/shared/normalization.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/fncall/shared/schema_render.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/fncall/shared/xml_helpers.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/keys.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/lifecycle/__init__.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/lifecycle/manager.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/lifecycle/updater.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/lifecycle/updater_pull.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/process/__init__.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/process/port.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/protocol/__init__.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/terminal/__init__.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/terminal/conpty.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/terminal/local/__init__.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/terminal/local/core.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/terminal/local/proc.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/terminal/local/unix.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/terminal/local/win.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/terminal/sanitize.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/terminal/session/__init__.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/terminal/session/base.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/terminal/session/client.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/terminal/ssh.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/exec/terminal/tmux.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/console/__init__.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/console/charmap.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/console/spinner.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/console/ui.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/console/uicore/mixins/__init__.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/console/uicore/mixins/uibase.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/console/uicore/mixins/uicmds.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/console/uicore/mixins/uiinteract.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/console/uicore/mixins/uioutput.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/console/uicore/mixins/uistream.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/console/uicore/ui_console.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/console/uicore/ui_io.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/console/uicore/ui_log.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/console/uicore/ui_platform.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/console/uicore/ui_text.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/console/uicore/ui_types.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/console/uilayout/ui_countdown.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/console/uilayout/ui_layout.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/console/uilayout/ui_misc.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/console/uilayout/ui_panel.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/console/uilayout/ui_table.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/console/uilayout/ui_tree.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/console/uiwidgets/ui_box.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/console/uiwidgets/ui_editor.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/console/uiwidgets/ui_progress.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/console/uiwidgets/ui_select.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/console/uiwidgets/ui_stream.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/events/__init__.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/events/bus.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/events/event.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/spinner/__init__.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/spinner/spinner.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/spinner/spinner_color.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/tracing/__init__.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/tracing/context.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/tracing/span.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/tracing/tracer.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/translate.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/watcher/__init__.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/watcher/file_watcher.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/web/__init__.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/web/application.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/web/broker.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/web/input_box/app.js +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/web/input_box/components/filezone.js +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/web/input_box/components/motionkit.js +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/web/input_box/components/sendbutton.js +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/web/input_box/components/sortablelist.css +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/web/input_box/components/sortablelist.js +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/web/input_box/components/textinput.js +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/web/input_box/components/voiceinput.js +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/web/input_box/fonts/inter-500.woff2 +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/web/input_box/fonts/inter-600.woff2 +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/web/input_box/fonts/inter400.woff2 +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/web/input_box/inputbox.css +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/web/input_box/inputbox.js +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/web/input_box/style.css +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/web/input_box/voicegif.js +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/web/middleware.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/web/stats.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/media/web/utils.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/plat/files/__init__.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/plat/files/file_util.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/plat/network/__init__.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/plat/network/http_utils.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/plat/plugin/__init__.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/plat/plugin/base.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/plat/plugin/discovery.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/plat/plugin/registry.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/plat/plugin/registry_ops.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/plat/proxy/__init__.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/plat/proxy/manager.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/plat/runtime/__init__.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/plat/runtime/collector.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/plat/scheduler/__init__.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/plat/scheduler/scheduler.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/plat/sdk/__init__.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/plat/sdk/facade.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools/version.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools.egg-info/dependency_links.txt +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools.egg-info/requires.txt +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/echotools.egg-info/top_level.txt +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/bench_import.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/conftest.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/fixtures/__init__.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/fixtures/simulated_fake_history_markup_responses.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/fixtures/simulated_fault_thinking_responses.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/fixtures/simulated_llm_tool_responses.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_adversarial_stream_splits.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_cache_retry.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_completion.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_config.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_config_extended.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_console.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_coverage_core.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_dispatch.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_dispatch_extended.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_dispatch_race.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_entml_agent_output_formats.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_entml_parser_comprehensive.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_entml_stream_json.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_entml_stream_json_exhaustive.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_entml_thinking_history.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_entml_thinking_parse.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_entml_tool_parse_leak.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_entml_tool_pipeline.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_entml_tools.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_errors.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_errors_common.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_events.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_events_event.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_facade.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_fake_history_markup_batch.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_fake_history_markup_invoke_preserve.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_fake_history_markup_reply_protect.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_fake_history_markup_stream.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_fault_thinking_close_batch.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_fault_thinking_close_stream.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_fncall.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_fncall_stream_thinking.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_history_markup_filter.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_ids.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_imports.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_io.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_keys.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_lifecycle.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_logger.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_merge.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_model_branch_matrix.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_plugin.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_printstream.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_protocols.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_proxy.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_proxy_selector.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_runtime.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_scheduler.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_simulated_llm_tool_parse.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_stream_partial_json_parity.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_stream_realtime_parse.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_tracing.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_usage.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_web.py +0 -0
- {echotools-2.3.87 → echotools-2.3.89}/src/tests/test_web_broker.py +0 -0
|
@@ -100,6 +100,11 @@ class FncallStreamParser(StreamFeedMixin, StreamDeltaMixin, StreamFinalMixin):
|
|
|
100
100
|
self._schema_index = _build_param_schema_index(self._tools)
|
|
101
101
|
return self._schema_index
|
|
102
102
|
|
|
103
|
+
def _get_known_tool_names(self):
|
|
104
|
+
from echotools.exec.fncall.protocols.entml_patterns import resolve_known_tool_names
|
|
105
|
+
|
|
106
|
+
return resolve_known_tool_names(self._tools, self._get_schema_index())
|
|
107
|
+
|
|
103
108
|
def _emit_text(self, text: str) -> None:
|
|
104
109
|
"""将文本路由给思考过滤器(若启用)或直接追加到 _text_parts。"""
|
|
105
110
|
if not text:
|
|
@@ -26,7 +26,7 @@ class StreamDeltaMixin:
|
|
|
26
26
|
|
|
27
27
|
complete = list(INVOKE_RE.finditer(self._fncall_buf))
|
|
28
28
|
complete_n = len(complete)
|
|
29
|
-
parsed = split_invoke_open(self._fncall_buf)
|
|
29
|
+
parsed = split_invoke_open(self._fncall_buf, known_names=self._get_known_tool_names())
|
|
30
30
|
if parsed is None:
|
|
31
31
|
return max(0, complete_n - 1)
|
|
32
32
|
_name, body_start = parsed
|
|
@@ -77,7 +77,7 @@ class StreamDeltaMixin:
|
|
|
77
77
|
build_streaming_json_snapshot,
|
|
78
78
|
split_invoke_open,
|
|
79
79
|
)
|
|
80
|
-
parsed = split_invoke_open(self._fncall_buf)
|
|
80
|
+
parsed = split_invoke_open(self._fncall_buf, known_names=self._get_known_tool_names())
|
|
81
81
|
if not parsed:
|
|
82
82
|
self._json_stream_encoder.reset()
|
|
83
83
|
return
|
|
@@ -125,7 +125,7 @@ class StreamDeltaMixin:
|
|
|
125
125
|
split_invoke_open,
|
|
126
126
|
)
|
|
127
127
|
|
|
128
|
-
parsed = split_invoke_open(self._fncall_buf)
|
|
128
|
+
parsed = split_invoke_open(self._fncall_buf, known_names=self._get_known_tool_names())
|
|
129
129
|
if not parsed:
|
|
130
130
|
self._json_stream_encoder.reset()
|
|
131
131
|
return
|
|
@@ -172,7 +172,7 @@ class StreamDeltaMixin:
|
|
|
172
172
|
split_invoke_open,
|
|
173
173
|
)
|
|
174
174
|
|
|
175
|
-
parsed = split_invoke_open(self._fncall_buf)
|
|
175
|
+
parsed = split_invoke_open(self._fncall_buf, known_names=self._get_known_tool_names())
|
|
176
176
|
if not parsed:
|
|
177
177
|
return None
|
|
178
178
|
name, body_start = parsed
|
|
@@ -241,7 +241,7 @@ class StreamDeltaMixin:
|
|
|
241
241
|
split_invoke_open,
|
|
242
242
|
)
|
|
243
243
|
|
|
244
|
-
parsed = split_invoke_open(self._fncall_buf)
|
|
244
|
+
parsed = split_invoke_open(self._fncall_buf, known_names=self._get_known_tool_names())
|
|
245
245
|
if not parsed:
|
|
246
246
|
return None
|
|
247
247
|
name, body_start = parsed
|
|
@@ -37,7 +37,7 @@ class StreamFeedMixin:
|
|
|
37
37
|
"""True 表示已消费 text(含 holdback)。"""
|
|
38
38
|
hold_from_fn = getattr(self._protocol, "find_fncall_hold_from", None)
|
|
39
39
|
if hold_from_fn is not None:
|
|
40
|
-
hold_from = hold_from_fn(text)
|
|
40
|
+
hold_from = hold_from_fn(text, tools=self._tools)
|
|
41
41
|
if hold_from is not None:
|
|
42
42
|
if hold_from > 0:
|
|
43
43
|
self._append_content_text(text[:hold_from])
|
|
@@ -52,7 +52,7 @@ class StreamFeedMixin:
|
|
|
52
52
|
def _hold_or_split_emit(self, text: str, trigger_tags) -> None:
|
|
53
53
|
hold_from_fn = getattr(self._protocol, "find_fncall_hold_from", None)
|
|
54
54
|
if hold_from_fn is not None:
|
|
55
|
-
hold_from = hold_from_fn(text)
|
|
55
|
+
hold_from = hold_from_fn(text, tools=self._tools)
|
|
56
56
|
if hold_from is not None:
|
|
57
57
|
if hold_from > 0:
|
|
58
58
|
self._emit_text(text[:hold_from])
|
|
@@ -81,7 +81,7 @@ class StreamFeedMixin:
|
|
|
81
81
|
self._fncall_buf += text
|
|
82
82
|
return
|
|
83
83
|
trigger_tags = self._protocol.get_trigger_tags()
|
|
84
|
-
found, pos = self._protocol.detect_start(text)
|
|
84
|
+
found, pos = self._protocol.detect_start(text, tools=self._tools)
|
|
85
85
|
if found:
|
|
86
86
|
if pos > 0:
|
|
87
87
|
self._append_content_text(text[:pos])
|
|
@@ -90,7 +90,7 @@ class StreamFeedMixin:
|
|
|
90
90
|
self._hold_or_split_content(text, trigger_tags)
|
|
91
91
|
return
|
|
92
92
|
trigger_tags = self._protocol.get_trigger_tags()
|
|
93
|
-
found, pos = self._protocol.detect_start(text)
|
|
93
|
+
found, pos = self._protocol.detect_start(text, tools=self._tools)
|
|
94
94
|
if not found:
|
|
95
95
|
self._hold_or_split_content(text, trigger_tags)
|
|
96
96
|
return
|
|
@@ -138,7 +138,7 @@ class StreamFeedMixin:
|
|
|
138
138
|
self._feed_waiting_thinking_plain(combined)
|
|
139
139
|
return
|
|
140
140
|
trigger_tags = self._protocol.get_trigger_tags()
|
|
141
|
-
found, pos = self._protocol.detect_start(combined)
|
|
141
|
+
found, pos = self._protocol.detect_start(combined, tools=self._tools)
|
|
142
142
|
if found:
|
|
143
143
|
if self._thinking_filter is not None:
|
|
144
144
|
from echotools.exec.fncall.protocols.entml_think.parse import (
|
|
@@ -67,10 +67,18 @@ class StreamFinalMixin:
|
|
|
67
67
|
|
|
68
68
|
lower = raw.lower()
|
|
69
69
|
cut = len(raw)
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
70
|
+
from echotools.exec.fncall.protocols.entml_patterns import (
|
|
71
|
+
find_actionable_entml_invoke_open,
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
invoke_pos = find_actionable_entml_invoke_open(
|
|
75
|
+
raw, known_names=self._get_known_tool_names()
|
|
76
|
+
)
|
|
77
|
+
if invoke_pos >= 0:
|
|
78
|
+
cut = min(cut, invoke_pos)
|
|
79
|
+
legacy_pos = lower.find("<entml:function_calls")
|
|
80
|
+
if legacy_pos >= 0:
|
|
81
|
+
cut = min(cut, legacy_pos)
|
|
74
82
|
segment = raw[:cut]
|
|
75
83
|
|
|
76
84
|
buf = stream_safe_visible_prefix(
|
|
@@ -128,12 +136,25 @@ class StreamFinalMixin:
|
|
|
128
136
|
)
|
|
129
137
|
clean_fn = getattr(self._protocol, "clean_tool_tags", None)
|
|
130
138
|
if callable(clean_fn):
|
|
131
|
-
|
|
139
|
+
import inspect
|
|
140
|
+
|
|
141
|
+
sig = inspect.signature(clean_fn)
|
|
142
|
+
if "tools" in sig.parameters:
|
|
143
|
+
clean_text = clean_fn(clean_text, tools=self._tools)
|
|
144
|
+
else:
|
|
145
|
+
clean_text = clean_fn(clean_text)
|
|
132
146
|
elif getattr(self._protocol, "id", None) == "entml":
|
|
133
147
|
from echotools.exec.fncall.protocols.entml_patterns import (
|
|
148
|
+
resolve_known_tool_names,
|
|
134
149
|
strip_tool_entml_residue,
|
|
135
150
|
)
|
|
136
|
-
|
|
151
|
+
|
|
152
|
+
clean_text = strip_tool_entml_residue(
|
|
153
|
+
clean_text,
|
|
154
|
+
known_names=resolve_known_tool_names(
|
|
155
|
+
self._tools, self._get_schema_index()
|
|
156
|
+
),
|
|
157
|
+
)
|
|
137
158
|
display_text = self._finalize_display_text(clean_text)
|
|
138
159
|
self._text_parts = [display_text] if display_text else []
|
|
139
160
|
self._finalized_result = (display_text, tool_calls)
|
|
@@ -25,7 +25,9 @@ from echotools.exec.fncall.protocols.entml_think.blocks import (
|
|
|
25
25
|
from echotools.exec.fncall.protocols.entml_patterns import (
|
|
26
26
|
entml_invoke_open_may_be_streaming,
|
|
27
27
|
extract_attr_value,
|
|
28
|
+
find_actionable_entml_invoke_open,
|
|
28
29
|
normalize_entml_name,
|
|
30
|
+
resolve_known_tool_names,
|
|
29
31
|
strip_actionable_entml_invoke_blocks,
|
|
30
32
|
strip_legacy_function_calls_wrapper,
|
|
31
33
|
strip_tool_entml_residue,
|
|
@@ -215,16 +217,28 @@ class EntmlProtocol(ToolProtocol):
|
|
|
215
217
|
|
|
216
218
|
return "\n\n".join(sections)
|
|
217
219
|
|
|
218
|
-
def detect_start(
|
|
219
|
-
|
|
220
|
-
|
|
220
|
+
def detect_start(
|
|
221
|
+
self,
|
|
222
|
+
buffer: str,
|
|
223
|
+
tools: Optional[List[Dict[str, Any]]] = None,
|
|
224
|
+
) -> Tuple[bool, int]:
|
|
225
|
+
"""invoke 开标签(闭合 ``>`` 且 name 在 tools 内)稳定后才视为工具流开始。"""
|
|
226
|
+
schema_index = _build_param_schema_index(tools) if tools else None
|
|
227
|
+
known = resolve_known_tool_names(tools, schema_index)
|
|
228
|
+
invoke_pos = find_actionable_entml_invoke_open(buffer, known_names=known)
|
|
221
229
|
if invoke_pos < 0:
|
|
222
230
|
return (False, -1)
|
|
223
231
|
return (True, invoke_pos)
|
|
224
232
|
|
|
225
|
-
def find_fncall_hold_from(
|
|
233
|
+
def find_fncall_hold_from(
|
|
234
|
+
self,
|
|
235
|
+
buffer: str,
|
|
236
|
+
tools: Optional[List[Dict[str, Any]]] = None,
|
|
237
|
+
) -> Optional[int]:
|
|
226
238
|
"""invoke 未稳定前 hold 前缀;legacy 外壳开标签未闭合时同样 hold。"""
|
|
227
|
-
|
|
239
|
+
schema_index = _build_param_schema_index(tools) if tools else None
|
|
240
|
+
known = resolve_known_tool_names(tools, schema_index)
|
|
241
|
+
if find_actionable_entml_invoke_open(buffer, known_names=known) >= 0:
|
|
228
242
|
return None
|
|
229
243
|
hold: Optional[int] = None
|
|
230
244
|
legacy_pos = buffer.find(self._LEGACY_WRAPPER_PREFIX)
|
|
@@ -235,28 +249,23 @@ class EntmlProtocol(ToolProtocol):
|
|
|
235
249
|
invoke_pos = buffer.find(self._TRIGGER_PREFIX)
|
|
236
250
|
if (
|
|
237
251
|
invoke_pos >= 0
|
|
238
|
-
and entml_invoke_open_may_be_streaming(
|
|
252
|
+
and entml_invoke_open_may_be_streaming(
|
|
253
|
+
buffer, invoke_pos, known_names=known
|
|
254
|
+
)
|
|
239
255
|
and (hold is None or invoke_pos < hold)
|
|
240
256
|
):
|
|
241
257
|
hold = invoke_pos
|
|
242
258
|
return hold
|
|
243
259
|
|
|
244
|
-
def _find_complete_invoke_open(
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
if close < 0:
|
|
254
|
-
return -1
|
|
255
|
-
attrs = buffer[pos + prefix_len : close]
|
|
256
|
-
name = extract_attr_value(attrs, "name")
|
|
257
|
-
if name and normalize_entml_name(name):
|
|
258
|
-
return pos
|
|
259
|
-
search_from = close + 1
|
|
260
|
+
def _find_complete_invoke_open(
|
|
261
|
+
self,
|
|
262
|
+
buffer: str,
|
|
263
|
+
tools: Optional[List[Dict[str, Any]]] = None,
|
|
264
|
+
) -> int:
|
|
265
|
+
"""返回首个可解析 ``<entml:invoke`` 起始下标;否则 ``-1``。"""
|
|
266
|
+
schema_index = _build_param_schema_index(tools) if tools else None
|
|
267
|
+
known = resolve_known_tool_names(tools, schema_index)
|
|
268
|
+
return find_actionable_entml_invoke_open(buffer, known_names=known)
|
|
260
269
|
|
|
261
270
|
def parse(
|
|
262
271
|
self,
|
|
@@ -282,6 +291,8 @@ class EntmlProtocol(ToolProtocol):
|
|
|
282
291
|
)
|
|
283
292
|
if unclosed_open_at >= 0:
|
|
284
293
|
parse_text = text[:unclosed_open_at]
|
|
294
|
+
schema_index = _build_param_schema_index(tools) if tools else None
|
|
295
|
+
known = resolve_known_tool_names(tools, schema_index)
|
|
285
296
|
tool_calls = parse_entml_tool_calls(parse_text, tools, schema_index)
|
|
286
297
|
tool_block_calls: List[Dict[str, Any]] = []
|
|
287
298
|
if include_tool_blocks:
|
|
@@ -297,8 +308,8 @@ class EntmlProtocol(ToolProtocol):
|
|
|
297
308
|
# 须在移除 invoke 之前剥离伪 history,且须晚于已解析的 ``<tool>`` 块剥离。
|
|
298
309
|
clean, _ = strip_fake_history_markup(clean)
|
|
299
310
|
if tool_calls:
|
|
300
|
-
clean = strip_actionable_entml_invoke_blocks(clean)
|
|
301
|
-
clean = strip_tool_entml_residue(clean)
|
|
311
|
+
clean = strip_actionable_entml_invoke_blocks(clean, known_names=known)
|
|
312
|
+
clean = strip_tool_entml_residue(clean, known_names=known)
|
|
302
313
|
return (clean, normalize_tool_calls(tool_calls, tools))
|
|
303
314
|
|
|
304
315
|
def parse_fragment(
|
|
@@ -313,9 +324,15 @@ class EntmlProtocol(ToolProtocol):
|
|
|
313
324
|
"""user 消息:仅去掉 ``entml:`` 前缀,不做其它剥离。"""
|
|
314
325
|
return strip_entml_from_content(content)
|
|
315
326
|
|
|
316
|
-
def clean_tool_tags(
|
|
327
|
+
def clean_tool_tags(
|
|
328
|
+
self,
|
|
329
|
+
content: str,
|
|
330
|
+
tools: Optional[List[Dict[str, Any]]] = None,
|
|
331
|
+
) -> str:
|
|
317
332
|
"""仅剥离工具相关标签残留,保留 thinking;并移除伪 history 块。"""
|
|
318
|
-
|
|
333
|
+
schema_index = _build_param_schema_index(tools) if tools else None
|
|
334
|
+
known = resolve_known_tool_names(tools, schema_index)
|
|
335
|
+
cleaned = strip_tool_entml_residue(content, known_names=known)
|
|
319
336
|
cleaned, _ = strip_fake_history_markup(cleaned)
|
|
320
337
|
return cleaned
|
|
321
338
|
|
|
@@ -11,9 +11,11 @@ from .entml_patterns import (
|
|
|
11
11
|
PARAMETERS_RE,
|
|
12
12
|
extract_attr_value,
|
|
13
13
|
extract_parameter_type_attr,
|
|
14
|
+
invoke_structural_gap_text,
|
|
14
15
|
iter_actionable_entml_invoke_blocks,
|
|
15
16
|
normalize_entml_name,
|
|
16
17
|
parse_sub_tags,
|
|
18
|
+
resolve_known_tool_names,
|
|
17
19
|
split_mangled_json_param_tail,
|
|
18
20
|
synthetic_close_invoke_body,
|
|
19
21
|
)
|
|
@@ -25,8 +27,9 @@ def _parse_direct_child_tags(
|
|
|
25
27
|
args: Dict[str, Any],
|
|
26
28
|
func_props: Dict[str, Dict[str, Any]],
|
|
27
29
|
) -> None:
|
|
28
|
-
"""模型用 ``<key>value</key>`` 代替 ``<parameter name=\"key\"
|
|
29
|
-
|
|
30
|
+
"""模型用 ``<key>value</key>`` 代替 ``<parameter name=\"key\">``(仅 structural gap)。"""
|
|
31
|
+
gap_text = invoke_structural_gap_text(body)
|
|
32
|
+
for match in INVOKE_DIRECT_CHILD_RE.finditer(gap_text):
|
|
30
33
|
key = normalize_entml_name(match.group(1))
|
|
31
34
|
if not key or key.lower() in INVOKE_DIRECT_CHILD_SKIP or key in args:
|
|
32
35
|
continue
|
|
@@ -42,7 +45,8 @@ def _parse_bare_invoke_children(
|
|
|
42
45
|
args: Dict[str, Any],
|
|
43
46
|
func_props: Dict[str, Dict[str, Any]],
|
|
44
47
|
) -> None:
|
|
45
|
-
|
|
48
|
+
gap_text = invoke_structural_gap_text(body)
|
|
49
|
+
for match in BARE_INVOKE_CHILD_RE.finditer(gap_text):
|
|
46
50
|
key = normalize_entml_name(match.group(1))
|
|
47
51
|
if not key or key in args:
|
|
48
52
|
continue
|
|
@@ -140,7 +144,10 @@ def parse_entml_tool_calls(
|
|
|
140
144
|
schema_index: Optional[Dict[str, Dict[str, Dict[str, Any]]]],
|
|
141
145
|
) -> List[Dict[str, Any]]:
|
|
142
146
|
tool_calls: List[Dict[str, Any]] = []
|
|
143
|
-
|
|
147
|
+
known = resolve_known_tool_names(tools, schema_index)
|
|
148
|
+
for _start, _end, attrs, body in iter_actionable_entml_invoke_blocks(
|
|
149
|
+
text, known_names=known
|
|
150
|
+
):
|
|
144
151
|
name = extract_attr_value(attrs, "name")
|
|
145
152
|
if not name:
|
|
146
153
|
continue
|