kimi-code / packages /kap-server /src /services /messages /messageProjection.ts
SaylorTwift's picture
SaylorTwift HF Staff
Add files using upload-large-folder tool
4e23b01 verified
Raw History Blame Contribute Delete
5.38 kB
import { daemonFileRefFromPart, parseDaemonFileUrl, type ContentPart, type ContextMessage } from '@moonshot-ai/agent-core-v2';
import type { Message, MessageContent, MessageRole, ToolUseContent } from '../../protocol/message';
function deriveMessageId(sessionId: string, index: number): string {
const padded = String(index).padStart(6, '0');
return `msg_${sessionId}_${padded}`;
}
function toProtocolRole(role: ContextMessage['role']): MessageRole {
return role as MessageRole;
}
function mapContentPart(part: ContextMessage['content'][number]): MessageContent {
switch (part.type) {
case 'text':
return { type: 'text', text: part.text };
case 'think': {
const sig = part.encrypted;
return sig !== undefined
? { type: 'thinking', thinking: part.think, signature: sig }
: { type: 'thinking', thinking: part.think };
}
case 'image_url': {
const ref = parseDaemonFileUrl(part.imageUrl.url);
return ref !== undefined
? { type: 'image', source: { kind: 'session_media', file_id: ref.fileId }, name: part.imageUrl.name }
: { type: 'image', source: { kind: 'url', url: part.imageUrl.url, id: part.imageUrl.id }, name: part.imageUrl.name };
}
case 'audio_url':
return { type: 'text', text: `[audio:${part.audioUrl.url}]` };
case 'video_url': {
const ref = parseDaemonFileUrl(part.videoUrl.url);
return ref !== undefined
? { type: 'video', source: { kind: 'session_media', file_id: ref.fileId }, name: part.videoUrl.name }
: { type: 'video', source: { kind: 'url', url: part.videoUrl.url, id: part.videoUrl.id }, name: part.videoUrl.name };
}
}
}
function buildProtocolContent(msg: ContextMessage): MessageContent[] {
const visibleContent = msg.content.filter((p) => p.type !== 'think' || p.hidden !== true);
if (msg.role === 'tool') {
if (msg.toolCallId === undefined) {
return visibleContent.map((p) => mapContentPart(p));
}
const hasMediaPart = visibleContent.some(
(p) => p.type === 'image_url' || p.type === 'video_url' || p.type === 'audio_url',
);
const output: unknown = hasMediaPart
? visibleContent
: visibleContent.map((p) => (p.type === 'text' ? p.text : '')).join('');
const part: MessageContent =
msg.isError === true
? {
type: 'tool_result',
tool_call_id: msg.toolCallId,
output,
is_error: true,
}
: {
type: 'tool_result',
tool_call_id: msg.toolCallId,
output,
};
return [part];
}
const base = visibleContent.map((p) => mapContentPart(p));
if (msg.role === 'assistant' && msg.toolCalls.length > 0) {
for (const call of msg.toolCalls) {
let parsedInput: unknown = call.arguments;
if (typeof call.arguments === 'string') {
try {
parsedInput = JSON.parse(call.arguments);
} catch {
parsedInput = call.arguments;
}
}
const part: ToolUseContent = {
type: 'tool_use',
tool_call_id: call.id,
tool_name: call.name,
input: parsedInput,
};
base.push(part);
}
}
return base;
}
export function projectPromptContentParts(content: readonly ContentPart[]): MessageContent[] {
const parts: MessageContent[] = [];
for (const part of content) {
const daemonRef = daemonFileRefFromPart(part);
if (daemonRef !== undefined) {
parts.push({
type: daemonRef.kind,
source: { kind: 'session_media', file_id: daemonRef.ref.fileId },
name:
part.type === 'image_url'
? part.imageUrl.name
: part.type === 'video_url'
? part.videoUrl.name
: undefined,
});
continue;
}
if (part.type === 'text') parts.push({ type: 'text', text: part.text });
else if (part.type === 'image_url') {
const match = /^data:([^;]+);base64,(.*)$/.exec(part.imageUrl.url);
parts.push(match === null
? { type: 'image', source: { kind: 'url', url: part.imageUrl.url, id: part.imageUrl.id }, name: part.imageUrl.name }
: { type: 'image', source: { kind: 'base64', media_type: match[1]!, data: match[2]! }, name: part.imageUrl.name });
} else if (part.type === 'video_url') {
const match = /^data:([^;]+);base64,(.*)$/.exec(part.videoUrl.url);
parts.push(match === null
? { type: 'video', source: { kind: 'url', url: part.videoUrl.url, id: part.videoUrl.id }, name: part.videoUrl.name }
: { type: 'video', source: { kind: 'base64', media_type: match[1]!, data: match[2]! }, name: part.videoUrl.name });
}
}
return parts;
}
export function toProtocolMessage(
sessionId: string,
index: number,
msg: ContextMessage,
sessionCreatedAtMs: number,
createdAtMsOverride?: number,
): Message {
const id = msg.id ?? deriveMessageId(sessionId, index);
const role = toProtocolRole(msg.role);
const content = buildProtocolContent(msg);
const createdAtMs = createdAtMsOverride ?? sessionCreatedAtMs + index;
const metadata = msg.origin !== undefined ? { origin: msg.origin } : undefined;
return {
id,
session_id: sessionId,
role,
content,
created_at: new Date(createdAtMs).toISOString(),
...(metadata !== undefined ? { metadata } : {}),
};
}