Merge pull request #1581 from pikasTech/fix/1567-read-side-projection
fix: Workbench 读侧 final text 推理清零
This commit is contained in:
@@ -3,7 +3,7 @@ import test from "node:test";
|
||||
|
||||
import type { AgentRunProvenance, ChatMessage, TraceEvent } from "../src/types/index.ts";
|
||||
import { canCancelMessage, canRetryMessage, messageTraceId, renderSafeMarkdown, traceEventBody, traceEventLabel, traceIdentityText, visibleTraceEvents } from "../src/components/workbench/message-rendering.ts";
|
||||
import { assistantTextFromTraceEvents, mergeRunnerTrace } from "../src/composables/useTraceSubscription.ts";
|
||||
import { mergeRunnerTrace } from "../src/composables/useTraceSubscription.ts";
|
||||
import { traceDisplayRows, traceNoiseEventCount } from "../../../tools/src/hwlab-cli/trace-renderer.ts";
|
||||
|
||||
test("R1 markdown rendering keeps structure and strips unsafe HTML", () => {
|
||||
@@ -103,16 +103,6 @@ test("R1 trace API snapshots stay authoritative over compact result traces", ()
|
||||
assert.equal(merged.events?.[1]?.message, "OK");
|
||||
});
|
||||
|
||||
test("R1 trace event assistant text prefers authoritative final assistant message", () => {
|
||||
const events: TraceEvent[] = [
|
||||
{ seq: 1, label: "agentrun:backend:resource-bundle-materialized", message: "bundle ready" },
|
||||
{ seq: 2, label: "agentrun:assistant:message", type: "assistant", status: "running", replyAuthority: false, final: false, message: "我先检查当前状态。" },
|
||||
{ seq: 3, label: "agentrun:assistant:message", type: "assistant", status: "completed", terminal: true, message: "OK" }
|
||||
];
|
||||
|
||||
assert.equal(assistantTextFromTraceEvents(events), "OK");
|
||||
});
|
||||
|
||||
test("R1 status summary keeps the restored 23-row floor", () => {
|
||||
const message = agentMessage({
|
||||
status: "failed",
|
||||
|
||||
@@ -91,9 +91,7 @@ function normalizeWorkbenchTurnResult(result: ApiResult<Record<string, unknown>>
|
||||
if (!result.ok || !result.data) return result as ApiResult<AgentChatResultResponse>;
|
||||
const turn = recordValue(result.data.turn) ?? result.data;
|
||||
const trace = recordValue(turn.trace);
|
||||
const envelopeStatus = textValue(result.data.status);
|
||||
const status = normalizeStatus(textValue(turn.status) ?? (envelopeStatus && !["ok", "succeeded", "found"].includes(envelopeStatus) ? envelopeStatus : null)) ?? "unknown";
|
||||
const terminal = turn.terminal === true || isTerminalStatus(status);
|
||||
const status = normalizeStatus(textValue(turn.status)) ?? "unknown";
|
||||
return {
|
||||
...result,
|
||||
data: {
|
||||
@@ -103,8 +101,8 @@ function normalizeWorkbenchTurnResult(result: ApiResult<Record<string, unknown>>
|
||||
lastProjectedSeq: Number.isFinite(Number(result.data.lastProjectedSeq)) ? Number(result.data.lastProjectedSeq) : undefined,
|
||||
traceId: textValue(turn.traceId) ?? traceId,
|
||||
status,
|
||||
running: !terminal && (turn.running === true || isActiveStatus(status)),
|
||||
terminal,
|
||||
running: typeof turn.running === "boolean" ? turn.running : undefined,
|
||||
terminal: typeof turn.terminal === "boolean" ? turn.terminal : undefined,
|
||||
sessionId: textValue(turn.sessionId) ?? undefined,
|
||||
threadId: textValue(turn.threadId) ?? undefined,
|
||||
agentRun: recordValue(turn.agentRun) ?? undefined,
|
||||
@@ -117,30 +115,32 @@ function normalizeWorkbenchTraceResult(result: ApiResult<Record<string, unknown>
|
||||
if (!result.ok || !result.data) return result as ApiResult<AgentChatResultResponse>;
|
||||
const events = Array.isArray(result.data.events) ? result.data.events : [];
|
||||
const nextSeq = Number(result.data.nextSeq ?? result.data.nextSinceSeq);
|
||||
const traceStatus = textValue(result.data.traceStatus, result.data.status) ?? "unknown";
|
||||
const traceStatus = textValue(result.data.traceStatus) ?? undefined;
|
||||
const eventCount = Number.isFinite(Number(result.data.eventCount)) ? Number(result.data.eventCount) : events.length;
|
||||
const normalizedNextSeq = Number.isFinite(nextSeq) ? Math.trunc(nextSeq) : null;
|
||||
const hasMore = result.data.hasMore === true;
|
||||
const fullTraceLoaded = typeof result.data.fullTraceLoaded === "boolean" ? result.data.fullTraceLoaded : undefined;
|
||||
return {
|
||||
...result,
|
||||
data: {
|
||||
...result.data,
|
||||
traceId: textValue(result.data.traceId) ?? traceId,
|
||||
status: traceStatus,
|
||||
status: undefined,
|
||||
traceStatus,
|
||||
events,
|
||||
traceEvents: events,
|
||||
eventCount,
|
||||
hasMore: result.data.hasMore === true,
|
||||
fullTraceLoaded: result.data.hasMore !== true,
|
||||
hasMore,
|
||||
fullTraceLoaded,
|
||||
nextSinceSeq: normalizedNextSeq,
|
||||
range: recordValue(result.data.range) ?? undefined,
|
||||
runnerTrace: {
|
||||
traceId: textValue(result.data.traceId) ?? traceId,
|
||||
status: traceStatus,
|
||||
status: undefined,
|
||||
events,
|
||||
eventCount,
|
||||
hasMore: result.data.hasMore === true,
|
||||
fullTraceLoaded: result.data.hasMore !== true,
|
||||
hasMore,
|
||||
fullTraceLoaded,
|
||||
nextSinceSeq: normalizedNextSeq,
|
||||
range: recordValue(result.data.range) ?? undefined,
|
||||
eventSource: "trace-api"
|
||||
@@ -156,14 +156,6 @@ function normalizeStatus(value: unknown): string | null {
|
||||
return normalized === "cancelled" ? "canceled" : normalized;
|
||||
}
|
||||
|
||||
function isActiveStatus(value: unknown): boolean {
|
||||
return ["accepted", "active", "busy", "creating", "pending", "processing", "running"].includes(normalizeStatus(value) ?? "");
|
||||
}
|
||||
|
||||
function isTerminalStatus(value: unknown): boolean {
|
||||
return ["blocked", "canceled", "completed", "failed", "stale", "thread-resume-failed", "timeout"].includes(normalizeStatus(value) ?? "");
|
||||
}
|
||||
|
||||
function recordValue(value: unknown): Record<string, unknown> | null {
|
||||
return value && typeof value === "object" ? value as Record<string, unknown> : null;
|
||||
}
|
||||
|
||||
@@ -144,12 +144,7 @@ export function mergeTraceResults(terminal: AgentChatResultResponse, trace: Trac
|
||||
error: trace.error ?? terminal.error
|
||||
};
|
||||
const events = Array.isArray(trace.events) ? trace.events : [];
|
||||
const assistantText = bestAssistantTextCandidate([
|
||||
finalResponseText(mergedTrace.finalResponse),
|
||||
terminalAssistantTextFromTraceEvents(events),
|
||||
firstNonEmptyResultText(terminal),
|
||||
assistantTextFromTraceEvents(events)
|
||||
]);
|
||||
const assistantText = firstNonEmptyString(finalResponseText(mergedTrace.finalResponse), terminal.assistantText);
|
||||
return {
|
||||
...terminal,
|
||||
traceId: mergedTrace.traceId ?? terminal.traceId,
|
||||
@@ -333,12 +328,6 @@ function sleep(ms: number): Promise<void> {
|
||||
return new Promise((resolve) => window.setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
function firstNonEmptyResultText(result: AgentChatResultResponse): string | null {
|
||||
const reply = result.reply;
|
||||
const replyText = typeof reply === "string" ? reply : typeof reply?.content === "string" ? reply.content : null;
|
||||
return firstNonEmptyString(result.assistantText, replyText);
|
||||
}
|
||||
|
||||
function finalResponseText(value: unknown): string | null {
|
||||
if (typeof value === "string") return value;
|
||||
if (value && typeof value === "object") {
|
||||
@@ -347,41 +336,3 @@ function finalResponseText(value: unknown): string | null {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function assistantTextFromTraceEvents(events: TraceEvent[]): string | null {
|
||||
const terminal = terminalAssistantTextFromTraceEvents(events);
|
||||
if (terminal) return terminal;
|
||||
for (let index = events.length - 1; index >= 0; index -= 1) {
|
||||
const event = events[index];
|
||||
if (!event || !isAssistantTraceEvent(event)) continue;
|
||||
const text = firstNonEmptyString(event.message, event.text, event.outputSummary);
|
||||
if (text) return text;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function terminalAssistantTextFromTraceEvents(events: TraceEvent[]): string | null {
|
||||
for (let index = events.length - 1; index >= 0; index -= 1) {
|
||||
const event = events[index];
|
||||
if (!event || !isTerminalAssistantTraceEvent(event)) continue;
|
||||
const text = firstNonEmptyString(event.message, event.text, event.outputSummary);
|
||||
if (text) return text;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function bestAssistantTextCandidate(candidates: Array<string | null | undefined>): string | null {
|
||||
return candidates.find((candidate) => typeof candidate === "string" && candidate.trim())?.trim() ?? null;
|
||||
}
|
||||
|
||||
function isAssistantTraceEvent(event: TraceEvent): boolean {
|
||||
const label = String(event.label ?? "");
|
||||
return label === "agentrun:assistant:message" || label === "assistant:message" || label === "assistant:completed" || event.type === "assistant" || event.type === "assistant_message";
|
||||
}
|
||||
|
||||
function isTerminalAssistantTraceEvent(event: TraceEvent): boolean {
|
||||
const label = String(event.label ?? "");
|
||||
if (label === "assistant:completed") return true;
|
||||
if (label === "agentrun:assistant:message") return event.replyAuthority === true || event.final === true || event.terminal === true || String(event.status ?? "") === "completed";
|
||||
return event.type === "assistant_message" && (event.status === "completed" || event.final === true || event.terminal === true);
|
||||
}
|
||||
|
||||
@@ -78,8 +78,9 @@ export function resolveComposerState(input: { messages: ChatMessage[]; sessions?
|
||||
const turn = activeTraceId ? input.turnStatusAuthority?.[activeTraceId] : null;
|
||||
const activeByRequest = Boolean(currentRequest && isActiveStatus(currentRequest.status ?? "running"));
|
||||
const activeByMessage = latestMessage?.role === "agent" && isActiveStatus(latestMessage.status);
|
||||
const activeByStatus = turn?.running === true || isActiveStatus(turn?.status) || activeByRequest || activeByMessage;
|
||||
const terminal = turn?.terminal === true || isTerminalStatus(turn?.status);
|
||||
const terminalByMessage = latestMessage?.role === "agent" && isTerminalStatus(latestMessage.status);
|
||||
const activeByStatus = !terminalByMessage && (turn?.running === true || isActiveStatus(turn?.status) || activeByRequest || activeByMessage);
|
||||
const terminal = terminalByMessage || turn?.terminal === true || isTerminalStatus(turn?.status);
|
||||
const active = activeSession(input.sessions ?? [], sessionId);
|
||||
const effectiveSessionId = firstNonEmptyString(turn?.sessionId, currentRequest?.sessionId, active?.sessionId, sessionId);
|
||||
const threadId = firstNonEmptyString(turn?.threadId, currentRequest?.threadId, active?.threadId);
|
||||
@@ -98,6 +99,7 @@ export function resolveCancelableAgentMessage(input: { messages: ChatMessage[];
|
||||
if (message.role !== "agent") continue;
|
||||
if (firstNonEmptyString(message.traceId, message.runnerTrace?.traceId) !== targetTraceId) continue;
|
||||
if (!messageBelongsToCancelTarget(message, input)) continue;
|
||||
if (isTerminalStatus(message.status)) continue;
|
||||
return message;
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -5,7 +5,7 @@ import { computed, nextTick, ref } from "vue";
|
||||
import { defineStore } from "pinia";
|
||||
import { api } from "@/api";
|
||||
import { connectWorkbenchEvents, type WorkbenchEventStream, type WorkbenchRealtimeEvent } from "@/api/workbench-events";
|
||||
import { assistantTextFromTraceEvents, mergeRunnerTrace, snapshotToRunnerTrace, type TraceSnapshot } from "@/composables/useTraceSubscription";
|
||||
import { mergeRunnerTrace, snapshotToRunnerTrace, type TraceSnapshot } from "@/composables/useTraceSubscription";
|
||||
import type { AgentChatResponse, AgentChatResultResponse, AgentRunProvenance, ApiResult, ChatMessage, LiveSurface, ProviderProfile, TraceEvent, WorkbenchSessionRecord } from "@/types";
|
||||
import { firstNonEmptyString, nextProtocolId, normalizeWorkbenchSessionId, normalizeWorkbenchSessionRouteId } from "@/utils";
|
||||
import { failWorkbenchSessionSwitch, failWorkbenchSubmitJourney, finishWorkbenchSessionSwitchFullLoad, markWorkbenchSubmitApiAccepted, markWorkbenchTraceEventsReceived, markWorkbenchTraceProjected, startWorkbenchSessionSwitch, startWorkbenchSubmitJourney } from "@/utils/workbench-performance";
|
||||
@@ -356,28 +356,23 @@ export const useWorkbenchStore = defineStore("workbench", () => {
|
||||
}
|
||||
|
||||
function syncTurnStatusToMessage(traceId: string, result: AgentChatResultResponse | TraceSnapshot): void {
|
||||
const status = statusFromResult(result.status);
|
||||
const terminal = (result as AgentChatResultResponse).terminal === true || isTerminalMessageStatus(status);
|
||||
const resultStatus = statusFromResult(result.status);
|
||||
const authoritySessionId = traceResultSessionId(result);
|
||||
updateActiveMessages((source) => source.map((message) => {
|
||||
if (!shouldApplyTraceToMessage(message, traceId, authoritySessionId)) return message;
|
||||
const status = isTerminalMessageStatus(message.status) ? message.status : resultStatus;
|
||||
const terminal = isTerminalMessageStatus(status) || (result as AgentChatResultResponse).terminal === true;
|
||||
const runnerTrace = mergeTerminalResultTrace(message.runnerTrace, result as AgentChatResultResponse);
|
||||
rememberTraceAuthority(runnerTrace);
|
||||
const error = normalizeAgentError((result as AgentChatResultResponse).error ?? runnerTrace?.error ?? message.error);
|
||||
const errorText = agentErrorDisplayText(error);
|
||||
const agentRun = agentRunFromResult(result as AgentChatResultResponse, runnerTrace) ?? agentRunFromMessage(message);
|
||||
const replyText = agentReplyText((result as AgentChatResultResponse).reply);
|
||||
const traceAssistantText = assistantTextFromTraceEvents(firstArray((result as AgentChatResultResponse).events, (result as AgentChatResultResponse).traceEvents, runnerTrace?.events));
|
||||
const text = terminal
|
||||
? terminalAgentMessageText({
|
||||
? projectedAgentMessageText({
|
||||
status,
|
||||
assistantText: (result as AgentChatResultResponse).assistantText,
|
||||
finalText: finalResponseText((result as AgentChatResultResponse).finalResponse),
|
||||
replyText,
|
||||
errorText,
|
||||
resultText: (result as AgentChatResultResponse).text,
|
||||
summaryText: (result as AgentChatResultResponse).summary,
|
||||
traceAssistantText
|
||||
baseText: message.text
|
||||
})
|
||||
: message.text;
|
||||
return { ...message, status, text, runnerTrace, error: error ?? message.error ?? null, agentRun: agentRun ?? undefined, updatedAt: new Date().toISOString() };
|
||||
@@ -563,12 +558,12 @@ export const useWorkbenchStore = defineStore("workbench", () => {
|
||||
updatedAt: new Date().toISOString()
|
||||
});
|
||||
const explicitStatus = normalizedStatusText(result.status);
|
||||
const status = explicitStatus ? statusFromResult(result.status) : message.status;
|
||||
const resultStatus = explicitStatus ? statusFromResult(result.status) : message.status;
|
||||
const status = isTerminalMessageStatus(message.status) ? message.status : resultStatus;
|
||||
const terminal = result.terminal === true || isTerminalMessageStatus(status);
|
||||
const error = normalizeAgentError(result.error ?? runnerTrace?.error ?? message.error);
|
||||
const errorText = agentErrorDisplayText(error);
|
||||
const traceAssistantText = assistantTextFromTraceEvents(events);
|
||||
const text = terminal ? firstNonEmptyString(result.assistantText, finalResponseText(result.finalResponse), agentReplyText(result.reply), errorText, result.text, result.summary, traceAssistantText, message.text) ?? message.text : message.text;
|
||||
const text = terminal ? projectedAgentMessageText({ status, finalText: finalResponseText(result.finalResponse), errorText, baseText: message.text }) : message.text;
|
||||
const agentRun = agentRunFromResult(result, runnerTrace) ?? agentRunFromMessage(message);
|
||||
rememberTraceAuthority(runnerTrace);
|
||||
return { ...message, status, text, runnerTrace, error: error ?? message.error ?? null, agentRun: agentRun ?? undefined, updatedAt: new Date().toISOString() };
|
||||
@@ -848,15 +843,14 @@ export const useWorkbenchStore = defineStore("workbench", () => {
|
||||
if (!shouldApplyTraceToMessage(message, traceId, authoritySessionId)) return message;
|
||||
const runnerTrace = mergeRunnerTrace(message.runnerTrace, trace);
|
||||
rememberTraceAuthority(runnerTrace);
|
||||
const status = statusFromResult(firstNonEmptyString(turn?.status, message.status) ?? message.status);
|
||||
const terminal = turn?.terminal === true || isTerminalMessageStatus(turn?.status);
|
||||
const traceAssistantText = message.role === "agent" ? assistantTextFromTraceEvents(Array.isArray(runnerTrace.events) ? runnerTrace.events : []) : null;
|
||||
const status = message.status;
|
||||
const terminal = isTerminalMessageStatus(status);
|
||||
const error = message.role === "agent" ? normalizeAgentError(runnerTrace.error ?? message.error) : normalizeAgentError(message.error);
|
||||
const errorText = message.role === "agent" ? agentErrorDisplayText(error) : null;
|
||||
const nextText = message.role === "agent" && terminal
|
||||
? firstNonEmptyString(finalResponseText(runnerTrace.finalResponse), errorText, traceAssistantText, message.text) ?? message.text
|
||||
? projectedAgentMessageText({ status, finalText: finalResponseText(runnerTrace.finalResponse), errorText, baseText: message.text })
|
||||
: message.text;
|
||||
return { ...message, status, text: nextText, traceAutoLifecycle: terminal ? "terminal" : "running", runnerTrace, error: error ?? message.error ?? null, updatedAt: new Date().toISOString() };
|
||||
return { ...message, status, text: nextText, traceAutoLifecycle: terminal ? "terminal" : message.traceAutoLifecycle, runnerTrace, error: error ?? message.error ?? null, updatedAt: new Date().toISOString() };
|
||||
}));
|
||||
markWorkbenchTraceProjected(traceId);
|
||||
void refreshSessions(trace.sessionId ?? selectedSessionId.value);
|
||||
@@ -865,25 +859,16 @@ export const useWorkbenchStore = defineStore("workbench", () => {
|
||||
function completeTrace(traceId: string, result: AgentChatResultResponse): void {
|
||||
const authoritySessionId = traceResultSessionId(result);
|
||||
if (!shouldApplyActiveTraceAuthority(traceId, authoritySessionId)) return;
|
||||
const resultTrace = recordValue(result.runnerTrace);
|
||||
const traceAssistantText = assistantTextFromTraceEvents(firstArray(result.events, result.traceEvents, resultTrace?.events));
|
||||
const terminalStatus = result.status === "completed" ? "completed" : statusFromResult(result.status);
|
||||
const text = terminalAgentMessageText({
|
||||
status: terminalStatus,
|
||||
assistantText: result.assistantText,
|
||||
finalText: finalResponseText(result.finalResponse),
|
||||
replyText: typeof result.reply === "string" ? result.reply : result.reply?.content,
|
||||
errorText: agentErrorDisplayText(result.error),
|
||||
resultText: result.text,
|
||||
summaryText: result.summary,
|
||||
traceAssistantText
|
||||
});
|
||||
const finalText = finalResponseText(result.finalResponse);
|
||||
const errorText = agentErrorDisplayText(result.error);
|
||||
updateActiveMessages((source) => source.map((message) => {
|
||||
if (!shouldApplyTraceToMessage(message, traceId, authoritySessionId)) return message;
|
||||
const runnerTrace = mergeTerminalResultTrace(message.runnerTrace, result);
|
||||
rememberTraceAuthority(runnerTrace);
|
||||
const error = normalizeAgentError(result.error ?? runnerTrace?.error ?? message.error);
|
||||
const agentRun = agentRunFromResult(result, runnerTrace) ?? agentRunFromMessage(message);
|
||||
const text = projectedAgentMessageText({ status: terminalStatus, finalText, errorText, baseText: message.text });
|
||||
return { ...message, status: terminalStatus, text, traceAutoLifecycle: "terminal", runnerTrace, error: error ?? message.error ?? null, agentRun: agentRun ?? undefined, updatedAt: new Date().toISOString() };
|
||||
}));
|
||||
rememberTurnStatus(traceId, result);
|
||||
@@ -1101,13 +1086,12 @@ function normalizeChatMessage(message: ChatMessage): ChatMessage {
|
||||
const status = normalizeChatMessageStatus(message.status);
|
||||
const baseText = firstNonEmptyString(message.text, messageText((message as Record<string, unknown>).content), messageText((message as Record<string, unknown>).message));
|
||||
const finalText = firstNonEmptyString(finalResponseText((message as Record<string, unknown>).finalResponse), finalResponseText(runnerTrace?.finalResponse));
|
||||
const traceAssistantText = assistantTextFromTraceEvents(Array.isArray(runnerTrace?.events) ? runnerTrace.events : []);
|
||||
const errorText = agentErrorDisplayText(error);
|
||||
const text = role === "agent"
|
||||
? isTerminalMessageStatus(status)
|
||||
? terminalAgentMessageText({ status, finalText, errorText, traceAssistantText, baseText })
|
||||
? projectedAgentMessageText({ status, finalText, errorText, baseText })
|
||||
: ""
|
||||
: firstNonEmptyString(baseText, finalText, traceAssistantText, errorText) ?? "";
|
||||
: firstNonEmptyString(baseText, finalText, errorText) ?? "";
|
||||
const messageId = firstNonEmptyString((message as Record<string, unknown>).messageId, message.id) ?? nextProtocolId("msg");
|
||||
return { ...message, role, text, id: messageId, messageId, title: normalizeWorkbenchMessageTitle(role, message.title), createdAt: message.createdAt ?? new Date().toISOString(), status, runnerTrace, error: error ?? message.error ?? null, agentRun: agentRun ?? undefined };
|
||||
}
|
||||
@@ -1306,33 +1290,10 @@ function finalResponseText(value: unknown): string | null {
|
||||
return firstNonEmptyString(messageText(record.text), messageText(record.content), messageText(record.message));
|
||||
}
|
||||
|
||||
function agentReplyText(value: AgentChatResultResponse["reply"]): string | null {
|
||||
if (typeof value === "string") return value;
|
||||
return value && typeof value === "object" ? firstNonEmptyString(value.content) : null;
|
||||
}
|
||||
|
||||
function terminalAgentMessageText(input: {
|
||||
status: unknown;
|
||||
assistantText?: unknown;
|
||||
finalText?: string | null;
|
||||
replyText?: string | null;
|
||||
errorText?: string | null;
|
||||
resultText?: unknown;
|
||||
summaryText?: unknown;
|
||||
traceAssistantText?: string | null;
|
||||
baseText?: string | null;
|
||||
}): string {
|
||||
const finalText = firstNonEmptyString(
|
||||
input.assistantText,
|
||||
input.finalText,
|
||||
input.replyText,
|
||||
input.resultText,
|
||||
input.summaryText,
|
||||
input.traceAssistantText,
|
||||
input.baseText
|
||||
);
|
||||
if (!isFailureTerminalStatus(input.status)) return finalText ?? "";
|
||||
return firstNonEmptyString(input.errorText, finalText) ?? "";
|
||||
function projectedAgentMessageText(input: { status: unknown; finalText?: string | null; errorText?: string | null; baseText?: string | null }): string {
|
||||
const text = firstNonEmptyString(input.finalText, input.baseText);
|
||||
if (!isFailureTerminalStatus(input.status)) return text ?? "";
|
||||
return firstNonEmptyString(input.errorText, text) ?? "";
|
||||
}
|
||||
|
||||
function isFailureTerminalStatus(value: unknown): boolean {
|
||||
|
||||
Reference in New Issue
Block a user