Skip to content

Commit 60a8518

Browse files
authored
[Agent Builder] Rename send message references to streaming context (#268876)
1 parent 7d78f79 commit 60a8518

25 files changed

Lines changed: 91 additions & 86 deletions

x-pack/platform/plugins/shared/agent_builder/CONTRIBUTOR_GUIDE.md

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1322,31 +1322,40 @@ The full implementation is ~130 lines and serves as the reference for new types.
13221322

13231323
## Streams lifecycle (frontend)
13241324

1325-
The chat streaming layer lives in `public/application/context/send_message/`. This section
1326-
documents how mutations, lifted state, and the React Query cache fit together. Read this
1327-
before touching any of:
1328-
`send_message_context.tsx`, `use_send_message.ts`, `use_send_message_mutation.ts`,
1329-
`use_resume_round_mutation.ts`, `use_subscribe_to_chat_events.ts`,
1325+
The chat streaming layer lives across two folders:
1326+
1327+
- `public/application/context/streaming/` — the lifted provider, its context hook, the
1328+
send/regenerate and resume mutation hooks, the chat-events subscriber, and shared types.
1329+
- `public/application/hooks/` — the per-conversation convenience hook
1330+
(`use_conversation_stream.ts`) and the "any stream active?" derived hook
1331+
(`use_is_any_conversation_streaming.ts`). They live here because they compose
1332+
`useConversation` (a sibling in `hooks/`) with the streaming context.
1333+
1334+
This section documents how mutations, lifted state, and the React Query cache fit
1335+
together. Read this before touching any of: `streaming_context.tsx`,
1336+
`use_send_message_mutation.ts`, `use_resume_round_mutation.ts`,
1337+
`use_subscribe_to_chat_events.ts`, `use_conversation_stream.ts`,
13301338
`use_is_any_conversation_streaming.ts`.
13311339

13321340
### The lift
13331341

1334-
`<SendMessageProvider>` is mounted **once** above the routes/sidebar:
1342+
`<StreamingProvider>` is mounted **once** above the routes/sidebar:
13351343

13361344
- Routed app: in `mount.tsx`, above `<AgentBuilderRoutes>`. The sidebar is part of the
13371345
routes, so it can read streaming state directly.
13381346
- Embeddable: in `embeddable_conversations_provider.tsx`, one provider per embeddable
13391347
instance because each instance has its own `QueryClient`.
13401348

1341-
The sidebar uses `useSendMessageContext()` directly. `useIsAnyConversationStreaming()`
1349+
The sidebar uses `useStreamingContext()` directly. `useIsAnyConversationStreaming()`
13421350
is derived from the same context and is used by the page-leave guard and the
13431351
embeddable welcome-message dismiss — both genuinely care about "is anything in
13441352
flight, anywhere?". Anything inside the conversation tree should use the per-conversation
1345-
scoped hook, `useSendMessage()` (in `use_send_message.ts`).
1353+
scoped hook, `useConversationStream()` (in `hooks/use_conversation_stream.ts`).
1354+
13461355

13471356
### Lifted state
13481357

1349-
`SendMessageProvider` owns two slices with split lifecycles:
1358+
`StreamingProvider` owns two slices with split lifecycles:
13501359

13511360
- `activeStreams: Map<conversationId, { type, agentReasoning }>` — one entry per
13521361
in-flight stream. Set synchronously when each mutation kicks off; deleted in the
@@ -1426,7 +1435,7 @@ cache, B writes to its own. Cancelling one doesn't affect the other.
14261435
What this means in practice:
14271436

14281437
- **Submit gate** (`conversation_input.tsx`) is per-conversation: `isResponseLoading`
1429-
from `useSendMessage()`. The new-conversation route (`/conversations/new`) has
1438+
from `useConversationStream()`. The new-conversation route (`/conversations/new`) has
14301439
no `conversationId`, so `isResponseLoading` is `false` and submit is always
14311440
allowed there even while other conversations stream.
14321441
- **HITL Approve / Cancel gate** (`round_layout.tsx`) is per-conversation:

x-pack/platform/plugins/shared/agent_builder/public/application/components/conversations/actions/start_new_conversation_button.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import React, { useCallback } from 'react';
99
import { EuiButton } from '@elastic/eui';
1010
import { i18n } from '@kbn/i18n';
1111
import { useConversationContext } from '../../../context/conversation/conversation_context';
12-
import { useSendMessage } from '../../../context/send_message/send_message_context';
12+
import { useConversationStream } from '../../../hooks/use_conversation_stream';
1313
import { useNavigation } from '../../../hooks/use_navigation';
1414
import { useLastAgentId } from '../../../hooks/use_last_agent_id';
1515
import { appPaths } from '../../../utils/app_paths';
@@ -24,7 +24,7 @@ const NEW_CONVERSATION_BUTTON_LABEL = i18n.translate(
2424
export const StartNewConversationButton: React.FC = () => {
2525
const { navigateToAgentBuilderUrl } = useNavigation();
2626
const { isEmbeddedContext, setConversationId } = useConversationContext();
27-
const { removeError } = useSendMessage();
27+
const { removeError } = useConversationStream();
2828
const lastAgentId = useLastAgentId();
2929

3030
const handleClick = useCallback(() => {

x-pack/platform/plugins/shared/agent_builder/public/application/components/conversations/conversation.tsx

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,8 @@ import { ConversationRounds } from './conversation_rounds/conversation_rounds';
2525
import { NewConversationPrompt } from './new_conversation_prompt';
2626
import { useConversationId } from '../../context/conversation/use_conversation_id';
2727
import { useShouldStickToBottom } from '../../context/conversation/use_should_stick_to_bottom';
28-
import {
29-
useSendMessage,
30-
useSendMessageContext,
31-
} from '../../context/send_message/send_message_context';
28+
import { useConversationStream } from '../../hooks/use_conversation_stream';
29+
import { useStreamingContext } from '../../context/streaming/streaming_context';
3230
import { useIsAnyConversationStreaming } from '../../hooks/use_is_any_conversation_streaming';
3331
import { useConversationScrollActions } from '../../hooks/use_conversation_scroll_actions';
3432
import { useConversationStatus } from '../../hooks/use_conversation';
@@ -56,9 +54,9 @@ export const Conversation: React.FC<{}> = () => {
5654
const { euiTheme } = useEuiTheme();
5755
const conversationId = useConversationId();
5856
const hasActiveConversation = useHasActiveConversation();
59-
const { isResponseLoading } = useSendMessage();
57+
const { isResponseLoading } = useConversationStream();
6058
const isAnyStreaming = useIsAnyConversationStreaming();
61-
const { cancelAllStreams } = useSendMessageContext();
59+
const { cancelAllStreams } = useStreamingContext();
6260
const conversationRounds = useConversationRounds();
6361
const lastRound = conversationRounds.at(-1);
6462
const { isFetched } = useConversationStatus();

x-pack/platform/plugins/shared/agent_builder/public/application/components/conversations/conversation_input/conversation_input.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { i18n } from '@kbn/i18n';
1717
import type { PropsWithChildren } from 'react';
1818
import React, { useEffect, useMemo } from 'react';
1919
import { useConversationId } from '../../../context/conversation/use_conversation_id';
20-
import { useSendMessage } from '../../../context/send_message/send_message_context';
20+
import { useConversationStream } from '../../../hooks/use_conversation_stream';
2121
import { useSubmitMessage } from '../../../hooks/use_submit_message';
2222
import { useAgentBuilderAgents } from '../../../hooks/agents/use_agents';
2323
import { useValidateAgentId } from '../../../hooks/agents/use_validate_agent_id';
@@ -144,7 +144,7 @@ export const ConversationInput: React.FC<ConversationInputProps> = ({
144144
onSubmit,
145145
onEditorFocus,
146146
}) => {
147-
const { pendingMessage, error, isResuming, isResponseLoading } = useSendMessage();
147+
const { pendingMessage, error, isResuming, isResponseLoading } = useConversationStream();
148148
const { isFetched } = useAgentBuilderAgents();
149149
const agentId = useAgentId();
150150
const conversationId = useConversationId();

x-pack/platform/plugins/shared/agent_builder/public/application/components/conversations/conversation_input/input_actions/conversation_action_button.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import React from 'react';
99
import { EuiButtonIcon, useEuiTheme } from '@elastic/eui';
1010
import { css } from '@emotion/react';
1111
import { i18n } from '@kbn/i18n';
12-
import { useSendMessage } from '../../../../context/send_message/send_message_context';
12+
import { useConversationStream } from '../../../../hooks/use_conversation_stream';
1313

1414
interface ConversationActionButtonProps {
1515
onSubmit: () => void;
@@ -31,7 +31,7 @@ export const ConversationActionButton: React.FC<ConversationActionButtonProps> =
3131
isSubmitDisabled,
3232
resetToPendingMessage,
3333
}) => {
34-
const { canCancel, cancel } = useSendMessage();
34+
const { canCancel, cancel } = useConversationStream();
3535
const { euiTheme } = useEuiTheme();
3636

3737
const cancelButtonStyles = css`

x-pack/platform/plugins/shared/agent_builder/public/application/components/conversations/conversation_rounds/round_layout.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { isConfirmationPrompt } from '@kbn/agent-builder-common/agents';
2121
import { RoundInput } from './round_input';
2222
import { RoundThinking } from './round_thinking/round_thinking';
2323
import { RoundResponse } from './round_response/round_response';
24-
import { useSendMessage } from '../../../context/send_message/send_message_context';
24+
import { useConversationStream } from '../../../hooks/use_conversation_stream';
2525
import { RoundError } from './round_error/round_error';
2626
import { ConfirmationPrompt } from './round_prompt';
2727
import { RoundAttachmentReferences } from './round_attachment_references';
@@ -91,7 +91,7 @@ export const RoundLayout: React.FC<RoundLayoutProps> = ({
9191
retry: retrySendMessage,
9292
resumeRound,
9393
isResuming,
94-
} = useSendMessage();
94+
} = useConversationStream();
9595
// HITL Approve / Cancel is per-conversation: streamActions are closure-bound to
9696
// vars.conversationId, so other in-flight conversations cannot corrupt this cache.
9797
// Use `isStreaming` (not `isResponseLoading`) so the buttons stay disabled during the

x-pack/platform/plugins/shared/agent_builder/public/application/components/conversations/conversation_rounds/round_response/round_response_actions.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import copy from 'copy-to-clipboard';
1111
import React, { useCallback } from 'react';
1212
import { i18n } from '@kbn/i18n';
1313
import { useToasts } from '../../../../hooks/use_toasts';
14-
import { useSendMessage } from '../../../../context/send_message/send_message_context';
14+
import { useConversationStream } from '../../../../hooks/use_conversation_stream';
1515

1616
const labels = {
1717
copy: i18n.translate('xpack.agentBuilder.roundResponseActions.copy', {
@@ -37,7 +37,7 @@ export const RoundResponseActions: React.FC<RoundResponseActionsProps> = ({
3737
isLastRound,
3838
}) => {
3939
const { addSuccessToast } = useToasts();
40-
const { regenerate, isRegenerating, isResponseLoading } = useSendMessage();
40+
const { regenerate, isRegenerating, isResponseLoading } = useConversationStream();
4141

4242
const handleCopy = useCallback(() => {
4343
const isSuccess = copy(content);

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiText } from '@elastic/eui';
99
import React from 'react';
1010
import { i18n } from '@kbn/i18n';
1111
import { css } from '@emotion/react';
12-
import { useSendMessage } from '../../../../context/send_message/send_message_context';
12+
import { useConversationStream } from '../../../../hooks/use_conversation_stream';
1313
import { RoundIcon } from './round_icon';
1414
import { lineClampStyles } from '../../../../../common.styles';
1515

@@ -38,7 +38,7 @@ interface RoundThinkingTitleProps {
3838
const MIN_HEIGHT = '40px';
3939

4040
export const RoundThinkingTitle = ({ isLoading, hasSteps, onShow }: RoundThinkingTitleProps) => {
41-
const { agentReasoning } = useSendMessage();
41+
const { agentReasoning } = useConversationStream();
4242

4343
let thinkingButtonLabel = thinkingCompletedLabel;
4444
if (isLoading) {

x-pack/platform/plugins/shared/agent_builder/public/application/components/conversations/conversation_rounds/rounds_screen_reader_status.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import React, { useEffect, useRef, useState } from 'react';
1010
import type { ConversationRound } from '@kbn/agent-builder-common';
1111
import { css } from '@emotion/react';
1212
import { euiScreenReaderOnly } from '@elastic/eui';
13-
import { useSendMessage } from '../../../context/send_message/send_message_context';
13+
import { useConversationStream } from '../../../hooks/use_conversation_stream';
1414

1515
// Intervals grow by 5s each announcement, capped at 30s.
1616
// e.g. announcements fire at: 0s, 5s, 15s, 30s, 50s, 75s, 105s, 135s, ...
@@ -66,7 +66,7 @@ const useGeneratingAnnouncements = (isActive: boolean) => {
6666
export const RoundsScreenReaderStatus: React.FC<{ lastRound?: ConversationRound }> = ({
6767
lastRound,
6868
}) => {
69-
const { isResponseLoading } = useSendMessage();
69+
const { isResponseLoading } = useConversationStream();
7070
const announcement = useGeneratingAnnouncements(isResponseLoading);
7171

7272
const responseWasLoading = useRef(false);

x-pack/platform/plugins/shared/agent_builder/public/application/components/conversations/embeddable_conversation_header/agents_popover_view.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { css } from '@emotion/react';
2020
import { i18n } from '@kbn/i18n';
2121
import type { AgentDefinition } from '@kbn/agent-builder-common';
2222
import { useConversationContext } from '../../../context/conversation/conversation_context';
23-
import { useSendMessageContext } from '../../../context/send_message/send_message_context';
23+
import { useStreamingContext } from '../../../context/streaming/streaming_context';
2424
import { useAgentBuilderAgents } from '../../../hooks/agents/use_agents';
2525
import { useNavigation } from '../../../hooks/use_navigation';
2626
import { appPaths } from '../../../utils/app_paths';
@@ -56,7 +56,7 @@ export const AgentsPopoverView: React.FC<AgentsPopoverViewProps> = ({
5656
}) => {
5757
const { euiTheme } = useEuiTheme();
5858
const { agentId, setAgentId } = useConversationContext();
59-
const { removeAllErrors } = useSendMessageContext();
59+
const { removeAllErrors } = useStreamingContext();
6060
const { agents } = useAgentBuilderAgents();
6161
const { agentOptions, renderAgentOption } = useAgentOptions({ agents, selectedAgentId: agentId });
6262

0 commit comments

Comments
 (0)