Archived
60 lines
2.1 KiB
TypeScript
60 lines
2.1 KiB
TypeScript
import type { MessagePage, SessionUiEvent } from "../shared/apiTypes.js";
|
|
|
|
/**
|
|
* Remove provider-only thinking data at the browser transport boundary. The
|
|
* runtime message remains unchanged because only affected messages and content
|
|
* blocks are copied.
|
|
*/
|
|
export function projectBrowserMessage(message: unknown): unknown {
|
|
if (!isRecord(message)) return message;
|
|
const originalContent = message["content"];
|
|
if (!isUnknownArray(originalContent)) return message;
|
|
|
|
const content = mapChanged(originalContent, (part) => {
|
|
if (!isRecord(part) || part["type"] !== "thinking" || !Object.hasOwn(part, "thinkingSignature")) return part;
|
|
const projected = { ...part };
|
|
delete projected["thinkingSignature"];
|
|
return projected;
|
|
});
|
|
|
|
return content === originalContent ? message : { ...message, content };
|
|
}
|
|
|
|
export function projectBrowserMessageResponse(response: unknown[] | MessagePage): unknown[] | MessagePage {
|
|
if (Array.isArray(response)) return mapChanged(response, projectBrowserMessage);
|
|
const messages = mapChanged(response.messages, projectBrowserMessage);
|
|
return messages === response.messages ? response : { ...response, messages };
|
|
}
|
|
|
|
export function projectBrowserSessionEvent(event: SessionUiEvent): SessionUiEvent {
|
|
if (event.type !== "message.end" || event.message === undefined) return event;
|
|
const message = projectBrowserMessage(event.message);
|
|
return message === event.message ? event : { ...event, message };
|
|
}
|
|
|
|
function mapChanged<T>(values: T[], project: (value: T) => T): T[] {
|
|
let projectedValues: T[] | undefined;
|
|
let index = 0;
|
|
for (const value of values) {
|
|
const projected = project(value);
|
|
if (projectedValues === undefined) {
|
|
if (projected === value) {
|
|
index += 1;
|
|
continue;
|
|
}
|
|
projectedValues = values.slice(0, index);
|
|
}
|
|
projectedValues.push(projected);
|
|
index += 1;
|
|
}
|
|
return projectedValues ?? values;
|
|
}
|
|
|
|
function isUnknownArray(value: unknown): value is unknown[] {
|
|
return Array.isArray(value);
|
|
}
|
|
|
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
}
|