feat: inline markdown output box — render AI reply with marked, do not replace cell
Flow (v3-final corrected):
1. Model call succeeds.
2. Server passes the AI reply through unchanged as 'markdown' (the
system prompt allows ```language fences + a brief explanation, so
the response is real markdown that marked can render into code
blocks, headings, etc.).
3. Client OpenCodeCellActions._handleResponse calls prompt.setOutput(
resp.markdown); the inline prompt widget renders it with
marked.parse and shows it in a new output area (hidden until a
response arrives). The cell source is NOT replaced.
4. User can close the output or cancel the whole prompt.
Server:
- New unified system prompt: '你是代码助手 ... 按指令修改代码,可附简
短说明' (allows ```fences``` + explanation; no more 'no markdown
fences' restriction).
- EditHandler returns {ok, markdown, sessionId, notebookPath} (raw
text, fences intact). _strip_code_fence kept as a helper for any
future apply-to-cell path; no longer called.
- finalSource field dropped (the cell-apply path is gone).
Client:
- OpenCodeSuccess: markdown: string (finalSource removed).
- OpenCodeInlinePrompt: new output area, setOutput(md) renders via
marked.parse, hideOutput() closes it.
- OpenCodeCellActions._handleResponse: setOutput(markdown) instead of
sharedModel.setSource + auto-hide. The prompt stays open so the
user can read the output.
- Uses marked@17 (already in node_modules via JupyterLab; no new dep).
- CSS: output area styling (border, max-height 320px scroll, code/pre
styling, close button).
Tests: pytest 34/34, jest 29/29. marked is mocked in jest.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
04f90ab5a0
commit
1d7f5da9d4
@@ -14,13 +14,15 @@ from .session_manager import SessionManager
|
||||
log = logging.getLogger("opencode_bridge.routes")
|
||||
|
||||
|
||||
# Unified system prompt — the LLM (OpenCode) itself judges whether the user's
|
||||
# natural-language instruction is an optimize / fix / edit request, based on
|
||||
# the code context and the optional <traceback> in the parts below.
|
||||
# Unified system prompt — the LLM (OpenCode) is asked to return its reply
|
||||
# as MARKDOWN (code wrapped in ```language fences; a brief explanation is
|
||||
# fine). The frontend renders this with `marked` directly — no fence
|
||||
# stripping on the server, so the response keeps the structure that makes
|
||||
# markdown rendering meaningful (code blocks, headings, etc.).
|
||||
UNIFIED_SYSTEM_PROMPT = (
|
||||
"你是一个代码编辑助手。基于提供的代码上下文(以及 traceback,如果有),"
|
||||
"按照用户的指令修改代码。返回只包含修改后完整代码的回复,"
|
||||
"不要任何解释或 markdown 围栏。"
|
||||
"你是一个代码助手。基于提供的代码上下文(以及可选的 traceback),"
|
||||
"按照用户的指令修改代码。"
|
||||
"可附简短说明。"
|
||||
)
|
||||
|
||||
|
||||
@@ -87,7 +89,11 @@ def _build_request_body(prompt: str, context: dict) -> dict:
|
||||
|
||||
|
||||
def _strip_code_fence(s: str) -> str:
|
||||
"""Strip ```language ... ``` fences from LLM output."""
|
||||
"""Strip ```language ... ``` fences from LLM output.
|
||||
|
||||
Kept for any future "apply-to-cell" path that needs clean source.
|
||||
Not used by the current markdown-rendering display flow.
|
||||
"""
|
||||
s = s.strip()
|
||||
if s.startswith("```"):
|
||||
lines = s.split("\n")
|
||||
@@ -185,11 +191,14 @@ class EditHandler(APIHandler):
|
||||
for p in result.get("parts", [])
|
||||
if p.get("type") == "text"
|
||||
]
|
||||
final_source = _strip_code_fence("\n".join(text_parts).strip())
|
||||
# The AI's reply is markdown (code in ```fences```, optional
|
||||
# explanation). Pass it through unchanged so the frontend
|
||||
# `marked.parse` can render the code blocks and structure.
|
||||
markdown = "\n".join(text_parts).strip()
|
||||
|
||||
self.finish(json.dumps({
|
||||
"ok": True,
|
||||
"finalSource": final_source,
|
||||
"markdown": markdown,
|
||||
"sessionId": sid,
|
||||
"notebookPath": notebook_path,
|
||||
}))
|
||||
|
||||
Reference in New Issue
Block a user