












@@ -15,7 +15,7 @@ import { resolveProviderIdForAuth } from "../../agents/provider-auth-aliases.js"
1515import { ensureSandboxWorkspaceForSession } from "../../agents/sandbox/context.js";
1616import { resolveAgentTimeoutMs } from "../../agents/timeout.js";
1717import { dispatchInboundMessage } from "../../auto-reply/dispatch.js";
18-import type { ReplyPayload } from "../../auto-reply/reply-payload.js";
18+import { getReplyPayloadMetadata, type ReplyPayload } from "../../auto-reply/reply-payload.js";
1919import { createReplyDispatcher } from "../../auto-reply/reply/reply-dispatcher.js";
2020import { stageSandboxMedia } from "../../auto-reply/reply/stage-sandbox-media.js";
2121import type { MsgContext, TemplateContext } from "../../auto-reply/templating.js";
@@ -1974,6 +1974,10 @@ function broadcastChatError(params: {
19741974params.context.agentRunSeq.delete(params.runId);
19751975}
197619761977+function isSourceReplyTranscriptMirrorPayload(payload: ReplyPayload | undefined) {
1978+return Boolean(payload && getReplyPayloadMetadata(payload)?.sourceReplyTranscriptMirror);
1979+}
1980+19771981export const chatHandlers: GatewayRequestHandlers = {
19781982"chat.history": async ({ params, respond, context }) => {
19791983if (!validateChatHistoryParams(params)) {
@@ -3067,7 +3071,90 @@ export const chatHandlers: GatewayRequestHandlers = {
30673071 message,
30683072});
30693073}
3070-} else if (returnedAgentErrorPayloads.length > 0) {
3074+} else {
3075+const sourceReplyPayloads = deliveredReplies
3076+.filter((entry) => entry.kind === "final")
3077+.map((entry) => entry.payload)
3078+.filter(isSourceReplyTranscriptMirrorPayload);
3079+if (sourceReplyPayloads.length > 0) {
3080+const finalPayloads = await normalizeWebchatReplyMediaPathsForDisplay({
3081+ cfg,
3082+ sessionKey,
3083+ agentId,
3084+ accountId,
3085+payloads: sourceReplyPayloads,
3086+});
3087+const { storePath: latestStorePath, entry: latestEntry } =
3088+loadSessionEntry(sessionKey);
3089+const sessionId = latestEntry?.sessionId ?? backingSessionId ?? clientRunId;
3090+const resolvedTranscriptPath = resolveTranscriptPath({
3091+ sessionId,
3092+storePath: latestStorePath,
3093+sessionFile: latestEntry?.sessionFile ?? entry?.sessionFile,
3094+ agentId,
3095+});
3096+const mediaLocalRoots = appendLocalMediaParentRoots(
3097+getAgentScopedMediaLocalRoots(cfg, agentId),
3098+resolvedTranscriptPath ? [resolvedTranscriptPath] : undefined,
3099+);
3100+const assistantContent = await buildAssistantDisplayContentFromReplyPayloads({
3101+ sessionKey,
3102+payloads: finalPayloads,
3103+managedImageLocalRoots: mediaLocalRoots,
3104+includeSensitiveMedia: false,
3105+onLocalAudioAccessDenied: (message) => {
3106+context.logGateway.warn(
3107+`webchat audio embedding denied local path: ${message}`,
3108+);
3109+},
3110+onManagedImagePrepareError: (message) => {
3111+context.logGateway.warn(
3112+`webchat image embedding skipped attachment: ${message}`,
3113+);
3114+},
3115+});
3116+const mediaMessage = await buildWebchatAssistantMediaMessage(finalPayloads, {
3117+localRoots: mediaLocalRoots,
3118+onLocalAudioAccessDenied: (message) => {
3119+context.logGateway.warn(
3120+`webchat audio embedding denied local path: ${message}`,
3121+);
3122+},
3123+});
3124+const broadcastAssistantContent = hasAssistantDisplayMediaContent(
3125+assistantContent,
3126+)
3127+ ? assistantContent
3128+ : hasAssistantDisplayMediaContent(mediaMessage?.content)
3129+ ? mediaMessage?.content
3130+ : assistantContent;
3131+const displayReply =
3132+extractAssistantDisplayTextFromContent(assistantContent) ??
3133+buildTranscriptReplyText(finalPayloads);
3134+if (broadcastAssistantContent?.length || displayReply) {
3135+const now = Date.now();
3136+const message = {
3137+role: "assistant",
3138+ ...(broadcastAssistantContent?.length
3139+ ? { content: broadcastAssistantContent }
3140+ : displayReply
3141+ ? { content: [{ type: "text", text: displayReply }] }
3142+ : {}),
3143+ ...(displayReply ? { text: displayReply } : {}),
3144+timestamp: now,
3145+stopReason: "stop",
3146+usage: { input: 0, output: 0, totalTokens: 0 },
3147+};
3148+broadcastChatFinal({
3149+ context,
3150+runId: clientRunId,
3151+ sessionKey,
3152+ message,
3153+});
3154+}
3155+}
3156+}
3157+if (returnedAgentErrorPayloads.length > 0) {
30713158if (!hasBeforeAgentRunGate) {
30723159await emitUserTranscriptUpdateAfterAgentRun();
30733160}
此內容由慣性聚合(RSS閱讀器)自動聚合整理,僅供閱讀參考。 原文來自 — 版權歸原作者所有。