This repository has been archived on 2026-08-23. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
pi-web/src/server/browserMessageProjection.ts
T

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);
}