feat: improve conversation timeline and agent plans

This commit is contained in:
shiyue
2026-07-29 16:50:12 +08:00
parent 4d97446a6f
commit 33c9783079
16 changed files with 663 additions and 59 deletions

View File

@@ -2903,18 +2903,32 @@ function normalizeTitleHistory(history) {
const title = String(event.title || '').replace(/\s+/g, ' ').trim().slice(0, 120);
const changedAtMs = Date.parse(String(event.changedAt || ''));
const messageIndex = Number(event.messageIndex);
const anchorMessageIndex = event.anchorMessageIndex;
const source = String(event.source || '').trim().toLowerCase();
if (!title || !Number.isFinite(changedAtMs) || !Number.isFinite(messageIndex) || messageIndex < 0 || source !== 'llm') return;
normalized.push({
const normalizedMessageIndex = Math.trunc(messageIndex);
const normalizedEvent = {
title,
changedAt: new Date(changedAtMs).toISOString(),
messageIndex: Math.trunc(messageIndex),
messageIndex: normalizedMessageIndex,
source: 'llm',
});
};
if (Number.isInteger(anchorMessageIndex) && anchorMessageIndex >= 0 && anchorMessageIndex < normalizedMessageIndex) {
normalizedEvent.anchorMessageIndex = anchorMessageIndex;
}
normalized.push(normalizedEvent);
});
return normalized.slice(-100);
}
function findLatestUserMessageIndex(messages) {
if (!Array.isArray(messages)) return null;
for (let index = messages.length - 1; index >= 0; index -= 1) {
if (messages[index]?.role === 'user') return index;
}
return null;
}
function normalizeSession(session) {
if (!session || typeof session !== 'object') return session;
session.agent = normalizeAgent(session.agent);
@@ -7320,10 +7334,13 @@ function setCurrentConversationTitle(args = {}, sourceSessionId = '') {
const changed = previousTitle !== normalizedTitle;
let titleEvent = null;
if (changed) {
const messageIndex = Array.isArray(session.messages) ? session.messages.length : 0;
const anchorMessageIndex = findLatestUserMessageIndex(session.messages);
titleEvent = {
title: normalizedTitle,
changedAt: new Date().toISOString(),
messageIndex: Array.isArray(session.messages) ? session.messages.length : 0,
messageIndex,
...(anchorMessageIndex !== null ? { anchorMessageIndex } : {}),
source: 'llm',
};
session.titleHistory = normalizeTitleHistory([...(session.titleHistory || []), titleEvent]);
@@ -8815,18 +8832,20 @@ function findLatestCcwebMcpCollabToolInToolCalls(toolCalls = []) {
}
function findCcwebMcpChildTargetToolInToolCalls(toolCalls = [], spawnToolId = '') {
return findExactCcwebMcpChildToolInToolCalls(toolCalls, spawnToolId)
|| findLatestCcwebMcpCollabToolInToolCalls(toolCalls);
const targetId = String(spawnToolId || '').trim();
if (targetId) return findExactCcwebMcpChildToolInToolCalls(toolCalls, targetId);
return findLatestCcwebMcpCollabToolInToolCalls(toolCalls);
}
function findCcwebMcpChildTargetToolInMessages(messages = [], spawnToolId = '') {
if (!Array.isArray(messages)) return null;
const targetId = String(spawnToolId || '').trim();
let latestCollabTool = null;
for (let i = messages.length - 1; i >= 0; i -= 1) {
const toolCalls = Array.isArray(messages[i]?.toolCalls) ? messages[i].toolCalls : [];
const exactTool = findExactCcwebMcpChildToolInToolCalls(toolCalls, spawnToolId);
const exactTool = findExactCcwebMcpChildToolInToolCalls(toolCalls, targetId);
if (exactTool) return exactTool;
if (!latestCollabTool) latestCollabTool = findLatestCcwebMcpCollabToolInToolCalls(toolCalls);
if (!targetId && !latestCollabTool) latestCollabTool = findLatestCcwebMcpCollabToolInToolCalls(toolCalls);
}
return latestCollabTool;
}
@@ -8959,6 +8978,9 @@ function syncCcwebMcpChildAgentsFromCollabItem(routed, item = {}) {
if (receiverThreadIds.length === 0) return;
const activityAgentPath = String(item.agentPath || item.agent_path || '').trim();
const activityPrompt = String(item.prompt || item.taskDescription || item.task_description || '').trim();
const activityVisibleToolId = isSubAgentActivity
? String((routed.role === 'child' ? routed.child?.spawnToolId : '') || item.id || '').trim()
: '';
const activityState = isSubAgentActivity ? {
label: activityAgentPath ? path.basename(activityAgentPath) : '',
role: String(item.role || item.agentRole || item.agent_role || '').trim(),
@@ -8985,7 +9007,7 @@ function syncCcwebMcpChildAgentsFromCollabItem(routed, item = {}) {
turnId: null,
parentSessionId: routed.sessionId,
parentThreadId,
spawnToolId: isSpawn ? item.id : '',
spawnToolId: isSpawn ? (activityVisibleToolId || item.id) : '',
label: ccwebMcpChildLabel(state, threadId),
role: String(state.role || state.agent || state.agentType || state.agent_type || '').trim(),
agentPath: String(state.agentPath || state.agent_path || '').trim(),
@@ -9001,6 +9023,7 @@ function syncCcwebMcpChildAgentsFromCollabItem(routed, item = {}) {
createdAt: now,
updatedAt: now,
};
if (isSubAgentActivity && activityVisibleToolId) child.spawnToolId = activityVisibleToolId;
if (!child.spawnToolId && isSpawn) child.spawnToolId = item.id;
if (!child.spawnToolId && item.id) child.spawnToolId = item.id;
child.parentSessionId = child.parentSessionId || routed.sessionId;