@mosaic/mosaic is now the single package providing both: - 'mosaic' binary (CLI: yolo, coord, prdy, tui, gateway, etc.) - 'mosaic-wizard' binary (installation wizard) Changes: - Move packages/cli/src/* into packages/mosaic/src/ - Convert dynamic @mosaic/mosaic imports to static relative imports - Add CLI deps (ink, react, socket.io-client, @mosaic/config) to mosaic - Add jsx: react-jsx to mosaic's tsconfig - Exclude packages/cli from workspace (pnpm-workspace.yaml) - Update install.sh to install @mosaic/mosaic instead of @mosaic/cli - Bump version to 0.0.17 This eliminates the circular dependency between @mosaic/cli and @mosaic/mosaic that was blocking the build graph.
54 lines
1.7 KiB
TypeScript
54 lines
1.7 KiB
TypeScript
import type { ConversationMessage } from '../../gateway-api.js';
|
|
|
|
const CONTEXT_WINDOW = 200_000;
|
|
const CHARS_PER_TOKEN = 4;
|
|
|
|
function estimateTokens(messages: ConversationMessage[]): number {
|
|
const totalChars = messages.reduce((sum, m) => sum + (m.content?.length ?? 0), 0);
|
|
return Math.round(totalChars / CHARS_PER_TOKEN);
|
|
}
|
|
|
|
export interface HistoryContext {
|
|
conversationId: string | undefined;
|
|
conversationTitle?: string | null;
|
|
gatewayUrl: string;
|
|
sessionCookie: string | undefined;
|
|
fetchMessages: (
|
|
gatewayUrl: string,
|
|
sessionCookie: string,
|
|
conversationId: string,
|
|
) => Promise<ConversationMessage[]>;
|
|
}
|
|
|
|
export async function executeHistory(ctx: HistoryContext): Promise<string> {
|
|
const { conversationId, conversationTitle, gatewayUrl, sessionCookie, fetchMessages } = ctx;
|
|
|
|
if (!conversationId) {
|
|
return 'No active conversation.';
|
|
}
|
|
|
|
if (!sessionCookie) {
|
|
return 'Not authenticated — cannot fetch conversation messages.';
|
|
}
|
|
|
|
const messages = await fetchMessages(gatewayUrl, sessionCookie, conversationId);
|
|
|
|
const userMessages = messages.filter((m) => m.role === 'user').length;
|
|
const assistantMessages = messages.filter((m) => m.role === 'assistant').length;
|
|
const totalMessages = messages.length;
|
|
|
|
const estimatedTokens = estimateTokens(messages);
|
|
const contextPercent = Math.round((estimatedTokens / CONTEXT_WINDOW) * 100);
|
|
|
|
const label = conversationTitle ?? conversationId;
|
|
|
|
const lines = [
|
|
`Conversation: ${label}`,
|
|
`Messages: ${totalMessages} (${userMessages} user, ${assistantMessages} assistant)`,
|
|
`Estimated tokens: ~${estimatedTokens.toLocaleString()}`,
|
|
`Context usage: ~${contextPercent}% of ${(CONTEXT_WINDOW / 1000).toFixed(0)}K`,
|
|
];
|
|
|
|
return lines.join('\n');
|
|
}
|