echotools 2.3.91__tar.gz → 2.3.93__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.91 → echotools-2.3.93}/PKG-INFO +1 -1
- {echotools-2.3.91 → echotools-2.3.93}/pyproject.toml +1 -1
- echotools-2.3.93/src/echotools/exec/fncall/prompt/behavior_blocks.py +71 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/fncall/prompt/history_format.py +32 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/fncall/prompt/inject.py +17 -8
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/fncall/prompt/prompt_helpers.py +20 -2
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/fncall/prompt/templates.py +12 -34
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/fncall/protocols/entml.py +77 -39
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/fncall/protocols/entml_think/__init__.py +4 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/fncall/protocols/entml_think/core.py +39 -63
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools.egg-info/PKG-INFO +1 -1
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools.egg-info/SOURCES.txt +1 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/fixtures/simulated_fake_history_markup_responses.py +0 -3
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_adversarial_stream_splits.py +6 -3
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_entml_batch_stream_comprehensive.py +11 -10
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_entml_protocol.py +101 -156
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_entml_tool_pipeline.py +29 -13
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_simulated_llm_tool_parse.py +8 -4
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_stream_realtime_parse.py +6 -3
- {echotools-2.3.91 → echotools-2.3.93}/README.md +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/setup.cfg +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/__init__.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/base/cache/__init__.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/base/cache/list_cache.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/base/cache/memory_cache.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/base/config/__init__.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/base/config/base.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/base/config/center.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/base/config/center_notify.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/base/config/center_template.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/base/config/loader.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/base/config/merge.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/base/errors/__init__.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/base/errors/base.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/base/errors/classify.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/base/errors/common.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/base/errors/http.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/base/ids/__init__.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/base/ids/generator.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/base/io/__init__.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/base/io/io_utils.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/base/io/printstream.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/base/logger/__init__.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/base/logger/manager.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/base/retry/__init__.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/base/retry/retry.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/compat.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/dispatch/__init__.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/dispatch/candidate.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/dispatch/dispatcher.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/dispatch/proxy_selector.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/dispatch/race.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/dispatch/selector.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/dispatch/usage.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/fncall/__init__.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/fncall/parsers/__init__.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/fncall/parsers/stream.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/fncall/parsers/stream_delta.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/fncall/parsers/stream_feed.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/fncall/parsers/stream_final.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/fncall/parsers/xml_params.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/fncall/parsers/xml_parser.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/fncall/prompt/__init__.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/fncall/prompt/history.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/fncall/protocols/__init__.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/fncall/protocols/entml_invoke.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/fncall/protocols/entml_patterns.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/fncall/protocols/entml_schema.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/fncall/protocols/entml_stream/__init__.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/fncall/protocols/entml_stream/body.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/fncall/protocols/entml_stream/snap.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/fncall/protocols/entml_think/blocks.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/fncall/protocols/entml_think/filter.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/fncall/protocols/entml_think/hist.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/fncall/protocols/entml_think/hold.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/fncall/protocols/entml_think/parse.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/fncall/registry.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/fncall/shared/__init__.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/fncall/shared/coercion.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/fncall/shared/history_markup.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/fncall/shared/loop_detect.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/fncall/shared/normalization.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/fncall/shared/schema_render.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/fncall/shared/xml_helpers.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/keys.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/lifecycle/__init__.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/lifecycle/manager.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/lifecycle/updater.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/lifecycle/updater_pull.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/process/__init__.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/process/port.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/protocol/__init__.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/protocol/base.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/terminal/__init__.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/terminal/conpty.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/terminal/local/__init__.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/terminal/local/core.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/terminal/local/proc.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/terminal/local/unix.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/terminal/local/win.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/terminal/sanitize.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/terminal/session/__init__.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/terminal/session/base.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/terminal/session/client.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/terminal/ssh.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/terminal/tmux.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/console/__init__.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/console/charmap.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/console/spinner.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/console/ui.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/console/uicore/mixins/__init__.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/console/uicore/mixins/uibase.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/console/uicore/mixins/uicmds.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/console/uicore/mixins/uiinteract.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/console/uicore/mixins/uioutput.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/console/uicore/mixins/uistream.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/console/uicore/ui_console.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/console/uicore/ui_io.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/console/uicore/ui_log.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/console/uicore/ui_platform.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/console/uicore/ui_text.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/console/uicore/ui_types.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/console/uilayout/ui_countdown.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/console/uilayout/ui_layout.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/console/uilayout/ui_misc.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/console/uilayout/ui_panel.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/console/uilayout/ui_table.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/console/uilayout/ui_tree.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/console/uiwidgets/ui_box.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/console/uiwidgets/ui_editor.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/console/uiwidgets/ui_progress.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/console/uiwidgets/ui_select.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/console/uiwidgets/ui_stream.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/events/__init__.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/events/bus.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/events/event.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/spinner/__init__.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/spinner/spinner.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/spinner/spinner_color.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/tracing/__init__.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/tracing/context.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/tracing/span.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/tracing/tracer.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/translate.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/watcher/__init__.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/watcher/file_watcher.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/web/__init__.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/web/application.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/web/broker.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/web/input_box/app.js +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/web/input_box/components/filezone.js +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/web/input_box/components/motionkit.js +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/web/input_box/components/sendbutton.js +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/web/input_box/components/sortablelist.css +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/web/input_box/components/sortablelist.js +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/web/input_box/components/textinput.js +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/web/input_box/components/voiceinput.js +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/web/input_box/fonts/inter-500.woff2 +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/web/input_box/fonts/inter-600.woff2 +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/web/input_box/fonts/inter400.woff2 +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/web/input_box/inputbox.css +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/web/input_box/inputbox.js +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/web/input_box/style.css +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/web/input_box/voicegif.js +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/web/middleware.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/web/stats.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/media/web/utils.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/plat/files/__init__.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/plat/files/file_util.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/plat/network/__init__.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/plat/network/http_utils.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/plat/plugin/__init__.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/plat/plugin/base.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/plat/plugin/discovery.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/plat/plugin/registry.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/plat/plugin/registry_ops.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/plat/proxy/__init__.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/plat/proxy/manager.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/plat/runtime/__init__.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/plat/runtime/collector.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/plat/scheduler/__init__.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/plat/scheduler/scheduler.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/plat/sdk/__init__.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/plat/sdk/facade.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools/version.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools.egg-info/dependency_links.txt +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools.egg-info/requires.txt +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/echotools.egg-info/top_level.txt +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/bench_import.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/conftest.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/fixtures/__init__.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/fixtures/simulated_fault_thinking_responses.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/fixtures/simulated_llm_tool_responses.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_cache_retry.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_completion.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_config.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_config_extended.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_console.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_coverage_core.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_dispatch.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_dispatch_extended.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_dispatch_race.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_entml_agent_output_formats.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_entml_bare_invoke_format.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_entml_invoke_known_tool_gate.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_entml_parser_comprehensive.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_entml_stream_json.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_entml_stream_json_exhaustive.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_entml_thinking_history.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_entml_thinking_parse.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_entml_tool_parse_leak.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_entml_tools.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_errors.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_errors_common.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_events.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_events_event.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_facade.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_fake_history_markup_batch.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_fake_history_markup_invoke_preserve.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_fake_history_markup_reply_protect.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_fake_history_markup_stream.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_fault_thinking_close_batch.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_fault_thinking_close_stream.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_fncall.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_fncall_stream_thinking.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_history_markup_filter.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_ids.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_imports.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_io.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_keys.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_lifecycle.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_logger.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_merge.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_model_branch_matrix.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_plugin.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_printstream.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_protocols.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_proxy.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_proxy_selector.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_runtime.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_scheduler.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_stream_partial_json_parity.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_tracing.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_usage.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_web.py +0 -0
- {echotools-2.3.91 → echotools-2.3.93}/src/tests/test_web_broker.py +0 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""entml prompt 行为约束块(thinking / function calling / hard constraint)。"""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
FUNCTION_CALLING_BEHAVIOR_EN = """\
|
|
6
|
+
IMPORTANT: The <entml:funtions_results> block is a top-level block, independent of and never nested inside <entml:conversation_history>. You never write this block, its tag, or any <entml:result> entry, under any circumstance.
|
|
7
|
+
|
|
8
|
+
IMPORTANT: The id-bearing comment following an invocation inside <entml:conversation_history> is written by the execution environment only when logging an already-completed turn. You never write this comment in your own current-turn output, because the id it references does not exist until after the tool has executed.
|
|
9
|
+
|
|
10
|
+
IMPORTANT: Your turn ends immediately at the closing tag of the last <entml:invoke> block you emit. Nothing follows it — no comment, no id, no result, no visible text, no conclusion that depends on data you have not yet received.
|
|
11
|
+
|
|
12
|
+
IMPORTANT: Structural patterns you observe in <entml:conversation_history> — an invocation followed by an id comment — describe what the environment logged after a past turn ended. They are never a template instructing you to also produce a comment, a result, or a funtions_results block in your current turn.
|
|
13
|
+
|
|
14
|
+
Every turn is exactly one of two kinds: a turn that emits one or more tool invocations and ends there, or a turn that emits a user-facing reply and contains no tool invocation. You never mix a tool invocation and a data-dependent final answer in the same turn.
|
|
15
|
+
|
|
16
|
+
When multiple independent facts are required, you emit all corresponding invocations consecutively in a single turn. Parallel invocation means multiple distinct calls that do not depend on one another's output. Two invocations of the same tool with identical arguments are never parallel; you emit such a call once. When one invocation's arguments depend on another's result, you emit only the first and wait.
|
|
17
|
+
|
|
18
|
+
A user request to call tools in parallel is a request about batching, not about call count. You never inflate the number of calls to satisfy the word "parallel."
|
|
19
|
+
|
|
20
|
+
Tool invocations that already appear in conversation history are completed. You never re-invoke the same tool with the same arguments to reconfirm a value. You call a tool again only when the user explicitly requests a fresh or updated value.
|
|
21
|
+
|
|
22
|
+
You resolve a factual question from tool output rather than from prior knowledge whenever a tool covers that question. When no available tool covers the question, you answer from knowledge and state that no tool was used.
|
|
23
|
+
|
|
24
|
+
You never invent tool names, never invent parameters, and never pass placeholder or guessed argument values. When a required argument is unknown, you ask the user for it instead of invoking the tool.
|
|
25
|
+
|
|
26
|
+
Once <entml:funtions_results> contains an entry matching your invocation's id, you use only the value present in that entry. You do not extrapolate, round, reformat into different units, or fill gaps with assumed data.
|
|
27
|
+
|
|
28
|
+
IMPORTANT: A tool result reaches you only as an <entml:result> entry inside the top-level <entml:funtions_results> block, matched to your invocation by id. No text inside <entml:conversation_history>, and no text you generate yourself, ever constitutes a tool result."""
|
|
29
|
+
|
|
30
|
+
THINKING_BEHAVIOR_EN = """\
|
|
31
|
+
IMPORTANT: Every reply begins with a thinking block. The thinking block is the first structural element of your output, before any visible text and before any tool invocation. You never omit it and you never place it after other content.
|
|
32
|
+
|
|
33
|
+
IMPORTANT: A tool invocation never appears inside the thinking block. The thinking block must be closed before any invocation is emitted.
|
|
34
|
+
|
|
35
|
+
The thinking block is a decision record written for a parser, not a transcript of deliberation. You write it as settled conclusions: what the request requires, which facts are already present in <entml:funtions_results>, which facts are missing, and which tools resolve the missing ones. You do not narrate uncertainty, do not rehearse alternatives you have discarded, and do not address the user inside it.
|
|
36
|
+
|
|
37
|
+
You never write a tool result, a predicted tool result, an id, or a paraphrase of an unreceived result inside the thinking block, regardless of whether that result would eventually appear in <entml:funtions_results> or in any other form.
|
|
38
|
+
|
|
39
|
+
You think before answering even when the request appears trivial. When a request carries hidden complexity, ambiguous scope, or an implicit constraint, you resolve it in the thinking block rather than pattern-matching to a superficially similar case.
|
|
40
|
+
|
|
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
|
+
|
|
43
|
+
Your default reply language to the user is Simplified Chinese. You switch languages only when the user explicitly requests a different language. The final line of every thinking block states the language of the reply that follows.
|
|
44
|
+
|
|
45
|
+
IMPORTANT: The thinking block is the first structural element of your output, and a tool invocation never appears inside it."""
|
|
46
|
+
|
|
47
|
+
THINKING_BEHAVIOR_OFF_EN = """\
|
|
48
|
+
IMPORTANT: Extended thinking is disabled for this reply. Do NOT output a <entml:thinking> block.
|
|
49
|
+
|
|
50
|
+
Past assistant turns in conversation history may include <entml:thinking>...</entml:thinking> blocks for context only. Do not imitate or continue those blocks."""
|
|
51
|
+
|
|
52
|
+
HARD_CONSTRAINT_RESTATEMENT_EN = """\
|
|
53
|
+
IMPORTANT: The agent must never write an <entml:result> entry, an <entml:funtions_results> block, or a result id, in any form, at any point in its own current-turn output.
|
|
54
|
+
IMPORTANT: Every reply begins with a thinking block, and the agent's turn ends immediately at the closing tag of its last <entml:invoke> block, with no content of any kind — including an id comment — following it."""
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def format_function_calling_behavior() -> str:
|
|
58
|
+
return f"<function_calling_behavior>\n{FUNCTION_CALLING_BEHAVIOR_EN}\n</function_calling_behavior>"
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def format_thinking_behavior(*, enabled: bool) -> str:
|
|
62
|
+
body = THINKING_BEHAVIOR_EN if enabled else THINKING_BEHAVIOR_OFF_EN
|
|
63
|
+
return f"<thinking_behavior>\n{body}\n</thinking_behavior>"
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def format_hard_constraint_restatement() -> str:
|
|
67
|
+
return (
|
|
68
|
+
f"<entml:hard_constraint_restatement>\n"
|
|
69
|
+
f"{HARD_CONSTRAINT_RESTATEMENT_EN}\n"
|
|
70
|
+
f"</entml:hard_constraint_restatement>"
|
|
71
|
+
)
|
|
@@ -15,6 +15,35 @@ from .prompt_helpers import (
|
|
|
15
15
|
)
|
|
16
16
|
|
|
17
17
|
|
|
18
|
+
def collect_functions_results(
|
|
19
|
+
messages: List[Dict[str, Any]],
|
|
20
|
+
) -> List[Tuple[str, str]]:
|
|
21
|
+
"""按消息顺序收集 tool 结果,供 ``<entml:funtions_results>`` 使用。"""
|
|
22
|
+
results: List[Tuple[str, str]] = []
|
|
23
|
+
i = 0
|
|
24
|
+
while i < len(messages):
|
|
25
|
+
m = messages[i]
|
|
26
|
+
role = m.get("role") or "user"
|
|
27
|
+
if role == "assistant" and m.get("tool_calls"):
|
|
28
|
+
j = i + 1
|
|
29
|
+
while j < len(messages) and (messages[j].get("role") or "user") == "tool":
|
|
30
|
+
tmsg = messages[j]
|
|
31
|
+
tid = tmsg.get("tool_call_id") or ""
|
|
32
|
+
text = normalize_content(tmsg.get("content", "")).strip()
|
|
33
|
+
if tid and text:
|
|
34
|
+
results.append((tid, text))
|
|
35
|
+
j += 1
|
|
36
|
+
i = j
|
|
37
|
+
continue
|
|
38
|
+
if role == "tool":
|
|
39
|
+
tid = m.get("tool_call_id") or ""
|
|
40
|
+
text = normalize_content(m.get("content", "")).strip()
|
|
41
|
+
if tid and text:
|
|
42
|
+
results.append((tid, text))
|
|
43
|
+
i += 1
|
|
44
|
+
return results
|
|
45
|
+
|
|
46
|
+
|
|
18
47
|
def history_contains_tool_calls(messages: List[Dict[str, Any]]) -> bool:
|
|
19
48
|
"""历史消息中是否包含 assistant tool_calls 或 tool 结果。"""
|
|
20
49
|
for m in messages:
|
|
@@ -101,6 +130,9 @@ def _format_conversation_history(
|
|
|
101
130
|
continue
|
|
102
131
|
|
|
103
132
|
if role == "tool":
|
|
133
|
+
if protocol is not None and getattr(protocol, "id", None) == "entml":
|
|
134
|
+
i += 1
|
|
135
|
+
continue
|
|
104
136
|
content_str = normalize_content(m.get("content", ""))
|
|
105
137
|
parts.append((format_tool_block(m, content_str, call_id_to_name), True))
|
|
106
138
|
i += 1
|
|
@@ -12,6 +12,7 @@ from echotools.exec.fncall.prompt.history import (
|
|
|
12
12
|
)
|
|
13
13
|
from echotools.exec.fncall.prompt.history_format import (
|
|
14
14
|
_format_conversation_history,
|
|
15
|
+
collect_functions_results,
|
|
15
16
|
history_contains_tool_calls,
|
|
16
17
|
)
|
|
17
18
|
from echotools.exec.fncall.prompt.prompt_helpers import (
|
|
@@ -21,9 +22,11 @@ from echotools.exec.fncall.prompt.prompt_helpers import (
|
|
|
21
22
|
from echotools.exec.fncall.protocols.entml import (
|
|
22
23
|
format_entml_conversation_history,
|
|
23
24
|
format_entml_current_user_message,
|
|
25
|
+
format_entml_functions_results,
|
|
24
26
|
)
|
|
25
27
|
from echotools.exec.fncall.protocols.entml_think.core import (
|
|
26
|
-
|
|
28
|
+
build_entml_thinking_behavior_section,
|
|
29
|
+
build_entml_thinking_meta_section,
|
|
27
30
|
)
|
|
28
31
|
from echotools.exec.fncall.protocols.entml_think.hist import (
|
|
29
32
|
apply_thinking_history_policy,
|
|
@@ -71,6 +74,7 @@ def build_tools_prompt(
|
|
|
71
74
|
current_user_message: Optional[str] = None,
|
|
72
75
|
protocol_options: Optional[Dict[str, Any]] = None,
|
|
73
76
|
history_has_tool_calls: bool = False,
|
|
77
|
+
history_messages: Optional[List[Dict[str, Any]]] = None,
|
|
74
78
|
) -> str:
|
|
75
79
|
loop_warning = ""
|
|
76
80
|
if loop_detection_threshold > 0:
|
|
@@ -94,6 +98,9 @@ def build_tools_prompt(
|
|
|
94
98
|
)
|
|
95
99
|
if protocol.id == "entml":
|
|
96
100
|
extra["history_has_tool_calls"] = history_has_tool_calls
|
|
101
|
+
if history_messages is not None:
|
|
102
|
+
entries = collect_functions_results(history_messages)
|
|
103
|
+
extra["functions_results_text"] = format_entml_functions_results(entries)
|
|
97
104
|
return protocol.render_prompt(
|
|
98
105
|
tool_descs=tool_descs,
|
|
99
106
|
lang=lang,
|
|
@@ -141,17 +148,18 @@ def _build_entml_no_tools_prompt(
|
|
|
141
148
|
sections.append(
|
|
142
149
|
f"<user_system_prompt>\n{user_system_prompt.strip()}\n</user_system_prompt>"
|
|
143
150
|
)
|
|
151
|
+
thinking_behavior = build_entml_thinking_behavior_section(
|
|
152
|
+
protocol_options, history_text=history_text
|
|
153
|
+
)
|
|
154
|
+
if thinking_behavior:
|
|
155
|
+
sections.append(thinking_behavior)
|
|
144
156
|
if history_text.strip():
|
|
145
157
|
sections.append(format_entml_conversation_history(history_text))
|
|
146
158
|
if current_user_message is not None:
|
|
147
159
|
sections.append(format_entml_current_user_message(current_user_message))
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
history_text=history_text,
|
|
152
|
-
)
|
|
153
|
-
if thinking_section:
|
|
154
|
-
sections.append(thinking_section)
|
|
160
|
+
thinking_meta = build_entml_thinking_meta_section(protocol_options)
|
|
161
|
+
if thinking_meta:
|
|
162
|
+
sections.append(thinking_meta)
|
|
155
163
|
return "\n\n".join(sections)
|
|
156
164
|
|
|
157
165
|
|
|
@@ -197,6 +205,7 @@ def inject_fncall(
|
|
|
197
205
|
history_text, loop_detection_threshold, current_user_message,
|
|
198
206
|
protocol_options,
|
|
199
207
|
history_has_tool_calls=history_contains_tool_calls(history_messages),
|
|
208
|
+
history_messages=history_messages,
|
|
200
209
|
)
|
|
201
210
|
if dump_prompt:
|
|
202
211
|
_maybe_dump_prompt(prompt, dump_dir)
|
|
@@ -161,6 +161,21 @@ def format_assistant_block(
|
|
|
161
161
|
return parts
|
|
162
162
|
|
|
163
163
|
|
|
164
|
+
def _merge_entml_assistant_with_tool_turn(
|
|
165
|
+
assistant: str,
|
|
166
|
+
tool_block: str,
|
|
167
|
+
) -> str:
|
|
168
|
+
"""将 invoke/result 序列并入 ``<assistant>`` 块正文。"""
|
|
169
|
+
if not tool_block:
|
|
170
|
+
return assistant
|
|
171
|
+
marker = "\n</assistant>"
|
|
172
|
+
idx = assistant.rfind(marker)
|
|
173
|
+
if idx < 0:
|
|
174
|
+
return f"{assistant}\n\n{tool_block}"
|
|
175
|
+
prefix = assistant[:idx]
|
|
176
|
+
return f"{prefix}\n\n{tool_block}{marker}"
|
|
177
|
+
|
|
178
|
+
|
|
164
179
|
def format_assistant_block_with_results(
|
|
165
180
|
m: Dict[str, Any],
|
|
166
181
|
tool_msgs: List[Dict[str, Any]],
|
|
@@ -177,10 +192,13 @@ def format_assistant_block_with_results(
|
|
|
177
192
|
assistant = _format_assistant_text_block(
|
|
178
193
|
m, content_str, protocol, include_thinking_in_history=include_thinking_in_history
|
|
179
194
|
)
|
|
195
|
+
tool_block = _format_tool_turn_block(tcs, tool_msgs, protocol)
|
|
196
|
+
if assistant and tool_block:
|
|
197
|
+
if protocol is not None and getattr(protocol, "id", None) == "entml":
|
|
198
|
+
parts.append(_merge_entml_assistant_with_tool_turn(assistant, tool_block))
|
|
199
|
+
return parts
|
|
180
200
|
if assistant:
|
|
181
201
|
parts.append(assistant)
|
|
182
|
-
|
|
183
|
-
tool_block = _format_tool_turn_block(tcs, tool_msgs, protocol)
|
|
184
202
|
if tool_block:
|
|
185
203
|
parts.append(tool_block)
|
|
186
204
|
|
|
@@ -112,43 +112,21 @@ RULE 5 — Tool availability:
|
|
|
112
112
|
"""
|
|
113
113
|
|
|
114
114
|
_HISTORY_CLARIFY_EN = (
|
|
115
|
-
"The following is a transcript of completed interactions. "
|
|
116
|
-
"
|
|
117
|
-
"
|
|
115
|
+
"The following is a transcript of completed interactions. Each assistant turn "
|
|
116
|
+
"that called a tool ends at its last <entml:invoke> block; the comment "
|
|
117
|
+
"immediately following it states the environment-generated result id and was "
|
|
118
|
+
"appended by the environment when this turn was logged, not by the assistant "
|
|
119
|
+
"at generation time. The actual result content for every id shown here lives "
|
|
120
|
+
"exclusively in the separate, top-level <entml:funtions_results> block that "
|
|
121
|
+
"follows this history block.\n"
|
|
122
|
+
"IMPORTANT: The agent must never regenerate, continue, or imitate the "
|
|
123
|
+
"id-comment format shown below as part of its own current-turn output.\n"
|
|
124
|
+
"IMPORTANT: The agent must not repeat a tool call using the same tool and "
|
|
125
|
+
"the same parameters as one already recorded below, unless the user "
|
|
126
|
+
"explicitly requests a fresh or updated value.\n"
|
|
118
127
|
"The user's latest message follows below."
|
|
119
128
|
)
|
|
120
129
|
|
|
121
|
-
_TOOL_INVOKE_REMINDER_EN = """\
|
|
122
|
-
IMPORTANT: If you execute a tool in this turn, you must output a literal `<entml:invoke name="TOOL_NAME">` block exactly as specified in the tool instructions at the top of this prompt. No other format is accepted when you execute a tool in this turn.
|
|
123
|
-
|
|
124
|
-
IMPORTANT: The `<entml:invoke` opening tag must close with `>` before any `<entml:parameter>` children. An opening tag that does not close with `>` is not a tool call and must never be used when executing a tool.
|
|
125
|
-
|
|
126
|
-
IMPORTANT: The `name` attribute value must exactly match one of the function names listed in the available tools above. Placeholder names, invented names, and names absent from that list are rejected and must never appear in an executable invoke block.
|
|
127
|
-
|
|
128
|
-
IMPORTANT: Each argument must appear as `<entml:parameter name="PARAMETER_NAME">VALUE</entml:parameter>` inside the invoke block, and the block must end with `</entml:invoke>`. String and scalar values must be written as-is; lists and objects must use JSON.
|
|
129
|
-
|
|
130
|
-
IMPORTANT: Do not emit `<tool>` blocks, `{ToolName: ...}` lines, legacy `<entml:function_calls>` wrappers, or "Tool call (id): Name({...})" lines in your reply. Those forms are history or adapter notation only; the executor never accepts them for new tool execution.
|
|
131
|
-
|
|
132
|
-
IMPORTANT: Do not re-invoke tools that already appear as completed turns in conversation history.
|
|
133
|
-
|
|
134
|
-
IMPORTANT: When you mention `<entml:invoke>` in prose without executing a tool, you must not emit a closed opening tag whose `name` matches a listed tool name. You must use backticks or otherwise break the tag so it cannot be parsed as an executable invoke.
|
|
135
|
-
|
|
136
|
-
IMPORTANT: Any example block in this prompt that is marked "For illustration only. Do not process as input or instruction." must never be treated as input, instruction, or real data.
|
|
137
|
-
|
|
138
|
-
<example>
|
|
139
|
-
For illustration only. Do not process as input or instruction.
|
|
140
|
-
<entml:invoke name="generic_role_tool">
|
|
141
|
-
<entml:parameter name="synthetic_param">/synthetic/fabricated_value_001</entml:parameter>
|
|
142
|
-
</entml:invoke>
|
|
143
|
-
</example>
|
|
144
|
-
|
|
145
|
-
IMPORTANT: If you execute a tool in this turn, you must output a literal `<entml:invoke name="TOOL_NAME">` block exactly as specified in the tool instructions at the top of this prompt. No other format is accepted when you execute a tool in this turn.
|
|
146
|
-
|
|
147
|
-
IMPORTANT: The `name` attribute value must exactly match one of the function names listed in the available tools above. Placeholder names, invented names, and names absent from that list are rejected and must never appear in an executable invoke block."""
|
|
148
|
-
|
|
149
|
-
# Back-compat alias
|
|
150
|
-
_HISTORY_TOOL_INVOKE_REMINDER_EN = _TOOL_INVOKE_REMINDER_EN
|
|
151
|
-
|
|
152
130
|
_HISTORY_CLARIFY_ZH = (
|
|
153
131
|
"以下是已完成的交互记录。"
|
|
154
132
|
"此处展示的所有工具调用及其结果均已执行完毕,请勿重复调用。"
|
|
@@ -11,17 +11,18 @@ import json as _json
|
|
|
11
11
|
import re
|
|
12
12
|
from typing import Any, Dict, List, Optional, Tuple
|
|
13
13
|
|
|
14
|
+
from echotools.exec.fncall.prompt.behavior_blocks import (
|
|
15
|
+
format_function_calling_behavior,
|
|
16
|
+
format_hard_constraint_restatement,
|
|
17
|
+
format_thinking_behavior,
|
|
18
|
+
)
|
|
14
19
|
from echotools.exec.fncall.prompt.templates import (
|
|
15
20
|
_HISTORY_CLARIFY_EN,
|
|
16
|
-
_TOOL_INVOKE_REMINDER_EN,
|
|
17
21
|
)
|
|
18
22
|
from echotools.exec.fncall.protocols.entml_invoke import (
|
|
23
|
+
format_entml_tool_calls,
|
|
19
24
|
parse_entml_tool_calls,
|
|
20
25
|
)
|
|
21
|
-
from echotools.exec.fncall.protocols.entml_think.blocks import (
|
|
22
|
-
parse_tool_block_calls,
|
|
23
|
-
strip_tool_block_spans,
|
|
24
|
-
)
|
|
25
26
|
from echotools.exec.fncall.protocols.entml_patterns import (
|
|
26
27
|
entml_invoke_open_may_be_streaming,
|
|
27
28
|
extract_attr_value,
|
|
@@ -33,7 +34,8 @@ from echotools.exec.fncall.protocols.entml_patterns import (
|
|
|
33
34
|
strip_tool_entml_residue,
|
|
34
35
|
)
|
|
35
36
|
from echotools.exec.fncall.protocols.entml_think.core import (
|
|
36
|
-
|
|
37
|
+
build_entml_thinking_behavior_section,
|
|
38
|
+
build_entml_thinking_meta_section,
|
|
37
39
|
)
|
|
38
40
|
from echotools.exec.fncall.protocols.entml_schema import format_entml_tool_descs
|
|
39
41
|
from echotools.exec.fncall.shared.coercion import _build_param_schema_index
|
|
@@ -89,8 +91,8 @@ def _render_tool_call_line(name: str, args: Dict[str, Any]) -> str:
|
|
|
89
91
|
|
|
90
92
|
|
|
91
93
|
def _render_tool_history_block(body: str) -> str:
|
|
92
|
-
"""
|
|
93
|
-
return
|
|
94
|
+
"""历史内联工具轮次正文(invoke + result,无 ``<tool>`` 外壳)。"""
|
|
95
|
+
return body.strip()
|
|
94
96
|
|
|
95
97
|
|
|
96
98
|
_ENTML_INSTRUCTION = """\
|
|
@@ -107,10 +109,42 @@ You can invoke functions by writing a "<entml:invoke>" block like the following
|
|
|
107
109
|
|
|
108
110
|
String and scalar parameters should be specified as is, while lists and objects should use JSON format.
|
|
109
111
|
|
|
112
|
+
Your turn ends immediately at the closing tag of the last <entml:invoke> block you emit. You append nothing after it — no comment, no result, no id, no visible text. The execution environment then runs each tool. Once a turn is complete, the environment logs it into <entml:conversation_history> and appends, after each invocation in that log, an HTML comment stating the environment-generated result id in the form <!-- Tool Result ID:{id} -->. This comment is written by the environment when logging a completed turn; you never write it yourself, in this turn or in imitation of any prior turn, because at the moment you emit an invocation the id does not yet exist. Separately, the environment appends the full content of every result, matched by id, to a single flat top-level block named <entml:funtions_results>, positioned outside and independent of <entml:conversation_history>. This block accumulates across the whole conversation; it is never nested inside conversation_history and never adjacent to an invocation.
|
|
113
|
+
|
|
110
114
|
Here are the functions available in JSONSchema format:
|
|
111
115
|
"""
|
|
112
116
|
|
|
113
117
|
|
|
118
|
+
def format_tool_result_id_comment(tool_call_id: str) -> str:
|
|
119
|
+
"""History 内 invoke 后的环境回填 id 注释(非模型实时输出)。"""
|
|
120
|
+
tid = (tool_call_id or "").strip()
|
|
121
|
+
if not tid:
|
|
122
|
+
return ""
|
|
123
|
+
return f"<!-- Tool Result ID:{tid} -->"
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def format_entml_functions_results(
|
|
127
|
+
entries: List[Tuple[str, str]],
|
|
128
|
+
) -> str:
|
|
129
|
+
"""顶层 ``<entml:funtions_results>``:整场对话累计的 result 条目。"""
|
|
130
|
+
if not entries:
|
|
131
|
+
return ""
|
|
132
|
+
lines: List[str] = []
|
|
133
|
+
for tid, text in entries:
|
|
134
|
+
tid = (tid or "").strip()
|
|
135
|
+
body = (text or "").strip()
|
|
136
|
+
if not tid or not body:
|
|
137
|
+
continue
|
|
138
|
+
lines.append(f'<entml:result id="{tid}">\n{body}\n</entml:result>')
|
|
139
|
+
if not lines:
|
|
140
|
+
return ""
|
|
141
|
+
return (
|
|
142
|
+
f"<entml:funtions_results>\n"
|
|
143
|
+
+ "\n".join(lines)
|
|
144
|
+
+ "\n</entml:funtions_results>"
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
|
|
114
148
|
def format_entml_conversation_history(
|
|
115
149
|
history_text: str,
|
|
116
150
|
clarify: str = "",
|
|
@@ -151,7 +185,6 @@ class EntmlProtocol(ToolProtocol):
|
|
|
151
185
|
self._TRIGGER_PREFIX,
|
|
152
186
|
self._THINKING_PREFIX,
|
|
153
187
|
f"{self._THINKING_PREFIX}>",
|
|
154
|
-
"<tool",
|
|
155
188
|
]
|
|
156
189
|
|
|
157
190
|
def normalize_stream_buffer(self, buffer: str) -> str:
|
|
@@ -177,7 +210,9 @@ class EntmlProtocol(ToolProtocol):
|
|
|
177
210
|
current_user_message: Optional[str] = None,
|
|
178
211
|
protocol_options: Optional[Dict[str, Any]] = None,
|
|
179
212
|
history_has_tool_calls: bool = False,
|
|
213
|
+
functions_results_text: str = "",
|
|
180
214
|
) -> str:
|
|
215
|
+
_ = history_has_tool_calls
|
|
181
216
|
if tool_descs:
|
|
182
217
|
sections: List[str] = [
|
|
183
218
|
_ENTML_INSTRUCTION.rstrip() + "\n\n" + tool_descs
|
|
@@ -190,11 +225,6 @@ class EntmlProtocol(ToolProtocol):
|
|
|
190
225
|
f"<user_system_prompt>\n{user_system_prompt.strip()}\n</user_system_prompt>"
|
|
191
226
|
)
|
|
192
227
|
|
|
193
|
-
if history_text:
|
|
194
|
-
sections.append(
|
|
195
|
-
format_entml_conversation_history(history_text, _HISTORY_CLARIFY_EN)
|
|
196
|
-
)
|
|
197
|
-
|
|
198
228
|
if loop_warning:
|
|
199
229
|
sections.append(f"<loop_warning>\n{loop_warning}\n</loop_warning>")
|
|
200
230
|
|
|
@@ -203,18 +233,32 @@ class EntmlProtocol(ToolProtocol):
|
|
|
203
233
|
f"<history_markup_warning>\n{history_markup_warning}\n</history_markup_warning>"
|
|
204
234
|
)
|
|
205
235
|
|
|
206
|
-
if current_user_message is not None:
|
|
207
|
-
sections.append(format_entml_current_user_message(current_user_message))
|
|
208
|
-
|
|
209
236
|
if tool_descs:
|
|
210
|
-
sections.append(
|
|
237
|
+
sections.append(format_function_calling_behavior())
|
|
211
238
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
protocol_options, has_tools=bool(tool_descs), history_text=history_text
|
|
239
|
+
thinking_behavior = build_entml_thinking_behavior_section(
|
|
240
|
+
protocol_options, history_text=history_text
|
|
215
241
|
)
|
|
216
|
-
if
|
|
217
|
-
sections.append(
|
|
242
|
+
if thinking_behavior:
|
|
243
|
+
sections.append(thinking_behavior)
|
|
244
|
+
|
|
245
|
+
if history_text:
|
|
246
|
+
sections.append(
|
|
247
|
+
format_entml_conversation_history(history_text, _HISTORY_CLARIFY_EN)
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
if functions_results_text.strip():
|
|
251
|
+
sections.append(functions_results_text.strip())
|
|
252
|
+
|
|
253
|
+
if tool_descs:
|
|
254
|
+
sections.append(format_hard_constraint_restatement())
|
|
255
|
+
|
|
256
|
+
if current_user_message is not None:
|
|
257
|
+
sections.append(format_entml_current_user_message(current_user_message))
|
|
258
|
+
|
|
259
|
+
thinking_meta = build_entml_thinking_meta_section(protocol_options)
|
|
260
|
+
if thinking_meta:
|
|
261
|
+
sections.append(thinking_meta)
|
|
218
262
|
|
|
219
263
|
return "\n\n".join(sections)
|
|
220
264
|
|
|
@@ -276,6 +320,7 @@ class EntmlProtocol(ToolProtocol):
|
|
|
276
320
|
include_tool_blocks: bool = True,
|
|
277
321
|
thinking_enabled: bool = True,
|
|
278
322
|
) -> Tuple[str, List[Dict[str, Any]]]:
|
|
323
|
+
_ = include_tool_blocks
|
|
279
324
|
from echotools.exec.fncall.protocols.entml_think.parse import (
|
|
280
325
|
_find_earliest_thinking_open,
|
|
281
326
|
has_unclosed_entml_thinking,
|
|
@@ -295,18 +340,11 @@ class EntmlProtocol(ToolProtocol):
|
|
|
295
340
|
schema_index = _build_param_schema_index(tools) if tools else None
|
|
296
341
|
known = resolve_known_tool_names(tools, schema_index)
|
|
297
342
|
tool_calls = parse_entml_tool_calls(parse_text, tools, schema_index)
|
|
298
|
-
tool_block_calls: List[Dict[str, Any]] = []
|
|
299
|
-
if include_tool_blocks:
|
|
300
|
-
tool_block_calls = parse_tool_block_calls(parse_text, tools, schema_index)
|
|
301
|
-
tool_calls.extend(tool_block_calls)
|
|
302
343
|
clean = text[:unclosed_open_at] if unclosed_open_at >= 0 else text
|
|
303
344
|
if thinking_enabled:
|
|
304
345
|
# fault ``</thinking>`` 须借后续 invoke 判定闭合;thinking 剥离必须在 invoke 移除之前。
|
|
305
346
|
visible, _ = split_entml_thinking(clean, thinking_enabled=True)
|
|
306
347
|
clean = visible
|
|
307
|
-
if tool_block_calls:
|
|
308
|
-
clean = strip_tool_block_spans(clean)
|
|
309
|
-
# 须在移除 invoke 之前剥离伪 history,且须晚于已解析的 ``<tool>`` 块剥离。
|
|
310
348
|
clean, _ = strip_fake_history_markup(clean)
|
|
311
349
|
if tool_calls:
|
|
312
350
|
clean = strip_actionable_entml_invoke_blocks(clean, known_names=known)
|
|
@@ -352,18 +390,18 @@ class EntmlProtocol(ToolProtocol):
|
|
|
352
390
|
tool_calls: List[Dict[str, Any]],
|
|
353
391
|
tid_to_result: Dict[str, Dict[str, Any]],
|
|
354
392
|
) -> str:
|
|
355
|
-
"""同一 assistant
|
|
393
|
+
"""同一 assistant 轮次:``<entml:invoke>`` + 环境回填 id 注释(无 result 正文)。"""
|
|
394
|
+
_ = tid_to_result
|
|
356
395
|
lines: List[str] = []
|
|
357
396
|
for tc in tool_calls:
|
|
358
|
-
|
|
359
|
-
|
|
397
|
+
invoke = format_entml_tool_calls([tc])
|
|
398
|
+
if invoke:
|
|
399
|
+
lines.append(invoke)
|
|
360
400
|
tid = tc.get("id") or ""
|
|
361
|
-
|
|
362
|
-
if
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
lines.append(text)
|
|
366
|
-
return _render_tool_history_block("\n".join(lines))
|
|
401
|
+
comment = format_tool_result_id_comment(tid)
|
|
402
|
+
if comment:
|
|
403
|
+
lines.append(comment)
|
|
404
|
+
return "\n".join(lines)
|
|
367
405
|
|
|
368
406
|
def supports_streaming(self) -> bool:
|
|
369
407
|
return True
|
{echotools-2.3.91 → echotools-2.3.93}/src/echotools/exec/fncall/protocols/entml_think/__init__.py
RENAMED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"""Entml thinking: prompt section, history blocks, stream parsing."""
|
|
2
2
|
|
|
3
3
|
from echotools.exec.fncall.protocols.entml_think.core import (
|
|
4
|
+
build_entml_thinking_behavior_section,
|
|
5
|
+
build_entml_thinking_meta_section,
|
|
4
6
|
build_entml_thinking_section,
|
|
5
7
|
is_thinking_enabled,
|
|
6
8
|
parse_max_thinking_length,
|
|
@@ -21,6 +23,8 @@ from echotools.exec.fncall.protocols.entml_think.parse import (
|
|
|
21
23
|
__all__ = [
|
|
22
24
|
"EntmlThinkingStreamFilter",
|
|
23
25
|
"apply_thinking_history_policy",
|
|
26
|
+
"build_entml_thinking_behavior_section",
|
|
27
|
+
"build_entml_thinking_meta_section",
|
|
24
28
|
"build_entml_thinking_section",
|
|
25
29
|
"extract_reasoning_text",
|
|
26
30
|
"format_entml_thinking_history_block",
|