Skip to content

Commit

Permalink
feat(answer): knowledge controller preparation
Browse files Browse the repository at this point in the history
  • Loading branch information
Danny Gauthier authored and Danny Gauthier committed Jul 9, 2024
1 parent eaef9fa commit bf21cf8
Show file tree
Hide file tree
Showing 10 changed files with 508 additions and 158 deletions.
3 changes: 2 additions & 1 deletion .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -264,13 +264,14 @@
"spworkflowprocesslist",
"spworkspacepagelist",
"stenciljs",
"SVCC",
"TDIDF",
"Techzample",
"testid",
"thisisanotherurl",
"thisisaurl",
"thisisnotadate",
"tryitnow",
"testid",
"tsdoc",
"ttfb",
"uikit",
Expand Down
1 change: 0 additions & 1 deletion packages/atomic/cypress/e2e/generated-answer.cypress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -565,7 +565,6 @@ describe('Generated Answer Test Suites', () => {
GeneratedAnswerSelectors.container().should('not.exist');
});
});

describe('Retryable error', () => {
[500, 429].forEach((errorCode) => {
describe(`${errorCode} error`, () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,6 @@ describe('generated answer', () => {
});
});

it('should subscribe to state updates', () => {
expect(engine.subscribe).toHaveBeenCalledTimes(1);
});

it('should return the state', () => {
expect(generatedAnswer.state).toEqual(getGeneratedAnswerInitialState());
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
import {Unsubscribe} from '@reduxjs/toolkit';
import {GeneratedAnswerAPIClient} from '../../../api/generated-answer/generated-answer-client';
import {GeneratedAnswerCitation} from '../../../api/generated-answer/generated-answer-event-payload';
import {CoreEngine} from '../../../app/engine';
import {ClientThunkExtraArguments} from '../../../app/thunk-extra-arguments';
import {
CustomAction,
LegacySearchAction,
} from '../../../features/analytics/analytics-utils';
import {
streamAnswer,
resetAnswer,
likeGeneratedAnswer,
dislikeGeneratedAnswer,
updateResponseFormat,
Expand All @@ -18,7 +13,6 @@ import {
setIsVisible,
sendGeneratedAnswerFeedback,
registerFieldsToIncludeInCitations,
setId,
expandGeneratedAnswer,
collapseGeneratedAnswer,
} from '../../../features/generated-answer/generated-answer-actions';
Expand All @@ -35,7 +29,6 @@ import {
SearchSection,
} from '../../../state/state-sections';
import {loadReducerError} from '../../../utils/errors';
import {randomID} from '../../../utils/utils';
import {
Controller,
buildController,
Expand Down Expand Up @@ -123,101 +116,6 @@ export interface GeneratedAnswer extends Controller {
logCitationHover(citationId: string, citationHoverTimeMs: number): void;
}

export interface GeneratedAnswerProps {
initialState?: {
/**
* Sets the component visibility state on load.
*/
isVisible?: boolean;
/**
* The initial formatting options applied to generated answers when the controller first loads.
*/
responseFormat?: GeneratedResponseFormat;
/**
* The initial expanded state of the generated answer.
*/
expanded?: boolean;
};
/**
* A list of indexed fields to include in the citations returned with the generated answer.
*/
fieldsToIncludeInCitations?: string[];
}

interface SubscribeStateManager {
engines: Record<
string,
{
abortController: AbortController | undefined;
lastRequestId: string;
lastStreamId: string;
}
>;
getIsStreamInProgress: (genQaEngineId: string) => boolean;
setAbortControllerRef: (ref: AbortController, genQaEngineId: string) => void;
subscribeToSearchRequests: (
engine: CoreEngine<
GeneratedAnswerSection & SearchSection & DebugSection,
ClientThunkExtraArguments<GeneratedAnswerAPIClient>
>
) => Unsubscribe;
}

const subscribeStateManager: SubscribeStateManager = {
engines: {},

setAbortControllerRef: (ref: AbortController, genQaEngineId: string) => {
subscribeStateManager.engines[genQaEngineId].abortController = ref;
},

getIsStreamInProgress: (genQaEngineId: string) => {
if (
!subscribeStateManager.engines[genQaEngineId].abortController ||
subscribeStateManager.engines[genQaEngineId].abortController?.signal
.aborted
) {
subscribeStateManager.engines[genQaEngineId].abortController = undefined;
return false;
}
return true;
},

subscribeToSearchRequests: (engine) => {
const strictListener = () => {
const state = engine.state;
const requestId = state.search.requestId;
const streamId =
state.search.extendedResults.generativeQuestionAnsweringId;
const genQaEngineId = state.generatedAnswer.id;

if (
subscribeStateManager.engines[genQaEngineId].lastRequestId !== requestId
) {
subscribeStateManager.engines[genQaEngineId].lastRequestId = requestId;
subscribeStateManager.engines[genQaEngineId].abortController?.abort();
engine.dispatch(resetAnswer());
}

const isStreamInProgress =
subscribeStateManager.getIsStreamInProgress(genQaEngineId);
if (
!isStreamInProgress &&
streamId &&
streamId !== subscribeStateManager.engines[genQaEngineId].lastStreamId
) {
subscribeStateManager.engines[genQaEngineId].lastStreamId = streamId;
engine.dispatch(
streamAnswer({
setAbortControllerRef: (ref: AbortController) =>
subscribeStateManager.setAbortControllerRef(ref, genQaEngineId),
})
);
}
};
return engine.subscribe(strictListener);
},
};

export interface GeneratedAnswerAnalyticsClient {
logLikeGeneratedAnswer: () => CustomAction;
logDislikeGeneratedAnswer: () => CustomAction;
Expand All @@ -241,8 +139,32 @@ export interface GeneratedAnswerAnalyticsClient {
logGeneratedAnswerCollapse: () => CustomAction;
}

export interface GeneratedAnswerPropsInitialState {
initialState?: {
/**
* Sets the component visibility state on load.
*/
isVisible?: boolean;
/**
* The initial formatting options applied to generated answers when the controller first loads.
*/
responseFormat?: GeneratedResponseFormat;
/**
* The initial expanded state of the generated answer.
*/
expanded?: boolean;
};
}

export interface GeneratedAnswerProps extends GeneratedAnswerPropsInitialState {
/**
* A list of indexed fields to include in the citations returned with the generated answer.
*/
fieldsToIncludeInCitations?: string[];
}

/**
* Creates a core `GeneratedAnswer` controller instance.
* Can be used as a basis for controllers aiming to return a `GeneratedAnswer` controller instance.
*
* @param engine - The headless engine.
* @param props - The configurable `GeneratedAnswer` properties.
Expand All @@ -261,16 +183,6 @@ export function buildCoreGeneratedAnswer(
const controller = buildController(engine);
const getState = () => engine.state;

if (!engine.state.generatedAnswer.id) {
const genQaEngineId = randomID('genQA-', 12);
dispatch(setId({id: genQaEngineId}));
subscribeStateManager.engines[genQaEngineId] = {
abortController: undefined,
lastRequestId: '',
lastStreamId: '',
};
}

const isVisible = props.initialState?.isVisible;
if (isVisible !== undefined) {
dispatch(setIsVisible(isVisible));
Expand All @@ -290,8 +202,6 @@ export function buildCoreGeneratedAnswer(
dispatch(expandGeneratedAnswer());
}

subscribeStateManager.subscribeToSearchRequests(engine);

return {
...controller,

Expand Down
Loading

0 comments on commit bf21cf8

Please sign in to comment.