Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions backend/client_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,13 @@ def enchante_agent_deeplink() -> str:
``enchante://agent/install?name=MyKnowledge 知识管理专家&config=<base64>``

Creates a one-click dedicated "MyKnowledge 知识管理专家" role in Enchanté's top
Agent dropdown. Payload schema confirmed with Enchante (2026-08-19):
Agent dropdown. Payload schema confirmed with Enchante (2026-08-19), amended
2026-08-26 after a real-device install failed silently — Enchanté requires
the display name **inside** the base64 JSON too (top-level ``name``), not
only as the outer ``?name=`` query param; without it, deserialization/
validation fails silently and the deeplink never surfaces an install prompt:
- ``name``: same display string as the outer query param, duplicated at
the JSON top level (Enchanté's requirement, not redundant on our side).
- ``role``: the agent persona / system instructions, reusing
``_agent_template("Enchante")`` (``MyKnowledge-agent-Enchante.md``, 精简版)
**as plain text — no YAML frontmatter** (Enchanté injects it verbatim as
Expand All @@ -289,7 +295,9 @@ def enchante_agent_deeplink() -> str:
Conflict Resolution float — Replace / Rename / Skip).
"""
import urllib.parse
display_name = "MyKnowledge 知识管理专家"
bundle = {
"name": display_name,
"role": _agent_template("Enchante"),
"skillNames": [],
"mcpServers": {
Expand All @@ -301,7 +309,7 @@ def enchante_agent_deeplink() -> str:
}
},
}
name = urllib.parse.quote("MyKnowledge 知识管理专家")
name = urllib.parse.quote(display_name)
return (f"enchante://agent/install?name={name}&config="
f"{_base64_quote(bundle)}")

Expand Down
13 changes: 9 additions & 4 deletions tests/test_client_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -723,12 +723,14 @@ def test_deeplink_base64_decodes_after_unquote(self, fake_home: Path) -> None:
assert bundle["config"]["env"]["MYKNOWLEDGE_CLIENT"] == "Enchante"

def test_agent_deeplink(self, fake_home: Path) -> None:
"""Agent deeplink (schema confirmed with Enchante 2026-08-19).
"""Agent deeplink (schema confirmed with Enchante 2026-08-19, amended
2026-08-26: top-level ``name`` added after a real-device install failed
silently without it — see ``enchante_agent_deeplink`` docstring).

Pins the URL scheme, display name ``MyKnowledge 知识管理专家``, the shared
'+'→'%2B' quoting + base64 round-trip, and the confirmed payload schema
``{role, skillNames, mcpServers}`` (role reuses the agent template, the
mcpServers bundle reuses mcp_entry("Enchante")).
'+'→'%2B' quoting + base64 round-trip, and the payload schema
``{name, role, skillNames, mcpServers}`` (role reuses the agent template,
the mcpServers bundle reuses mcp_entry("Enchante")).
"""
import base64
import urllib.parse
Expand All @@ -741,6 +743,9 @@ def test_agent_deeplink(self, fake_home: Path) -> None:
assert "+" not in enc # '+'→'%2B'
bundle = json.loads(
base64.b64decode(urllib.parse.unquote(enc)).decode("utf-8"))
# top-level name must match the outer ?name= query param exactly —
# Enchante requires it duplicated inside the JSON, not only outside.
assert bundle["name"] == "MyKnowledge 知识管理专家"
assert bundle["role"].startswith("# MyKnowledge Agent")
# no standalone skill is shipped anymore → skillNames stays empty
assert bundle["skillNames"] == []
Expand Down
Loading