Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import type {
MessagePartsUserTextPreferences,
MessagePartMessage,
MessagePartsHost,
} from './contract';
} from '~/hooks/Chat/contract';
import type { Artifact } from '~/common';
import {
liveAppliedSteerFamily,
Expand Down
1 change: 1 addition & 0 deletions client/src/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export * from './artifacts';
export * from './types';
export * from './menus';
export * from './tools';
export * from './ptc';
export * from './selector';
export * from './assistants-types';
export * from './agents-types';
29 changes: 29 additions & 0 deletions client/src/common/ptc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import type { PtcToolCallStatus } from 'librechat-data-provider';

/**
* A row's outcome. Widens the wire status with `interrupted`, which the
* backend never sends: it is what the client concludes locally about a call
* that was still running when a stream gap swallowed its settling event.
*/
export type PtcTraceStatus = PtcToolCallStatus | 'interrupted';

/** One tool call a programmatic (PTC) program made from inside the sandbox. */
export interface PtcTraceEntry {
/** Stable id from the backend; the settle event updates this row in place. */
callId: string;
/** Inner tool id, e.g. `search_code_mcp_github`. */
name: string;
status: PtcTraceStatus;
/** `key=value` preview of the call's input. */
args?: string;
/** Truncated failure message on a failed call. */
error?: string;
durationMs?: number;
}

/** One PTC program's trace: the retained tail plus what the cap discarded. */
export interface PtcTrace {
entries: PtcTraceEntry[];
/** Rows evicted by the trace cap (`PTC_TRACE_MAX_ENTRIES`), so the cap is never silent. */
dropped: number;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import type { TAttachment, PartMetadata } from 'librechat-data-provider';
import { parseBackgroundHandle, splitBackgroundAttachments } from './handle';
import ProgressText from '~/components/Chat/Messages/Content/ProgressText';
import parseJsonField, { areToolCallArgsComplete } from './parseJsonField';
import { useMessagePartsHost } from '~/Providers/MessagePartsHostContext';
import CopyButton from '~/components/Messages/Content/CopyButton';
import LangIcon from '~/components/Messages/Content/LangIcon';
import { toolPanelSpacingClassName } from '../disclosure';
import { useMessagePartsHost } from '~/hooks/Chat/parts';
import useToolCallState from './useToolCallState';
import useLazyHighlight from './useLazyHighlight';
import useFollowScroll from './useFollowScroll';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { SquareTerminal } from 'lucide-react';
import type { TAttachment, PartMetadata } from 'librechat-data-provider';
import { parseBackgroundHandle, splitBackgroundAttachments } from './handle';
import ProgressText from '~/components/Chat/Messages/Content/ProgressText';
import { useMessagePartsHost } from '~/Providers/MessagePartsHostContext';
import { toolPanelSpacingClassName } from '../disclosure';
import { useMessagePartsHost } from '~/hooks/Chat/parts';
import useLazyHighlight from './useLazyHighlight';
import useToolCallState from './useToolCallState';
import CodeWindowHeader from './CodeWindowHeader';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React from 'react';
import { FileSources, sharedFileDownload } from 'librechat-data-provider';
import { getDownloadFilename, isHttpDownloadTarget, triggerDownload } from '~/utils';
import { useMessagePartsHost } from '~/Providers/MessagePartsHostContext';
import { useCodeOutputDownload, useFileDownload } from '~/data-provider';
import { useMessagePartsHost } from '~/hooks/Chat/parts';
import useLocalize from '~/hooks/useLocalize';
import { useShareContext } from '~/Providers';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import { QueryKeys, type TMessage } from 'librechat-data-provider';
import type { SteerReceiptState } from '~/components/Chat/Steering/Receipt';
import useSteerCancel, { useSteerMoveToQueue, useSteerRehome } from '~/hooks/Chat/useSteerCancel';
import EscalateNowButton from '~/components/Chat/Input/EscalateNowButton';
import { useMessagePartsHost } from '~/Providers/MessagePartsHostContext';
import useSteerEscalate from '~/hooks/Chat/useSteerEscalate';
import useSteerRecovery from '~/hooks/Chat/useSteerRecovery';
import { hasLiveRunPause } from '~/hooks/Chat/useSteering';
import { useGetMessagesByConvoId } from '~/data-provider';
import { useMessagePartsHost } from '~/hooks/Chat/parts';
import { cn, isLegacyDeliveryUncertain } from '~/utils';
import { useLatestMessage } from '~/hooks/Messages';
import { useLocalize } from '~/hooks';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { useTranslation } from 'react-i18next';
import { isReportableRunStepDuration } from 'librechat-data-provider';
import type { PtcTraceEntry } from '~/hooks/Chat/contract';
import type { TranslationKeys } from '~/hooks';
import type { PtcTraceEntry } from '~/common';
import { useMessagePartsHost } from '~/Providers/MessagePartsHostContext';
import { cn, parseToolName, getRunStepDurationLabels } from '~/utils';
import { useMessagePartsHost } from '~/hooks/Chat/parts';
import { useMCPServerNames } from '~/hooks/MCP';
import useFollowScroll from './useFollowScroll';
import { useLocalize } from '~/hooks';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ import {
useInViewport,
} from './Thinking';
import { useLocalize, useExpandCollapse, useLazyCollapseBody } from '~/hooks';
import { useMessagePartsHost } from '~/Providers/MessagePartsHostContext';
import useSmoothStreaming from '~/hooks/Messages/useSmoothStreaming';
import CopyButton from '~/components/Messages/Content/CopyButton';
import { useMessagePartsHost } from '~/hooks/Chat/parts';
import { useReasoningDisclosure } from '../disclosure';
import { ROW_GLYPH_SLOT } from '../rows';
import { cn } from '~/utils';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import MessageTimestamp from '~/components/Chat/Messages/ui/MessageTimestamp';
import MessageQuotes from '~/components/Chat/Messages/Content/MessageQuotes';
import { cn, hydrateFileDeliveryMetadata, usesImagePreview } from '~/utils';
import MarkdownLite from '~/components/Chat/Messages/Content/MarkdownLite';
import { useMessagePartsHost } from '~/Providers/MessagePartsHostContext';
import FileContainer from '~/components/Chat/Input/Files/FileContainer';
import Image from '~/components/Chat/Messages/Content/Image';
import { useMessagePartsHost } from '~/hooks/Chat/parts';
import CollapsibleText from './CollapsibleText';
import { useShareContext } from '~/Providers';
import { useLocalize } from '~/hooks';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { ScrollText, ChevronDown, ChevronUp } from 'lucide-react';
import { Button, MorphIcon, TooltipAnchor } from '@librechat/client';
import type { SummaryContentPart } from 'librechat-data-provider';
import type { MouseEvent, FocusEvent } from 'react';
import { useMessagePartsHost } from '~/hooks/Chat/parts';
import { useMessagePartsHost } from '~/Providers/MessagePartsHostContext';
import { useLocalize } from '~/hooks';
import { cn } from '~/utils';

Expand Down
2 changes: 1 addition & 1 deletion client/src/components/Chat/Messages/Content/Parts/Text.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { memo, useMemo, ReactElement } from 'react';
import MarkdownLite from '~/components/Chat/Messages/Content/MarkdownLite';
import { useMessagePartsHost } from '~/Providers/MessagePartsHostContext';
import useSmoothStreaming from '~/hooks/Messages/useSmoothStreaming';
import Markdown from '~/components/Chat/Messages/Content/Markdown';
import { useMessagePartsHost } from '~/hooks/Chat/parts';
import CollapsibleText from './CollapsibleText';
import { cn } from '~/utils';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import { Lightbulb, ChevronDown } from 'lucide-react';
import { Button, MorphIcon, TooltipAnchor } from '@librechat/client';
import { ChevronUp as ChevronUpNode, ChevronDown as ChevronDownNode } from 'lucide';
import type { FocusEvent, FC } from 'react';
import { useMessagePartsHost } from '~/Providers/MessagePartsHostContext';
import CopyButton from '~/components/Messages/Content/CopyButton';
import { useMessagePartsHost } from '~/hooks/Chat/parts';
import { useLocalize, useExpandCollapse } from '~/hooks';
import { AnimatedText } from '../animate';
import { ROW_GLYPH_SLOT } from '../rows';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { memo, useEffect, useId, useLayoutEffect, useRef } from 'react';
import type { TAttachment, TFile, TAttachmentMetadata } from 'librechat-data-provider';
import type { Artifact } from '~/common';
import { useMessagePartsHost } from '~/Providers/MessagePartsHostContext';
import { artifactRowKind, isCodeOnlyArtifact } from '~/utils/artifacts';
import { useMessagePartsHost } from '~/hooks/Chat/parts';
import { displayFilename } from './attachmentTypes';
import { useAttachmentLink } from './LogLink';
import ArtifactRow from './ArtifactRow';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { memo, useId, useLayoutEffect, useMemo, useState } from 'react';
import { Download } from 'lucide-react';
import type { TAttachment, TFile, TAttachmentMetadata } from 'librechat-data-provider';
import { fileToArtifact, TOOL_ARTIFACT_TYPES, toolArtifactKey } from '~/utils/artifacts';
import { useMessagePartsHost } from '~/Providers/MessagePartsHostContext';
import Mermaid from '~/components/Messages/Content/Mermaid/Mermaid';
import { useMessagePartsHost } from '~/hooks/Chat/parts';
import { displayFilename } from './attachmentTypes';
import { useAttachmentLink } from './LogLink';
import { useLocalize } from '~/hooks';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import { RecoilRoot } from 'recoil';
import { render } from '@testing-library/react';
import type { PtcTraceEntry } from '~/store/ptc';
import type { PtcTraceEntry } from '~/common';
import { ptcTraceByToolCallId, ptcTraceKey } from '~/store/ptc';
import { MessageContext } from '~/Providers/MessageContext';
import ExecuteCode from '../ExecuteCode';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { Constants, ContentTypes, QueryKeys } from 'librechat-data-provider';
import { render, screen, fireEvent, waitFor, act } from '@testing-library/react';
import type { Agents, TConversation, TMessage } from 'librechat-data-provider';
import type { PendingSteer } from '~/store/families';
import type { PendingSteer } from '~/hooks/Chat/queue';
import { siblingIdxFamily, siblingKey } from '~/components/Chat/Messages/Thread/state';
import { hasLiveRunPause } from '~/hooks/Chat/useSteering';
import { applyPendingAction } from '~/utils/approval';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import { RecoilRoot, useSetRecoilState } from 'recoil';
import { render, screen } from '@testing-library/react';
import type { PtcTraceEntry } from '~/store/ptc';
import type { PtcTraceEntry } from '~/common';
import { ptcTraceByToolCallId, ptcTraceKey } from '~/store/ptc';
import { MessageContext } from '~/Providers/MessageContext';
import PtcToolTrace from '../PtcToolTrace';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@ import type {
MessagePartArtifactPanel,
MessagePartMessage,
MessagePartsHost,
PtcTrace,
} from '~/hooks/Chat/contract';
import type { Artifact } from '~/common';
import { MessagePartsHostProvider, appMessagePartsHost } from '~/hooks/Chat/parts';
import type { Artifact, PtcTrace } from '~/common';
import { MessagePartsHostProvider, appMessagePartsHost } from '~/Providers/MessagePartsHostContext';
import ToolArtifactCard from '../ToolArtifactCard';
import PtcToolTrace from '../PtcToolTrace';
import TextPart from '../Text';
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/Chat/Messages/MessagesView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import {
useMessageScrolling,
useConversationSeen,
} from '~/hooks';
import { MessagePartsHostProvider, appMessagePartsHost } from '~/Providers/MessagePartsHostContext';
import { MessagesViewProvider, useChatContext, useFileMapContext } from '~/Providers';
import { MessagePartsHostProvider, appMessagePartsHost } from '~/hooks/Chat/parts';
import { RowMountProvider, useProgressiveRowMount } from '~/hooks/Messages';
import { useChatSurface } from '~/components/Chat/Subagents/surface';
import useThreadRows from '~/hooks/Messages/useThreadRows';
Expand Down
2 changes: 1 addition & 1 deletion client/src/hooks/Chat/__tests__/transport.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import type {
} from 'librechat-data-provider';
import type { MutableSnapshot } from 'recoil';
import type { Transport } from '~/hooks/Chat/contract';
import type { PendingSteer } from '~/store/families';
import type { PendingSteer } from '~/hooks/Chat/queue';
import { queuedMessagesByConvoId, resetQueueFamilies } from '~/hooks/Chat/queue';
import { ChatTransportContext } from '~/Providers/ChatTransportContext';
import { useSteerReclaim } from '~/hooks/Chat/useSteerCancel';
Expand Down
2 changes: 1 addition & 1 deletion client/src/hooks/Chat/__tests__/useSteerCancel.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { RecoilRoot, useRecoilValue } from 'recoil';
import { act, renderHook } from '@testing-library/react';
import { ReasoningEffort } from 'librechat-data-provider';
import type { RestoreToComposer } from '~/Providers/ComposerRestoreContext';
import type { PendingSteer } from '~/store/families';
import type { PendingSteer } from '~/hooks/Chat/queue';
import {
ComposerRestoreProvider,
useComposerRestoreHost,
Expand Down
2 changes: 1 addition & 1 deletion client/src/hooks/Chat/__tests__/useSteerEscalate.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { RecoilRoot, useRecoilValue } from 'recoil';
import { getDefaultStore, useAtomValue } from 'jotai';
import { act, renderHook, waitFor } from '@testing-library/react';
import type { MutableSnapshot } from 'recoil';
import type { PendingSteer } from '~/store/families';
import type { PendingSteer } from '~/hooks/Chat/queue';
import { escalatingSteerFamily } from '~/store/steer';
import useSteerEscalate from '../useSteerEscalate';
import store from '~/store';
Expand Down
6 changes: 2 additions & 4 deletions client/src/hooks/Chat/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,9 @@ import type {
ExtendedFile,
TAskFunction,
Artifact,
PtcTrace,
} from '~/common';
import type { PendingSteer } from '~/store/families';
import type { PtcTrace } from '~/store/ptc';

export type { PtcTrace, PtcTraceEntry } from '~/store/ptc';
import type { PendingSteer } from './queue';

/** Options accepted by {@link ChatConversationContract.newConversation}: the shared params plus
* the two flags only the root pane's generator honors. */
Expand Down
48 changes: 48 additions & 0 deletions client/src/hooks/Chat/queue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,54 @@ import { atom } from 'jotai';
import { atomFamily, RESET } from 'jotai/utils';
import type { TMessage } from 'librechat-data-provider';
import type { PrimitiveAtom } from 'jotai';
import type { GenerationProtocolVersion } from '~/data-provider/SSE/protocol';

/**
* A steer message submitted mid-run. Server truth: `sending` covers the POST
* in flight, `pending` means the server queued it (awaiting its injection
* boundary — the next tool batch, or the next safe token boundary when
* `preempt` was armed), `failed` keeps the text recoverable after a rejected
* POST. The chip disappears when `on_steer_applied` lands (the inline content
* part becomes the durable record).
*/
export type PendingSteer = {
steerId: string;
/** Optimistic id echoed by server state when SYNC beats the POST callback. */
clientSteerId?: string;
text: string;
status: 'sending' | 'pending' | 'failed';
/** The transport failed without a definitive server rejection. The durable
* enqueue may have committed. Same-id Retry is safe only under protocol v2;
* edit/queue/remove stay hidden until ownership is resolved. */
deliveryUncertain?: boolean;
/** Protocol selected for the generation that owns this attempt. */
generationProtocolVersion?: GenerationProtocolVersion;
createdAt: number;
/** Attachments steered with the message (refs; already uploaded). */
files?: TMessage['files'];
/** Quoted excerpts riding this steer (also sent on the POST — the server
* merges them into the injected turn); kept on the chip so a steer that
* never injects restores onto the queued item with them intact. */
quotes?: string[];
/** Manual skill picks, carried for restoration only (a skill pick
* configures a NEW turn's run, so it never rides the steer POST). */
manualSkills?: string[];
/** Full-generation setting carried for restoration only; it cannot alter a live steer. */
reasoningOverride?: TMessage['reasoningOverride'];
/** Asked the run to seal generation at the next safe boundary rather than
* wait for a tool step. Labelling only — the server owns the behaviour and
* echoes what it actually armed. */
preempt?: boolean;
/** Monotonic server revision; delayed ACKs cannot undo SSE corrections. */
preemptRevision?: number;
/** Exact server generation this steer belongs to. Conversation ids are
* reused by later turns, so retries/arm/cancel must retain this epoch rather
* than mutating whatever generation currently occupies the conversation. */
generationCreatedAt?: number;
/** Exact client queue identity/order to restore if this accepted steer is
* returned as a terminal leftover before injection. */
queuedOrigin?: QueuedMessageOrigin;
};

/** A message composed during a run, queued to send after it finishes.
* Attachments ride the queued item (already uploaded at attach time) and are
Expand Down
2 changes: 1 addition & 1 deletion client/src/hooks/Chat/useSteerCancel.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useCallback } from 'react';
import { useSetAtom, useStore } from 'jotai';
import { useRecoilCallback, useRecoilValue } from 'recoil';
import type { PendingSteer } from '~/store/families';
import type { PendingSteer } from '~/hooks/Chat/queue';
import { useComposerRestoreHost } from '~/Providers/ComposerRestoreContext';
import { appendAppliedSteerIds, carriedSteerContext } from '~/utils';
import { pendingSteerCancelClientIdsFamily } from '~/store/steer';
Expand Down
2 changes: 1 addition & 1 deletion client/src/hooks/Chat/useSteerRecovery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useCallback } from 'react';
import { useStore } from 'jotai';
import { useRecoilCallback } from 'recoil';
import type { Snapshot } from 'recoil';
import type { PendingSteer } from '~/store/families';
import type { PendingSteer } from '~/hooks/Chat/queue';
import {
getSteerErrorCode,
isDefiniteSteerRejection,
Expand Down
2 changes: 1 addition & 1 deletion client/src/hooks/Chat/useSteering.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import type {
import type { AgentQueuedTurnReceipt, GenerationProtocolVersion } from '~/data-provider';
import type { QueueSendLock } from '~/utils/queueIntent';
import type { ExtendedFile, FileSetter } from '~/common';
import type { PendingSteer } from '~/store/families';
import type { PendingSteer } from '~/hooks/Chat/queue';
import type { DuringRunAction } from './contract';
import {
useGetStartupConfig,
Expand Down
2 changes: 1 addition & 1 deletion client/src/hooks/SSE/__tests__/useResumableSSE.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
} from 'librechat-data-provider';
import type { TMessage, TSubmission } from 'librechat-data-provider';
import type { Query, QueryKey } from '@tanstack/react-query';
import type { PendingSteer } from '~/store/families';
import type { PendingSteer } from '~/hooks/Chat/queue';
import {
activeUsageResponseIdFamily,
liveTokensFamily,
Expand Down
2 changes: 1 addition & 1 deletion client/src/hooks/SSE/__tests__/useResumeOnLoad.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type { Agents, TMessage, TConversation, TSubmission } from 'librechat-dat
import type { MutableSnapshot } from 'recoil';
import type { ReactNode } from 'react';
import type { QueuedMessage } from '~/hooks/Chat/queue';
import type { PendingSteer } from '~/store/families';
import type { PendingSteer } from '~/hooks/Chat/queue';
import { siblingIdxFamily, siblingKey } from '~/components/Chat/Messages/Thread/state';
import { queuedMessagesByConvoId, resetQueueFamilies } from '~/hooks/Chat/queue';
import { pendingApprovalActionFamily } from '~/components/Chat/approval/state';
Expand Down
2 changes: 1 addition & 1 deletion client/src/hooks/SSE/__tests__/useStepHandler.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import type {
PtcToolCallEvent,
Agents,
} from 'librechat-data-provider';
import type { PtcTrace, PtcTraceEntry } from '~/store/ptc';
import type { PtcTrace, PtcTraceEntry } from '~/common';
import {
subagentProgressByToolCallId,
subagentProgressKey,
Expand Down
2 changes: 1 addition & 1 deletion client/src/hooks/SSE/useResumableSSE.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ import type { DrainAfterAbort, QueuedMessageOrigin } from '~/hooks/Chat/queue';
import type { GenerationProtocolVersion } from '~/data-provider';
import type { EventHandlerParams } from './useEventHandlers';
import type { TResData, TFinalResData } from '~/common';
import type { PendingSteer } from '~/store/families';
import type { PendingSteer } from '~/hooks/Chat/queue';
import {
logger,
clearComposerDrafts,
Expand Down
Loading
Loading