echotools 2.3.16__tar.gz → 2.3.19__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.16 → echotools-2.3.19}/PKG-INFO +1 -1
- {echotools-2.3.16 → echotools-2.3.19}/pyproject.toml +1 -1
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/fncall/prompt/inject.py +6 -0
- echotools-2.3.19/src/echotools/exec/fncall/protocols/entml_thinking.py +141 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools.egg-info/PKG-INFO +1 -1
- {echotools-2.3.16 → echotools-2.3.19}/src/tests/test_entml_protocol.py +81 -7
- echotools-2.3.16/src/echotools/exec/fncall/protocols/entml_thinking.py +0 -53
- {echotools-2.3.16 → echotools-2.3.19}/README.md +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/docs/README.md +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/setup.cfg +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/__init__.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/base/cache/__init__.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/base/cache/list_cache.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/base/cache/memory_cache.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/base/config/__init__.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/base/config/base.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/base/config/center.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/base/config/center_notify.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/base/config/center_template.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/base/config/loader.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/base/config/merge.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/base/errors/__init__.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/base/errors/base.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/base/errors/classify.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/base/errors/common.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/base/errors/http.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/base/ids/__init__.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/base/ids/generator.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/base/io/__init__.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/base/io/io_utils.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/base/io/printstream.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/base/logger/__init__.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/base/logger/manager.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/base/retry/__init__.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/base/retry/retry.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/compat.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/dispatch/__init__.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/dispatch/candidate.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/dispatch/dispatcher.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/dispatch/proxy_selector.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/dispatch/race.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/dispatch/selector.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/dispatch/usage.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/fncall/__init__.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/fncall/parsers/__init__.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/fncall/parsers/stream.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/fncall/parsers/xml_params.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/fncall/parsers/xml_parser.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/fncall/prompt/__init__.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/fncall/prompt/history.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/fncall/prompt/history_format.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/fncall/prompt/prompt_helpers.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/fncall/prompt/templates.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/fncall/protocols/__init__.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/fncall/protocols/entml.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/fncall/protocols/entml_invoke.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/fncall/protocols/entml_patterns.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/fncall/protocols/entml_thinking_parse.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/fncall/protocols/entml_tools.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/fncall/protocols/entml_values.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/fncall/registry.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/fncall/shared/__init__.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/fncall/shared/coercion.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/fncall/shared/loop_detect.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/fncall/shared/normalization.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/fncall/shared/schema_render.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/fncall/shared/xml_helpers.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/keys.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/lifecycle/__init__.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/lifecycle/manager.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/lifecycle/updater.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/lifecycle/updater_pull.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/process/__init__.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/process/port.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/protocol/__init__.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/protocol/base.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/terminal/__init__.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/terminal/conpty.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/terminal/local/__init__.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/terminal/local/core.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/terminal/local/proc.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/terminal/local/unix.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/terminal/local/win.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/terminal/sanitize.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/terminal/session/__init__.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/terminal/session/base.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/terminal/session/client.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/terminal/ssh.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/exec/terminal/tmux.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/events/__init__.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/events/bus.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/events/event.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/spinner/__init__.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/spinner/spinner.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/spinner/spinner_color.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/tracing/__init__.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/tracing/context.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/tracing/span.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/tracing/tracer.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/translate.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/watcher/__init__.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/watcher/file_watcher.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/web/__init__.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/web/application.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/web/broker.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/web/input_box/app.js +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/web/input_box/components/filezone.js +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/web/input_box/components/motionkit.js +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/web/input_box/components/sendbutton.js +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/web/input_box/components/sortablelist.css +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/web/input_box/components/sortablelist.js +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/web/input_box/components/textinput.js +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/web/input_box/components/voiceinput.js +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/web/input_box/fonts/inter-500.woff2 +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/web/input_box/fonts/inter-600.woff2 +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/web/input_box/fonts/inter400.woff2 +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/web/input_box/fonts/tailwind.css +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/web/input_box/inputbox.css +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/web/input_box/inputbox.js +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/web/input_box/style.css +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/web/input_box/voicegif.js +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/web/middleware.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/web/stats.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/web/utils.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/plat/files/__init__.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/plat/files/file_util.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/plat/network/__init__.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/plat/network/http_utils.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/plat/plugin/__init__.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/plat/plugin/base.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/plat/plugin/discovery.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/plat/plugin/registry.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/plat/plugin/registry_ops.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/plat/proxy/__init__.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/plat/proxy/manager.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/plat/runtime/__init__.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/plat/runtime/collector.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/plat/scheduler/__init__.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/plat/scheduler/scheduler.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/plat/sdk/__init__.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/plat/sdk/facade.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools/version.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools.egg-info/SOURCES.txt +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools.egg-info/dependency_links.txt +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools.egg-info/requires.txt +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/echotools.egg-info/top_level.txt +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/tests/bench_import.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/tests/conftest.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/tests/test_cache_retry.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/tests/test_completion.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/tests/test_config.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/tests/test_config_extended.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/tests/test_coverage_core.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/tests/test_dispatch.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/tests/test_dispatch_extended.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/tests/test_dispatch_race.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/tests/test_entml_thinking_parse.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/tests/test_entml_tools.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/tests/test_errors.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/tests/test_errors_common.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/tests/test_events.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/tests/test_events_event.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/tests/test_facade.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/tests/test_fncall.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/tests/test_ids.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/tests/test_imports.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/tests/test_io.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/tests/test_keys.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/tests/test_lifecycle.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/tests/test_logger.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/tests/test_merge.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/tests/test_plugin.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/tests/test_printstream.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/tests/test_protocols.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/tests/test_proxy.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/tests/test_proxy_selector.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/tests/test_runtime.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/tests/test_scheduler.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/tests/test_tracing.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/tests/test_usage.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/tests/test_web.py +0 -0
- {echotools-2.3.16 → echotools-2.3.19}/src/tests/test_web_broker.py +0 -0
|
@@ -21,6 +21,7 @@ from echotools.exec.fncall.protocols.entml import (
|
|
|
21
21
|
format_entml_conversation_history,
|
|
22
22
|
format_entml_current_user_message,
|
|
23
23
|
)
|
|
24
|
+
from echotools.exec.fncall.protocols.entml_thinking import build_entml_thinking_section
|
|
24
25
|
from echotools.exec.fncall.shared.loop_detect import detect_tool_loop
|
|
25
26
|
from echotools.exec.fncall.shared.normalization import format_tool_descs
|
|
26
27
|
from echotools.exec.protocol.base import ToolProtocol
|
|
@@ -108,12 +109,17 @@ def inject_fncall(
|
|
|
108
109
|
if not tools:
|
|
109
110
|
if protocol.id == "entml":
|
|
110
111
|
sections: List[str] = []
|
|
112
|
+
thinking_section = build_entml_thinking_section(protocol_options)
|
|
113
|
+
if thinking_section:
|
|
114
|
+
sections.append(thinking_section)
|
|
111
115
|
if history_text.strip():
|
|
112
116
|
sections.append(format_entml_conversation_history(history_text))
|
|
113
117
|
sections.append(format_entml_current_user_message(current_user_message))
|
|
114
118
|
prompt = "\n\n".join(sections)
|
|
115
119
|
else:
|
|
116
120
|
prompt = build_no_tools_prompt(history_text, current_user_message)
|
|
121
|
+
if dump_prompt:
|
|
122
|
+
_maybe_dump_prompt(prompt, dump_dir)
|
|
117
123
|
return [{"role": "user", "content": prompt}]
|
|
118
124
|
|
|
119
125
|
prompt = build_tools_prompt(
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict, Optional
|
|
4
|
+
|
|
5
|
+
_CANONICAL_MODES = frozenset({"off", "on", "auto"})
|
|
6
|
+
|
|
7
|
+
_OFF_ALIASES = frozenset(
|
|
8
|
+
{"off", "disabled", "disable", "false", "none", "no", "never"}
|
|
9
|
+
)
|
|
10
|
+
_ON_ALIASES = frozenset(
|
|
11
|
+
{
|
|
12
|
+
"on",
|
|
13
|
+
"enabled",
|
|
14
|
+
"enable",
|
|
15
|
+
"true",
|
|
16
|
+
"force",
|
|
17
|
+
"forced",
|
|
18
|
+
"required",
|
|
19
|
+
"must",
|
|
20
|
+
"static",
|
|
21
|
+
"thinking",
|
|
22
|
+
}
|
|
23
|
+
)
|
|
24
|
+
_AUTO_ALIASES = frozenset(
|
|
25
|
+
{"auto", "automatic", "adaptive", "interleaved"}
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
_THINKING_BLOCK_OPEN = "<entml:thinking>"
|
|
29
|
+
_THINKING_BLOCK_CLOSE = "</entml:thinking>"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def normalize_thinking_mode(mode: Any) -> Optional[str]:
|
|
33
|
+
"""将外界声明归一化为 off | on | auto;无法识别时返回 None。"""
|
|
34
|
+
if mode is None:
|
|
35
|
+
return None
|
|
36
|
+
key = str(mode).strip().lower()
|
|
37
|
+
if not key:
|
|
38
|
+
return None
|
|
39
|
+
if key in _OFF_ALIASES:
|
|
40
|
+
return "off"
|
|
41
|
+
if key in _ON_ALIASES:
|
|
42
|
+
return "on"
|
|
43
|
+
if key in _AUTO_ALIASES:
|
|
44
|
+
return "auto"
|
|
45
|
+
if key in _CANONICAL_MODES:
|
|
46
|
+
return key
|
|
47
|
+
return None
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _policy_header(mode: str) -> str:
|
|
51
|
+
labels = {
|
|
52
|
+
"off": "off (forced no thinking)",
|
|
53
|
+
"on": "on (forced thinking)",
|
|
54
|
+
"auto": "auto (model decides)",
|
|
55
|
+
}
|
|
56
|
+
return (
|
|
57
|
+
f"The thinking_mode for this request is {labels[mode]}. "
|
|
58
|
+
f"Follow the rules below exactly."
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _prompt_off() -> list[str]:
|
|
63
|
+
return [
|
|
64
|
+
_policy_header("off"),
|
|
65
|
+
"",
|
|
66
|
+
"You must NOT output any thinking blocks in this response.",
|
|
67
|
+
f"Do not write `{_THINKING_BLOCK_OPEN}` or `{_THINKING_BLOCK_CLOSE}`.",
|
|
68
|
+
"Respond with only the visible answer text and any "
|
|
69
|
+
"`<entml:function_calls>` blocks if tools are needed.",
|
|
70
|
+
]
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _prompt_on() -> list[str]:
|
|
74
|
+
return [
|
|
75
|
+
_policy_header("on"),
|
|
76
|
+
"",
|
|
77
|
+
"You MUST output a thinking block before any other content.",
|
|
78
|
+
"At the very start of your response, output:",
|
|
79
|
+
"",
|
|
80
|
+
_THINKING_BLOCK_OPEN,
|
|
81
|
+
"...your reasoning here...",
|
|
82
|
+
_THINKING_BLOCK_CLOSE,
|
|
83
|
+
"",
|
|
84
|
+
"Only after that block, output your visible reply and/or "
|
|
85
|
+
"`<entml:function_calls>`. Never skip the thinking block.",
|
|
86
|
+
]
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _prompt_auto() -> list[str]:
|
|
90
|
+
return [
|
|
91
|
+
_policy_header("auto"),
|
|
92
|
+
"",
|
|
93
|
+
"Thinking blocks are optional but encouraged when they would help.",
|
|
94
|
+
"At the very start of your response, think carefully about whether "
|
|
95
|
+
f"a `{_THINKING_BLOCK_OPEN}` `{_THINKING_BLOCK_CLOSE}` block would be "
|
|
96
|
+
"appropriate and strongly prefer to output one if you are uncertain.",
|
|
97
|
+
"",
|
|
98
|
+
"After function results, you should strongly consider outputting a "
|
|
99
|
+
"thinking block before continuing. Example:",
|
|
100
|
+
"",
|
|
101
|
+
"<entml:function_calls>",
|
|
102
|
+
"...",
|
|
103
|
+
"</entml:function_calls>",
|
|
104
|
+
"",
|
|
105
|
+
"<function_results>",
|
|
106
|
+
"...",
|
|
107
|
+
"</function_results>",
|
|
108
|
+
"",
|
|
109
|
+
_THINKING_BLOCK_OPEN,
|
|
110
|
+
"...thinking about results...",
|
|
111
|
+
_THINKING_BLOCK_CLOSE,
|
|
112
|
+
]
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def build_entml_thinking_section(
|
|
116
|
+
protocol_options: Optional[Dict[str, Any]] = None,
|
|
117
|
+
) -> str:
|
|
118
|
+
"""按 thinking_mode 构建思考链指令块(off / on / auto 三套 prompt)。"""
|
|
119
|
+
opts = protocol_options or {}
|
|
120
|
+
mode = normalize_thinking_mode(opts.get("thinking_mode"))
|
|
121
|
+
max_thinking_length = opts.get("max_thinking_length")
|
|
122
|
+
|
|
123
|
+
if mode is None and max_thinking_length is None:
|
|
124
|
+
return ""
|
|
125
|
+
|
|
126
|
+
lines: list[str] = []
|
|
127
|
+
if mode is not None:
|
|
128
|
+
lines.append(f"<entml:thinking_mode>{mode}</entml:thinking_mode>")
|
|
129
|
+
if max_thinking_length is not None:
|
|
130
|
+
lines.append(
|
|
131
|
+
f"<entml:max_thinking_length>{int(max_thinking_length)}</entml:max_thinking_length>"
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
if mode == "off":
|
|
135
|
+
lines.extend([""] + _prompt_off())
|
|
136
|
+
elif mode == "on":
|
|
137
|
+
lines.extend([""] + _prompt_on())
|
|
138
|
+
elif mode == "auto":
|
|
139
|
+
lines.extend([""] + _prompt_auto())
|
|
140
|
+
|
|
141
|
+
return "\n".join(lines)
|
|
@@ -6,7 +6,10 @@ import pytest
|
|
|
6
6
|
|
|
7
7
|
from echotools.exec.fncall import get_protocol, inject_fncall
|
|
8
8
|
from echotools.exec.fncall.protocols.entml_invoke import parse_entml_tool_calls
|
|
9
|
-
from echotools.exec.fncall.protocols.entml_thinking import
|
|
9
|
+
from echotools.exec.fncall.protocols.entml_thinking import (
|
|
10
|
+
build_entml_thinking_section,
|
|
11
|
+
normalize_thinking_mode,
|
|
12
|
+
)
|
|
10
13
|
from echotools.exec.fncall.protocols.entml_values import coerce_entml_parameter_value
|
|
11
14
|
from echotools.exec.fncall.shared.coercion import _build_param_schema_index
|
|
12
15
|
|
|
@@ -54,13 +57,13 @@ def test_inject_with_thinking_options_only_when_declared() -> None:
|
|
|
54
57
|
tools,
|
|
55
58
|
proto,
|
|
56
59
|
protocol_options={
|
|
57
|
-
"thinking_mode": "
|
|
60
|
+
"thinking_mode": "on",
|
|
58
61
|
"max_thinking_length": 22000,
|
|
59
62
|
},
|
|
60
63
|
)[0]["content"]
|
|
61
|
-
assert "<entml:thinking_mode>
|
|
64
|
+
assert "<entml:thinking_mode>on</entml:thinking_mode>" in with_opts
|
|
62
65
|
assert "<entml:max_thinking_length>22000</entml:max_thinking_length>" in with_opts
|
|
63
|
-
assert "
|
|
66
|
+
assert "MUST output a thinking block" in with_opts
|
|
64
67
|
assert "At the very start of your response" in with_opts
|
|
65
68
|
|
|
66
69
|
|
|
@@ -69,6 +72,76 @@ def test_build_entml_thinking_section_empty_without_options() -> None:
|
|
|
69
72
|
assert build_entml_thinking_section({}) == ""
|
|
70
73
|
|
|
71
74
|
|
|
75
|
+
@pytest.mark.parametrize(
|
|
76
|
+
"raw,expected",
|
|
77
|
+
[
|
|
78
|
+
("off", "off"),
|
|
79
|
+
("disabled", "off"),
|
|
80
|
+
("on", "on"),
|
|
81
|
+
("enabled", "on"),
|
|
82
|
+
("interleaved", "auto"),
|
|
83
|
+
("auto", "auto"),
|
|
84
|
+
("adaptive", "auto"),
|
|
85
|
+
("bogus", None),
|
|
86
|
+
],
|
|
87
|
+
)
|
|
88
|
+
def test_normalize_thinking_mode(raw, expected) -> None:
|
|
89
|
+
assert normalize_thinking_mode(raw) == expected
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def test_thinking_prompt_off() -> None:
|
|
93
|
+
section = build_entml_thinking_section({"thinking_mode": "off"})
|
|
94
|
+
assert "<entml:thinking_mode>off</entml:thinking_mode>" in section
|
|
95
|
+
assert "forced no thinking" in section
|
|
96
|
+
assert "You must NOT output any thinking blocks" in section
|
|
97
|
+
assert "MUST output a thinking block" not in section
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def test_thinking_prompt_on() -> None:
|
|
101
|
+
section = build_entml_thinking_section({"thinking_mode": "on"})
|
|
102
|
+
assert "<entml:thinking_mode>on</entml:thinking_mode>" in section
|
|
103
|
+
assert "forced thinking" in section
|
|
104
|
+
assert "MUST output a thinking block" in section
|
|
105
|
+
assert "<entml:thinking>" in section
|
|
106
|
+
assert "You must NOT output any thinking blocks" not in section
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def test_thinking_prompt_auto() -> None:
|
|
110
|
+
section = build_entml_thinking_section({"thinking_mode": "auto"})
|
|
111
|
+
assert "<entml:thinking_mode>auto</entml:thinking_mode>" in section
|
|
112
|
+
assert "model decides" in section
|
|
113
|
+
assert "<function_results>" in section
|
|
114
|
+
assert "strongly prefer to output one if you are uncertain" in section
|
|
115
|
+
assert "MUST output a thinking block" not in section
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def test_inject_no_tools_with_thinking_off() -> None:
|
|
119
|
+
proto = get_protocol("entml")
|
|
120
|
+
msgs = [{"role": "user", "content": "hi"}]
|
|
121
|
+
result = inject_fncall(
|
|
122
|
+
msgs,
|
|
123
|
+
[],
|
|
124
|
+
proto,
|
|
125
|
+
protocol_options={"thinking_mode": "off"},
|
|
126
|
+
)[0]["content"]
|
|
127
|
+
assert "<entml:thinking_mode>off</entml:thinking_mode>" in result
|
|
128
|
+
assert "You must NOT output any thinking blocks" in result
|
|
129
|
+
assert "<current_user_message>\nhi\n</current_user_message>" in result
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def test_inject_no_tools_with_thinking_on() -> None:
|
|
133
|
+
proto = get_protocol("entml")
|
|
134
|
+
msgs = [{"role": "user", "content": "hi"}]
|
|
135
|
+
result = inject_fncall(
|
|
136
|
+
msgs,
|
|
137
|
+
[],
|
|
138
|
+
proto,
|
|
139
|
+
protocol_options={"thinking_mode": "on"},
|
|
140
|
+
)[0]["content"]
|
|
141
|
+
assert "<entml:thinking_mode>on</entml:thinking_mode>" in result
|
|
142
|
+
assert "MUST output a thinking block" in result
|
|
143
|
+
|
|
144
|
+
|
|
72
145
|
def test_inject_with_history_entml_tags() -> None:
|
|
73
146
|
proto = get_protocol("entml")
|
|
74
147
|
tools = [
|
|
@@ -167,7 +240,7 @@ def test_entml_instruction_matches_spec_format() -> None:
|
|
|
167
240
|
lang="en",
|
|
168
241
|
current_user_message="pick one",
|
|
169
242
|
protocol_options={
|
|
170
|
-
"thinking_mode": "
|
|
243
|
+
"thinking_mode": "on",
|
|
171
244
|
"max_thinking_length": 22000,
|
|
172
245
|
},
|
|
173
246
|
)
|
|
@@ -179,9 +252,10 @@ def test_entml_instruction_matches_spec_format() -> None:
|
|
|
179
252
|
assert '<entml:invoke name="$FUNCTION_NAME">' in prompt
|
|
180
253
|
assert '<entml:parameter name="$PARAMETER_NAME">' in prompt
|
|
181
254
|
assert "String and scalar parameters should be specified as is" in prompt
|
|
182
|
-
assert "<entml:thinking_mode>
|
|
255
|
+
assert "<entml:thinking_mode>on</entml:thinking_mode>" in prompt
|
|
183
256
|
assert "<entml:max_thinking_length>22000</entml:max_thinking_length>" in prompt
|
|
184
|
-
assert "
|
|
257
|
+
assert "MUST output a thinking block" in prompt
|
|
258
|
+
assert "<function_results>" not in prompt
|
|
185
259
|
assert "<entml:conversation_history>" not in prompt
|
|
186
260
|
assert "<entml:history>" not in prompt
|
|
187
261
|
assert "<functions>" not in prompt
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from typing import Any, Dict, Optional
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def build_entml_thinking_section(
|
|
7
|
-
protocol_options: Optional[Dict[str, Any]] = None,
|
|
8
|
-
) -> str:
|
|
9
|
-
"""仅当外界声明 thinking_mode / max_thinking_length 时构建思考链指令块。"""
|
|
10
|
-
opts = protocol_options or {}
|
|
11
|
-
thinking_mode = opts.get("thinking_mode")
|
|
12
|
-
max_thinking_length = opts.get("max_thinking_length")
|
|
13
|
-
|
|
14
|
-
if thinking_mode is None and max_thinking_length is None:
|
|
15
|
-
return ""
|
|
16
|
-
|
|
17
|
-
lines: list[str] = []
|
|
18
|
-
if thinking_mode is not None:
|
|
19
|
-
mode = str(thinking_mode).strip()
|
|
20
|
-
if mode:
|
|
21
|
-
lines.append(f"<entml:thinking_mode>{mode}</entml:thinking_mode>")
|
|
22
|
-
if max_thinking_length is not None:
|
|
23
|
-
lines.append(
|
|
24
|
-
f"<entml:max_thinking_length>{int(max_thinking_length)}</entml:max_thinking_length>"
|
|
25
|
-
)
|
|
26
|
-
|
|
27
|
-
mode_lower = str(thinking_mode or "").strip().lower()
|
|
28
|
-
if mode_lower in ("interleaved", "auto"):
|
|
29
|
-
lines.extend(
|
|
30
|
-
[
|
|
31
|
-
"",
|
|
32
|
-
"If the thinking_mode is interleaved or auto, then after function "
|
|
33
|
-
"results you should strongly consider outputting a thinking block. "
|
|
34
|
-
"Here is an example:",
|
|
35
|
-
"",
|
|
36
|
-
"<entml:function_calls>",
|
|
37
|
-
"...",
|
|
38
|
-
"</entml:function_calls>",
|
|
39
|
-
"",
|
|
40
|
-
"<function_results>",
|
|
41
|
-
"...",
|
|
42
|
-
"</function_results>",
|
|
43
|
-
"",
|
|
44
|
-
"<entml:thinking>",
|
|
45
|
-
"...thinking about results",
|
|
46
|
-
"</entml:thinking>",
|
|
47
|
-
"At the very start of your response, think carefully about whether "
|
|
48
|
-
"an `<entml:thinking>` `</entml:thinking>` block would be appropriate "
|
|
49
|
-
"and strongly prefer to output a thinking block if you are uncertain.",
|
|
50
|
-
]
|
|
51
|
-
)
|
|
52
|
-
|
|
53
|
-
return "\n".join(lines)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
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.16 → echotools-2.3.19}/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.16 → echotools-2.3.19}/src/echotools/media/web/input_box/components/filezone.js
RENAMED
|
File without changes
|
{echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/web/input_box/components/motionkit.js
RENAMED
|
File without changes
|
{echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/web/input_box/components/sendbutton.js
RENAMED
|
File without changes
|
{echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/web/input_box/components/sortablelist.css
RENAMED
|
File without changes
|
{echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/web/input_box/components/sortablelist.js
RENAMED
|
File without changes
|
{echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/web/input_box/components/textinput.js
RENAMED
|
File without changes
|
{echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/web/input_box/components/voiceinput.js
RENAMED
|
File without changes
|
{echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/web/input_box/fonts/inter-500.woff2
RENAMED
|
File without changes
|
{echotools-2.3.16 → echotools-2.3.19}/src/echotools/media/web/input_box/fonts/inter-600.woff2
RENAMED
|
File without changes
|
{echotools-2.3.16 → echotools-2.3.19}/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
|