echotools 2.3.14__tar.gz → 2.3.16__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.14 → echotools-2.3.16}/PKG-INFO +1 -1
- {echotools-2.3.14 → echotools-2.3.16}/pyproject.toml +1 -1
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/fncall/protocols/entml_thinking.py +4 -4
- echotools-2.3.16/src/echotools/exec/fncall/protocols/entml_thinking_parse.py +122 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools.egg-info/PKG-INFO +1 -1
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools.egg-info/SOURCES.txt +2 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/tests/test_entml_protocol.py +1 -2
- echotools-2.3.16/src/tests/test_entml_thinking_parse.py +27 -0
- {echotools-2.3.14 → echotools-2.3.16}/README.md +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/docs/README.md +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/setup.cfg +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/__init__.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/base/cache/__init__.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/base/cache/list_cache.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/base/cache/memory_cache.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/base/config/__init__.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/base/config/base.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/base/config/center.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/base/config/center_notify.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/base/config/center_template.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/base/config/loader.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/base/config/merge.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/base/errors/__init__.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/base/errors/base.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/base/errors/classify.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/base/errors/common.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/base/errors/http.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/base/ids/__init__.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/base/ids/generator.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/base/io/__init__.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/base/io/io_utils.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/base/io/printstream.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/base/logger/__init__.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/base/logger/manager.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/base/retry/__init__.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/base/retry/retry.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/compat.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/dispatch/__init__.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/dispatch/candidate.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/dispatch/dispatcher.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/dispatch/proxy_selector.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/dispatch/race.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/dispatch/selector.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/dispatch/usage.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/fncall/__init__.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/fncall/parsers/__init__.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/fncall/parsers/stream.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/fncall/parsers/xml_params.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/fncall/parsers/xml_parser.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/fncall/prompt/__init__.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/fncall/prompt/history.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/fncall/prompt/history_format.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/fncall/prompt/inject.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/fncall/prompt/prompt_helpers.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/fncall/prompt/templates.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/fncall/protocols/__init__.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/fncall/protocols/entml.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/fncall/protocols/entml_invoke.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/fncall/protocols/entml_patterns.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/fncall/protocols/entml_tools.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/fncall/protocols/entml_values.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/fncall/registry.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/fncall/shared/__init__.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/fncall/shared/coercion.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/fncall/shared/loop_detect.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/fncall/shared/normalization.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/fncall/shared/schema_render.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/fncall/shared/xml_helpers.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/keys.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/lifecycle/__init__.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/lifecycle/manager.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/lifecycle/updater.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/lifecycle/updater_pull.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/process/__init__.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/process/port.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/protocol/__init__.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/protocol/base.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/terminal/__init__.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/terminal/conpty.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/terminal/local/__init__.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/terminal/local/core.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/terminal/local/proc.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/terminal/local/unix.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/terminal/local/win.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/terminal/sanitize.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/terminal/session/__init__.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/terminal/session/base.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/terminal/session/client.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/terminal/ssh.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/exec/terminal/tmux.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/events/__init__.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/events/bus.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/events/event.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/spinner/__init__.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/spinner/spinner.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/spinner/spinner_color.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/tracing/__init__.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/tracing/context.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/tracing/span.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/tracing/tracer.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/translate.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/watcher/__init__.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/watcher/file_watcher.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/web/__init__.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/web/application.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/web/broker.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/web/input_box/app.js +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/web/input_box/components/filezone.js +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/web/input_box/components/motionkit.js +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/web/input_box/components/sendbutton.js +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/web/input_box/components/sortablelist.css +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/web/input_box/components/sortablelist.js +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/web/input_box/components/textinput.js +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/web/input_box/components/voiceinput.js +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/web/input_box/fonts/inter-500.woff2 +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/web/input_box/fonts/inter-600.woff2 +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/web/input_box/fonts/inter400.woff2 +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/web/input_box/fonts/tailwind.css +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/web/input_box/inputbox.css +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/web/input_box/inputbox.js +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/web/input_box/style.css +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/web/input_box/voicegif.js +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/web/middleware.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/web/stats.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/web/utils.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/plat/files/__init__.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/plat/files/file_util.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/plat/network/__init__.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/plat/network/http_utils.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/plat/plugin/__init__.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/plat/plugin/base.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/plat/plugin/discovery.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/plat/plugin/registry.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/plat/plugin/registry_ops.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/plat/proxy/__init__.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/plat/proxy/manager.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/plat/runtime/__init__.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/plat/runtime/collector.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/plat/scheduler/__init__.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/plat/scheduler/scheduler.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/plat/sdk/__init__.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/plat/sdk/facade.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools/version.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools.egg-info/dependency_links.txt +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools.egg-info/requires.txt +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/echotools.egg-info/top_level.txt +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/tests/bench_import.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/tests/conftest.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/tests/test_cache_retry.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/tests/test_completion.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/tests/test_config.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/tests/test_config_extended.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/tests/test_coverage_core.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/tests/test_dispatch.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/tests/test_dispatch_extended.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/tests/test_dispatch_race.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/tests/test_entml_tools.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/tests/test_errors.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/tests/test_errors_common.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/tests/test_events.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/tests/test_events_event.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/tests/test_facade.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/tests/test_fncall.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/tests/test_ids.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/tests/test_imports.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/tests/test_io.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/tests/test_keys.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/tests/test_lifecycle.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/tests/test_logger.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/tests/test_merge.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/tests/test_plugin.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/tests/test_printstream.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/tests/test_protocols.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/tests/test_proxy.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/tests/test_proxy_selector.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/tests/test_runtime.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/tests/test_scheduler.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/tests/test_tracing.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/tests/test_usage.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/tests/test_web.py +0 -0
- {echotools-2.3.14 → echotools-2.3.16}/src/tests/test_web_broker.py +0 -0
|
@@ -41,12 +41,12 @@ def build_entml_thinking_section(
|
|
|
41
41
|
"...",
|
|
42
42
|
"</function_results>",
|
|
43
43
|
"",
|
|
44
|
-
"<thinking>",
|
|
44
|
+
"<entml:thinking>",
|
|
45
45
|
"...thinking about results",
|
|
46
|
-
"</thinking>",
|
|
46
|
+
"</entml:thinking>",
|
|
47
47
|
"At the very start of your response, think carefully about whether "
|
|
48
|
-
"
|
|
49
|
-
"strongly prefer to output a thinking block if you are uncertain.",
|
|
48
|
+
"an `<entml:thinking>` `</entml:thinking>` block would be appropriate "
|
|
49
|
+
"and strongly prefer to output a thinking block if you are uncertain.",
|
|
50
50
|
]
|
|
51
51
|
)
|
|
52
52
|
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from typing import List, Tuple
|
|
5
|
+
|
|
6
|
+
THINKING_BLOCK_RE = re.compile(
|
|
7
|
+
r"<entml:thinking\b[^>]*>([\s\S]*?)</entml:thinking>",
|
|
8
|
+
re.DOTALL,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
_THINKING_OPEN_PREFIX = "<entml:thinking"
|
|
12
|
+
_THINKING_CLOSE = "</entml:thinking>"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def split_entml_thinking(text: str) -> Tuple[str, str]:
|
|
16
|
+
"""从文本中剥离 <entml:thinking> 块,返回 (正文, 思考链拼接)。"""
|
|
17
|
+
if not text:
|
|
18
|
+
return "", ""
|
|
19
|
+
|
|
20
|
+
parts: List[str] = []
|
|
21
|
+
|
|
22
|
+
def _collect(match: re.Match[str]) -> str:
|
|
23
|
+
parts.append(match.group(1))
|
|
24
|
+
return ""
|
|
25
|
+
|
|
26
|
+
clean = THINKING_BLOCK_RE.sub(_collect, text)
|
|
27
|
+
thinking = "\n".join(part.strip() for part in parts if part.strip())
|
|
28
|
+
return clean.strip(), thinking
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _split_safe_prefix(buffer: str) -> Tuple[str, str]:
|
|
32
|
+
"""保留可能未闭合的 <entml:thinking 开标签尾部。"""
|
|
33
|
+
if not buffer:
|
|
34
|
+
return "", ""
|
|
35
|
+
|
|
36
|
+
open_pos = buffer.rfind(_THINKING_OPEN_PREFIX)
|
|
37
|
+
if open_pos < 0:
|
|
38
|
+
return buffer, ""
|
|
39
|
+
|
|
40
|
+
tail = buffer[open_pos:]
|
|
41
|
+
if ">" in tail and _THINKING_CLOSE not in tail:
|
|
42
|
+
return buffer, ""
|
|
43
|
+
|
|
44
|
+
close_pos = buffer.rfind(_THINKING_CLOSE)
|
|
45
|
+
if close_pos >= 0 and close_pos > open_pos:
|
|
46
|
+
return buffer, ""
|
|
47
|
+
|
|
48
|
+
if tail == _THINKING_OPEN_PREFIX[: len(tail)]:
|
|
49
|
+
return buffer[:open_pos], tail
|
|
50
|
+
|
|
51
|
+
return buffer[:open_pos], tail
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class EntmlThinkingStreamFilter:
|
|
55
|
+
"""流式拆分 entml:thinking 与可见正文。"""
|
|
56
|
+
|
|
57
|
+
def __init__(self) -> None:
|
|
58
|
+
self._pending = ""
|
|
59
|
+
self._in_block = False
|
|
60
|
+
self._block_buf = ""
|
|
61
|
+
|
|
62
|
+
def feed(self, chunk: str) -> List[Tuple[str, str]]:
|
|
63
|
+
"""返回 [(kind, text), ...],kind 为 content 或 thinking。"""
|
|
64
|
+
if not chunk:
|
|
65
|
+
return []
|
|
66
|
+
|
|
67
|
+
self._pending += chunk
|
|
68
|
+
out: List[Tuple[str, str]] = []
|
|
69
|
+
|
|
70
|
+
while self._pending:
|
|
71
|
+
if self._in_block:
|
|
72
|
+
close_at = self._pending.find(_THINKING_CLOSE)
|
|
73
|
+
if close_at < 0:
|
|
74
|
+
self._block_buf += self._pending
|
|
75
|
+
self._pending = ""
|
|
76
|
+
break
|
|
77
|
+
self._block_buf += self._pending[:close_at]
|
|
78
|
+
thinking = self._block_buf.strip()
|
|
79
|
+
if thinking:
|
|
80
|
+
out.append(("thinking", thinking))
|
|
81
|
+
self._block_buf = ""
|
|
82
|
+
self._in_block = False
|
|
83
|
+
self._pending = self._pending[close_at + len(_THINKING_CLOSE) :]
|
|
84
|
+
continue
|
|
85
|
+
|
|
86
|
+
open_at = self._pending.find(_THINKING_OPEN_PREFIX)
|
|
87
|
+
if open_at < 0:
|
|
88
|
+
safe, self._pending = _split_safe_prefix(self._pending)
|
|
89
|
+
if safe:
|
|
90
|
+
out.append(("content", safe))
|
|
91
|
+
break
|
|
92
|
+
|
|
93
|
+
if open_at > 0:
|
|
94
|
+
prefix = self._pending[:open_at]
|
|
95
|
+
out.append(("content", prefix))
|
|
96
|
+
self._pending = self._pending[open_at:]
|
|
97
|
+
|
|
98
|
+
gt = self._pending.find(">")
|
|
99
|
+
if gt < 0:
|
|
100
|
+
break
|
|
101
|
+
|
|
102
|
+
self._in_block = True
|
|
103
|
+
self._pending = self._pending[gt + 1 :]
|
|
104
|
+
|
|
105
|
+
return out
|
|
106
|
+
|
|
107
|
+
def finalize(self) -> List[Tuple[str, str]]:
|
|
108
|
+
out: List[Tuple[str, str]] = []
|
|
109
|
+
if self._in_block:
|
|
110
|
+
thinking = (self._block_buf + self._pending).strip()
|
|
111
|
+
if thinking:
|
|
112
|
+
out.append(("thinking", thinking))
|
|
113
|
+
elif self._pending:
|
|
114
|
+
content, thinking = split_entml_thinking(self._pending)
|
|
115
|
+
if thinking:
|
|
116
|
+
out.append(("thinking", thinking))
|
|
117
|
+
if content:
|
|
118
|
+
out.append(("content", content))
|
|
119
|
+
self._pending = ""
|
|
120
|
+
self._block_buf = ""
|
|
121
|
+
self._in_block = False
|
|
122
|
+
return out
|
|
@@ -58,6 +58,7 @@ src/echotools/exec/fncall/protocols/entml.py
|
|
|
58
58
|
src/echotools/exec/fncall/protocols/entml_invoke.py
|
|
59
59
|
src/echotools/exec/fncall/protocols/entml_patterns.py
|
|
60
60
|
src/echotools/exec/fncall/protocols/entml_thinking.py
|
|
61
|
+
src/echotools/exec/fncall/protocols/entml_thinking_parse.py
|
|
61
62
|
src/echotools/exec/fncall/protocols/entml_tools.py
|
|
62
63
|
src/echotools/exec/fncall/protocols/entml_values.py
|
|
63
64
|
src/echotools/exec/fncall/shared/__init__.py
|
|
@@ -150,6 +151,7 @@ src/tests/test_dispatch.py
|
|
|
150
151
|
src/tests/test_dispatch_extended.py
|
|
151
152
|
src/tests/test_dispatch_race.py
|
|
152
153
|
src/tests/test_entml_protocol.py
|
|
154
|
+
src/tests/test_entml_thinking_parse.py
|
|
153
155
|
src/tests/test_entml_tools.py
|
|
154
156
|
src/tests/test_errors.py
|
|
155
157
|
src/tests/test_errors_common.py
|
|
@@ -60,9 +60,8 @@ def test_inject_with_thinking_options_only_when_declared() -> None:
|
|
|
60
60
|
)[0]["content"]
|
|
61
61
|
assert "<entml:thinking_mode>interleaved</entml:thinking_mode>" in with_opts
|
|
62
62
|
assert "<entml:max_thinking_length>22000</entml:max_thinking_length>" in with_opts
|
|
63
|
-
assert "<thinking>" in with_opts
|
|
63
|
+
assert "<entml:thinking>" in with_opts
|
|
64
64
|
assert "At the very start of your response" in with_opts
|
|
65
|
-
assert "<entml:thinking>" not in with_opts
|
|
66
65
|
|
|
67
66
|
|
|
68
67
|
def test_build_entml_thinking_section_empty_without_options() -> None:
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from echotools.exec.fncall.protocols.entml_thinking_parse import (
|
|
2
|
+
EntmlThinkingStreamFilter,
|
|
3
|
+
split_entml_thinking,
|
|
4
|
+
)
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def test_split_entml_thinking() -> None:
|
|
8
|
+
text = (
|
|
9
|
+
"prefix\n<entml:thinking>\nstep one\n</entml:thinking>\n"
|
|
10
|
+
"answer tail"
|
|
11
|
+
)
|
|
12
|
+
content, thinking = split_entml_thinking(text)
|
|
13
|
+
assert thinking == "step one"
|
|
14
|
+
assert "prefix" in content
|
|
15
|
+
assert "answer tail" in content
|
|
16
|
+
assert "<entml:thinking>" not in content
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def test_entml_thinking_stream_filter() -> None:
|
|
20
|
+
filt = EntmlThinkingStreamFilter()
|
|
21
|
+
parts = []
|
|
22
|
+
for chunk in ["hello ", "<entml:thinking>rea", "son</entml:thinking> world"]:
|
|
23
|
+
parts.extend(filt.feed(chunk))
|
|
24
|
+
parts.extend(filt.finalize())
|
|
25
|
+
kinds = {kind for kind, _ in parts}
|
|
26
|
+
assert "thinking" in kinds
|
|
27
|
+
assert "content" in kinds
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/web/input_box/components/filezone.js
RENAMED
|
File without changes
|
{echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/web/input_box/components/motionkit.js
RENAMED
|
File without changes
|
{echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/web/input_box/components/sendbutton.js
RENAMED
|
File without changes
|
{echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/web/input_box/components/sortablelist.css
RENAMED
|
File without changes
|
{echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/web/input_box/components/sortablelist.js
RENAMED
|
File without changes
|
{echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/web/input_box/components/textinput.js
RENAMED
|
File without changes
|
{echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/web/input_box/components/voiceinput.js
RENAMED
|
File without changes
|
{echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/web/input_box/fonts/inter-500.woff2
RENAMED
|
File without changes
|
{echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/web/input_box/fonts/inter-600.woff2
RENAMED
|
File without changes
|
{echotools-2.3.14 → echotools-2.3.16}/src/echotools/media/web/input_box/fonts/inter400.woff2
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|