echotools 2.4.7__tar.gz → 2.4.9__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.4.7 → echotools-2.4.9}/PKG-INFO +2 -2
- {echotools-2.4.7 → echotools-2.4.9}/README.md +1 -1
- {echotools-2.4.7 → echotools-2.4.9}/pyproject.toml +18 -1
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/base/cache/__init__.py +0 -2
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/base/cache/list_cache.py +1 -35
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/base/cache/memory_cache.py +1 -11
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/base/config/__init__.py +0 -2
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/base/config/center.py +8 -68
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/base/errors/__init__.py +0 -2
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/base/errors/base.py +0 -7
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/base/ids/__init__.py +0 -2
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/base/ids/generator.py +2 -24
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/base/io/__init__.py +0 -2
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/base/io/printstream.py +8 -103
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/base/logger/__init__.py +0 -2
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/base/retry/__init__.py +0 -2
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/base/retry/retry.py +4 -42
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/dispatch/__init__.py +0 -2
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/__init__.py +0 -2
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/shared/__init__.py +0 -2
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/lifecycle/__init__.py +0 -2
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/lifecycle/manager.py +1 -11
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/lifecycle/updater.py +0 -12
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/process/__init__.py +0 -2
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/protocol/__init__.py +0 -2
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/terminal/local/core.py +0 -2
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/terminal/ssh.py +1 -22
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/console/uicore/mixins/__init__.py +0 -2
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/console/uicore/mixins/uibase.py +0 -12
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/events/__init__.py +0 -2
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/events/bus.py +2 -24
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/tracing/__init__.py +0 -2
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/tracing/span.py +0 -12
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/tracing/tracer.py +2 -22
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/watcher/__init__.py +0 -2
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/watcher/file_watcher.py +1 -12
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/web/__init__.py +0 -2
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/web/application.py +0 -11
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/plat/capture/audio_monitor/types.py +0 -4
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/plat/capture/shared/__init__.py +11 -12
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/plat/capture/shared/win_com.py +6 -3
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/plat/files/__init__.py +0 -2
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/plat/plugin/__init__.py +0 -2
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/plat/plugin/registry.py +5 -60
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/plat/proxy/__init__.py +0 -2
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/plat/proxy/manager.py +2 -18
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/plat/sdk/__init__.py +0 -2
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/plat/sdk/facade.py +0 -20
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/plat/sdk/runtime.py +1 -22
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/plat/sdk/scheduler.py +1 -26
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools.egg-info/PKG-INFO +2 -2
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_plat_capture.py +95 -2
- {echotools-2.4.7 → echotools-2.4.9}/setup.cfg +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/__init__.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/base/config/base.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/base/config/center_notify.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/base/config/center_template.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/base/config/loader.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/base/config/merge.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/base/errors/classify.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/base/errors/common.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/base/errors/http.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/base/io/io_utils.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/base/logger/manager.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/dispatch/candidate.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/dispatch/dispatcher.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/dispatch/proxy_selector.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/dispatch/race.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/dispatch/selector.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/dispatch/usage.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/parsers/__init__.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/parsers/stream.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/parsers/stream_delta.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/parsers/stream_feed.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/parsers/stream_final.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/prompt/__init__.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/prompt/behavior_blocks.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/prompt/history.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/prompt/history_format.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/prompt/inject.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/prompt/prompt_helpers.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/protocols/__init__.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/protocols/entml.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/protocols/entml_patterns/__init__.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/protocols/entml_patterns/invoke.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/protocols/entml_patterns/params.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/protocols/entml_patterns/regex.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/protocols/entml_patterns/strip.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/protocols/entml_schema/__init__.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/protocols/entml_schema/mangled.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/protocols/entml_schema/validate.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/protocols/entml_stream/__init__.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/protocols/entml_stream/body.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/protocols/entml_stream/snap.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/protocols/entml_think/__init__.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/protocols/entml_think/core.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/protocols/entml_think/filter.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/protocols/entml_think/hist.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/protocols/entml_think/hold.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/protocols/entml_think/parse.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/protocols/entml_tool/__init__.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/protocols/entml_tool/comment.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/protocols/entml_tool/fakemarkup.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/protocols/entml_tool/invoke.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/protocols/entml_tool/tools.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/protocols/entml_tool/values.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/registry.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/shared/coercion.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/shared/entml_format.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/shared/history_markup.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/shared/loop_detect.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/shared/normalization.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/shared/schema_render.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/fncall/tool_id.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/keys.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/lifecycle/updater_pull.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/process/port.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/protocol/base.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/terminal/__init__.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/terminal/conpty.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/terminal/local/__init__.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/terminal/local/proc.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/terminal/local/unix.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/terminal/local/win.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/terminal/sanitize.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/terminal/session/__init__.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/terminal/session/base.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/terminal/session/client.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/exec/terminal/tmux.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/console/__init__.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/console/charmap.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/console/spinner.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/console/ui.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/console/uicore/mixins/uicmds.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/console/uicore/mixins/uiinteract.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/console/uicore/mixins/uioutput.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/console/uicore/mixins/uistream.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/console/uicore/ui_console.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/console/uicore/ui_io.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/console/uicore/ui_log.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/console/uicore/ui_platform.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/console/uicore/ui_text.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/console/uicore/ui_types.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/console/uilayout/ui_bridge.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/console/uilayout/ui_countdown.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/console/uilayout/ui_layout.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/console/uilayout/ui_misc.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/console/uilayout/ui_panel.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/console/uilayout/ui_table.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/console/uilayout/ui_tree.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/console/uiwidgets/ui_box.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/console/uiwidgets/ui_editor.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/console/uiwidgets/ui_progress.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/console/uiwidgets/ui_richcli.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/console/uiwidgets/ui_select.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/console/uiwidgets/ui_stream.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/console/uiwidgets/ui_themes.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/events/event.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/spinner/__init__.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/spinner/spinner.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/spinner/spinner_color.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/tracing/context.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/translate.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/web/broker.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/web/input_box/app.js +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/web/input_box/components/filezone.js +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/web/input_box/components/motionkit.js +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/web/input_box/components/sendbutton.js +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/web/input_box/components/sortablelist.css +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/web/input_box/components/sortablelist.js +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/web/input_box/components/textinput.js +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/web/input_box/components/voiceinput.js +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/web/input_box/fonts/inter-500.woff2 +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/web/input_box/fonts/inter-600.woff2 +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/web/input_box/fonts/inter400.woff2 +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/web/input_box/inputbox.css +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/web/input_box/inputbox.js +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/web/input_box/style.css +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/web/input_box/voicegif.js +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/web/middleware.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/web/stats.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/media/web/utils.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/plat/capture/__init__.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/plat/capture/audio_monitor/api.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/plat/capture/audio_monitor/config.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/plat/capture/audio_monitor/linux.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/plat/capture/audio_monitor/mac.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/plat/capture/audio_monitor/win.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/plat/capture/audio_record/api.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/plat/capture/audio_record/config.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/plat/capture/audio_record/linux.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/plat/capture/audio_record/mac.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/plat/capture/audio_record/win.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/plat/capture/audio_record/win_wasapi.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/plat/capture/audio_record/win_winmm.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/plat/capture/screenshot/api.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/plat/capture/screenshot/config.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/plat/capture/screenshot/linux.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/plat/capture/screenshot/mac.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/plat/capture/screenshot/win.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/plat/capture/screenshot/win_dxgi.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/plat/capture/screenshot/win_gdi.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/plat/capture/shared/bmp.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/plat/capture/shared/pcm.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/plat/capture/shared/platform.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/plat/capture/shared/wav.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/plat/files/file_util.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/plat/network/__init__.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/plat/network/http_utils.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/plat/plugin/base.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/plat/plugin/discovery.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/plat/plugin/registry_ops.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools/version.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools.egg-info/SOURCES.txt +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools.egg-info/dependency_links.txt +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools.egg-info/requires.txt +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/echotools.egg-info/top_level.txt +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/_check_parity.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/bench_import.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/conftest.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/fixtures/__init__.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/fixtures/entml_golden.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/fixtures/entml_golden_update.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/fixtures/simulated_fake_history_markup_responses.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/fixtures/simulated_fault_thinking_responses.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/fixtures/simulated_llm_tool_responses.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_adversarial_stream_splits.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_cache_retry.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_completion.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_config.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_config_extended.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_console.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_coverage_core.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_dispatch.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_dispatch_extended.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_dispatch_race.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_entml_agent_output_formats.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_entml_bare_invoke_format.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_entml_batch_stream_comprehensive.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_entml_fake_structure_markup.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_entml_golden.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_entml_invoke_known_tool_gate.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_entml_parser_comprehensive.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_entml_protocol.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_entml_stream_json.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_entml_stream_json_exhaustive.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_entml_thinking_history.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_entml_thinking_parse.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_entml_tool_parse_leak.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_entml_tool_pipeline.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_entml_tools.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_errors.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_errors_common.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_events.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_events_event.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_facade.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_fake_history_markup_batch.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_fake_history_markup_invoke_preserve.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_fake_history_markup_reply_protect.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_fake_history_markup_stream.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_fault_thinking_close_batch.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_fault_thinking_close_stream.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_fncall.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_fncall_stream_thinking.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_history_markup_filter.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_ids.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_imports.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_io.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_keys.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_lifecycle.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_logger.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_merge.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_model_branch_matrix.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_multiline_parameter_comprehensive.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_plugin.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_printstream.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_protocols.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_proxy.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_proxy_selector.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_runtime.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_scheduler.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_schema_validate.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_simulated_llm_tool_parse.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_stream_partial_json_parity.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_stream_realtime_parse.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_tool_id.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_tracing.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_ui_bridge.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_usage.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_web.py +0 -0
- {echotools-2.4.7 → echotools-2.4.9}/src/tests/test_web_broker.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: echotools
|
|
3
|
-
Version: 2.4.
|
|
3
|
+
Version: 2.4.9
|
|
4
4
|
Summary: 通用基础设施 SDK:配置、日志、事件、调度、插件、协议、调用链
|
|
5
5
|
Home-page: https://github.com/nichengfuben/echotools
|
|
6
6
|
Author: nichengfuben
|
|
@@ -58,7 +58,7 @@ Requires-Dist: ruff>=0.4.0; extra == "dev"
|
|
|
58
58
|
|
|
59
59
|
通用基础设施 SDK:配置、日志、事件、调度、插件、调用链,以及 **entml** LLM 工具调用协议与终端 Console UI。
|
|
60
60
|
|
|
61
|
-
完全项目无关,兼容 Python 3.8–3.14。当前版本:**2.4.
|
|
61
|
+
完全项目无关,兼容 Python 3.8–3.14。当前版本:**2.4.9**(详见 [CHANGELOG](docs/CHANGELOG.md))。
|
|
62
62
|
|
|
63
63
|
## 安装
|
|
64
64
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "echotools"
|
|
7
|
-
version = "2.4.
|
|
7
|
+
version = "2.4.9"
|
|
8
8
|
description = "通用基础设施 SDK:配置、日志、事件、调度、插件、协议、调用链"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.8"
|
|
@@ -142,6 +142,23 @@ omit = [
|
|
|
142
142
|
"*/web/application.py",
|
|
143
143
|
"*/web/middleware.py",
|
|
144
144
|
"*/web/utils.py",
|
|
145
|
+
"*/plat/capture/shared/win_com.py",
|
|
146
|
+
"*/plat/capture/audio_monitor/api.py",
|
|
147
|
+
"*/plat/capture/audio_record/api.py",
|
|
148
|
+
"*/plat/capture/screenshot/api.py",
|
|
149
|
+
"*/plat/capture/audio_monitor/win.py",
|
|
150
|
+
"*/plat/capture/audio_monitor/mac.py",
|
|
151
|
+
"*/plat/capture/audio_monitor/linux.py",
|
|
152
|
+
"*/plat/capture/audio_record/win.py",
|
|
153
|
+
"*/plat/capture/audio_record/win_wasapi.py",
|
|
154
|
+
"*/plat/capture/audio_record/win_winmm.py",
|
|
155
|
+
"*/plat/capture/audio_record/mac.py",
|
|
156
|
+
"*/plat/capture/audio_record/linux.py",
|
|
157
|
+
"*/plat/capture/screenshot/win.py",
|
|
158
|
+
"*/plat/capture/screenshot/win_dxgi.py",
|
|
159
|
+
"*/plat/capture/screenshot/win_gdi.py",
|
|
160
|
+
"*/plat/capture/screenshot/mac.py",
|
|
161
|
+
"*/plat/capture/screenshot/linux.py",
|
|
145
162
|
]
|
|
146
163
|
|
|
147
164
|
[tool.coverage.report]
|
|
@@ -19,14 +19,7 @@ logger = get_logger(__name__)
|
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
class ListCache:
|
|
22
|
-
"""
|
|
23
|
-
|
|
24
|
-
职责:
|
|
25
|
-
1. 从持久化文件读取缓存
|
|
26
|
-
2. 定时调用 fetch_fn 刷新远程列表
|
|
27
|
-
3. 根据 overwrite 决定覆盖或追加
|
|
28
|
-
4. 更新后触发 on_update 回调
|
|
29
|
-
"""
|
|
22
|
+
"""持久化字符串列表;定时 fetch 刷新,overwrite 控制覆盖或只增不减。"""
|
|
30
23
|
|
|
31
24
|
def __init__(
|
|
32
25
|
self,
|
|
@@ -36,15 +29,6 @@ class ListCache:
|
|
|
36
29
|
overwrite: bool = True,
|
|
37
30
|
data_key: str = "items",
|
|
38
31
|
) -> None:
|
|
39
|
-
"""初始化列表缓存。
|
|
40
|
-
|
|
41
|
-
Args:
|
|
42
|
-
name: 缓存标识名(仅用于日志)。
|
|
43
|
-
fallback: 兜底列表。
|
|
44
|
-
cache_path: 持久化文件路径。
|
|
45
|
-
overwrite: True=覆盖,False=只增不减。
|
|
46
|
-
data_key: JSON 中存储列表的键名,默认 "items"。
|
|
47
|
-
"""
|
|
48
32
|
self._name = name
|
|
49
33
|
self._fallback = list(fallback)
|
|
50
34
|
self._overwrite = overwrite
|
|
@@ -54,11 +38,6 @@ class ListCache:
|
|
|
54
38
|
self._data_key = data_key
|
|
55
39
|
|
|
56
40
|
async def load(self) -> List[str]:
|
|
57
|
-
"""从缓存文件加载列表。
|
|
58
|
-
|
|
59
|
-
Returns:
|
|
60
|
-
缓存列表,无缓存则返回兜底列表。
|
|
61
|
-
"""
|
|
62
41
|
try:
|
|
63
42
|
if self._cache_path.is_file():
|
|
64
43
|
text = self._cache_path.read_text(encoding="utf-8")
|
|
@@ -76,11 +55,6 @@ class ListCache:
|
|
|
76
55
|
return list(self._items)
|
|
77
56
|
|
|
78
57
|
async def save(self, items: List[str]) -> None:
|
|
79
|
-
"""保存列表到缓存文件。
|
|
80
|
-
|
|
81
|
-
Args:
|
|
82
|
-
items: 要保存的列表。
|
|
83
|
-
"""
|
|
84
58
|
try:
|
|
85
59
|
self._cache_path.parent.mkdir(parents=True, exist_ok=True)
|
|
86
60
|
data = {self._data_key: items, "updated_at": int(time.time())}
|
|
@@ -92,7 +66,6 @@ class ListCache:
|
|
|
92
66
|
logger.warning("[%s] 缓存保存失败: %s", self._name, e)
|
|
93
67
|
|
|
94
68
|
def _merge(self, remote: List[str]) -> List[str]:
|
|
95
|
-
"""根据策略合并列表。"""
|
|
96
69
|
if self._overwrite:
|
|
97
70
|
return list(remote) if remote else list(self._items)
|
|
98
71
|
existing = set(self._items)
|
|
@@ -111,13 +84,6 @@ class ListCache:
|
|
|
111
84
|
Callable[[List[str]], Awaitable[None]]
|
|
112
85
|
] = None,
|
|
113
86
|
) -> None:
|
|
114
|
-
"""启动定时刷新循环(永久运行)。
|
|
115
|
-
|
|
116
|
-
Args:
|
|
117
|
-
fetch_fn: 返回远程列表的异步函数。
|
|
118
|
-
interval: 刷新间隔(秒)。
|
|
119
|
-
on_update: 更新回调。
|
|
120
|
-
"""
|
|
121
87
|
while True:
|
|
122
88
|
await self._do_refresh(fetch_fn, on_update)
|
|
123
89
|
await asyncio.sleep(interval)
|
|
@@ -14,19 +14,12 @@ class MemoryCache:
|
|
|
14
14
|
"""Thread-safe TTL memory cache with optional LRU eviction."""
|
|
15
15
|
|
|
16
16
|
def __init__(self, default_ttl: float = 0.0, max_size: int = 0) -> None:
|
|
17
|
-
"""初始化缓存。
|
|
18
|
-
|
|
19
|
-
Args:
|
|
20
|
-
default_ttl: 默认存活秒数,0 表示永不过期。
|
|
21
|
-
max_size: 最大条目数,0 表示不限制。
|
|
22
|
-
"""
|
|
23
17
|
self._store: "OrderedDict[str, Tuple[Any, float]]" = OrderedDict()
|
|
24
18
|
self._default_ttl = default_ttl
|
|
25
19
|
self._max_size = max_size
|
|
26
20
|
self._lock = threading.RLock()
|
|
27
21
|
|
|
28
22
|
def set(self, key: str, value: Any, ttl: Optional[float] = None) -> None:
|
|
29
|
-
"""写入缓存。"""
|
|
30
23
|
effective = self._default_ttl if ttl is None else ttl
|
|
31
24
|
expire = 0.0 if effective <= 0 else time.time() + effective
|
|
32
25
|
with self._lock:
|
|
@@ -36,7 +29,6 @@ class MemoryCache:
|
|
|
36
29
|
self._evict_if_needed()
|
|
37
30
|
|
|
38
31
|
def get(self, key: str, default: Any = None) -> Any:
|
|
39
|
-
"""读取缓存。"""
|
|
40
32
|
with self._lock:
|
|
41
33
|
item = self._store.get(key)
|
|
42
34
|
if item is None:
|
|
@@ -49,17 +41,15 @@ class MemoryCache:
|
|
|
49
41
|
return value
|
|
50
42
|
|
|
51
43
|
def delete(self, key: str) -> None:
|
|
52
|
-
"""删除键。"""
|
|
53
44
|
with self._lock:
|
|
54
45
|
self._store.pop(key, None)
|
|
55
46
|
|
|
56
47
|
def clear(self) -> None:
|
|
57
|
-
"""清空缓存。"""
|
|
58
48
|
with self._lock:
|
|
59
49
|
self._store.clear()
|
|
60
50
|
|
|
61
51
|
def cleanup(self) -> int:
|
|
62
|
-
"""
|
|
52
|
+
"""返回被剔除的过期条目数。"""
|
|
63
53
|
now = time.time()
|
|
64
54
|
with self._lock:
|
|
65
55
|
expired = [k for k, (_, exp) in self._store.items() if exp and now > exp]
|
|
@@ -52,7 +52,6 @@ class ConfigCenter:
|
|
|
52
52
|
"""
|
|
53
53
|
|
|
54
54
|
def __init__(self) -> None:
|
|
55
|
-
"""初始化配置中心。"""
|
|
56
55
|
self._raw: Dict[str, Any] = {}
|
|
57
56
|
self._path: Optional[Path] = None
|
|
58
57
|
self._callbacks: Dict[str, List[Callable[[Any, Any], Any]]] = {}
|
|
@@ -77,19 +76,7 @@ class ConfigCenter:
|
|
|
77
76
|
filename: str = "config.toml",
|
|
78
77
|
data: Optional[Dict[str, Any]] = None,
|
|
79
78
|
) -> Dict[str, Any]:
|
|
80
|
-
"""
|
|
81
|
-
|
|
82
|
-
Args:
|
|
83
|
-
path: 配置文件路径。
|
|
84
|
-
filename: 自动查找时的文件名。
|
|
85
|
-
data: 直接提供字典(最高优先,跳过文件)。
|
|
86
|
-
|
|
87
|
-
Returns:
|
|
88
|
-
原始配置字典。
|
|
89
|
-
|
|
90
|
-
Raises:
|
|
91
|
-
ConfigError: 无法定位或解析配置。
|
|
92
|
-
"""
|
|
79
|
+
"""加载配置;data 非空时跳过文件读取。"""
|
|
93
80
|
if data is not None:
|
|
94
81
|
self._raw = copy.deepcopy(data)
|
|
95
82
|
return dict(self._raw)
|
|
@@ -104,15 +91,7 @@ class ConfigCenter:
|
|
|
104
91
|
return dict(self._raw)
|
|
105
92
|
|
|
106
93
|
def get(self, path: str, default: Any = None) -> Any:
|
|
107
|
-
"""按点路径获取配置值。
|
|
108
|
-
|
|
109
|
-
Args:
|
|
110
|
-
path: 形如 "server.port" 的点路径。
|
|
111
|
-
default: 缺省值。
|
|
112
|
-
|
|
113
|
-
Returns:
|
|
114
|
-
配置值或默认值。
|
|
115
|
-
"""
|
|
94
|
+
"""按点路径获取配置值。"""
|
|
116
95
|
node: Any = self._raw
|
|
117
96
|
for part in path.split("."):
|
|
118
97
|
if isinstance(node, dict) and part in node:
|
|
@@ -122,12 +101,7 @@ class ConfigCenter:
|
|
|
122
101
|
return node
|
|
123
102
|
|
|
124
103
|
def set(self, path: str, value: Any) -> None:
|
|
125
|
-
"""
|
|
126
|
-
|
|
127
|
-
Args:
|
|
128
|
-
path: 点路径。
|
|
129
|
-
value: 新值。
|
|
130
|
-
"""
|
|
104
|
+
"""按点路径设置配置值(仅内存,不写文件)。"""
|
|
131
105
|
parts = path.split(".")
|
|
132
106
|
node = self._raw
|
|
133
107
|
for part in parts[:-1]:
|
|
@@ -137,15 +111,7 @@ class ConfigCenter:
|
|
|
137
111
|
node[parts[-1]] = value
|
|
138
112
|
|
|
139
113
|
def bind(self, schema: Type[C], section: str = "") -> C:
|
|
140
|
-
"""将配置绑定到类型化 ConfigBase 子类。
|
|
141
|
-
|
|
142
|
-
Args:
|
|
143
|
-
schema: ConfigBase 子类。
|
|
144
|
-
section: 子段点路径,空表示根。
|
|
145
|
-
|
|
146
|
-
Returns:
|
|
147
|
-
类型化配置实例。
|
|
148
|
-
"""
|
|
114
|
+
"""将配置绑定到类型化 ConfigBase 子类。"""
|
|
149
115
|
data = self.get(section, {}) if section else self._raw
|
|
150
116
|
if not isinstance(data, dict):
|
|
151
117
|
raise ConfigError(
|
|
@@ -155,31 +121,20 @@ class ConfigCenter:
|
|
|
155
121
|
|
|
156
122
|
@property
|
|
157
123
|
def raw(self) -> Dict[str, Any]:
|
|
158
|
-
"""原始配置字典副本。"""
|
|
159
124
|
return copy.deepcopy(self._raw)
|
|
160
125
|
|
|
161
126
|
@property
|
|
162
127
|
def path(self) -> Optional[Path]:
|
|
163
|
-
"""配置文件路径。"""
|
|
164
128
|
return self._path
|
|
165
129
|
|
|
166
130
|
def on_change(
|
|
167
131
|
self, path: str, callback: Callable[[Any, Any], Any]
|
|
168
132
|
) -> None:
|
|
169
|
-
"""
|
|
170
|
-
|
|
171
|
-
Args:
|
|
172
|
-
path: 监听的点路径。
|
|
173
|
-
callback: 回调(old, new),支持同步/异步。
|
|
174
|
-
"""
|
|
133
|
+
"""注册配置变更回调;callback(old, new) 支持同步或异步。"""
|
|
175
134
|
self._callbacks.setdefault(path, []).append(callback)
|
|
176
135
|
|
|
177
136
|
async def reload(self) -> bool:
|
|
178
|
-
"""
|
|
179
|
-
|
|
180
|
-
Returns:
|
|
181
|
-
是否成功。
|
|
182
|
-
"""
|
|
137
|
+
"""热重载配置文件并触发已注册的变更回调。"""
|
|
183
138
|
if self._path is None or not self._path.exists():
|
|
184
139
|
return False
|
|
185
140
|
async with self._get_lock():
|
|
@@ -214,11 +169,7 @@ class ConfigCenter:
|
|
|
214
169
|
return init_from_template(self, **kwargs)
|
|
215
170
|
|
|
216
171
|
def write(self, data: Optional[Dict[str, Any]] = None) -> None:
|
|
217
|
-
"""将配置写回文件(tomlkit 保留注释)。
|
|
218
|
-
|
|
219
|
-
Args:
|
|
220
|
-
data: 要写入的字典,None 则写入当前 _raw。
|
|
221
|
-
"""
|
|
172
|
+
"""将配置写回文件(tomlkit 保留注释)。"""
|
|
222
173
|
if self._path is None:
|
|
223
174
|
raise ConfigError("配置路径未设置")
|
|
224
175
|
write_toml(self._path, data if data is not None else self._raw)
|
|
@@ -226,14 +177,7 @@ class ConfigCenter:
|
|
|
226
177
|
self._raw = copy.deepcopy(data)
|
|
227
178
|
|
|
228
179
|
def backup(self, backup_dir: Optional[str] = None) -> Optional[Path]:
|
|
229
|
-
"""
|
|
230
|
-
|
|
231
|
-
Args:
|
|
232
|
-
backup_dir: 备份目录,默认 <config_dir>/template/old。
|
|
233
|
-
|
|
234
|
-
Returns:
|
|
235
|
-
备份文件路径,无配置路径时返回 None。
|
|
236
|
-
"""
|
|
180
|
+
"""创建配置文件的带时间戳备份;默认目录为 <config_dir>/template/old。"""
|
|
237
181
|
if self._path is None or not self._path.exists():
|
|
238
182
|
return None
|
|
239
183
|
if backup_dir is None:
|
|
@@ -247,10 +191,6 @@ class ConfigCenter:
|
|
|
247
191
|
logger.debug("已备份: %s", backup_path)
|
|
248
192
|
return backup_path
|
|
249
193
|
|
|
250
|
-
# ------------------------------------------------------------------
|
|
251
|
-
# __getattr__ 代理
|
|
252
|
-
# ------------------------------------------------------------------
|
|
253
|
-
|
|
254
194
|
def bind_proxy(self, schema: Type[C], section: str = "") -> C:
|
|
255
195
|
"""绑定 schema 并启用 __getattr__ 代理。
|
|
256
196
|
|
|
@@ -19,13 +19,6 @@ class EchoError(Exception):
|
|
|
19
19
|
original: Optional[Exception] = None,
|
|
20
20
|
status_code: int = 500,
|
|
21
21
|
) -> None:
|
|
22
|
-
"""初始化异常。
|
|
23
|
-
|
|
24
|
-
Args:
|
|
25
|
-
message: 错误信息。
|
|
26
|
-
original: 原始异常。
|
|
27
|
-
status_code: 关联状态码。
|
|
28
|
-
"""
|
|
29
22
|
super().__init__(message)
|
|
30
23
|
self.message = message
|
|
31
24
|
self.original = original
|
|
@@ -11,11 +11,7 @@ __all__ = ["uuid7", "short_id", "trace_id", "span_id", "gen_tool_id"]
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
def uuid7() -> str:
|
|
14
|
-
"""
|
|
15
|
-
|
|
16
|
-
Returns:
|
|
17
|
-
符合 UUIDv7 位布局的字符串。
|
|
18
|
-
"""
|
|
14
|
+
"""时间有序的 UUIDv7。"""
|
|
19
15
|
ts_ms = int(time.time() * 1000) & 0xFFFFFFFFFFFF
|
|
20
16
|
rand_bytes = secrets.token_bytes(10)
|
|
21
17
|
rand_a = struct.unpack(">H", rand_bytes[:2])[0] & 0x0FFF
|
|
@@ -31,37 +27,19 @@ def uuid7() -> str:
|
|
|
31
27
|
|
|
32
28
|
|
|
33
29
|
def short_id(length: int = 12) -> str:
|
|
34
|
-
"""生成短随机 ID。
|
|
35
|
-
|
|
36
|
-
Args:
|
|
37
|
-
length: 长度,默认为 12。
|
|
38
|
-
|
|
39
|
-
Returns:
|
|
40
|
-
十六进制随机字符串。
|
|
41
|
-
"""
|
|
42
30
|
if length <= 0:
|
|
43
31
|
raise ValueError("length 必须为正整数")
|
|
44
32
|
return uuid.uuid4().hex[:length]
|
|
45
33
|
|
|
46
34
|
|
|
47
35
|
def trace_id() -> str:
|
|
48
|
-
"""生成 trace_id(32 位十六进制)。
|
|
49
|
-
|
|
50
|
-
Returns:
|
|
51
|
-
trace_id 字符串。
|
|
52
|
-
"""
|
|
53
36
|
return secrets.token_hex(16)
|
|
54
37
|
|
|
55
38
|
|
|
56
39
|
def span_id() -> str:
|
|
57
|
-
"""生成 span_id(16 位十六进制)。
|
|
58
|
-
|
|
59
|
-
Returns:
|
|
60
|
-
span_id 字符串。
|
|
61
|
-
"""
|
|
62
40
|
return secrets.token_hex(8)
|
|
63
41
|
|
|
64
42
|
|
|
65
43
|
def gen_tool_id() -> str:
|
|
66
|
-
"""
|
|
44
|
+
"""Anthropic 兼容 tool_use id(``toolu_`` + 24 hex)。"""
|
|
67
45
|
return f"toolu_{uuid.uuid4().hex[:24]}"
|
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
"""
|
|
2
|
-
|
|
3
|
-
This module provides a PrintStream class that implements dynamic speed
|
|
4
|
-
printing with ordered queue management, suitable for controlled output
|
|
5
|
-
of large text blocks with adaptive speed based on queue depth.
|
|
6
|
-
"""
|
|
1
|
+
"""动态速率打印流:按队列深度自适应输出速度。"""
|
|
7
2
|
|
|
8
3
|
from __future__ import annotations
|
|
9
4
|
|
|
@@ -17,21 +12,7 @@ from typing import Any, Optional
|
|
|
17
12
|
|
|
18
13
|
|
|
19
14
|
class PrintStream:
|
|
20
|
-
"""
|
|
21
|
-
|
|
22
|
-
This class manages a queue of text blocks and outputs them with
|
|
23
|
-
adaptive speed based on the current queue depth. The output speed
|
|
24
|
-
increases as more text is pending, providing smooth, controlled output.
|
|
25
|
-
|
|
26
|
-
Attributes:
|
|
27
|
-
min_speed: Minimum output speed in characters per second.
|
|
28
|
-
max_speed: Maximum output speed in characters per second.
|
|
29
|
-
decay_factor: Controls how quickly speed adapts to queue depth.
|
|
30
|
-
smoothing_factor: Controls speed change smoothing (0.0-1.0).
|
|
31
|
-
current_speed: Current output speed in characters per second.
|
|
32
|
-
accumulated_chars: Fractional characters pending output.
|
|
33
|
-
total_pending_chars: Total characters waiting to be output.
|
|
34
|
-
"""
|
|
15
|
+
"""按队列深度自适应输出速度的打印流。"""
|
|
35
16
|
|
|
36
17
|
def __init__(
|
|
37
18
|
self,
|
|
@@ -40,14 +21,6 @@ class PrintStream:
|
|
|
40
21
|
decay_factor: float = 20.0,
|
|
41
22
|
smoothing_factor: float = 0.8,
|
|
42
23
|
) -> None:
|
|
43
|
-
"""Initialize the print stream.
|
|
44
|
-
|
|
45
|
-
Args:
|
|
46
|
-
min_speed: Minimum output speed (characters/second).
|
|
47
|
-
max_speed: Maximum output speed (characters/second).
|
|
48
|
-
decay_factor: Controls speed adaptation curve.
|
|
49
|
-
smoothing_factor: Controls speed change smoothing.
|
|
50
|
-
"""
|
|
51
24
|
# Queue management
|
|
52
25
|
self._text_queue: deque[str] = deque()
|
|
53
26
|
self._current_text: str = ""
|
|
@@ -80,10 +53,7 @@ class PrintStream:
|
|
|
80
53
|
self._output_thread.start()
|
|
81
54
|
|
|
82
55
|
def stop(self) -> None:
|
|
83
|
-
"""
|
|
84
|
-
|
|
85
|
-
Waits for all pending output to complete before stopping.
|
|
86
|
-
"""
|
|
56
|
+
"""停止输出;会等待队列中待输出内容排空。"""
|
|
87
57
|
if self._running:
|
|
88
58
|
self._running = False
|
|
89
59
|
# Wait for all content to be output
|
|
@@ -98,11 +68,7 @@ class PrintStream:
|
|
|
98
68
|
self._output_thread.join(timeout=1)
|
|
99
69
|
|
|
100
70
|
def add_to_buffer(self, text: str) -> None:
|
|
101
|
-
"""
|
|
102
|
-
|
|
103
|
-
Args:
|
|
104
|
-
text: Text to add to the queue.
|
|
105
|
-
"""
|
|
71
|
+
"""将文本加入输出队列。"""
|
|
106
72
|
if not self._running:
|
|
107
73
|
self.start()
|
|
108
74
|
|
|
@@ -129,14 +95,7 @@ class PrintStream:
|
|
|
129
95
|
self.accumulated_chars = 0.0
|
|
130
96
|
|
|
131
97
|
def _calculate_dynamic_speed(self, buffer_length: int) -> float:
|
|
132
|
-
"""
|
|
133
|
-
|
|
134
|
-
Args:
|
|
135
|
-
buffer_length: Number of pending characters.
|
|
136
|
-
|
|
137
|
-
Returns:
|
|
138
|
-
Calculated speed in characters per second.
|
|
139
|
-
"""
|
|
98
|
+
"""根据待输出字符数计算当前输出速率。"""
|
|
140
99
|
if buffer_length <= 0:
|
|
141
100
|
return self.min_speed
|
|
142
101
|
|
|
@@ -201,31 +160,16 @@ class PrintStream:
|
|
|
201
160
|
|
|
202
161
|
@property
|
|
203
162
|
def buffer_size(self) -> int:
|
|
204
|
-
"""Get total characters waiting to be output.
|
|
205
|
-
|
|
206
|
-
Returns:
|
|
207
|
-
Number of pending characters.
|
|
208
|
-
"""
|
|
209
163
|
with self._lock:
|
|
210
164
|
queue_chars = sum(len(text) for text in self._text_queue)
|
|
211
165
|
return len(self._current_text) + queue_chars
|
|
212
166
|
|
|
213
167
|
@property
|
|
214
168
|
def is_running(self) -> bool:
|
|
215
|
-
"""Check if the system is running.
|
|
216
|
-
|
|
217
|
-
Returns:
|
|
218
|
-
True if running, False otherwise.
|
|
219
|
-
"""
|
|
220
169
|
return self._running
|
|
221
170
|
|
|
222
171
|
@property
|
|
223
172
|
def queue_length(self) -> int:
|
|
224
|
-
"""Get number of text blocks in queue.
|
|
225
|
-
|
|
226
|
-
Returns:
|
|
227
|
-
Number of queued text blocks.
|
|
228
|
-
"""
|
|
229
173
|
with self._lock:
|
|
230
174
|
return len(self._text_queue)
|
|
231
175
|
|
|
@@ -240,17 +184,7 @@ def print_stream(
|
|
|
240
184
|
end: str = "\n",
|
|
241
185
|
flush: bool = False,
|
|
242
186
|
) -> None:
|
|
243
|
-
"""
|
|
244
|
-
|
|
245
|
-
This function provides a drop-in replacement for the built-in print()
|
|
246
|
-
function with dynamic speed output based on queue depth.
|
|
247
|
-
|
|
248
|
-
Args:
|
|
249
|
-
*args: Content to print.
|
|
250
|
-
sep: Separator between arguments (default: space).
|
|
251
|
-
end: End character (default: newline).
|
|
252
|
-
flush: If True, output immediately without queuing.
|
|
253
|
-
"""
|
|
187
|
+
"""动态速率 print 替代;flush=True 时立即输出不入队。"""
|
|
254
188
|
try:
|
|
255
189
|
# Ensure system is started
|
|
256
190
|
if not _global_print_stream.is_running:
|
|
@@ -288,39 +222,19 @@ def flush_print_stream() -> None:
|
|
|
288
222
|
|
|
289
223
|
|
|
290
224
|
def get_buffer_size() -> int:
|
|
291
|
-
"""Get current buffer size.
|
|
292
|
-
|
|
293
|
-
Returns:
|
|
294
|
-
Number of pending characters.
|
|
295
|
-
"""
|
|
296
225
|
return _global_print_stream.buffer_size
|
|
297
226
|
|
|
298
227
|
|
|
299
228
|
def get_queue_length() -> int:
|
|
300
|
-
"""Get number of text blocks in queue.
|
|
301
|
-
|
|
302
|
-
Returns:
|
|
303
|
-
Number of queued text blocks.
|
|
304
|
-
"""
|
|
305
229
|
return _global_print_stream.queue_length
|
|
306
230
|
|
|
307
231
|
|
|
308
232
|
def is_print_stream_running() -> bool:
|
|
309
|
-
"""Check if the print stream system is running.
|
|
310
|
-
|
|
311
|
-
Returns:
|
|
312
|
-
True if running, False otherwise.
|
|
313
|
-
"""
|
|
314
233
|
return _global_print_stream.is_running
|
|
315
234
|
|
|
316
235
|
|
|
317
236
|
def set_print_speed(min_speed: float = 5.0, max_speed: float = 50.0) -> None:
|
|
318
|
-
"""
|
|
319
|
-
|
|
320
|
-
Args:
|
|
321
|
-
min_speed: Minimum print speed (characters/second).
|
|
322
|
-
max_speed: Maximum print speed (characters/second).
|
|
323
|
-
"""
|
|
237
|
+
"""设置输出速率上下限。"""
|
|
324
238
|
_global_print_stream.min_speed = max(1.0, min_speed)
|
|
325
239
|
_global_print_stream.max_speed = max(_global_print_stream.min_speed, max_speed)
|
|
326
240
|
|
|
@@ -331,14 +245,7 @@ def configure_print_stream(
|
|
|
331
245
|
decay_factor: float = 20.0,
|
|
332
246
|
smoothing_factor: float = 0.8,
|
|
333
247
|
) -> None:
|
|
334
|
-
"""
|
|
335
|
-
|
|
336
|
-
Args:
|
|
337
|
-
min_speed: Minimum print speed.
|
|
338
|
-
max_speed: Maximum print speed.
|
|
339
|
-
decay_factor: Decay factor for speed adaptation.
|
|
340
|
-
smoothing_factor: Smoothing factor for speed changes.
|
|
341
|
-
"""
|
|
248
|
+
"""配置输出速率与平滑参数。"""
|
|
342
249
|
_global_print_stream.min_speed = max(1.0, min_speed)
|
|
343
250
|
_global_print_stream.max_speed = max(_global_print_stream.min_speed, max_speed)
|
|
344
251
|
_global_print_stream.decay_factor = max(1.0, decay_factor)
|
|
@@ -357,8 +264,6 @@ def _cleanup() -> None:
|
|
|
357
264
|
# Register cleanup function
|
|
358
265
|
atexit.register(_cleanup)
|
|
359
266
|
|
|
360
|
-
|
|
361
|
-
# Module exports
|
|
362
267
|
__all__ = [
|
|
363
268
|
"PrintStream",
|
|
364
269
|
"print_stream",
|