Feat/2.6.0 beta4#2160
Open
RUCYancy wants to merge 12 commits into
Open
Conversation
The previous AUTOCOMMIT approach broke chat completions on DaMeng: returning an isolation_level="AUTOCOMMIT" connection to the pool makes SQLAlchemy reset the isolation level on checkin, and the dmAsync dialect cannot change session characteristics while a transaction is open -> dmPython [CODE:-6510] "Try to change property before transaction end". Drop async_execute_autocommit entirely and instead wrap touch_session's UPDATE->COMMIT in asyncio.shield, so a cancelled request cannot interrupt it between taking the row lock and committing (which leaked the lock). This uses the normal transaction path (no isolation-level changes), so it is DaMeng-safe. Test: test_touch_session_completes_write_despite_cancellation.
…o feat/2.6.0-beta4
There was a problem hiding this comment.
Pull request overview
This PR advances the v2.6.0 “Linsight task mode” groundwork (Wave-0/Track-0) by adding shared fixtures/POC scripts, introducing a plain-Redis LangGraph checkpointer, and updating backend runtime/build baselines (Python 3.11, dependency + Docker changes) alongside a new default loading SVG for the frontend brand config.
Changes:
- Add shared Linsight fixtures/stubs (WS event samples, step_type variants, Skill API mock, in-memory workspace backend) plus POC spike scripts and results docs.
- Introduce
PlainRedisCheckpointer(plain Redis, no RediSearch) and addlinsight_skilldomain model + Alembic migration + Skill error codes / contract updates. - Upgrade backend baseline to Python 3.11 (deps + Dockerfile/base image adjustments) and set brand loading icon SVG paths in both frontend bundles.
Reviewed changes
Copilot reviewed 33 out of 36 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| src/frontend/platform/public/assets/bisheng/loading.svg | Adds animated loading SVG asset for platform bundle. |
| src/frontend/platform/public/assets/bisheng/config.js | Points brand loading icon config to the new SVG. |
| src/frontend/client/public/assets/bisheng/loading.svg | Adds animated loading SVG asset for client bundle. |
| src/frontend/client/public/assets/bisheng/config.js | Points brand loading icon config to the new SVG. |
| src/backend/test/linsight/fixtures/ws_events/step_types.json | Adds WS fixture covering task_execute_step.step_type variants. |
| src/backend/test/linsight/fixtures/ws_events/event_samples.json | Adds canonical WS event samples fixture for protocol C1. |
| src/backend/test/linsight/fixtures/skill_api_mock.json | Adds Skill API mock responses + frontmatter/activation/errcode contract notes. |
| src/backend/test/linsight/fixtures/README.md | Documents purpose/usage of shared fixtures/stubs. |
| src/backend/test/linsight/fixtures/fake_workspace_backend.py | Provides in-memory WorkspaceBackend stub for cross-track development. |
| src/backend/test/linsight/fixtures/init.py | Package marker / high-level fixture description. |
| src/backend/test/database/test_session_lock_safety.py | Updates regression tests around cancellation rollback + touch_session behavior. |
| src/backend/scripts/035-linsight-deepagents/RESULTS.md | Captures Wave-0 POC spike conclusions and decisions. |
| src/backend/scripts/035-linsight-deepagents/README.md | Documents how to run POC scripts and what they validate. |
| src/backend/scripts/035-linsight-deepagents/poc_p5_required_files.py | Adds P5 evaluation skeleton for required_files compliance. |
| src/backend/scripts/035-linsight-deepagents/poc_p4_skill_call_reason.py | Adds P4 evaluation skeleton for call_reason + skill hit rate. |
| src/backend/scripts/035-linsight-deepagents/poc_p3_redis_checkpointer_resume.py | Adds P3 checkpointer/interrupt-resume validation script. |
| src/backend/scripts/035-linsight-deepagents/poc_p2_subgraph_streaming.py | Adds P2 subgraph streaming + namespace isolation script. |
| src/backend/scripts/035-linsight-deepagents/poc_p1_backend_injection.py | Adds P1 backend injection validation script. |
| src/backend/pyproject.toml | Raises Python baseline to 3.11, swaps to faust-cchardet, adds deepagents. |
| src/backend/Dockerfile.dm-test | Removes DaMeng connectivity test Dockerfile. |
| src/backend/Dockerfile | Refactors build to use uv sync + venv, updates DM_HOME pathing. |
| src/backend/bisheng/linsight/domain/services/checkpointer.py | Implements plain-Redis LangGraph checkpointer (PlainRedisCheckpointer). |
| src/backend/bisheng/linsight/domain/models/linsight_skill.py | Adds SQLModel for tenant-scoped custom Skill metadata. |
| src/backend/bisheng/database/models/session.py | Changes touch_session to use a shielded update/commit path. |
| src/backend/bisheng/core/database/tenant_filter.py | Type-hint/style adjustments; adds linsight_skill module to import list. |
| src/backend/bisheng/core/database/manager.py | Removes async_execute_autocommit helper wrapper. |
| src/backend/bisheng/core/database/connection.py | Removes async_execute_autocommit implementation. |
| src/backend/bisheng/core/database/alembic/versions/v2_6_0_f035_linsight_skill.py | Adds Alembic migration creating linsight_skill table. |
| src/backend/bisheng/core/database/init.py | Updates exports to remove async_execute_autocommit. |
| src/backend/bisheng/common/errcode/linsight.py | Normalizes strings + adds Skill-management error codes (11051–11055). |
| src/backend/base.Dockerfile | Switches base image to Python 3.11 slim; caches Playwright Chromium install. |
| features/v2.6.0/release-contract.md | Updates release-contract notes for F035 errcode/pylib baseline details. |
| features/v2.6.0/035-linsight-task-mode/依赖与契约约定.md | Freezes contracts; updates C2/C3/C5 details and checklists. |
| features/v2.6.0/035-linsight-task-mode/tasks.md | Updates task plan/status and records key deviations/decisions. |
| features/v2.6.0/035-linsight-task-mode/design.md | Minor wording correction re: tenant resolution in worker context. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+5
to
+8
| # 先装依赖再复制源码,利用 Docker 层缓存:uv.lock 不变时此层命中缓存 | ||
| COPY ./pyproject.toml ./uv.lock ./ | ||
| RUN uv sync --frozen --no-dev && uv cache clean | ||
| ENV PATH="/app/.venv/bin:$PATH" |
Comment on lines
+10
to
+13
| # 安装 NLTK 数据(依赖 Python 环境,放在 uv sync 之后) | ||
| RUN python -c "import nltk; nltk.download('punkt'); nltk.download('punkt_tab'); nltk.download('averaged_perceptron_tagger'); nltk.download('averaged_perceptron_tagger_eng')" | ||
|
|
||
| # Patch SQLAlchemy's aiomysql adapter: AsyncAdapt_aiomysql_connection.ping is | ||
| # declared with `reconnect: bool` (no default) in every released 2.0.x, but | ||
| # the pymysql dialect's pool pre-checkout calls `dbapi_connection.ping()` | ||
| # without args (PyMySQL >= 1.0 defaults reconnect=False, so SQLAlchemy infers | ||
| # it can be called bare). The mismatch raises TypeError on every connection | ||
| # checkout, which breaks login. Upstream has no fix as of 2.0.49, so we | ||
| # inject the default here. Safe to remove once SQLAlchemy ships the fix. | ||
| RUN SITE=$(python -c "import site; print(site.getsitepackages()[0])") && \ | ||
| AIOMYSQL_PY="$SITE/sqlalchemy/dialects/mysql/aiomysql.py" && \ | ||
| if [ -f "$AIOMYSQL_PY" ]; then \ | ||
| sed -i 's|def ping(self, reconnect: bool) -> None:|def ping(self, reconnect: bool = False) -> None:|' "$AIOMYSQL_PY" && \ | ||
| grep -q "def ping(self, reconnect: bool = False)" "$AIOMYSQL_PY" || (echo "sqlalchemy aiomysql ping patch did not apply, aborting build" && exit 1); \ | ||
| fi | ||
| COPY ./ ./ |
Comment on lines
+84
to
+87
| @staticmethod | ||
| def _decode_task_id(encoded: str) -> str: | ||
| padding = 4 - len(encoded) % 4 | ||
| return base64.urlsafe_b64decode(encoded + "=" * padding).decode() |
Comment on lines
+345
to
+369
| def get_tuple(self, config: RunnableConfig) -> CheckpointTuple | None: | ||
| return asyncio.get_event_loop().run_until_complete(self.aget_tuple(config)) | ||
|
|
||
| def list( | ||
| self, | ||
| config: RunnableConfig | None, | ||
| *, | ||
| filter: dict[str, Any] | None = None, | ||
| before: RunnableConfig | None = None, | ||
| limit: int | None = None, | ||
| ): | ||
| async def _collect(): | ||
| return [t async for t in self.alist(config, filter=filter, before=before, limit=limit)] | ||
|
|
||
| return iter(asyncio.get_event_loop().run_until_complete(_collect())) | ||
|
|
||
| def put( | ||
| self, | ||
| config: RunnableConfig, | ||
| checkpoint: Checkpoint, | ||
| metadata: CheckpointMetadata, | ||
| new_versions: ChannelVersions, | ||
| ) -> RunnableConfig: | ||
| return asyncio.get_event_loop().run_until_complete(self.aput(config, checkpoint, metadata, new_versions)) | ||
|
|
Comment on lines
+82
to
+86
| task = asyncio.ensure_future(session_module.MessageSessionDao.touch_session("chat-abc")) | ||
| await asyncio.sleep(0) # let the shielded write start | ||
| task.cancel() | ||
| with pytest.raises(asyncio.CancelledError): | ||
| await task |
Comment on lines
+318
to
+328
| async def _run() -> None: | ||
| async with get_async_db_session() as session: | ||
| await session.exec(statement) | ||
| await session.commit() | ||
|
|
||
| # Shield the UPDATE -> COMMIT so a cancelled request cannot interrupt it | ||
| # between taking the row lock and committing, which would leak the lock | ||
| # (idle-in-transaction) and stall the pool. AUTOCOMMIT was avoided | ||
| # because the dmAsync dialect cannot reset the isolation level on | ||
| # connection checkin while a transaction is open ([CODE:-6510]). | ||
| await asyncio.shield(_run()) |
Comment on lines
+36
to
+40
| enabled: bool = Field( | ||
| default=True, | ||
| description="Whether the skill is enabled", | ||
| sa_column=Column("enabled", Integer, nullable=False, server_default=text("1"), comment="Enabled flag"), | ||
| ) |
Comment on lines
+19
to
+29
| import asyncio | ||
| import operator | ||
| import uuid | ||
| from typing import Annotated, TypedDict | ||
|
|
||
| from langgraph.checkpoint.memory import InMemorySaver | ||
| from langgraph.graph import END, START, StateGraph | ||
| from langgraph.types import Command, interrupt | ||
|
|
||
| REDIS_URL = "redis://192.168.106.116:6379/9" | ||
|
|
…o feat/2.6.0-beta4
…yed batch-move when no permission; relabel REBUILDING as Processing
…ling && from uv-cache-clean sed; replace line-number inserts with content-anchored awk)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.