mirror of
https://github.com/hansjone/oclaw.git
synced 2026-10-09 04:40:45 +08:00
统一会话展示与专家路由行为,修复图片异步显示与气泡宽度问题。
本次移除 image 专家角色并同步更新路由/绑定/测试,同时增强 session-bootstrap 的共享与角色分层记忆加载,减少刷新依赖并提升默认可用性。 Made-with: Cursor
This commit is contained in:
parent
1ebfa47dd3
commit
d5e30542aa
19 changed files with 199 additions and 62 deletions
|
|
@ -3445,6 +3445,7 @@ async function renderChatUi() {
|
|||
let hasRealStreamText = false;
|
||||
let sawWsChatEvent = false;
|
||||
let sawWsTerminalEvent = false;
|
||||
let sawStreamToolRefAttachments = false;
|
||||
let markerState = { p: 0, e: false, ep: 0, t: 0, s: 0, k: 0, reclaimed: 0 };
|
||||
let turnAcceptedAtMs = null;
|
||||
let phaseRunningAtMs = null;
|
||||
|
|
@ -3796,6 +3797,31 @@ ${autoLimit ? `<div style="margin-top:8px;"><span class="muted">auto-added claus
|
|||
const body = formatToolPanelText(name, rawPayload, { streamMode: true });
|
||||
const sqlAudit = extractSqlAuditPayload(rawPayload);
|
||||
const images = extractToolImageItems(rawPayload);
|
||||
const _containsRefAttachments = (obj, depth = 0) => {
|
||||
if (!obj || typeof obj !== "object" || depth > 4) return false;
|
||||
// Common case: { attachments: [...] }
|
||||
if (Array.isArray(obj.attachments)) {
|
||||
for (const att of obj.attachments) {
|
||||
if (!att || typeof att !== "object") continue;
|
||||
const typ = String(att.type || "").toLowerCase();
|
||||
if (!typ) continue;
|
||||
if (typ.endsWith("_ref") || typ === "relay_pointer") return true;
|
||||
}
|
||||
}
|
||||
// Recurse a few common container keys first.
|
||||
const keys = ["result", "payload", "message", "data", "output"];
|
||||
for (const k of keys) {
|
||||
if (k in obj && _containsRefAttachments(obj[k], depth + 1)) return true;
|
||||
}
|
||||
// Shallow scan other object values (bounded).
|
||||
let scanned = 0;
|
||||
for (const v of Object.values(obj)) {
|
||||
if (scanned++ > 12) break;
|
||||
if (_containsRefAttachments(v, depth + 1)) return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
if (_containsRefAttachments(rawPayload)) sawStreamToolRefAttachments = true;
|
||||
chatStreamSegments.push({ type: "tool", key, title: `${name} ${liveTag}`, body, sqlAudit, images });
|
||||
};
|
||||
const appendFinalAssistant = async (message, fallbackText) => {
|
||||
|
|
@ -3954,6 +3980,15 @@ ${autoLimit ? `<div style="margin-top:8px;"><span class="muted">auto-added claus
|
|||
renderStreamComposite();
|
||||
_markStreamTerminal("end", t("chat.status.end"));
|
||||
ok = true;
|
||||
} else if (sawStreamToolRefAttachments) {
|
||||
// Streaming UI cannot render image_ref/relay_pointer; recover from persisted history so images appear
|
||||
// without requiring a manual refresh.
|
||||
try {
|
||||
if (streamRow && streamRow.parentNode) streamRow.remove();
|
||||
} catch (_) {}
|
||||
await loadMessagesForActive();
|
||||
scrollMessagesToBottom(true);
|
||||
ok = true;
|
||||
} else {
|
||||
ok = await appendFinalAssistant(payload.message, chatStream || extractWsAssistantText(payload.message || {}));
|
||||
}
|
||||
|
|
@ -3961,6 +3996,7 @@ ${autoLimit ? `<div style="margin-top:8px;"><span class="muted">auto-added claus
|
|||
chatStream = "";
|
||||
streamTextBuffer = "";
|
||||
chatRunId = null;
|
||||
sawStreamToolRefAttachments = false;
|
||||
const streamedEnough = hasRealStreamText || chatStreamSegments.length > 0 || sawWsChatEvent;
|
||||
turnFinalized = true;
|
||||
turnStreamedEnough = streamedEnough;
|
||||
|
|
|
|||
|
|
@ -471,7 +471,9 @@ body.theme-ds-body .card {
|
|||
|
||||
/* 与 .chat-avatar-slot 48px + .chat-row gap 10px 一致 */
|
||||
.chat-msg-col--assistant {
|
||||
width: min(max(0px, calc(50% + 2cm - 58px)), 100%);
|
||||
/* 宽度随容器自适应,但最宽限制为 50% + 2cm(扣除头像轨 58px)。 */
|
||||
flex: 1 1 auto;
|
||||
width: auto;
|
||||
max-width: min(max(0px, calc(50% + 2cm - 58px)), 100%);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue