echotools 2.3.100__tar.gz → 2.3.103__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.100 → echotools-2.3.103}/PKG-INFO +1 -1
- {echotools-2.3.100 → echotools-2.3.103}/pyproject.toml +1 -1
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/fncall/parsers/xml_parser.py +1 -1
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/fncall/prompt/behavior_blocks.py +1 -1
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/fncall/prompt/history.py +1 -1
- echotools-2.3.103/src/echotools/exec/fncall/protocols/entml.py +241 -0
- echotools-2.3.103/src/echotools/exec/fncall/protocols/entml_patterns/__init__.py +93 -0
- echotools-2.3.103/src/echotools/exec/fncall/protocols/entml_patterns/invoke.py +197 -0
- echotools-2.3.103/src/echotools/exec/fncall/protocols/entml_patterns/params.py +219 -0
- echotools-2.3.103/src/echotools/exec/fncall/protocols/entml_patterns/regex.py +107 -0
- echotools-2.3.103/src/echotools/exec/fncall/protocols/entml_patterns/strip.py +42 -0
- echotools-2.3.103/src/echotools/exec/fncall/protocols/entml_schema/__init__.py +26 -0
- echotools-2.3.103/src/echotools/exec/fncall/protocols/entml_schema/mangled.py +201 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/fncall/protocols/entml_stream/body.py +1 -1
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/fncall/protocols/entml_stream/snap.py +28 -26
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/fncall/protocols/entml_think/blocks.py +2 -2
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/fncall/protocols/entml_think/parse.py +1 -1
- echotools-2.3.103/src/echotools/exec/fncall/protocols/entml_tool/__init__.py +56 -0
- echotools-2.3.100/src/echotools/exec/fncall/protocols/entml_tool_blocks.py → echotools-2.3.103/src/echotools/exec/fncall/protocols/entml_tool/blocks.py +4 -3
- echotools-2.3.100/src/echotools/exec/fncall/protocols/entml_fake_structure_markup.py → echotools-2.3.103/src/echotools/exec/fncall/protocols/entml_tool/fakemarkup.py +1 -1
- echotools-2.3.100/src/echotools/exec/fncall/protocols/entml_invoke.py → echotools-2.3.103/src/echotools/exec/fncall/protocols/entml_tool/invoke.py +14 -10
- echotools-2.3.103/src/echotools/exec/fncall/shared/entml_format.py +169 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/fncall/shared/history_markup.py +1 -1
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/fncall/shared/loop_detect.py +39 -0
- echotools-2.3.103/src/echotools/media/console/__init__.py +89 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/console/uicore/ui_text.py +59 -32
- echotools-2.3.103/src/echotools/media/console/uilayout/ui_bridge.py +205 -0
- echotools-2.3.103/src/echotools/media/console/uiwidgets/ui_richcli.py +110 -0
- echotools-2.3.103/src/echotools/media/console/uiwidgets/ui_themes.py +243 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools.egg-info/PKG-INFO +1 -1
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools.egg-info/SOURCES.txt +22 -10
- echotools-2.3.103/src/tests/_check_parity.py +75 -0
- echotools-2.3.103/src/tests/fixtures/entml_golden.py +104 -0
- echotools-2.3.103/src/tests/fixtures/entml_golden_update.py +24 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_entml_bare_invoke_format.py +1 -1
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_entml_batch_stream_comprehensive.py +13 -2
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_entml_fake_structure_markup.py +2 -2
- echotools-2.3.103/src/tests/test_entml_golden.py +44 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_entml_protocol.py +7 -4
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_entml_tool_pipeline.py +1 -1
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_printstream.py +3 -3
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_stream_partial_json_parity.py +11 -5
- echotools-2.3.103/src/tests/test_ui_bridge.py +62 -0
- echotools-2.3.100/src/echotools/exec/fncall/protocols/entml.py +0 -408
- echotools-2.3.100/src/echotools/exec/fncall/protocols/entml_patterns.py +0 -553
- echotools-2.3.100/src/echotools/exec/fncall/protocols/entml_schema.py +0 -493
- echotools-2.3.100/src/echotools/exec/fncall/protocols/entml_stream_json.py +0 -460
- echotools-2.3.100/src/echotools/exec/fncall/shared/xml_helpers.py +0 -56
- echotools-2.3.100/src/echotools/media/console/__init__.py +0 -38
- echotools-2.3.100/src/tests/_check_parity.py +0 -77
- {echotools-2.3.100 → echotools-2.3.103}/README.md +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/setup.cfg +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/__init__.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/base/cache/__init__.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/base/cache/list_cache.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/base/cache/memory_cache.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/base/config/__init__.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/base/config/base.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/base/config/center.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/base/config/center_notify.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/base/config/center_template.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/base/config/loader.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/base/config/merge.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/base/errors/__init__.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/base/errors/base.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/base/errors/classify.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/base/errors/common.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/base/errors/http.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/base/ids/__init__.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/base/ids/generator.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/base/io/__init__.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/base/io/io_utils.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/base/io/printstream.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/base/logger/__init__.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/base/logger/manager.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/base/retry/__init__.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/base/retry/retry.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/compat.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/dispatch/__init__.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/dispatch/candidate.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/dispatch/dispatcher.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/dispatch/proxy_selector.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/dispatch/race.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/dispatch/selector.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/dispatch/usage.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/fncall/__init__.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/fncall/parsers/__init__.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/fncall/parsers/stream.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/fncall/parsers/stream_delta.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/fncall/parsers/stream_feed.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/fncall/parsers/stream_final.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/fncall/parsers/xml_params.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/fncall/prompt/__init__.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/fncall/prompt/history_format.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/fncall/prompt/inject.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/fncall/prompt/prompt_helpers.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/fncall/prompt/templates.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/fncall/protocols/__init__.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/fncall/protocols/entml_stream/__init__.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/fncall/protocols/entml_think/__init__.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/fncall/protocols/entml_think/core.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/fncall/protocols/entml_think/filter.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/fncall/protocols/entml_think/hist.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/fncall/protocols/entml_think/hold.py +0 -0
- /echotools-2.3.100/src/echotools/exec/fncall/protocols/entml_tool_result_comment.py → /echotools-2.3.103/src/echotools/exec/fncall/protocols/entml_tool/comment.py +0 -0
- /echotools-2.3.100/src/echotools/exec/fncall/protocols/entml_tools.py → /echotools-2.3.103/src/echotools/exec/fncall/protocols/entml_tool/tools.py +0 -0
- /echotools-2.3.100/src/echotools/exec/fncall/protocols/entml_values.py → /echotools-2.3.103/src/echotools/exec/fncall/protocols/entml_tool/values.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/fncall/registry.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/fncall/shared/__init__.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/fncall/shared/coercion.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/fncall/shared/normalization.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/fncall/shared/schema_render.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/keys.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/lifecycle/__init__.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/lifecycle/manager.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/lifecycle/updater.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/lifecycle/updater_pull.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/process/__init__.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/process/port.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/protocol/__init__.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/protocol/base.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/terminal/__init__.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/terminal/conpty.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/terminal/local/__init__.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/terminal/local/core.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/terminal/local/proc.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/terminal/local/unix.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/terminal/local/win.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/terminal/sanitize.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/terminal/session/__init__.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/terminal/session/base.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/terminal/session/client.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/terminal/ssh.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/exec/terminal/tmux.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/console/charmap.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/console/spinner.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/console/ui.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/console/uicore/mixins/__init__.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/console/uicore/mixins/uibase.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/console/uicore/mixins/uicmds.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/console/uicore/mixins/uiinteract.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/console/uicore/mixins/uioutput.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/console/uicore/mixins/uistream.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/console/uicore/ui_console.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/console/uicore/ui_io.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/console/uicore/ui_log.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/console/uicore/ui_platform.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/console/uicore/ui_types.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/console/uilayout/ui_countdown.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/console/uilayout/ui_layout.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/console/uilayout/ui_misc.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/console/uilayout/ui_panel.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/console/uilayout/ui_table.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/console/uilayout/ui_tree.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/console/uiwidgets/ui_box.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/console/uiwidgets/ui_editor.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/console/uiwidgets/ui_progress.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/console/uiwidgets/ui_select.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/console/uiwidgets/ui_stream.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/events/__init__.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/events/bus.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/events/event.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/spinner/__init__.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/spinner/spinner.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/spinner/spinner_color.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/tracing/__init__.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/tracing/context.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/tracing/span.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/tracing/tracer.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/translate.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/watcher/__init__.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/watcher/file_watcher.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/web/__init__.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/web/application.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/web/broker.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/web/input_box/app.js +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/web/input_box/components/filezone.js +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/web/input_box/components/motionkit.js +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/web/input_box/components/sendbutton.js +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/web/input_box/components/sortablelist.css +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/web/input_box/components/sortablelist.js +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/web/input_box/components/textinput.js +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/web/input_box/components/voiceinput.js +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/web/input_box/fonts/inter-500.woff2 +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/web/input_box/fonts/inter-600.woff2 +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/web/input_box/fonts/inter400.woff2 +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/web/input_box/inputbox.css +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/web/input_box/inputbox.js +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/web/input_box/style.css +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/web/input_box/voicegif.js +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/web/middleware.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/web/stats.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/media/web/utils.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/plat/files/__init__.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/plat/files/file_util.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/plat/network/__init__.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/plat/network/http_utils.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/plat/plugin/__init__.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/plat/plugin/base.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/plat/plugin/discovery.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/plat/plugin/registry.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/plat/plugin/registry_ops.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/plat/proxy/__init__.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/plat/proxy/manager.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/plat/runtime/__init__.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/plat/runtime/collector.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/plat/scheduler/__init__.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/plat/scheduler/scheduler.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/plat/sdk/__init__.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/plat/sdk/facade.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools/version.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools.egg-info/dependency_links.txt +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools.egg-info/requires.txt +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/echotools.egg-info/top_level.txt +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/bench_import.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/conftest.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/fixtures/__init__.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/fixtures/simulated_fake_history_markup_responses.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/fixtures/simulated_fault_thinking_responses.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/fixtures/simulated_llm_tool_responses.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_adversarial_stream_splits.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_cache_retry.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_completion.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_config.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_config_extended.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_console.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_coverage_core.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_dispatch.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_dispatch_extended.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_dispatch_race.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_entml_agent_output_formats.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_entml_invoke_known_tool_gate.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_entml_parser_comprehensive.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_entml_stream_json.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_entml_stream_json_exhaustive.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_entml_thinking_history.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_entml_thinking_parse.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_entml_tool_parse_leak.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_entml_tools.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_errors.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_errors_common.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_events.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_events_event.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_facade.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_fake_history_markup_batch.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_fake_history_markup_invoke_preserve.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_fake_history_markup_reply_protect.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_fake_history_markup_stream.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_fault_thinking_close_batch.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_fault_thinking_close_stream.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_fncall.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_fncall_stream_thinking.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_history_markup_filter.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_ids.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_imports.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_io.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_keys.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_lifecycle.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_logger.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_merge.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_model_branch_matrix.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_plugin.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_protocols.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_proxy.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_proxy_selector.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_runtime.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_scheduler.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_simulated_llm_tool_parse.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_stream_realtime_parse.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_tracing.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_usage.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_web.py +0 -0
- {echotools-2.3.100 → echotools-2.3.103}/src/tests/test_web_broker.py +0 -0
|
@@ -17,7 +17,7 @@ from echotools.exec.fncall.shared.coercion import (
|
|
|
17
17
|
_coerce_param_value,
|
|
18
18
|
)
|
|
19
19
|
from echotools.exec.fncall.shared.normalization import normalize_tool_calls
|
|
20
|
-
from echotools.exec.fncall.shared.
|
|
20
|
+
from echotools.exec.fncall.shared.loop_detect import (
|
|
21
21
|
_PROVIDER_BLOCK_RE,
|
|
22
22
|
_PROVIDER_INVOKE_RE,
|
|
23
23
|
_PROVIDER_PARAM_RE,
|
|
@@ -40,7 +40,7 @@ You think before answering even when the request appears trivial. When a request
|
|
|
40
40
|
|
|
41
41
|
Depth scales with the request. Routine requests receive a short block. Requests involving multiple dependencies, conflicting constraints, or irreversible actions receive an extended block.
|
|
42
42
|
|
|
43
|
-
Your default reply language to the user is Simplified Chinese. You switch languages only when the user explicitly requests a different language.
|
|
43
|
+
Your default reply language to the user is Simplified Chinese. You switch languages only when the user explicitly requests a different language.
|
|
44
44
|
|
|
45
45
|
IMPORTANT: The thinking block is the first structural element of your output, and a tool invocation never appears inside it."""
|
|
46
46
|
|
|
@@ -83,7 +83,7 @@ def _clean_entml_tags(content: str) -> str:
|
|
|
83
83
|
# ---------------------------------------------------------------------------
|
|
84
84
|
|
|
85
85
|
|
|
86
|
-
from echotools.exec.fncall.protocols.
|
|
86
|
+
from echotools.exec.fncall.protocols.entml_tool.invoke import format_entml_parameter_value
|
|
87
87
|
|
|
88
88
|
|
|
89
89
|
def _render_parameter_value(v: Any) -> str:
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
"""Entropy ML (entml) 协议实现。
|
|
2
|
+
|
|
3
|
+
- 工具调用:<entml:invoke> / <entml:parameter>(legacy ``function_calls`` 外壳仅解析兼容)
|
|
4
|
+
- 对话历史:<entml:conversation_history>
|
|
5
|
+
- 当前用户消息:<current_user_message>
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from typing import Any, Dict, List, Optional, Tuple
|
|
11
|
+
|
|
12
|
+
from echotools.exec.fncall.protocols.entml_patterns import (
|
|
13
|
+
entml_invoke_open_may_be_streaming,
|
|
14
|
+
find_actionable_entml_invoke_open,
|
|
15
|
+
resolve_known_tool_names,
|
|
16
|
+
strip_actionable_entml_invoke_blocks,
|
|
17
|
+
strip_legacy_function_calls_wrapper,
|
|
18
|
+
strip_tool_entml_residue,
|
|
19
|
+
)
|
|
20
|
+
from echotools.exec.fncall.protocols.entml_schema import format_entml_tool_descs
|
|
21
|
+
from echotools.exec.fncall.protocols.entml_tool.fakemarkup import strip_orphan_entml_close_tags
|
|
22
|
+
from echotools.exec.fncall.protocols.entml_tool.invoke import (
|
|
23
|
+
format_entml_tool_calls,
|
|
24
|
+
parse_entml_tool_calls,
|
|
25
|
+
)
|
|
26
|
+
from echotools.exec.fncall.shared.coercion import _build_param_schema_index
|
|
27
|
+
from echotools.exec.fncall.shared.entml_format import (
|
|
28
|
+
_parse_tool_call_args,
|
|
29
|
+
_render_tool_call_line,
|
|
30
|
+
_render_tool_history_block,
|
|
31
|
+
build_entml_render_prompt,
|
|
32
|
+
format_entml_conversation_history,
|
|
33
|
+
format_entml_current_user_message,
|
|
34
|
+
format_entml_functions_results,
|
|
35
|
+
format_tool_result_id_comment,
|
|
36
|
+
strip_entml_from_content,
|
|
37
|
+
)
|
|
38
|
+
from echotools.exec.fncall.shared.history_markup import strip_fake_history_markup
|
|
39
|
+
from echotools.exec.fncall.shared.normalization import normalize_tool_calls
|
|
40
|
+
from echotools.exec.protocol.base import ToolProtocol
|
|
41
|
+
|
|
42
|
+
__all__ = [
|
|
43
|
+
"EntmlProtocol",
|
|
44
|
+
"format_entml_conversation_history",
|
|
45
|
+
"format_entml_current_user_message",
|
|
46
|
+
"format_entml_functions_results",
|
|
47
|
+
"format_tool_result_id_comment",
|
|
48
|
+
"strip_entml_from_content",
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class EntmlProtocol(ToolProtocol):
|
|
53
|
+
"""Entropy ML (entml) 格式工具调用协议适配器。"""
|
|
54
|
+
|
|
55
|
+
@property
|
|
56
|
+
def id(self) -> str:
|
|
57
|
+
return "entml"
|
|
58
|
+
|
|
59
|
+
_TRIGGER = "<entml:invoke>"
|
|
60
|
+
_TRIGGER_PREFIX = "<entml:invoke"
|
|
61
|
+
_LEGACY_WRAPPER_PREFIX = "<entml:function_calls"
|
|
62
|
+
_THINKING_PREFIX = "<entml:thinking"
|
|
63
|
+
|
|
64
|
+
def get_trigger_tags(self) -> List[str]:
|
|
65
|
+
return [
|
|
66
|
+
self._TRIGGER,
|
|
67
|
+
self._TRIGGER_PREFIX,
|
|
68
|
+
self._THINKING_PREFIX,
|
|
69
|
+
f"{self._THINKING_PREFIX}>",
|
|
70
|
+
]
|
|
71
|
+
|
|
72
|
+
def normalize_stream_buffer(self, buffer: str) -> str:
|
|
73
|
+
return strip_legacy_function_calls_wrapper(buffer)
|
|
74
|
+
|
|
75
|
+
def get_stream_end_tags(self) -> List[str]:
|
|
76
|
+
return []
|
|
77
|
+
|
|
78
|
+
@staticmethod
|
|
79
|
+
def format_tool_descs(tools: List[Dict[str, Any]]) -> str:
|
|
80
|
+
return format_entml_tool_descs(tools)
|
|
81
|
+
|
|
82
|
+
def render_prompt(
|
|
83
|
+
self,
|
|
84
|
+
tool_descs: str,
|
|
85
|
+
lang: str,
|
|
86
|
+
user_system_prompt: str = "",
|
|
87
|
+
history_text: str = "",
|
|
88
|
+
loop_warning: str = "",
|
|
89
|
+
history_markup_warning: str = "",
|
|
90
|
+
current_user_message: Optional[str] = None,
|
|
91
|
+
protocol_options: Optional[Dict[str, Any]] = None,
|
|
92
|
+
history_has_tool_calls: bool = False,
|
|
93
|
+
functions_results_text: str = "",
|
|
94
|
+
) -> str:
|
|
95
|
+
_ = (lang, history_has_tool_calls)
|
|
96
|
+
return build_entml_render_prompt(
|
|
97
|
+
tool_descs=tool_descs,
|
|
98
|
+
user_system_prompt=user_system_prompt,
|
|
99
|
+
history_text=history_text,
|
|
100
|
+
loop_warning=loop_warning,
|
|
101
|
+
history_markup_warning=history_markup_warning,
|
|
102
|
+
current_user_message=current_user_message,
|
|
103
|
+
protocol_options=protocol_options,
|
|
104
|
+
functions_results_text=functions_results_text,
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
def detect_start(
|
|
108
|
+
self,
|
|
109
|
+
buffer: str,
|
|
110
|
+
tools: Optional[List[Dict[str, Any]]] = None,
|
|
111
|
+
) -> Tuple[bool, int]:
|
|
112
|
+
schema_index = _build_param_schema_index(tools) if tools else None
|
|
113
|
+
known = resolve_known_tool_names(tools, schema_index)
|
|
114
|
+
invoke_pos = find_actionable_entml_invoke_open(buffer, known_names=known)
|
|
115
|
+
if invoke_pos < 0:
|
|
116
|
+
return (False, -1)
|
|
117
|
+
return (True, invoke_pos)
|
|
118
|
+
|
|
119
|
+
def find_fncall_hold_from(
|
|
120
|
+
self,
|
|
121
|
+
buffer: str,
|
|
122
|
+
tools: Optional[List[Dict[str, Any]]] = None,
|
|
123
|
+
) -> Optional[int]:
|
|
124
|
+
schema_index = _build_param_schema_index(tools) if tools else None
|
|
125
|
+
known = resolve_known_tool_names(tools, schema_index)
|
|
126
|
+
if find_actionable_entml_invoke_open(buffer, known_names=known) >= 0:
|
|
127
|
+
return None
|
|
128
|
+
hold: Optional[int] = None
|
|
129
|
+
legacy_pos = buffer.find(self._LEGACY_WRAPPER_PREFIX)
|
|
130
|
+
if legacy_pos >= 0:
|
|
131
|
+
close = buffer.find(">", legacy_pos)
|
|
132
|
+
if close < 0 and (hold is None or legacy_pos < hold):
|
|
133
|
+
hold = legacy_pos
|
|
134
|
+
invoke_pos = buffer.find(self._TRIGGER_PREFIX)
|
|
135
|
+
if (
|
|
136
|
+
invoke_pos >= 0
|
|
137
|
+
and entml_invoke_open_may_be_streaming(
|
|
138
|
+
buffer, invoke_pos, known_names=known
|
|
139
|
+
)
|
|
140
|
+
and (hold is None or invoke_pos < hold)
|
|
141
|
+
):
|
|
142
|
+
hold = invoke_pos
|
|
143
|
+
return hold
|
|
144
|
+
|
|
145
|
+
def _find_complete_invoke_open(
|
|
146
|
+
self,
|
|
147
|
+
buffer: str,
|
|
148
|
+
tools: Optional[List[Dict[str, Any]]] = None,
|
|
149
|
+
) -> int:
|
|
150
|
+
schema_index = _build_param_schema_index(tools) if tools else None
|
|
151
|
+
known = resolve_known_tool_names(tools, schema_index)
|
|
152
|
+
return find_actionable_entml_invoke_open(buffer, known_names=known)
|
|
153
|
+
|
|
154
|
+
def parse(
|
|
155
|
+
self,
|
|
156
|
+
text: str,
|
|
157
|
+
tools: Optional[List[Dict[str, Any]]] = None,
|
|
158
|
+
*,
|
|
159
|
+
include_tool_blocks: bool = True,
|
|
160
|
+
thinking_enabled: bool = True,
|
|
161
|
+
) -> Tuple[str, List[Dict[str, Any]]]:
|
|
162
|
+
_ = include_tool_blocks
|
|
163
|
+
from echotools.exec.fncall.protocols.entml_think.parse import (
|
|
164
|
+
_find_earliest_thinking_open,
|
|
165
|
+
has_unclosed_entml_thinking,
|
|
166
|
+
split_entml_thinking,
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
schema_index = _build_param_schema_index(tools) if tools else None
|
|
170
|
+
parse_text, _thinking = split_entml_thinking(text, thinking_enabled=True)
|
|
171
|
+
unclosed_open_at = -1
|
|
172
|
+
if has_unclosed_entml_thinking(text, thinking_enabled=True):
|
|
173
|
+
unclosed_open_at, _ = _find_earliest_thinking_open(
|
|
174
|
+
text, thinking_enabled=True
|
|
175
|
+
)
|
|
176
|
+
if unclosed_open_at >= 0:
|
|
177
|
+
parse_text = text[:unclosed_open_at]
|
|
178
|
+
known = resolve_known_tool_names(tools, schema_index)
|
|
179
|
+
tool_calls = parse_entml_tool_calls(parse_text, tools, schema_index)
|
|
180
|
+
clean = text[:unclosed_open_at] if unclosed_open_at >= 0 else text
|
|
181
|
+
if thinking_enabled:
|
|
182
|
+
visible, _ = split_entml_thinking(clean, thinking_enabled=True)
|
|
183
|
+
clean = visible
|
|
184
|
+
clean, _ = strip_fake_history_markup(clean)
|
|
185
|
+
if tool_calls:
|
|
186
|
+
clean = strip_actionable_entml_invoke_blocks(clean, known_names=known)
|
|
187
|
+
clean = strip_tool_entml_residue(clean, known_names=known)
|
|
188
|
+
clean, _ = strip_orphan_entml_close_tags(clean)
|
|
189
|
+
return (clean, normalize_tool_calls(tool_calls, tools))
|
|
190
|
+
|
|
191
|
+
def parse_fragment(
|
|
192
|
+
self,
|
|
193
|
+
fragment: str,
|
|
194
|
+
tools: Optional[List[Dict[str, Any]]] = None,
|
|
195
|
+
) -> List[Dict[str, Any]]:
|
|
196
|
+
_, tool_calls = self.parse(fragment, tools)
|
|
197
|
+
return tool_calls
|
|
198
|
+
|
|
199
|
+
def clean_tags(self, content: str) -> str:
|
|
200
|
+
return strip_entml_from_content(content)
|
|
201
|
+
|
|
202
|
+
def clean_tool_tags(
|
|
203
|
+
self,
|
|
204
|
+
content: str,
|
|
205
|
+
tools: Optional[List[Dict[str, Any]]] = None,
|
|
206
|
+
) -> str:
|
|
207
|
+
schema_index = _build_param_schema_index(tools) if tools else None
|
|
208
|
+
known = resolve_known_tool_names(tools, schema_index)
|
|
209
|
+
cleaned = strip_tool_entml_residue(content, known_names=known)
|
|
210
|
+
cleaned, _ = strip_fake_history_markup(cleaned)
|
|
211
|
+
return cleaned
|
|
212
|
+
|
|
213
|
+
def format_assistant_tool_calls(
|
|
214
|
+
self,
|
|
215
|
+
tool_calls: List[Dict[str, Any]],
|
|
216
|
+
) -> str:
|
|
217
|
+
lines: List[str] = []
|
|
218
|
+
for tc in tool_calls:
|
|
219
|
+
name, args = _parse_tool_call_args(tc)
|
|
220
|
+
lines.append(_render_tool_call_line(name, args))
|
|
221
|
+
return "\n".join(lines)
|
|
222
|
+
|
|
223
|
+
def format_assistant_tool_turn_block(
|
|
224
|
+
self,
|
|
225
|
+
tool_calls: List[Dict[str, Any]],
|
|
226
|
+
tid_to_result: Dict[str, Dict[str, Any]],
|
|
227
|
+
) -> str:
|
|
228
|
+
_ = tid_to_result
|
|
229
|
+
lines: List[str] = []
|
|
230
|
+
for tc in tool_calls:
|
|
231
|
+
invoke = format_entml_tool_calls([tc])
|
|
232
|
+
if invoke:
|
|
233
|
+
lines.append(invoke)
|
|
234
|
+
tid = tc.get("id") or ""
|
|
235
|
+
comment = format_tool_result_id_comment(tid)
|
|
236
|
+
if comment:
|
|
237
|
+
lines.append(comment)
|
|
238
|
+
return "\n".join(lines)
|
|
239
|
+
|
|
240
|
+
def supports_streaming(self) -> bool:
|
|
241
|
+
return True
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""Regex patterns and helpers for entml invoke/parameter parsing."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from ..entml_schema.mangled import (
|
|
5
|
+
mangled_json_param_tail_in_progress,
|
|
6
|
+
split_mangled_json_param_tail,
|
|
7
|
+
)
|
|
8
|
+
from .invoke import (
|
|
9
|
+
entml_invoke_open_is_actionable,
|
|
10
|
+
entml_invoke_open_may_be_streaming,
|
|
11
|
+
find_actionable_entml_invoke_open,
|
|
12
|
+
is_placeholder_invoke_name,
|
|
13
|
+
iter_actionable_entml_invoke_blocks,
|
|
14
|
+
resolve_known_tool_names,
|
|
15
|
+
)
|
|
16
|
+
from .params import (
|
|
17
|
+
extract_attr_value,
|
|
18
|
+
extract_parameter_type_attr,
|
|
19
|
+
find_valid_parameter_close,
|
|
20
|
+
inside_parameter_value,
|
|
21
|
+
invoke_structural_gap_text,
|
|
22
|
+
invoke_structural_gaps,
|
|
23
|
+
normalize_entml_name,
|
|
24
|
+
parameter_block_spans,
|
|
25
|
+
parameter_close_at,
|
|
26
|
+
parameter_value_spans,
|
|
27
|
+
parse_sub_tags,
|
|
28
|
+
strip_actionable_entml_invoke_blocks,
|
|
29
|
+
synthetic_close_invoke_body,
|
|
30
|
+
)
|
|
31
|
+
from .regex import (
|
|
32
|
+
BARE_INVOKE_CHILD_OPEN_RE,
|
|
33
|
+
BARE_INVOKE_CHILD_RE,
|
|
34
|
+
BLOCK_RE,
|
|
35
|
+
INVOKE_DIRECT_CHILD_OPEN_RE,
|
|
36
|
+
INVOKE_DIRECT_CHILD_RE,
|
|
37
|
+
INVOKE_DIRECT_CHILD_SKIP,
|
|
38
|
+
INVOKE_RE,
|
|
39
|
+
PARAM_CLOSE_BARE,
|
|
40
|
+
PARAM_CLOSE_ENTML,
|
|
41
|
+
PARAM_OPEN_PATTERN,
|
|
42
|
+
PARAM_RE,
|
|
43
|
+
PARAMETERS_RE,
|
|
44
|
+
SUB_TAG_RE,
|
|
45
|
+
_INVOKE_CLOSE,
|
|
46
|
+
_INVOKE_OPEN_PREFIX,
|
|
47
|
+
_PARAM_CLOSE_VALID_RE,
|
|
48
|
+
_PARAM_CLOSE_VALID_STREAM_RE,
|
|
49
|
+
)
|
|
50
|
+
from .strip import strip_legacy_function_calls_wrapper, strip_tool_entml_residue
|
|
51
|
+
|
|
52
|
+
__all__ = [
|
|
53
|
+
"BARE_INVOKE_CHILD_OPEN_RE",
|
|
54
|
+
"BARE_INVOKE_CHILD_RE",
|
|
55
|
+
"BLOCK_RE",
|
|
56
|
+
"INVOKE_DIRECT_CHILD_OPEN_RE",
|
|
57
|
+
"INVOKE_DIRECT_CHILD_RE",
|
|
58
|
+
"INVOKE_DIRECT_CHILD_SKIP",
|
|
59
|
+
"INVOKE_RE",
|
|
60
|
+
"PARAM_CLOSE_BARE",
|
|
61
|
+
"PARAM_CLOSE_ENTML",
|
|
62
|
+
"PARAM_OPEN_PATTERN",
|
|
63
|
+
"PARAM_RE",
|
|
64
|
+
"PARAMETERS_RE",
|
|
65
|
+
"SUB_TAG_RE",
|
|
66
|
+
"_INVOKE_CLOSE",
|
|
67
|
+
"_INVOKE_OPEN_PREFIX",
|
|
68
|
+
"_PARAM_CLOSE_VALID_RE",
|
|
69
|
+
"_PARAM_CLOSE_VALID_STREAM_RE",
|
|
70
|
+
"entml_invoke_open_is_actionable",
|
|
71
|
+
"entml_invoke_open_may_be_streaming",
|
|
72
|
+
"extract_attr_value",
|
|
73
|
+
"extract_parameter_type_attr",
|
|
74
|
+
"find_actionable_entml_invoke_open",
|
|
75
|
+
"find_valid_parameter_close",
|
|
76
|
+
"inside_parameter_value",
|
|
77
|
+
"invoke_structural_gap_text",
|
|
78
|
+
"invoke_structural_gaps",
|
|
79
|
+
"is_placeholder_invoke_name",
|
|
80
|
+
"iter_actionable_entml_invoke_blocks",
|
|
81
|
+
"mangled_json_param_tail_in_progress",
|
|
82
|
+
"normalize_entml_name",
|
|
83
|
+
"parameter_block_spans",
|
|
84
|
+
"parameter_close_at",
|
|
85
|
+
"parameter_value_spans",
|
|
86
|
+
"parse_sub_tags",
|
|
87
|
+
"resolve_known_tool_names",
|
|
88
|
+
"split_mangled_json_param_tail",
|
|
89
|
+
"strip_actionable_entml_invoke_blocks",
|
|
90
|
+
"strip_legacy_function_calls_wrapper",
|
|
91
|
+
"strip_tool_entml_residue",
|
|
92
|
+
"synthetic_close_invoke_body",
|
|
93
|
+
]
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from typing import Any, Dict, Iterator, List, Optional, Set, Tuple
|
|
5
|
+
|
|
6
|
+
from .params import extract_attr_value, normalize_entml_name
|
|
7
|
+
from .regex import _INVOKE_CLOSE, _INVOKE_OPEN_PREFIX
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def is_placeholder_invoke_name(name: str) -> bool:
|
|
11
|
+
"""提示词占位符(如 ``$FUNCTION_NAME``)不算真实工具调用。"""
|
|
12
|
+
n = (name or "").strip()
|
|
13
|
+
return not n or "$" in n
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def resolve_known_tool_names(
|
|
17
|
+
tools: Optional[List[Dict[str, Any]]] = None,
|
|
18
|
+
schema_index: Optional[Dict[str, Dict[str, Dict[str, Any]]]] = None,
|
|
19
|
+
) -> Optional[Set[str]]:
|
|
20
|
+
"""从 tools / schema_index 解析已知工具名;无约束时返回 ``None``。"""
|
|
21
|
+
if schema_index:
|
|
22
|
+
return {normalize_entml_name(str(k)) for k in schema_index.keys()}
|
|
23
|
+
names: Set[str] = set()
|
|
24
|
+
for tool in tools or []:
|
|
25
|
+
fn = tool.get("function") or {}
|
|
26
|
+
name = fn.get("name")
|
|
27
|
+
if name:
|
|
28
|
+
names.add(normalize_entml_name(str(name)))
|
|
29
|
+
return names if names else None
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _name_is_known(name: str, known_names: Optional[Set[str]]) -> bool:
|
|
33
|
+
if known_names is None:
|
|
34
|
+
return True
|
|
35
|
+
if not known_names:
|
|
36
|
+
return False
|
|
37
|
+
return normalize_entml_name(name) in known_names
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def entml_invoke_open_is_actionable(
|
|
41
|
+
buffer: str,
|
|
42
|
+
pos: int,
|
|
43
|
+
*,
|
|
44
|
+
known_names: Optional[Set[str]] = None,
|
|
45
|
+
) -> bool:
|
|
46
|
+
"""``pos`` 处 ``<entml:invoke`` 是否为已闭合、含真实 name 且(若提供)在已知工具表内的开标签。"""
|
|
47
|
+
if pos < 0 or not buffer.startswith(_INVOKE_OPEN_PREFIX, pos):
|
|
48
|
+
return False
|
|
49
|
+
gt = buffer.find(">", pos + len(_INVOKE_OPEN_PREFIX))
|
|
50
|
+
if gt < 0:
|
|
51
|
+
return False
|
|
52
|
+
attrs = buffer[pos + len(_INVOKE_OPEN_PREFIX) : gt]
|
|
53
|
+
name = extract_attr_value(attrs, "name")
|
|
54
|
+
if not name:
|
|
55
|
+
return False
|
|
56
|
+
name = normalize_entml_name(name)
|
|
57
|
+
if not name or is_placeholder_invoke_name(name):
|
|
58
|
+
return False
|
|
59
|
+
return _name_is_known(name, known_names)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def entml_invoke_open_may_be_streaming(
|
|
63
|
+
buffer: str,
|
|
64
|
+
pos: int,
|
|
65
|
+
*,
|
|
66
|
+
known_names: Optional[Set[str]] = None,
|
|
67
|
+
) -> bool:
|
|
68
|
+
"""``pos`` 处 ``<entml:invoke`` 是否仍可能长成可解析工具开标签(非 prose 提及)。"""
|
|
69
|
+
if pos < 0 or not buffer.startswith(_INVOKE_OPEN_PREFIX, pos):
|
|
70
|
+
return False
|
|
71
|
+
gt = buffer.find(">", pos + len(_INVOKE_OPEN_PREFIX))
|
|
72
|
+
if gt < 0:
|
|
73
|
+
return True
|
|
74
|
+
return entml_invoke_open_is_actionable(buffer, pos, known_names=known_names)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def find_actionable_entml_invoke_open(
|
|
78
|
+
buffer: str,
|
|
79
|
+
*,
|
|
80
|
+
known_names: Optional[Set[str]] = None,
|
|
81
|
+
) -> int:
|
|
82
|
+
"""返回首个可解析 ``<entml:invoke`` 起始下标;否则 ``-1``。"""
|
|
83
|
+
if not buffer:
|
|
84
|
+
return -1
|
|
85
|
+
search_from = 0
|
|
86
|
+
prefix_len = len(_INVOKE_OPEN_PREFIX)
|
|
87
|
+
while search_from < len(buffer):
|
|
88
|
+
pos = buffer.find(_INVOKE_OPEN_PREFIX, search_from)
|
|
89
|
+
if pos < 0:
|
|
90
|
+
return -1
|
|
91
|
+
if entml_invoke_open_is_actionable(buffer, pos, known_names=known_names):
|
|
92
|
+
return pos
|
|
93
|
+
gt = buffer.find(">", pos + prefix_len)
|
|
94
|
+
search_from = (gt + 1) if gt >= 0 else (pos + prefix_len)
|
|
95
|
+
return -1
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _actionable_invoke_open_before_close(
|
|
99
|
+
content: str,
|
|
100
|
+
close_pos: int,
|
|
101
|
+
*,
|
|
102
|
+
known_names: Optional[Set[str]] = None,
|
|
103
|
+
) -> bool:
|
|
104
|
+
"""``close_pos`` 处的 ``</entml:invoke>`` 是否闭合带真实 name 的开标签。"""
|
|
105
|
+
search = close_pos - 1
|
|
106
|
+
while search >= 0:
|
|
107
|
+
pos = content.rfind(_INVOKE_OPEN_PREFIX, 0, search + 1)
|
|
108
|
+
if pos < 0:
|
|
109
|
+
return False
|
|
110
|
+
if entml_invoke_open_is_actionable(content, pos, known_names=known_names):
|
|
111
|
+
gt = content.find(">", pos)
|
|
112
|
+
if gt < 0 or gt >= close_pos:
|
|
113
|
+
search = pos - 1
|
|
114
|
+
continue
|
|
115
|
+
inner_close = content.find(_INVOKE_CLOSE, gt + 1, close_pos)
|
|
116
|
+
if inner_close < 0:
|
|
117
|
+
return True
|
|
118
|
+
search = pos - 1
|
|
119
|
+
continue
|
|
120
|
+
search = pos - 1
|
|
121
|
+
return False
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def _invoke_close_should_strip(
|
|
125
|
+
content: str,
|
|
126
|
+
close_pos: int,
|
|
127
|
+
*,
|
|
128
|
+
known_names: Optional[Set[str]] = None,
|
|
129
|
+
) -> bool:
|
|
130
|
+
"""是否应剥离 ``</entml:invoke>``(孤儿噪声或真实工具块残留)。"""
|
|
131
|
+
if _actionable_invoke_open_before_close(content, close_pos, known_names=known_names):
|
|
132
|
+
return True
|
|
133
|
+
open_pos = content.rfind(_INVOKE_OPEN_PREFIX, 0, close_pos)
|
|
134
|
+
if open_pos < 0:
|
|
135
|
+
return True
|
|
136
|
+
return entml_invoke_open_is_actionable(content, open_pos, known_names=known_names)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def iter_actionable_entml_invoke_blocks(
|
|
140
|
+
text: str,
|
|
141
|
+
*,
|
|
142
|
+
known_names: Optional[Set[str]] = None,
|
|
143
|
+
) -> Iterator[Tuple[int, int, str, str]]:
|
|
144
|
+
"""迭代含真实 ``name`` 的完整 ``<entml:invoke>…</entml:invoke>`` 块。"""
|
|
145
|
+
if not text:
|
|
146
|
+
return
|
|
147
|
+
search_from = 0
|
|
148
|
+
prefix_len = len(_INVOKE_OPEN_PREFIX)
|
|
149
|
+
close_len = len(_INVOKE_CLOSE)
|
|
150
|
+
while search_from < len(text):
|
|
151
|
+
pos = text.find(_INVOKE_OPEN_PREFIX, search_from)
|
|
152
|
+
if pos < 0:
|
|
153
|
+
break
|
|
154
|
+
if not entml_invoke_open_is_actionable(text, pos, known_names=known_names):
|
|
155
|
+
gt = text.find(">", pos + prefix_len)
|
|
156
|
+
search_from = (gt + 1) if gt >= 0 else (pos + prefix_len)
|
|
157
|
+
continue
|
|
158
|
+
gt = text.find(">", pos + prefix_len)
|
|
159
|
+
if gt < 0:
|
|
160
|
+
break
|
|
161
|
+
close = text.find(_INVOKE_CLOSE, gt + 1)
|
|
162
|
+
if close < 0:
|
|
163
|
+
break
|
|
164
|
+
attrs = text[pos + prefix_len : gt]
|
|
165
|
+
body = text[gt + 1 : close]
|
|
166
|
+
yield pos, close + close_len, attrs, body
|
|
167
|
+
search_from = close + close_len
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def _strip_orphan_invoke_tags(
|
|
171
|
+
content: str,
|
|
172
|
+
*,
|
|
173
|
+
known_names: Optional[Set[str]] = None,
|
|
174
|
+
) -> str:
|
|
175
|
+
"""仅剥离带真实 name 的 invoke 孤儿标签;保留 prose 中的 ``<entml:invoke>`` 提及。"""
|
|
176
|
+
pattern = re.compile(r"</?entml:invoke\b[^>]*/?>", re.DOTALL)
|
|
177
|
+
|
|
178
|
+
def repl(match: re.Match[str]) -> str:
|
|
179
|
+
tag = match.group(0)
|
|
180
|
+
if tag.startswith("</"):
|
|
181
|
+
if _invoke_close_should_strip(content, match.start(), known_names=known_names):
|
|
182
|
+
return ""
|
|
183
|
+
return tag
|
|
184
|
+
if entml_invoke_open_is_actionable(content, match.start(), known_names=known_names):
|
|
185
|
+
return ""
|
|
186
|
+
return tag
|
|
187
|
+
|
|
188
|
+
return pattern.sub(repl, content)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def _strip_orphan_non_invoke_tool_tags(content: str) -> str:
|
|
192
|
+
return re.sub(
|
|
193
|
+
r"</?entml:(?:function_calls|parameter|parameters)\b[^>]*/?>",
|
|
194
|
+
"",
|
|
195
|
+
content,
|
|
196
|
+
flags=re.DOTALL,
|
|
197
|
+
)
|