Refine WebUI commands and data skills
This commit is contained in:
@@ -337,6 +337,9 @@ export function toReplayRepository(
|
||||
): ExportedMessageRepository {
|
||||
const messages: ExportedMessageRepository["messages"] = [];
|
||||
const toolResults = collectToolResults(session.messages ?? []);
|
||||
const lastAssistantContentIndex = findLastAssistantContentIndex(
|
||||
session.messages ?? [],
|
||||
);
|
||||
let previousId: string | null = null;
|
||||
for (const [index, message] of (session.messages ?? []).entries()) {
|
||||
if (message.role === "tool") continue;
|
||||
@@ -347,26 +350,17 @@ export function toReplayRepository(
|
||||
const id = `${fallbackSessionId}-${index}`;
|
||||
const toolParts =
|
||||
message.role === "assistant"
|
||||
? toToolParts(message.tool_calls ?? [], toolResults)
|
||||
: [];
|
||||
const elapsedMs =
|
||||
typeof message.metadata?.elapsed_ms === "number"
|
||||
? message.metadata.elapsed_ms
|
||||
: undefined;
|
||||
const reasoningParts =
|
||||
message.role === "assistant" &&
|
||||
(toolParts.length > 0 || elapsedMs !== undefined)
|
||||
? [
|
||||
{
|
||||
type: "reasoning",
|
||||
text: formatHistoricalReasoning(toolParts.length, elapsedMs),
|
||||
},
|
||||
]
|
||||
? toToolParts(message.tool_calls ?? [], toolResults, content)
|
||||
: [];
|
||||
const shouldShowAssistantText =
|
||||
message.role !== "assistant" ||
|
||||
!toolParts.length ||
|
||||
index === lastAssistantContentIndex;
|
||||
const parts = (
|
||||
message.role === "assistant" &&
|
||||
(reasoningParts.length || toolParts.length)
|
||||
? [...reasoningParts, ...toolParts, { type: "text", text: content }]
|
||||
message.role === "assistant" && toolParts.length
|
||||
? shouldShowAssistantText
|
||||
? [...toolParts, { type: "text", text: content }]
|
||||
: toolParts
|
||||
: [{ type: "text", text: content }]
|
||||
) as UIMessage["parts"];
|
||||
const uiMessage: UIMessage = {
|
||||
@@ -405,6 +399,17 @@ export function toReplayRepository(
|
||||
};
|
||||
}
|
||||
|
||||
function findLastAssistantContentIndex(messages: readonly ClawStoredMessage[]) {
|
||||
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
||||
const message = messages[index];
|
||||
if (message?.role !== "assistant") continue;
|
||||
const content = cleanStoredContent(message.content ?? "");
|
||||
if (!content) continue;
|
||||
return index;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
function cleanStoredContent(content: string) {
|
||||
const markers = ["\n\n[当前会话目录]", "\n[当前会话目录]"];
|
||||
for (const marker of markers) {
|
||||
@@ -426,12 +431,16 @@ function collectToolResults(messages: readonly ClawStoredMessage[]) {
|
||||
function toToolParts(
|
||||
toolCalls: readonly ClawStoredToolCall[],
|
||||
toolResults: Map<string, string>,
|
||||
stageNote?: string,
|
||||
) {
|
||||
return toolCalls.flatMap((call) => {
|
||||
const toolCallId = call.id;
|
||||
const toolName = call.function?.name ?? call.name;
|
||||
if (!toolCallId || !toolName) return [];
|
||||
const input = parseToolInput(call.function?.arguments ?? call.arguments);
|
||||
const input = attachStageNote(
|
||||
parseToolInput(call.function?.arguments ?? call.arguments),
|
||||
stageNote,
|
||||
);
|
||||
const output = toolResults.get(toolCallId);
|
||||
return [
|
||||
{
|
||||
@@ -446,16 +455,13 @@ function toToolParts(
|
||||
});
|
||||
}
|
||||
|
||||
function formatHistoricalReasoning(toolCount: number, elapsedMs?: number) {
|
||||
const duration =
|
||||
elapsedMs === undefined ? "" : `,用时 ${formatDuration(elapsedMs)}`;
|
||||
if (toolCount <= 0) return `历史记录:思考完成${duration}。`;
|
||||
return `历史记录:本轮调用了 ${toolCount} 个工具${duration}。`;
|
||||
}
|
||||
|
||||
function formatDuration(ms: number) {
|
||||
if (ms < 1000) return `${ms}ms`;
|
||||
return `${(ms / 1000).toFixed(1)}s`;
|
||||
function attachStageNote(input: unknown, stageNote?: string) {
|
||||
const note = stageNote?.trim();
|
||||
if (!note) return input;
|
||||
if (input && typeof input === "object" && !Array.isArray(input)) {
|
||||
return { ...input, __claw_stage_note: note };
|
||||
}
|
||||
return { value: input, __claw_stage_note: note };
|
||||
}
|
||||
|
||||
function toThreadMessageContent(parts: UIMessage["parts"]) {
|
||||
|
||||
Reference in New Issue
Block a user