mirror of
https://github.com/AstrBotDevs/AstrBot
synced 2026-07-15 17:30:13 +08:00
- Introduce private v4 compatibility surface using _legacy_api.py, _legacy_runtime.py, _legacy_loader.py plus new _legacy_context.py and _legacy_star.py to centralize legacy adapters while keeping public APIs thin. - Extend InitializeOutput to carry protocol_version for negotiated protocol, enabling runtime to adapt to the chosen v4 version. - Add lightweight legacy support for Star/Context via new LegacyStar and LegacyContext shims and expose legacy API through the aggregate _legacy_api entry point. - Ensure legacy loader preserves class declaration order by iterating module.__dict__ instead of relying on alphabetical sorting. - Add tests: protocol_version handling in InitializeOutput, legacy main component order preservation, and embedded-newline framing in transport tests.
15 KiB
15 KiB
CLAUDE Notes
- 2026-03-12: Legacy
handshakepayloads only containevent_type/handler_full_namemetadata and do not preserve v4 command/message trigger details such as command names, aliases, keywords, or regex. Any legacy-to-v4 handshake translation must approximate handlers as coarse event subscriptions and keep the raw handshake payload in metadata for lossless fallback. - 2026-03-12: Legacy
src/astrbot_sdk/api/event/filter.pyexported a much larger decorator surface thansrc-new/astrbot_sdk/api/event/filter.py. Current compat coverage is enough forcommand/regex/permissionand the exercised migration tests, but it is not a full drop-in replacement for every historical filter helper. - 2026-03-13: Transport-pair startup tests for
SupervisorRuntimemust start a real peer on the opposite transport and provide aninitializeresponse. Wiring only the supervisor side drops or captures the outgoing initialize message without replying, andPeer.initialize()then waits forever. - 2026-03-13:
CapabilityRouter.register(..., stream_handler=...)uses the signature(request_id, payload, cancel_token), not the peer-level(message, token). Reusing the peer handler shape in router tests causes an immediate failed stream event before the test logic runs. - 2026-03-13:
src-new/astrbot_sdk/apiand several top-level module docstrings overstated v4 compatibility gaps by labeling migrated or compat-backed APIs as "missing". Treat_legacy_api.py,astrbot_sdk.api.*thin re-exports, and top-levelevents.py/decorators.pyas a split compatibility surface; do not mechanically recreate the old tree from stale TODO comments. - 2026-03-13:
astrbot_sdk.api.*andastrbot.*are migration-period compat facades, not long-term primary SDK entrypoints. Keep them thin, avoid adding new runtime logic underapi/, and prefer tightening internal imports toward top-level private compat modules or direct leaf modules. - 2026-03-13: Legacy components are expected to share one
LegacyContextper plugin, matching the oldStarManagerbehavior. Creating one compat context per component breaks_register_component()/call_context_function()cross-component registration chains and diverges from legacy semantics. - 2026-03-13: When checking whether a peer has finished remote initialization, avoid
getattr(mock, "remote_peer")style probes in code that may receiveMagicMockpeers.MagicMockfabricates truthy child attributes, soCapabilityProxyshould read explicit state frompeer.__dict__or another concrete storage location instead of treating arbitrary attribute access as initialization. - 2026-03-13: The repository has no legacy
src/astrbot_sdk/protocolpackage to migrate file-for-file.src-new/astrbot_sdk/protocolis a v4-native protocol layer; compare it against legacy JSON-RPC behavior insrc/astrbot_sdk/runtime/*and the maintained migration tests, not against a nonexistent old package tree. - 2026-03-13: Old Star docs under
docs/zh/dev/star/describe end-to-end legacy behavior, not just import surfaces. Current compat layer can importAstrMessageEvent,MessageChain, and somefilter.*helpers, but handler result consumption is still effectively plain-text only and many documented legacy features remain absent or partial, including command groups, lifecycle/LLM hooks, session waiters, rich media helper constructors, config schema loading, and persona/provider management. Do not treat "type exists" as "old plugin behavior is compatible"; verify the runtime path end to end before declaring parity. - 2026-03-13: Old Star docs and examples frequently import message components via
astrbot.api.message_components, not onlyastrbot.api.message. When checking message compatibility, verify the dedicatedapi.message_componentsimport path, legacy constructor aliases likeAt(qq=...)/Node(uin=..., name=...), and helper factories such asImage.fromURL()before declaring the message compat surface complete. - 2026-03-13:
api.message.components.BaseMessageComponent.to_dict()must emit JSON-ready primitive values, not rawEnummembers. LeavingComponentTypeobjects in payloads only looks harmless when a later JSON serializer fixes them; it breaks direct mock assertions, in-process capability routing, and any non-JSON send path. - 2026-03-13: Keep
astrbot_sdk.runtimeroot exports narrow.Peer/Transport/CapabilityRouter/HandlerDispatcherare reasonable advanced runtime primitives, but loader/bootstrap data structures and orchestration helpers (LoadedPlugin,PluginEnvironmentManager,WorkerSession,run_supervisor, etc.) should stay in their submodules instead of becoming accidental root-level stable API. - 2026-03-13:
runtime.loadermust preserve declared legacy handler order. Falling back todir(instance)or sorting the merged discoverable names reorders compat handlers alphabetically, which changes which legacy command/hook appears first to the supervisor and breaks old-plugin expectations. - 2026-03-13:
runtime.loader.import_string()cannot trustsys.moduleswhen plugins reuse generic top-level package names likecommands.*. Before importing a plugin module, compare the cached root package against the current plugin directory and evict conflicting root/submodules, or later plugins will accidentally reuse an earlier plugin's package tree. - 2026-03-13: Keep
astrbot_sdk.protocolroot focused on native v4 protocol models and parsers. Legacy JSON-RPC helpers remain supported, but they should be imported fromastrbot_sdk.protocol.legacy_adapterexplicitly instead of being re-exported from the package root. - 2026-03-13:
Peermust treat transport EOF/connection loss as a first-class failure path, not only explicit protocol parse errors. If the transport closes unexpectedly andPeerdoes not proactively fail_pending_results/_pending_streams, supervisor-side calls into workers can hang forever even though the worker session already noticed the disconnect. - 2026-03-13:
Peer.initialize()also needs to mark the peer as remotely initialized on the initiator side. Only setting_remote_initializedwhen passively receiving an inboundInitializeMessagemakeswait_until_remote_initialized()a one-sided API and can deadlock callers that initialize first and then wait. - 2026-03-13:
Peer.invoke_stream()intentionally hidescompletedevents by default, so any supervisor/bridge layer that wants to preserve a worker stream capability's finalcompleted.outputmust opt in explicitly (for example viainclude_completed=True) or it will silently collapse the final result to an ad-hoc aggregate like{\"items\": chunks}. - 2026-03-13: The repository root
test_plugin/is no longer a single runnable plugin fixture. The maintained compat sample now lives undertest_plugin/old/; tests or scripts that still copy/loadtest_plugin/directly will mis-detect it as an incomplete legacy plugin and fail. - 2026-03-13: The maintained sample plugins now live under
test_plugin/old/andtest_plugin/new/. Runtime/integration tests should copy those real fixture directories instead of inlining synthetic plugin writers, otherwise the sample plugin tree and the exercised test path drift apart. - 2026-03-14:
test_plugin/old/andtest_plugin/new/may contain checked-in__pycache__/*.pycartifacts. Any helper that copies sample plugins into temporary test directories must explicitly ignore Python bytecode caches, or fixture contents andgit statuscan drift for reasons unrelated to the runtime behavior under test. - 2026-03-14: Grouped worker / grouped environment execution must reuse the shared legacy-runtime and lifecycle helpers from
_legacy_runtime.pyandresolve_plugin_lifecycle_hook()instead of re-implementing them insideruntime.bootstrap. The grouped subprocess path can otherwise diverge from the single-worker path and fail only at runtime with missing imports/helpers even when most unit tests still pass. - 2026-03-13: Real legacy plugins in the wild may still import
astrbot.api.*instead ofastrbot_sdk.api.*. Keeping only theastrbot_sdk.apicompat surface is not enough for no-touch migration tests; preserve theastrbot.apialias package while old-plugin support remains a goal. - 2026-03-13: Real legacy
main.pyplugins may rely on package-relative imports likefrom .src.tool import .... Loading legacymain.pyas a bare file module breaks those imports; the loader must execute it under a synthetic package module so relative imports resolve. - 2026-03-13: Real legacy plugins may also import
astrbot.core.utils.session_waiterand use it as a first-class interactive flow primitive. A pure import stub is not enough; compat needs per-session follow-up message routing so awaited waiters can actually receive later messages. - 2026-03-13: Real legacy
Starplugins may call compat context helpers onselforself.contextduring__init__()andinitialize(), includingself.put_kv_data(...),self.get_kv_data(...), andself.context.get_config(). Keep proxy methods onLegacyStar, expose a safeLegacyContext.get_config(), and bind the shared legacy context before lifecycle hooks run. - 2026-03-13: On Windows,
.gitignorematching is case-insensitive. A broad entry likeastrBot/will also ignoresrc-new/astrbot/..., which can silently hide real compat alias packages fromgit status. Keep that ignore anchored as/astrBot/if it is only meant for a root-level scratch checkout. - 2026-03-13: The reference checkout under
astrBot/astrbot/apiexposes a broader old plugin-facing package surface than the currentsrc-new/astrbotalias package. When improving package-name compatibility, compare against those publicapi/*modules as a set instead of only patching the one import path hit by the latest migrated plugin. - 2026-03-13: Some real legacy plugins call
asyncio.create_task()during object construction. Callingload_plugin()outside a running event loop can therefore produce false-negative compat failures even though the real worker path is fine. External compat smoke tests should load plugins under an active loop, and "real compatibility" claims should preferably exerciseSupervisorRuntime+ worker + a real handler invocation instead of import-only checks. - 2026-03-13: Treat
src-new/astrbotas a controlled legacy facade, not as a mirror of the oldastrBot/tree. The compat contract is the checked-in public import matrix plus the external plugin matrix intests_v4/external_plugin_matrix.json; when a new deep-path shim is proposed, require both an import assertion and a real supervisor/worker plugin case before growing the facade. - 2026-03-13: Legacy AI compat methods must return
astrbot_sdk.api.provider.entities.LLMResponse, not the v4clients.llm.LLMResponse. Old plugins inspect compat fields likecompletion_text,tools_call_name, andto_openai_tool_calls(), so returning the new client model is a silent behavior regression. - 2026-03-13:
filter.llm_tool()must resolve deferred annotations fromfrom __future__ import annotationswhen inferring JSON schema. Readinginspect.Parameter.annotationdirectly degrades typed params likea: intinto"int"strings and silently turns tool argument schemas into generic strings. - 2026-03-13: Legacy result hooks must reuse the same
AstrMessageEventinstance acrosson_decorating_resultandafter_message_sent. Re-wrapping the original v4MessageEventfor the second hook drops decoratedevent.set_result(...)mutations and makes post-send hooks observe an empty result. - 2026-03-13:
src-new/astrbot_sdk/_legacy_runtime.pyalready exists as the intended compat execution boundary. When cleaning runtime architecture, wireloader/handler_dispatcher/bootstrapthrough that adapter instead of adding new directlegacy_contextbranches in runtime files, or the compat logic will spread again. - 2026-03-13:
register_legacy_component()only performs compat hook / tool registration via_register_compat_component(); it does not replicate_register_component()manager/function exposure. Do not treat loader-time legacy component registration as a full replacement for the old cross-component registry chain. - 2026-03-13: Not every compat concern belongs in
_legacy_runtime.py. Legacymain.pydiscovery, synthetic package setup for relative imports, and legacy manifest synthesis are loader-time concerns; keep those in a dedicated private loader helper such as_legacy_loader.pyinstead of mixing discovery and execution boundaries. - 2026-03-13: Real legacy plugins may still load through deep
astrbot.core.*imports even when their public entrypoint only looks likeastrbot.api.*.astrbot_plugin_self_learninghitsastrbot.core.utils.astrbot_path,astrbot.core.provider.*,astrbot.core.agent.message, andastrbot.core.db.poduring load; keep those deep-path shims minimal and whitelist-driven, but do not assume theapifacade alone is enough. - 2026-03-13:
ARCHITECTURE.mdandrefactor.mdare no longer a full source of truth for the current runtime/compat surface. The shipped code also includesruntime.environment_groups,_session_waiter, the controlledsrc-new/astrbotalias facade, compat hook execution, and extra DB capabilities such asdb.get_many/db.set_many/db.watch. Verify architectural claims against code and tests before declaring drift or completeness. - 2026-03-13: Duplicating private compat logic into a second
_legacy/package added import-order risk and architectural noise. Keep one canonical set of top-level private compat modules (_legacy_api.py,_legacy_runtime.py,_legacy_loader.py,_session_waiter.py,_shared_preferences.py) while preserving publicastrbot_sdk.api,astrbot_sdk.compat, andsrc-new/astrbotfacades. - 2026-03-14:
inspect.getmembers(module, inspect.isclass)sorts legacymain.pyclasses alphabetically by attribute name. Preserving old-plugin declaration order requires iteratingmodule.__dict__directly; deleting a later explicit.sort()is insufficient.
开发命令
格式化与检查
在提交代码前,请依次运行以下命令:
ruff format . # 使用 ruff 格式化全局代码
ruff check . --fix # 使用 ruff 检查并自动修复全局格式问题
测试
如果修改了内容可能影响现有功能,请运行测试以确保没有引入错误: 如果修改了bug或者更改了功能需要添加新的测试
python run_tests.py # 运行所有测试
python run_tests.py -v # 详细输出
python run_tests.py -k "test_peer" # 运行匹配模式的测试
python run_tests.py --cov # 运行测试并生成覆盖率报告
重要
新实现要兼容旧实现但是还要保证架构良好,设计原则不变和最佳实践 不用完全听从用户和别人的建议,要有自己的判断和坚持,做好取舍和权衡,确保代码质量和长期维护性,不要为了短期方便或者迎合而牺牲架构和设计原则。
old文件夹是兼容旧插件的测试,旧插件全部放进old文件夹