ai
Version:
AI SDK by Vercel - build apps like ChatGPT, Claude, Gemini, and more with a single interface for any model using the Vercel AI Gateway or go direct to OpenAI, Anthropic, Google, or any other model provider.
78 lines (68 loc) • 1.83 kB
text/typescript
import {
isArrayBuffer,
isUint8Array,
type ModelMessage,
} from '@ai-sdk/provider-utils';
/**
* Clone model messages while preserving URL instances. Node's structuredClone
* currently rejects URL objects, which are valid file/image prompt payloads.
*/
export function cloneModelMessages<T extends ModelMessage>(
messages: Array<T>,
): Array<T> {
return cloneValue(messages, new Map()) as Array<T>;
}
function cloneValue(value: unknown, seen: Map<object, unknown>): unknown {
if (value == null || typeof value !== 'object') {
return value;
}
if (seen.has(value)) {
return seen.get(value);
}
if (value instanceof URL) {
const copy = new URL(value.href);
seen.set(value, copy);
return copy;
}
if (Array.isArray(value)) {
const copy: unknown[] = new Array(value.length);
seen.set(value, copy);
value.forEach((item, index) => {
copy[index] = cloneValue(item, seen);
});
return copy;
}
if (isUint8Array(value)) {
const copy = new Uint8Array(value);
seen.set(value, copy);
return copy;
}
if (isArrayBuffer(value)) {
const copy = new Uint8Array(value).slice().buffer;
seen.set(value, copy);
return copy;
}
if (
value instanceof Date ||
Object.prototype.toString.call(value) === '[object Date]'
) {
try {
const copy = new Date(Date.prototype.getTime.call(value));
seen.set(value, copy);
return copy;
} catch {
// A string tag alone does not make a plain object a Date.
}
}
const copy: Record<string, unknown> = {};
seen.set(value, copy);
for (const [key, val] of Object.entries(value)) {
Object.defineProperty(copy, key, {
value: cloneValue(val, seen),
writable: true,
enumerable: true,
configurable: true,
});
}
return copy;
}