All files / src/app/extensions/copilot-embedded/models/copilot-embedded-answer copilot-embedded-answer.mapper.ts

100% Statements 13/13
90% Branches 18/20
100% Functions 4/4
100% Lines 13/13

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 527x 7x             2x     7x   8x                               9x 5x   4x 1x   3x 2x   1x           9x              
import { CopilotEmbeddedChoiceMapper } from '../copilot-embedded-choice/copilot-embedded-choice.mapper';
import { CopilotEmbeddedProductMapper } from '../copilot-embedded-product/copilot-embedded-product.mapper';
import { CopilotEmbeddedToolCall } from '../copilot-embedded-tool-call/copilot-embedded-tool-call.model';
 
import { CopilotEmbeddedAnswerData, CopilotEmbeddedStreamEvent } from './copilot-embedded-answer.interface';
import { CopilotEmbeddedAnswer } from './copilot-embedded-answer.model';
 
function isMetadata(data: unknown): data is { chatId?: string } {
  return !!data && typeof data === 'object';
}
 
export class CopilotEmbeddedAnswerMapper {
  static fromData(data: CopilotEmbeddedAnswerData): CopilotEmbeddedAnswer {
    return {
      text: data?.text ?? '',
      chatId: data?.chatId,
      messageId: data?.chatMessageId,
      ...CopilotEmbeddedAnswerMapper.fromToolCalls(data?.usedTools),
    };
  }
 
  /**
   * Adds a streamed Flowise event to the answer received so far.
   * Returns the given answer unchanged for events that do not affect it.
   */
  static fromStreamEvent(
    answer: CopilotEmbeddedAnswer,
    { event, data }: CopilotEmbeddedStreamEvent
  ): CopilotEmbeddedAnswer {
    if (event === 'token' && typeof data === 'string') {
      return { ...answer, text: answer.text + data };
    }
    if (event === 'usedTools' && Array.isArray(data)) {
      return { ...answer, ...CopilotEmbeddedAnswerMapper.fromToolCalls(data as CopilotEmbeddedToolCall[]) };
    }
    if (event === 'metadata' && isMetadata(data)) {
      return { ...answer, chatId: data.chatId ?? answer.chatId };
    }
    return answer;
  }
 
  private static fromToolCalls(
    usedTools: CopilotEmbeddedToolCall[]
  ): Pick<CopilotEmbeddedAnswer, 'choices' | 'products' | 'usedTools'> {
    return {
      usedTools: usedTools ?? [],
      products: CopilotEmbeddedProductMapper.fromToolCalls(usedTools),
      choices: CopilotEmbeddedChoiceMapper.fromToolCalls(usedTools),
    };
  }
}