Skip to content

Commit c8a2767

Browse files
authored
[Agent Builder] Expose thinking complete event and update round to include time to first and last token (#241681)
1 parent f1ddc18 commit c8a2767

File tree

18 files changed

+235
-35
lines changed

18 files changed

+235
-35
lines changed

x-pack/platform/packages/shared/onechat/onechat-common/chat/conversation.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,17 +151,33 @@ export interface ConversationRound {
151151
steps: ConversationRoundStep[];
152152
/** The final response from the assistant */
153153
response: AssistantResponse;
154+
/** when the round was started */
155+
started_at: string;
156+
/** time it took to first token, in ms */
157+
time_to_first_token: number;
158+
/** time it took to last token, in ms */
159+
time_to_last_token: number;
154160
/** when tracing is enabled, contains the traceId associated with this round */
155161
trace_id?: string;
156162
}
157163

164+
/**
165+
* Main structure representing a conversation with an agent.
166+
*/
158167
export interface Conversation {
168+
/** unique id for this conversation */
159169
id: string;
170+
/** id of the agent this conversation is bound to */
160171
agent_id: string;
172+
/** info of the owner of the discussion */
161173
user: UserIdAndName;
174+
/** title of the conversation */
162175
title: string;
176+
/** creation date */
163177
created_at: string;
178+
/** update date */
164179
updated_at: string;
180+
/** list of round for this conversation */
165181
rounds: ConversationRound[];
166182
}
167183

x-pack/platform/packages/shared/onechat/onechat-common/chat/events.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export enum ChatEventType {
1616
reasoning = 'reasoning',
1717
messageChunk = 'message_chunk',
1818
messageComplete = 'message_complete',
19+
thinkingComplete = 'thinking_complete',
1920
roundComplete = 'round_complete',
2021
conversationCreated = 'conversation_created',
2122
conversationUpdated = 'conversation_updated',
@@ -122,6 +123,24 @@ export const isMessageCompleteEvent = (
122123
return event.type === ChatEventType.messageComplete;
123124
};
124125

126+
// Thinking complete
127+
128+
export interface ThinkingCompleteEventData {
129+
/** time elapsed from round start to first token arrival, in ms */
130+
time_to_first_token: number;
131+
}
132+
133+
export type ThinkingCompleteEvent = ChatEventBase<
134+
ChatEventType.thinkingComplete,
135+
ThinkingCompleteEventData
136+
>;
137+
138+
export const isThinkingCompleteEvent = (
139+
event: OnechatEvent<string, any>
140+
): event is ThinkingCompleteEvent => {
141+
return event.type === ChatEventType.thinkingComplete;
142+
};
143+
125144
// Round complete
126145

127146
export interface RoundCompleteEventData {
@@ -200,6 +219,7 @@ export type ChatAgentEvent =
200219
| ReasoningEvent
201220
| MessageChunkEvent
202221
| MessageCompleteEvent
222+
| ThinkingCompleteEvent
203223
| RoundCompleteEvent;
204224

205225
/**

x-pack/platform/packages/shared/onechat/onechat-common/chat/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ export {
4646
type MessageChunkEvent,
4747
type MessageCompleteEventData,
4848
type MessageCompleteEvent,
49+
type ThinkingCompleteEventData,
50+
type ThinkingCompleteEvent,
4951
type RoundCompleteEventData,
5052
type RoundCompleteEvent,
5153
isToolCallEvent,
@@ -54,6 +56,7 @@ export {
5456
isReasoningEvent,
5557
isMessageChunkEvent,
5658
isMessageCompleteEvent,
59+
isThinkingCompleteEvent,
5760
isRoundCompleteEvent,
5861
isConversationCreatedEvent,
5962
isConversationUpdatedEvent,

x-pack/platform/packages/shared/onechat/onechat-common/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ export {
123123
type MessageChunkEvent,
124124
type MessageCompleteEventData,
125125
type MessageCompleteEvent,
126+
type ThinkingCompleteEventData,
127+
type ThinkingCompleteEvent,
126128
type RoundCompleteEventData,
127129
type RoundCompleteEvent,
128130
type ToolCallProgress,
@@ -131,6 +133,7 @@ export {
131133
isReasoningEvent,
132134
isMessageChunkEvent,
133135
isMessageCompleteEvent,
136+
isThinkingCompleteEvent,
134137
isRoundCompleteEvent,
135138
isConversationCreatedEvent,
136139
isConversationUpdatedEvent,

x-pack/platform/packages/shared/onechat/onechat-genai-utils/langchain/graph_events.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import type {
1010
MessageChunkEvent,
1111
MessageCompleteEvent,
1212
ReasoningEvent,
13+
ThinkingCompleteEvent,
1314
ToolCallEvent,
1415
ToolResultEvent,
1516
} from '@kbn/onechat-common';
@@ -108,3 +109,12 @@ export const createReasoningEvent = (
108109
},
109110
};
110111
};
112+
113+
export const createThinkingCompleteEvent = (timeToFirstToken: number): ThinkingCompleteEvent => {
114+
return {
115+
type: ChatEventType.thinkingComplete,
116+
data: {
117+
time_to_first_token: timeToFirstToken,
118+
},
119+
};
120+
};

x-pack/platform/packages/shared/onechat/onechat-genai-utils/langchain/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export {
1717
createReasoningEvent,
1818
createToolCallEvent,
1919
createToolResultEvent,
20+
createThinkingCompleteEvent,
2021
} from './graph_events';
2122
export {
2223
extractTextContent,

x-pack/platform/plugins/shared/onechat/public/application/components/conversations/conversation_rounds/round_thinking/round_thinking.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import React, { useState } from 'react';
1313
import { useSendMessage } from '../../../../context/send_message/send_message_context';
1414
import { RoundFlyout } from '../round_flyout';
1515
import { RoundSteps } from './steps/round_steps';
16+
import { ThinkingTimeDisplay } from './thinking_time_display';
1617

1718
interface RoundThinkingProps {
1819
rawRound: ConversationRound;
@@ -91,6 +92,7 @@ export const RoundThinking: React.FC<RoundThinkingProps> = ({ steps, isLoading,
9192
{rawResponseButtonLabel}
9293
</EuiButton>
9394
)}
95+
<ThinkingTimeDisplay timeToFirstToken={rawRound.time_to_first_token} />
9496
</EuiPanel>
9597
<RoundFlyout isOpen={showFlyout} onClose={toggleFlyout} rawRound={rawRound} />
9698
</EuiAccordion>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0; you may not use this file except in compliance with the Elastic License
5+
* 2.0.
6+
*/
7+
8+
import React from 'react';
9+
import { EuiSpacer, EuiText } from '@elastic/eui';
10+
import { FormattedMessage } from '@kbn/i18n-react';
11+
import { css } from '@emotion/react';
12+
13+
export const ThinkingTimeDisplay = ({ timeToFirstToken }: { timeToFirstToken: number }) => {
14+
if (timeToFirstToken === 0) {
15+
return null;
16+
}
17+
return (
18+
<>
19+
<EuiSpacer size="m" />
20+
<EuiText
21+
size="s"
22+
color="subdued"
23+
css={css`
24+
font-style: italic;
25+
`}
26+
>
27+
<FormattedMessage
28+
id="xpack.onechat.conversation.thinking.timeToFirstToken"
29+
defaultMessage="Thought for {timeToFirstToken} seconds."
30+
values={{
31+
timeToFirstToken: Math.round(timeToFirstToken / 1000),
32+
}}
33+
/>
34+
</EuiText>
35+
</>
36+
);
37+
};

x-pack/platform/plugins/shared/onechat/public/application/context/conversation/use_conversation_actions.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ export interface ConversationActions {
4949
}) => void;
5050
setAssistantMessage: ({ assistantMessage }: { assistantMessage: string }) => void;
5151
addAssistantMessageChunk: ({ messageChunk }: { messageChunk: string }) => void;
52+
setTimeToFirstToken: ({ timeToFirstToken }: { timeToFirstToken: number }) => void;
5253
onConversationCreated: ({
5354
conversationId,
5455
title,
@@ -110,6 +111,9 @@ const createConversationActions = ({
110111
input: { message: userMessage },
111112
response: { message: '' },
112113
steps: [],
114+
started_at: new Date().toISOString(),
115+
time_to_first_token: 0,
116+
time_to_last_token: 0,
113117
};
114118

115119
if (!draft) {
@@ -129,7 +133,6 @@ const createConversationActions = ({
129133
})
130134
);
131135
},
132-
133136
setAgentId: (agentId: string) => {
134137
// We allow to change agent only at the start of the conversation
135138
if (conversationId) {
@@ -148,7 +151,6 @@ const createConversationActions = ({
148151
);
149152
setAgentIdStorage(agentId);
150153
},
151-
152154
addReasoningStep: ({ step }: { step: ReasoningStep }) => {
153155
setCurrentRound((round) => {
154156
round.steps.push(step);
@@ -194,7 +196,11 @@ const createConversationActions = ({
194196
round.response.message += messageChunk;
195197
});
196198
},
197-
199+
setTimeToFirstToken: ({ timeToFirstToken }: { timeToFirstToken: number }) => {
200+
setCurrentRound((round) => {
201+
round.time_to_first_token = timeToFirstToken;
202+
});
203+
},
198204
onConversationCreated: ({
199205
conversationId: id,
200206
title,
@@ -224,7 +230,6 @@ const createConversationActions = ({
224230
onConversationCreated({ conversationId: id, title });
225231
}
226232
},
227-
228233
deleteConversation: async (id: string) => {
229234
await conversationsService.delete({ conversationId: id });
230235

x-pack/platform/plugins/shared/onechat/public/application/context/send_message/use_subscribe_to_chat_events.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
isToolCallEvent,
1616
isToolProgressEvent,
1717
isToolResultEvent,
18+
isThinkingCompleteEvent,
1819
} from '@kbn/onechat-common';
1920
import { createReasoningStep, createToolCallStep } from '@kbn/onechat-common/chat/conversation';
2021
import type { Observable } from 'rxjs';
@@ -77,6 +78,10 @@ export const useSubscribeToChatEvents = ({
7778
} else if (isConversationCreatedEvent(event)) {
7879
const { conversation_id: id, title } = event.data;
7980
conversationActions.onConversationCreated({ conversationId: id, title });
81+
} else if (isThinkingCompleteEvent(event)) {
82+
conversationActions.setTimeToFirstToken({
83+
timeToFirstToken: event.data.time_to_first_token,
84+
});
8085
}
8186
},
8287
complete: () => {

0 commit comments

Comments
 (0)