echotools 2.3.21__tar.gz → 2.3.22__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.21 → echotools-2.3.22}/PKG-INFO +1 -1
- {echotools-2.3.21 → echotools-2.3.22}/pyproject.toml +1 -1
- echotools-2.3.22/src/echotools/exec/fncall/protocols/entml_thinking_history.py +133 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools.egg-info/PKG-INFO +1 -1
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools.egg-info/SOURCES.txt +2 -0
- echotools-2.3.22/src/tests/test_entml_thinking_history.py +71 -0
- {echotools-2.3.21 → echotools-2.3.22}/README.md +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/docs/README.md +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/setup.cfg +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/__init__.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/base/cache/__init__.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/base/cache/list_cache.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/base/cache/memory_cache.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/base/config/__init__.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/base/config/base.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/base/config/center.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/base/config/center_notify.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/base/config/center_template.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/base/config/loader.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/base/config/merge.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/base/errors/__init__.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/base/errors/base.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/base/errors/classify.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/base/errors/common.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/base/errors/http.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/base/ids/__init__.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/base/ids/generator.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/base/io/__init__.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/base/io/io_utils.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/base/io/printstream.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/base/logger/__init__.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/base/logger/manager.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/base/retry/__init__.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/base/retry/retry.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/compat.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/dispatch/__init__.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/dispatch/candidate.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/dispatch/dispatcher.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/dispatch/proxy_selector.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/dispatch/race.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/dispatch/selector.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/dispatch/usage.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/fncall/__init__.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/fncall/parsers/__init__.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/fncall/parsers/stream.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/fncall/parsers/xml_params.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/fncall/parsers/xml_parser.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/fncall/prompt/__init__.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/fncall/prompt/history.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/fncall/prompt/history_format.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/fncall/prompt/inject.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/fncall/prompt/prompt_helpers.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/fncall/prompt/templates.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/fncall/protocols/__init__.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/fncall/protocols/entml.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/fncall/protocols/entml_invoke.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/fncall/protocols/entml_patterns.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/fncall/protocols/entml_thinking.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/fncall/protocols/entml_thinking_parse.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/fncall/protocols/entml_tools.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/fncall/protocols/entml_values.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/fncall/registry.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/fncall/shared/__init__.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/fncall/shared/coercion.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/fncall/shared/loop_detect.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/fncall/shared/normalization.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/fncall/shared/schema_render.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/fncall/shared/xml_helpers.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/keys.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/lifecycle/__init__.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/lifecycle/manager.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/lifecycle/updater.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/lifecycle/updater_pull.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/process/__init__.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/process/port.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/protocol/__init__.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/protocol/base.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/terminal/__init__.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/terminal/conpty.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/terminal/local/__init__.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/terminal/local/core.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/terminal/local/proc.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/terminal/local/unix.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/terminal/local/win.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/terminal/sanitize.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/terminal/session/__init__.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/terminal/session/base.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/terminal/session/client.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/terminal/ssh.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/exec/terminal/tmux.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/events/__init__.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/events/bus.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/events/event.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/spinner/__init__.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/spinner/spinner.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/spinner/spinner_color.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/tracing/__init__.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/tracing/context.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/tracing/span.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/tracing/tracer.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/translate.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/watcher/__init__.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/watcher/file_watcher.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/web/__init__.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/web/application.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/web/broker.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/web/input_box/app.js +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/web/input_box/components/filezone.js +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/web/input_box/components/motionkit.js +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/web/input_box/components/sendbutton.js +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/web/input_box/components/sortablelist.css +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/web/input_box/components/sortablelist.js +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/web/input_box/components/textinput.js +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/web/input_box/components/voiceinput.js +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/web/input_box/fonts/inter-500.woff2 +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/web/input_box/fonts/inter-600.woff2 +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/web/input_box/fonts/inter400.woff2 +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/web/input_box/fonts/tailwind.css +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/web/input_box/inputbox.css +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/web/input_box/inputbox.js +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/web/input_box/style.css +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/web/input_box/voicegif.js +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/web/middleware.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/web/stats.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/web/utils.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/plat/files/__init__.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/plat/files/file_util.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/plat/network/__init__.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/plat/network/http_utils.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/plat/plugin/__init__.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/plat/plugin/base.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/plat/plugin/discovery.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/plat/plugin/registry.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/plat/plugin/registry_ops.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/plat/proxy/__init__.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/plat/proxy/manager.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/plat/runtime/__init__.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/plat/runtime/collector.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/plat/scheduler/__init__.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/plat/scheduler/scheduler.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/plat/sdk/__init__.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/plat/sdk/facade.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools/version.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools.egg-info/dependency_links.txt +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools.egg-info/requires.txt +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/echotools.egg-info/top_level.txt +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/tests/bench_import.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/tests/conftest.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/tests/test_cache_retry.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/tests/test_completion.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/tests/test_config.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/tests/test_config_extended.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/tests/test_coverage_core.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/tests/test_dispatch.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/tests/test_dispatch_extended.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/tests/test_dispatch_race.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/tests/test_entml_protocol.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/tests/test_entml_thinking_parse.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/tests/test_entml_tools.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/tests/test_errors.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/tests/test_errors_common.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/tests/test_events.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/tests/test_events_event.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/tests/test_facade.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/tests/test_fncall.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/tests/test_ids.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/tests/test_imports.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/tests/test_io.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/tests/test_keys.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/tests/test_lifecycle.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/tests/test_logger.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/tests/test_merge.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/tests/test_plugin.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/tests/test_printstream.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/tests/test_protocols.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/tests/test_proxy.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/tests/test_proxy_selector.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/tests/test_runtime.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/tests/test_scheduler.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/tests/test_tracing.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/tests/test_usage.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/tests/test_web.py +0 -0
- {echotools-2.3.21 → echotools-2.3.22}/src/tests/test_web_broker.py +0 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict, List, Mapping, Optional
|
|
4
|
+
|
|
5
|
+
REASONING_KEYS = ("reasoning", "reasoning_content", "reasoning_details")
|
|
6
|
+
HISTORY_FLAG_KEYS = (
|
|
7
|
+
"include_thinking_in_history",
|
|
8
|
+
"pass_thinking",
|
|
9
|
+
"include_thinking",
|
|
10
|
+
"interleaved_history",
|
|
11
|
+
)
|
|
12
|
+
_THINKING_BLOCK_TYPES = frozenset({"thinking", "reasoning", "redacted_thinking"})
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def parse_interleaved_history(
|
|
16
|
+
body: Mapping[str, Any],
|
|
17
|
+
extra: Optional[Mapping[str, Any]] = None,
|
|
18
|
+
thinking: Any = None,
|
|
19
|
+
) -> bool:
|
|
20
|
+
"""解析是否将历史 assistant 思考链传给模型(Entropy interleaved_history)。"""
|
|
21
|
+
extra = extra or {}
|
|
22
|
+
if thinking is None:
|
|
23
|
+
thinking = body.get("thinking")
|
|
24
|
+
for key in ("interleaved_history", "include_in_history"):
|
|
25
|
+
if key in body:
|
|
26
|
+
return bool(body[key])
|
|
27
|
+
if key in extra:
|
|
28
|
+
return bool(extra[key])
|
|
29
|
+
if isinstance(thinking, dict):
|
|
30
|
+
for key in ("interleaved_history", "include_in_history"):
|
|
31
|
+
if key in thinking:
|
|
32
|
+
return bool(thinking[key])
|
|
33
|
+
return False
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _thinking_from_content_block(block: Any) -> str:
|
|
37
|
+
if not isinstance(block, dict):
|
|
38
|
+
return ""
|
|
39
|
+
btype = str(block.get("type", "")).strip().lower()
|
|
40
|
+
if btype in ("thinking", "redacted_thinking"):
|
|
41
|
+
val = block.get("thinking") or block.get("data")
|
|
42
|
+
return str(val).strip() if val else ""
|
|
43
|
+
if btype == "reasoning":
|
|
44
|
+
val = block.get("text") or block.get("reasoning")
|
|
45
|
+
return str(val).strip() if val else ""
|
|
46
|
+
return ""
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def extract_reasoning_text(msg: Mapping[str, Any]) -> str:
|
|
50
|
+
"""从 assistant 消息字段或 Entropy/Anthropic 内容块提取思考文本。"""
|
|
51
|
+
for key in ("reasoning", "reasoning_content"):
|
|
52
|
+
val = msg.get(key)
|
|
53
|
+
if isinstance(val, str) and val.strip():
|
|
54
|
+
return val.strip()
|
|
55
|
+
|
|
56
|
+
details = msg.get("reasoning_details")
|
|
57
|
+
if isinstance(details, list):
|
|
58
|
+
parts: List[str] = []
|
|
59
|
+
for item in details:
|
|
60
|
+
if not isinstance(item, dict):
|
|
61
|
+
continue
|
|
62
|
+
text = item.get("text")
|
|
63
|
+
if text:
|
|
64
|
+
parts.append(str(text))
|
|
65
|
+
if parts:
|
|
66
|
+
return "".join(parts)
|
|
67
|
+
|
|
68
|
+
content = msg.get("content")
|
|
69
|
+
if isinstance(content, list):
|
|
70
|
+
parts = []
|
|
71
|
+
for block in content:
|
|
72
|
+
text = _thinking_from_content_block(block)
|
|
73
|
+
if text:
|
|
74
|
+
parts.append(text)
|
|
75
|
+
if parts:
|
|
76
|
+
return "\n".join(parts)
|
|
77
|
+
return ""
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _strip_thinking_blocks(content: List[Any]) -> List[Any]:
|
|
81
|
+
kept: List[Any] = []
|
|
82
|
+
for block in content:
|
|
83
|
+
if isinstance(block, dict) and str(block.get("type", "")).lower() in _THINKING_BLOCK_TYPES:
|
|
84
|
+
continue
|
|
85
|
+
kept.append(block)
|
|
86
|
+
return kept
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _collapse_text_content(blocks: List[Any]) -> Any:
|
|
90
|
+
if len(blocks) == 1:
|
|
91
|
+
only = blocks[0]
|
|
92
|
+
if isinstance(only, dict) and only.get("type") == "text":
|
|
93
|
+
return only.get("text", "")
|
|
94
|
+
return blocks
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _strip_reasoning_from_message(msg: Dict[str, Any]) -> Dict[str, Any]:
|
|
98
|
+
out = dict(msg)
|
|
99
|
+
for key in REASONING_KEYS:
|
|
100
|
+
out.pop(key, None)
|
|
101
|
+
content = out.get("content")
|
|
102
|
+
if isinstance(content, list):
|
|
103
|
+
stripped = _strip_thinking_blocks(content)
|
|
104
|
+
out["content"] = _collapse_text_content(stripped) if stripped else ""
|
|
105
|
+
return out
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _normalize_message_with_reasoning(msg: Dict[str, Any]) -> Dict[str, Any]:
|
|
109
|
+
out = dict(msg)
|
|
110
|
+
if out.get("role") != "assistant":
|
|
111
|
+
for key in REASONING_KEYS:
|
|
112
|
+
out.pop(key, None)
|
|
113
|
+
return out
|
|
114
|
+
|
|
115
|
+
text = extract_reasoning_text(out)
|
|
116
|
+
if text:
|
|
117
|
+
out["reasoning"] = text
|
|
118
|
+
out.setdefault("reasoning_content", text)
|
|
119
|
+
return out
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def apply_thinking_history_policy(
|
|
123
|
+
messages: List[Dict[str, Any]],
|
|
124
|
+
include: bool,
|
|
125
|
+
) -> List[Dict[str, Any]]:
|
|
126
|
+
"""按 interleaved_history 保留或剥离历史思考链。
|
|
127
|
+
|
|
128
|
+
include=True: 保留 reasoning 字段与 content 中的 thinking 块。
|
|
129
|
+
include=False: 仅保留可见回复,剥离思考链。
|
|
130
|
+
"""
|
|
131
|
+
if include:
|
|
132
|
+
return [_normalize_message_with_reasoning(dict(m)) for m in messages]
|
|
133
|
+
return [_strip_reasoning_from_message(dict(m)) for m in messages]
|
|
@@ -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_history.py
|
|
61
62
|
src/echotools/exec/fncall/protocols/entml_thinking_parse.py
|
|
62
63
|
src/echotools/exec/fncall/protocols/entml_tools.py
|
|
63
64
|
src/echotools/exec/fncall/protocols/entml_values.py
|
|
@@ -151,6 +152,7 @@ src/tests/test_dispatch.py
|
|
|
151
152
|
src/tests/test_dispatch_extended.py
|
|
152
153
|
src/tests/test_dispatch_race.py
|
|
153
154
|
src/tests/test_entml_protocol.py
|
|
155
|
+
src/tests/test_entml_thinking_history.py
|
|
154
156
|
src/tests/test_entml_thinking_parse.py
|
|
155
157
|
src/tests/test_entml_tools.py
|
|
156
158
|
src/tests/test_errors.py
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from echotools.exec.fncall.protocols.entml_thinking_history import (
|
|
4
|
+
apply_thinking_history_policy,
|
|
5
|
+
extract_reasoning_text,
|
|
6
|
+
parse_interleaved_history,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def test_parse_interleaved_history_from_thinking_object() -> None:
|
|
11
|
+
body = {"thinking": {"mode": "on", "interleaved_history": True}}
|
|
12
|
+
assert parse_interleaved_history(body) is True
|
|
13
|
+
assert parse_interleaved_history({"thinking": {"interleaved_history": False}}) is False
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def test_parse_interleaved_history_top_level() -> None:
|
|
17
|
+
assert parse_interleaved_history({"interleaved_history": True}) is True
|
|
18
|
+
assert parse_interleaved_history({}, extra={"interleaved_history": True}) is True
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def test_strip_reasoning_fields_when_disabled() -> None:
|
|
22
|
+
msgs = [
|
|
23
|
+
{
|
|
24
|
+
"role": "assistant",
|
|
25
|
+
"content": "answer",
|
|
26
|
+
"reasoning": "thought",
|
|
27
|
+
"reasoning_content": "thought",
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
out = apply_thinking_history_policy(msgs, False)
|
|
31
|
+
assert out[0]["content"] == "answer"
|
|
32
|
+
assert "reasoning" not in out[0]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def test_strip_entropy_thinking_blocks_when_disabled() -> None:
|
|
36
|
+
msgs = [
|
|
37
|
+
{
|
|
38
|
+
"role": "assistant",
|
|
39
|
+
"content": [
|
|
40
|
+
{"type": "thinking", "thinking": "step 1"},
|
|
41
|
+
{"type": "text", "text": "hello"},
|
|
42
|
+
],
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
out = apply_thinking_history_policy(msgs, False)
|
|
46
|
+
assert out[0]["content"] == "hello"
|
|
47
|
+
assert "reasoning" not in out[0]
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def test_preserve_entropy_thinking_blocks_when_enabled() -> None:
|
|
51
|
+
msgs = [
|
|
52
|
+
{
|
|
53
|
+
"role": "assistant",
|
|
54
|
+
"content": [
|
|
55
|
+
{"type": "thinking", "thinking": "step 1"},
|
|
56
|
+
{"type": "text", "text": "hello"},
|
|
57
|
+
],
|
|
58
|
+
}
|
|
59
|
+
]
|
|
60
|
+
out = apply_thinking_history_policy(msgs, True)
|
|
61
|
+
assert out[0]["reasoning"] == "step 1"
|
|
62
|
+
assert out[0]["reasoning_content"] == "step 1"
|
|
63
|
+
assert out[0]["content"][0]["type"] == "thinking"
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def test_extract_reasoning_text_from_blocks() -> None:
|
|
67
|
+
msg = {
|
|
68
|
+
"role": "assistant",
|
|
69
|
+
"content": [{"type": "thinking", "thinking": "a"}, {"type": "text", "text": "b"}],
|
|
70
|
+
}
|
|
71
|
+
assert extract_reasoning_text(msg) == "a"
|
|
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.21 → echotools-2.3.22}/src/echotools/exec/fncall/protocols/entml_thinking_parse.py
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
|
{echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/web/input_box/components/filezone.js
RENAMED
|
File without changes
|
{echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/web/input_box/components/motionkit.js
RENAMED
|
File without changes
|
{echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/web/input_box/components/sendbutton.js
RENAMED
|
File without changes
|
{echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/web/input_box/components/sortablelist.css
RENAMED
|
File without changes
|
{echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/web/input_box/components/sortablelist.js
RENAMED
|
File without changes
|
{echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/web/input_box/components/textinput.js
RENAMED
|
File without changes
|
{echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/web/input_box/components/voiceinput.js
RENAMED
|
File without changes
|
{echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/web/input_box/fonts/inter-500.woff2
RENAMED
|
File without changes
|
{echotools-2.3.21 → echotools-2.3.22}/src/echotools/media/web/input_box/fonts/inter-600.woff2
RENAMED
|
File without changes
|
{echotools-2.3.21 → echotools-2.3.22}/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
|
|
File without changes
|
|
File without changes
|