echotools 2.3.2__tar.gz → 2.3.4__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.2 → echotools-2.3.4}/PKG-INFO +2 -3
- {echotools-2.3.2 → echotools-2.3.4}/pyproject.toml +3 -4
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/fncall/prompt/history.py +49 -1
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/fncall/prompt/inject.py +33 -16
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/fncall/protocols/entml.py +33 -3
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools.egg-info/PKG-INFO +2 -3
- {echotools-2.3.2 → echotools-2.3.4}/README.md +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/setup.cfg +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/__init__.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/_version.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/cache/__init__.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/cache/list_cache.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/cache/memory_cache.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/config/__init__.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/config/base.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/config/center.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/config/loader.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/config/merge.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/dispatch/__init__.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/dispatch/candidate.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/dispatch/dispatcher.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/dispatch/proxy_selector.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/dispatch/selector.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/dispatch/usage.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/errors/__init__.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/errors/base.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/errors/classify.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/errors/common.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/errors/http.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/events/__init__.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/events/bus.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/events/event.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/files/__init__.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/files/file_util.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/fncall/__init__.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/fncall/parsers/__init__.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/fncall/parsers/stream.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/fncall/parsers/xml_parser.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/fncall/prompt/__init__.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/fncall/prompt/templates.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/fncall/protocols/__init__.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/fncall/registry.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/fncall/shared/__init__.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/fncall/shared/coercion.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/fncall/shared/loop_detect.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/fncall/shared/normalization.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/fncall/shared/xml_helpers.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/ids/__init__.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/ids/generator.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/io/__init__.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/io/io_utils.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/io/printstream.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/keys.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/lifecycle/__init__.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/lifecycle/manager.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/lifecycle/updater.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/logger/__init__.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/logger/manager.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/network/__init__.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/network/http_utils.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/plugin/__init__.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/plugin/base.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/plugin/discovery.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/plugin/registry.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/process/__init__.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/process/port.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/protocol/__init__.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/protocol/base.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/proxy/__init__.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/proxy/manager.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/py.typed +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/retry/__init__.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/retry/retry.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/runtime/__init__.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/runtime/collector.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/scheduler/__init__.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/scheduler/scheduler.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/sdk/__init__.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/sdk/facade.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/terminal/__init__.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/terminal/conpty.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/terminal/local.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/terminal/sanitize.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/terminal/session.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/terminal/ssh.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/terminal/tmux.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/tracing/__init__.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/tracing/context.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/tracing/span.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/tracing/tracer.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/translate.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/watcher/__init__.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/watcher/file_watcher.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/web/__init__.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/web/application.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/web/broker.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/web/input_box/app.js +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/web/input_box/file-zone/file-zone.js +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/web/input_box/fonts/inter-400.woff2 +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/web/input_box/fonts/inter-500.woff2 +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/web/input_box/fonts/inter-600.woff2 +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/web/input_box/fonts/tailwind.min.css +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/web/input_box/input-box.css +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/web/input_box/input-box.js +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/web/input_box/motion-kit/motion-kit.js +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/web/input_box/send-button/send-button.js +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/web/input_box/sortable-list/sortable-list.css +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/web/input_box/sortable-list/sortable-list.js +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/web/input_box/style.css +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/web/input_box/text-input/text-input.js +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/web/input_box/voice-input/voice-input.js +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/web/middleware.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/web/stats.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools/web/utils.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools.egg-info/SOURCES.txt +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools.egg-info/dependency_links.txt +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools.egg-info/requires.txt +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/src/echotools.egg-info/top_level.txt +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/tests/test_cache_retry.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/tests/test_completion.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/tests/test_config.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/tests/test_config_extended.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/tests/test_coverage_core.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/tests/test_dispatch.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/tests/test_dispatch_extended.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/tests/test_dispatch_race.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/tests/test_errors.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/tests/test_errors_common.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/tests/test_events.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/tests/test_events_event.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/tests/test_facade.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/tests/test_fncall.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/tests/test_ids.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/tests/test_imports.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/tests/test_io.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/tests/test_keys.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/tests/test_lifecycle.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/tests/test_logger.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/tests/test_merge.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/tests/test_plugin.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/tests/test_printstream.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/tests/test_protocols.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/tests/test_proxy.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/tests/test_proxy_selector.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/tests/test_runtime.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/tests/test_scheduler.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/tests/test_tracing.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/tests/test_usage.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/tests/test_web.py +0 -0
- {echotools-2.3.2 → echotools-2.3.4}/tests/test_web_broker.py +0 -0
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: echotools
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.4
|
|
4
4
|
Summary: 通用基础设施 SDK:配置、日志、事件、调度、插件、协议、调用链
|
|
5
5
|
Author: nichengfuben
|
|
6
|
-
License: MIT
|
|
6
|
+
License-Expression: MIT
|
|
7
7
|
Project-URL: Homepage, https://github.com/nichengfuben/echotools
|
|
8
8
|
Project-URL: Repository, https://github.com/nichengfuben/echotools
|
|
9
9
|
Project-URL: Issues, https://github.com/nichengfuben/echotools/issues
|
|
10
10
|
Classifier: Development Status :: 4 - Beta
|
|
11
11
|
Classifier: Intended Audience :: Developers
|
|
12
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
13
12
|
Classifier: Programming Language :: Python :: 3
|
|
14
13
|
Classifier: Programming Language :: Python :: 3.8
|
|
15
14
|
Classifier: Programming Language :: Python :: 3.9
|
|
@@ -4,16 +4,15 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "echotools"
|
|
7
|
-
version = "2.3.
|
|
7
|
+
version = "2.3.4"
|
|
8
8
|
description = "通用基础设施 SDK:配置、日志、事件、调度、插件、协议、调用链"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.8"
|
|
11
|
-
license =
|
|
11
|
+
license = "MIT"
|
|
12
12
|
authors = [{ name = "nichengfuben" }]
|
|
13
13
|
classifiers = [
|
|
14
14
|
"Development Status :: 4 - Beta",
|
|
15
15
|
"Intended Audience :: Developers",
|
|
16
|
-
"License :: OSI Approved :: MIT License",
|
|
17
16
|
"Programming Language :: Python :: 3",
|
|
18
17
|
"Programming Language :: Python :: 3.8",
|
|
19
18
|
"Programming Language :: Python :: 3.9",
|
|
@@ -136,4 +135,4 @@ exclude_lines = [
|
|
|
136
135
|
"def __repr__",
|
|
137
136
|
"if TYPE_CHECKING:",
|
|
138
137
|
"raise NotImplementedError",
|
|
139
|
-
]
|
|
138
|
+
]
|
|
@@ -36,6 +36,45 @@ _TOOL_CALL_MARKER_RE = re.compile(
|
|
|
36
36
|
r"|<invoke\s+name=",
|
|
37
37
|
)
|
|
38
38
|
|
|
39
|
+
# entml 标签清理正则
|
|
40
|
+
_ENTML_FNCALL_BLOCK_RE = re.compile(
|
|
41
|
+
r"<entml:function_calls\b[^>]*>.*?</entml:function_calls>",
|
|
42
|
+
re.DOTALL,
|
|
43
|
+
)
|
|
44
|
+
_ENTML_INVOKE_RE = re.compile(
|
|
45
|
+
r'<entml:invoke\s+name="[^"]+"\s*>.*?</entml:invoke>',
|
|
46
|
+
re.DOTALL,
|
|
47
|
+
)
|
|
48
|
+
_ENTML_PARAMETERS_RE = re.compile(
|
|
49
|
+
r'<entml:parameters>.*?</entml:parameters>',
|
|
50
|
+
re.DOTALL,
|
|
51
|
+
)
|
|
52
|
+
_ENTML_PARAM_RE = re.compile(
|
|
53
|
+
r'<entml:parameter\s+name="[^"]+"\s*>.*?</entml:parameter>',
|
|
54
|
+
re.DOTALL,
|
|
55
|
+
)
|
|
56
|
+
# 清理任意 entml:* 标签
|
|
57
|
+
_ENTML_ANY_TAG_RE = re.compile(
|
|
58
|
+
r'<entml:[a-zA-Z_][\w]*\b[^>]*>.*?</entml:[a-zA-Z_][\w]*>',
|
|
59
|
+
re.DOTALL,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _clean_entml_tags(content: str) -> str:
|
|
64
|
+
"""移除内容中的所有 entml 标签及其内部内容。"""
|
|
65
|
+
if not content:
|
|
66
|
+
return content
|
|
67
|
+
cleaned = content
|
|
68
|
+
cleaned = _ENTML_FNCALL_BLOCK_RE.sub("", cleaned)
|
|
69
|
+
cleaned = _ENTML_INVOKE_RE.sub("", cleaned)
|
|
70
|
+
cleaned = _ENTML_PARAMETERS_RE.sub("", cleaned)
|
|
71
|
+
cleaned = _ENTML_PARAM_RE.sub("", cleaned)
|
|
72
|
+
cleaned = _ENTML_ANY_TAG_RE.sub("", cleaned)
|
|
73
|
+
# 清理多余空行
|
|
74
|
+
lines = [line for line in cleaned.splitlines() if line.strip()]
|
|
75
|
+
return "\n".join(lines)
|
|
76
|
+
|
|
77
|
+
|
|
39
78
|
# ---------------------------------------------------------------------------
|
|
40
79
|
# 渲染工具调用 / 工具结果
|
|
41
80
|
# ---------------------------------------------------------------------------
|
|
@@ -335,6 +374,7 @@ def _format_conversation_history(
|
|
|
335
374
|
protocol: 可选的 ToolProtocol 实例。提供时使用
|
|
336
375
|
protocol.format_assistant_tool_calls() 渲染工具调用,
|
|
337
376
|
确保历史中的工具调用格式与 LLM 指令中的格式一致。
|
|
377
|
+
同时使用 protocol.clean_tags() 清理 user 消息中的 entml 标签。
|
|
338
378
|
|
|
339
379
|
始终渲染所有消息角色(包括 assistant tool_calls 和 tool results),
|
|
340
380
|
不区分客户端类型。
|
|
@@ -346,11 +386,19 @@ def _format_conversation_history(
|
|
|
346
386
|
seen_assistant_keys: Set[Tuple[str, Tuple[Tuple[str, str], ...]]] = set()
|
|
347
387
|
parts: List[Tuple[str, bool]] = []
|
|
348
388
|
|
|
389
|
+
# 获取清理函数
|
|
390
|
+
clean_fn = None
|
|
391
|
+
if protocol and hasattr(protocol, 'clean_tags'):
|
|
392
|
+
clean_fn = protocol.clean_tags
|
|
393
|
+
|
|
349
394
|
for m in messages:
|
|
350
395
|
role: str = m.get("role") or "user"
|
|
351
396
|
content_str = normalize_content(m.get("content", ""))
|
|
352
397
|
|
|
353
398
|
if role == "user":
|
|
399
|
+
# 清理用户消息中的 entml 标签
|
|
400
|
+
if clean_fn:
|
|
401
|
+
content_str = clean_fn(content_str)
|
|
354
402
|
parts.append((f"<user>\n{content_str}\n</user>", False))
|
|
355
403
|
|
|
356
404
|
elif role == "assistant":
|
|
@@ -371,7 +419,7 @@ def _format_conversation_history(
|
|
|
371
419
|
content_str and _TOOL_CALL_MARKER_RE.search(content_str)
|
|
372
420
|
)
|
|
373
421
|
if not content_has_markers:
|
|
374
|
-
if protocol is not None:
|
|
422
|
+
if protocol is not None and hasattr(protocol, 'format_assistant_tool_calls'):
|
|
375
423
|
blocks.append(protocol.format_assistant_tool_calls(tcs))
|
|
376
424
|
else:
|
|
377
425
|
for tc in tcs:
|
|
@@ -50,7 +50,9 @@ def inject_fncall(
|
|
|
50
50
|
dump_dir: Optional[str] = None,
|
|
51
51
|
) -> List[Dict[str, Any]]:
|
|
52
52
|
"""注入工具定义为单条 user 消息。
|
|
53
|
-
|
|
53
|
+
|
|
54
|
+
无论是否有 tools,都构建包含历史的 prompt 返回单条 user 消息。
|
|
55
|
+
|
|
54
56
|
Args:
|
|
55
57
|
messages: 消息列表。
|
|
56
58
|
tools: 工具定义。
|
|
@@ -64,26 +66,18 @@ def inject_fncall(
|
|
|
64
66
|
Returns:
|
|
65
67
|
单条 user 消息列表。
|
|
66
68
|
"""
|
|
67
|
-
if not tools:
|
|
68
|
-
return list(messages)
|
|
69
69
|
normalized = _normalize_messages(list(messages))
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
result = detect_tool_loop(normalized, loop_detection_threshold)
|
|
73
|
-
if result.is_looping:
|
|
74
|
-
logger.debug(
|
|
75
|
-
"检测到工具循环(%d 次)", result.repeat_count
|
|
76
|
-
)
|
|
77
|
-
loop_warning = result.suggestion
|
|
70
|
+
|
|
71
|
+
# 提取最后一条 user 消息和历史
|
|
78
72
|
last_user_idx: Optional[int] = None
|
|
79
73
|
for i in range(len(normalized) - 1, -1, -1):
|
|
80
74
|
if (normalized[i].get("role") or "user") == "user":
|
|
81
75
|
last_user_idx = i
|
|
82
76
|
break
|
|
77
|
+
|
|
83
78
|
if last_user_idx is not None:
|
|
84
79
|
history_messages = (
|
|
85
|
-
normalized[:last_user_idx]
|
|
86
|
-
+ normalized[last_user_idx + 1 :]
|
|
80
|
+
normalized[:last_user_idx] + normalized[last_user_idx + 1:]
|
|
87
81
|
)
|
|
88
82
|
current_user_message = normalize_content(
|
|
89
83
|
normalized[last_user_idx].get("content", "")
|
|
@@ -91,13 +85,34 @@ def inject_fncall(
|
|
|
91
85
|
else:
|
|
92
86
|
history_messages = normalized
|
|
93
87
|
current_user_message = ""
|
|
88
|
+
|
|
89
|
+
# 清理当前用户消息中的 entml 标签
|
|
90
|
+
if hasattr(protocol, 'clean_tags'):
|
|
91
|
+
current_user_message = protocol.clean_tags(current_user_message)
|
|
92
|
+
|
|
93
|
+
# 构建历史文本(传入 protocol 以便清理 user 消息中的 entml 标签)
|
|
94
|
+
history_text = _format_conversation_history(
|
|
95
|
+
history_messages, protocol=protocol
|
|
96
|
+
).strip()
|
|
97
|
+
|
|
98
|
+
# 如果没有 tools,直接拼历史 + 当前消息,不注入工具定义
|
|
99
|
+
if not tools:
|
|
100
|
+
prompt = f"<conversation_history>\n{history_text}\n</conversation_history>\n\n<current_user_message>\n{current_user_message}\n</current_user_message>"
|
|
101
|
+
return [{"role": "user", "content": prompt}]
|
|
102
|
+
|
|
103
|
+
# 有 tools:走原有逻辑
|
|
104
|
+
loop_warning = ""
|
|
105
|
+
if loop_detection_threshold > 0:
|
|
106
|
+
result = detect_tool_loop(normalized, loop_detection_threshold)
|
|
107
|
+
if result.is_looping:
|
|
108
|
+
logger.debug("检测到工具循环(%d 次)", result.repeat_count)
|
|
109
|
+
loop_warning = result.suggestion
|
|
110
|
+
|
|
94
111
|
if hasattr(protocol, 'format_tool_descs'):
|
|
95
112
|
tool_descs = protocol.format_tool_descs(tools)
|
|
96
113
|
else:
|
|
97
114
|
tool_descs = format_tool_descs(tools)
|
|
98
|
-
|
|
99
|
-
history_messages, protocol=protocol
|
|
100
|
-
).strip()
|
|
115
|
+
|
|
101
116
|
prompt = protocol.render_prompt(
|
|
102
117
|
tool_descs=tool_descs,
|
|
103
118
|
lang=lang,
|
|
@@ -106,6 +121,8 @@ def inject_fncall(
|
|
|
106
121
|
loop_warning=loop_warning,
|
|
107
122
|
current_user_message=current_user_message,
|
|
108
123
|
)
|
|
124
|
+
|
|
109
125
|
if dump_prompt:
|
|
110
126
|
_maybe_dump_prompt(prompt, dump_dir)
|
|
127
|
+
|
|
111
128
|
return [{"role": "user", "content": prompt}]
|
|
@@ -75,6 +75,29 @@ _PARAMETERS_RE = re.compile(
|
|
|
75
75
|
r'<entml:parameters>([\s\S]*?)</entml:parameters>',
|
|
76
76
|
re.DOTALL,
|
|
77
77
|
)
|
|
78
|
+
# 用于解析 <entml:parameters> 内的子标签
|
|
79
|
+
_SUB_TAG_RE = re.compile(
|
|
80
|
+
r'<([^>]+)>([\s\S]*?)</\1>',
|
|
81
|
+
re.DOTALL,
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _parse_sub_tags(content: str, schema_index: Optional[Dict[str, Any]] = None, func_name: str = "") -> Dict[str, Any]:
|
|
86
|
+
"""解析 <entml:parameters> 内的子标签,返回参数字典。"""
|
|
87
|
+
args: Dict[str, Any] = {}
|
|
88
|
+
for m in _SUB_TAG_RE.finditer(content):
|
|
89
|
+
pname = m.group(1).strip()
|
|
90
|
+
pval = m.group(2).strip()
|
|
91
|
+
pschema = schema_index.get(func_name, {}).get(pname, {}) if schema_index else {}
|
|
92
|
+
if pschema:
|
|
93
|
+
args[pname] = _coerce_param_value(pval, pschema)
|
|
94
|
+
else:
|
|
95
|
+
try:
|
|
96
|
+
args[pname] = json.loads(pval)
|
|
97
|
+
except json.JSONDecodeError:
|
|
98
|
+
args[pname] = pval
|
|
99
|
+
return args
|
|
100
|
+
|
|
78
101
|
|
|
79
102
|
# ---------------------------------------------------------------------------
|
|
80
103
|
# Entml 协议
|
|
@@ -179,11 +202,18 @@ class EntmlProtocol(ToolProtocol):
|
|
|
179
202
|
# Try <entml:parameters>{json}</entml:parameters> format first
|
|
180
203
|
params_m = _PARAMETERS_RE.search(body)
|
|
181
204
|
if params_m:
|
|
182
|
-
|
|
205
|
+
params_content = params_m.group(1).strip()
|
|
183
206
|
try:
|
|
184
|
-
|
|
207
|
+
# 尝试 JSON 解析
|
|
208
|
+
args = json.loads(params_content)
|
|
209
|
+
if not isinstance(args, dict):
|
|
210
|
+
args = {"value": args}
|
|
185
211
|
except json.JSONDecodeError:
|
|
186
|
-
|
|
212
|
+
# 不是 JSON,尝试解析子标签
|
|
213
|
+
args = _parse_sub_tags(params_content, schema_index, name)
|
|
214
|
+
# 如果子标签解析也没结果,整个当作值
|
|
215
|
+
if not args:
|
|
216
|
+
args = {"value": params_content}
|
|
187
217
|
else:
|
|
188
218
|
# Try <entml:parameter name="...">value</entml:parameter> format
|
|
189
219
|
for param_m in _PARAM_RE.finditer(body):
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: echotools
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.4
|
|
4
4
|
Summary: 通用基础设施 SDK:配置、日志、事件、调度、插件、协议、调用链
|
|
5
5
|
Author: nichengfuben
|
|
6
|
-
License: MIT
|
|
6
|
+
License-Expression: MIT
|
|
7
7
|
Project-URL: Homepage, https://github.com/nichengfuben/echotools
|
|
8
8
|
Project-URL: Repository, https://github.com/nichengfuben/echotools
|
|
9
9
|
Project-URL: Issues, https://github.com/nichengfuben/echotools/issues
|
|
10
10
|
Classifier: Development Status :: 4 - Beta
|
|
11
11
|
Classifier: Intended Audience :: Developers
|
|
12
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
13
12
|
Classifier: Programming Language :: Python :: 3
|
|
14
13
|
Classifier: Programming Language :: Python :: 3.8
|
|
15
14
|
Classifier: Programming Language :: Python :: 3.9
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
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.2 → echotools-2.3.4}/src/echotools/web/input_box/sortable-list/sortable-list.css
RENAMED
|
File without changes
|
{echotools-2.3.2 → echotools-2.3.4}/src/echotools/web/input_box/sortable-list/sortable-list.js
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
|