release: v1.6.6

Ship the v1.6.5 feedback sweep: answers that could not submit now
arrive, a copy button reports what actually happened, partners can use
connected knowledge bases, Codex sign-in finishes inside Docker, and the
home route is 100KB lighter.

Release notes: assets/releases/ver1-6-6.md
This commit is contained in:
Bingxi Zhao (Frank)
2026-09-08 15:46:59 +08:00
parent abd7fbcdce
commit 7a96bba1ae
7 changed files with 79 additions and 11 deletions
+5 -3
View File
@@ -50,17 +50,19 @@
### 📦 Releases
> **[2026.9.8]** [v1.6.6](https://github.com/HKUDS/DeepTutor/releases/tag/v1.6.6) — A fix release: answers that could not submit, a copy button that lied, connected knowledge bases for partners, Codex sign-in inside Docker, and a 100 KB lighter home route.
> **[2026.9.6]** [v1.6.5](https://github.com/HKUDS/DeepTutor/releases/tag/v1.6.5) — A content workspace you point at any folder, one `exec` tool for every language, Mastery Path modes that gate its tools, and Settings that grades readiness.
> **[2026.9.3]** [v1.6.4](https://github.com/HKUDS/DeepTutor/releases/tag/v1.6.4) — Faster isolated runtimes, controllable Book generation, source-complete Mastery paths and Chat hand-offs, durable Reading, unified activity UI, recoverable sessions, and explicit per-model API capabilities.
> **[2026.9.2]** [v1.6.3](https://github.com/HKUDS/DeepTutor/releases/tag/v1.6.3) — Breaking front/back-end refactor, strict canonical routes and recoverable streams, plus learner/guardian accounts, grounded Reading, WeKnora, broader parsing, Python 3.14, and DashScope media.
> **[2026.8.31]** [v1.6.2](https://github.com/HKUDS/DeepTutor/releases/tag/v1.6.2) — Immersive YouTube learning, a plugin-driven Visualize catalog, three new agent harnesses, safer reading citations, multi-format MinerU, live Partner channel status, and guided updates.
<details>
<summary><b>Past releases (more than 1 week ago)</b></summary>
> **[2026.8.31]** [v1.6.2](https://github.com/HKUDS/DeepTutor/releases/tag/v1.6.2) — Immersive YouTube learning, a plugin-driven Visualize catalog, three new agent harnesses, safer reading citations, multi-format MinerU, live Partner channel status, and guided updates.
> **[2026.8.30]** [v1.6.1](https://github.com/HKUDS/DeepTutor/releases/tag/v1.6.1) — One vendor key linked to every service it serves, a task model for background work, Settings as a searchable navigator, a sidebar you arrange, and first-party **LightRAG**.
> **[2026.8.27]** [v1.6.0](https://github.com/HKUDS/DeepTutor/releases/tag/v1.6.0) — Faithful EPUB reading and annotations, Courses with Little Tutor and Ask Questions, bounded web-source sync, shared Books with private learning state, and Serply/native search.
@@ -205,7 +207,7 @@
</details>
> ✨ **v1.6.5 is live.** `pip install -U deeptutor` picks up the latest stable release.
> ✨ **v1.6.6 is live.** `pip install -U deeptutor` picks up the latest stable release.
### 📰 News
+61
View File
@@ -0,0 +1,61 @@
# DeepTutor v1.6.6 Release Notes
**Release Date:** 2026.09.08
v1.6.6 is a fix release, and an unusually clarifying one. Working through the v1.6.5 feedback showed that most of what people reported was not a regression: v1.6.5 mostly removed things that had been masking older breakage, so answers that silently failed to submit, a copy button that reported success it never had, and reading actions unusable since v1.6.0 all became visible at once. Those are fixed here, along with the batch of community pull requests behind them. Drop-in — no migrations.
## What's New
### Answers you submit actually arrive
An `ask_user` card whose turn had already ended could no longer reach the backend, so submitting did nothing. Worse, the three composers discarded what you had typed when a submission was refused, while the error told you to send a new message — which was the very thing being blocked. Both are fixed: a finished turn that still owns an unanswered card keeps its address, and a refused answer is re-sent as an ordinary message instead of being thrown away.
Notebook entries with answer images could not be saved at all since v1.6.3 — the insert listed 23 columns against 22 values and raised `OperationalError` every time.
### A noticeably lighter first load
The generated brand-icon table — every store logo, about 95 KB — was riding in the app-shell chunk that every route shares, for the sake of one footer link. It is out, the sidebar's session-organization UI and the Co-Writer notebook picker now load on demand, and the home route dropped from 305 KB to 203 KB against a 300 KB budget. No route is over budget any more.
### Copy actually copies
The copy button reported success whether or not anything reached the clipboard, and announced that false success through `aria-live` — so a screen-reader user was told the copy worked when it had not. Clipboard access is now probed before the first `await` (spending the user-gesture allowance too early was the underlying cause) and a real failure is shown as one.
### Knowledge bases: names, uploads, empty bases
A knowledge base named with a slash could be created and then never deleted. Validation now lives on the manager, so all eight registration entry points share it, and a bad name that already exists can be removed. Large uploads that failed mid-transfer with a bare "Failed to fetch" also work: the proxy was replaying the client's `Expect: 100-continue` header, which undici rejects outright. Creating an empty knowledge base no longer raises progress errors.
### Partners can use your connected knowledge bases
Assigning an Obsidian vault, a linked index, WeKnora or IMA to a partner used to fail outright: provisioning only knew how to copy a folder, and a pointer knowledge base has none by design. Connected bases are now registered as pointers, stay visible in the partner's library, and can be removed again. Obsidian, MarginNote and subagent bases are deliberately declined — each drives an exclusive capability that would take over every one of that partner's turns.
Files a partner presents in chat download for the person who asked, and a partner conversation now shows which chat it came from, so a Feishu group thread is no longer indistinguishable from a direct message.
### Chat stops reaching for tools it does not have
`read_source` belongs to the context investigator that runs before the answer loop, not to the loop itself. The prompt and the attached-sources manifest said otherwise, so the model kept trying to reopen PDFs through a file tool it was never given.
### Reasoning arrives where it was missing
The shared agentic loop never captured a round's reasoning — the field did not exist on its result type — so surfaces built on it, including book quizzes, surfaced provider reasoning errors instead of content. It is carried through now.
### Codex sign-in finishes inside Docker
When the browser cannot reach the container's loopback callback, you can paste the address the browser landed on and complete the sign-in. The pasted address must match the redirect URI registered for that attempt exactly, and duplicated OAuth parameters are refused as ambiguous; it is parsed and discarded, never fetched, stored, or echoed back. The catalog compatibility version was also raised, so eligible models that older versions omitted now appear.
### Smaller fixes worth naming
Four reading actions that need a text selection have been unusable by mouse since v1.6.0 — the annotation popover disarmed the toolbar before the click landed. Asking a tutor for another language works, and the browser and server copies of that preference stop drifting apart. Mastery Path recognises `mastery_mode` as a tool that rebinds the path. Learner accounts can open courses again. Malformed `###heading` text is normalized without touching `#include` inside a code fence.
## Fixes
The Moonshot Kimi `k3` family is named once instead of per released id, so `k3-256k` and later variants keep their temperature override; Responses requests rejected for an unsupported `input[N].status` retry once without it and remember the model; the LightRAG SDK moves off the release candidate to 1.5.7; and the README overview screenshot is current.
## Upgrade Notes
Run `pip install -U deeptutor`; Docker users pull `ghcr.io/hkuds/deeptutor:latest`. Nothing needs migrating.
- **Rolling back to v1.6.4 fixes almost none of this.** Most of these defects predate v1.6.5; only the knowledge-base naming and Mastery Path issues have genuinely new v1.6.5 surface area.
- If a custom prompt or plugin told the answer loop to call `read_source`, move that work to the context investigator — the loop does not mount it.
- The English and Chinese guides have been updated together at [deeptutor.info](https://deeptutor.info/).
**Full Changelog**: https://github.com/HKUDS/DeepTutor/compare/v1.6.5...v1.6.6
+1 -1
View File
@@ -6,6 +6,6 @@ before publishing to PyPI; the web sidebar badge and CLI banner read from this
file directly.
"""
__version__ = "1.6.5"
__version__ = "1.6.6"
__all__ = ("__version__",)
+8 -4
View File
@@ -776,17 +776,21 @@ async def _selected_remote_parser_reachable(
) -> bool | None:
try:
if engine_id == "tika":
from deeptutor.services.parsing.engines.tika.remote import verify_remote
from deeptutor.services.parsing.engines.tika.remote import (
verify_remote as verify_tika_remote,
)
ok, _ = await asyncio.wait_for(
asyncio.to_thread(verify_remote, config, 2.0), timeout=3.0
asyncio.to_thread(verify_tika_remote, config, 2.0), timeout=3.0
)
return bool(ok)
if engine_id == "docling" and bool(getattr(config, "is_remote", False)):
from deeptutor.services.parsing.engines.docling.remote import verify_remote
from deeptutor.services.parsing.engines.docling.remote import (
verify_remote as verify_docling_remote,
)
ok, _ = await asyncio.wait_for(
asyncio.to_thread(verify_remote, config, 2.0), timeout=3.0
asyncio.to_thread(verify_docling_remote, config, 2.0), timeout=3.0
)
return bool(ok)
if engine_id == "mineru" and bool(getattr(config, "is_cloud", False)):
+2 -2
View File
@@ -341,10 +341,10 @@ def list_assets(partner_id: str) -> dict[str, list[dict[str, Any]]]:
# cannot see one. Left out, an assigned WeKnora or linked KB was invisible
# in the partner's library AND never excluded from the picker, so the user
# kept assigning it and kept seeing nothing happen.
for name, entry in sorted(_partner_kb_config(root).items()):
for name, config_entry in sorted(_partner_kb_config(root).items()):
if any(row["name"] == name for row in kbs):
continue
kbs.append({"name": name, "documents": 0, "type": entry.get("type", "")})
kbs.append({"name": name, "documents": 0, "type": config_entry.get("type", "")})
skills: list[dict[str, Any]] = []
skills_root = service.get_workspace_dir() / "skills"
+2 -1
View File
@@ -683,7 +683,8 @@ class ContentWorkspaceService:
generated=relative.startswith("outputs/"),
)
manifest = manifests / f"{item_id}.json"
atomic_update(manifest, lambda _stored, payload=item.to_dict(): payload)
payload = item.to_dict()
atomic_update(manifest, lambda _stored: payload)
published.append(item)
return published