





















@@ -11,6 +11,7 @@ import type { TemplateContext } from "../templating.js";
11111212const MAX_UNTRUSTED_JSON_STRING_CHARS = 2_000;
1313const MAX_UNTRUSTED_HISTORY_ENTRIES = 20;
14+const MAX_UNTRUSTED_TRANSCRIPT_FIELD_CHARS = 500;
14151516function stripNullBytes(value: string): string {
1617return value.replaceAll("\u0000", "");
@@ -59,6 +60,30 @@ function sanitizeUntrustedJsonValue(value: unknown): unknown {
5960);
6061}
616263+function isRecord(value: unknown): value is Record<string, unknown> {
64+return typeof value === "object" && value !== null && !Array.isArray(value);
65+}
66+67+function truncateUntrustedTranscriptField(value: string): string {
68+if (value.length <= MAX_UNTRUSTED_TRANSCRIPT_FIELD_CHARS) {
69+return value;
70+}
71+return `${truncateUtf16Safe(
72+ value,
73+ Math.max(0, MAX_UNTRUSTED_TRANSCRIPT_FIELD_CHARS - 14),
74+ ).trimEnd()}…[truncated]`;
75+}
76+77+function sanitizeTranscriptField(value: unknown): string | undefined {
78+const body = sanitizePromptBody(value);
79+if (!body) {
80+return undefined;
81+}
82+return neutralizeMarkdownFences(truncateUntrustedTranscriptField(body))
83+.replace(/\s+/g, " ")
84+.trim();
85+}
86+6287function formatUntrustedStructuredContextLabel(label: unknown): string {
6388const normalized = normalizePromptMetadataString(label);
6489return normalized
@@ -75,6 +100,67 @@ function formatUntrustedJsonBlock(label: string, payload: unknown): string {
75100].join("\n");
76101}
77102103+function formatStructuredContextRelation(value: unknown): string | undefined {
104+const relation = normalizePromptMetadataString(value);
105+if (relation === "before_current_message") {
106+return "before current message";
107+}
108+if (relation === "around_reply_target") {
109+return "around replied-to message";
110+}
111+return relation?.replaceAll("_", " ");
112+}
113+114+function formatChatWindowMessage(
115+value: unknown,
116+envelope?: EnvelopeFormatOptions,
117+): string | undefined {
118+if (!isRecord(value)) {
119+return undefined;
120+}
121+const messageId = normalizePromptMetadataString(value["message_id"]);
122+const sender = normalizePromptMetadataString(value["sender"]) ?? "unknown sender";
123+const timestamp = formatConversationTimestamp(value["timestamp_ms"], envelope);
124+const replyToId = normalizePromptMetadataString(value["reply_to_id"]);
125+const mediaType = normalizePromptMetadataString(value["media_type"]);
126+const mediaRef = normalizePromptMetadataString(value["media_ref"]);
127+const body = sanitizeTranscriptField(value["body"]);
128+const details = [
129+messageId ? `#${messageId}` : undefined,
130+timestamp,
131+value["is_reply_target"] === true ? "[reply target]" : undefined,
132+replyToId ? `->#${replyToId}` : undefined,
133+].filter(Boolean);
134+const media = mediaType ? `[${mediaType}${mediaRef ? ` ${mediaRef}` : ""}]` : undefined;
135+const content = [body, media].filter(Boolean).join(" ");
136+if (!content) {
137+return undefined;
138+}
139+return `${details.length > 0 ? `${details.join(" ")} ` : ""}${sender}: ${content}`;
140+}
141+142+function formatChatWindowStructuredContext(
143+entry: NonNullable<TemplateContext["UntrustedStructuredContext"]>[number],
144+envelope?: EnvelopeFormatOptions,
145+): string | undefined {
146+if (normalizePromptMetadataString(entry.type) !== "chat_window" || !isRecord(entry.payload)) {
147+return undefined;
148+}
149+const messages = Array.isArray(entry.payload["messages"]) ? entry.payload["messages"] : [];
150+const lines = messages.flatMap((message) => {
151+const line = formatChatWindowMessage(message, envelope);
152+return line ? [line] : [];
153+});
154+if (lines.length === 0) {
155+return undefined;
156+}
157+const label = normalizePromptMetadataString(entry.label) ?? "Chat window";
158+const relation = formatStructuredContextRelation(entry.payload["relation"]);
159+const order = normalizePromptMetadataString(entry.payload["order"]);
160+const qualifiers = ["untrusted", order, relation].filter(Boolean).join(", ");
161+return [`${label} (${qualifiers}):`, ...lines].join("\n");
162+}
163+78164function buildLocationContextPayload(ctx: TemplateContext): Record<string, unknown> | undefined {
79165const payload = {
80166latitude: typeof ctx.LocationLat === "number" ? ctx.LocationLat : undefined,
@@ -350,6 +436,11 @@ export function buildInboundUserContextPrefix(
350436if (!entry || typeof entry !== "object") {
351437continue;
352438}
439+const chatWindow = formatChatWindowStructuredContext(entry, envelope);
440+if (chatWindow) {
441+blocks.push(chatWindow);
442+continue;
443+}
353444blocks.push(
354445formatUntrustedJsonBlock(formatUntrustedStructuredContextLabel(entry.label), {
355446source: normalizePromptMetadataString(entry.source),
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。