@molecule/app-ide-react 1.1.2 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -1
- package/dist/components/ChatItemBoundary.d.ts +65 -0
- package/dist/components/ChatItemBoundary.d.ts.map +1 -0
- package/dist/components/ChatItemBoundary.js +70 -0
- package/dist/components/ChatItemBoundary.js.map +1 -0
- package/dist/components/ChatPanel.d.ts +3 -1
- package/dist/components/ChatPanel.d.ts.map +1 -1
- package/dist/components/ChatPanel.js +143 -115
- package/dist/components/ChatPanel.js.map +1 -1
- package/dist/components/ToolCallCard.d.ts.map +1 -1
- package/dist/components/ToolCallCard.js +50 -28
- package/dist/components/ToolCallCard.js.map +1 -1
- package/dist/components/chat-models-utilities.d.ts +68 -8
- package/dist/components/chat-models-utilities.d.ts.map +1 -1
- package/dist/components/chat-models-utilities.js +116 -12
- package/dist/components/chat-models-utilities.js.map +1 -1
- package/dist/components/tool-call-utilities.d.ts +49 -0
- package/dist/components/tool-call-utilities.d.ts.map +1 -1
- package/dist/components/tool-call-utilities.js +131 -27
- package/dist/components/tool-call-utilities.js.map +1 -1
- package/dist/types.d.ts +8 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@ AUTO-GENERATED — DO NOT EDIT THIS FILE.
|
|
|
3
3
|
Generated by `mlcl sync-docs` from the package's src/index.ts JSDoc + mlcl/registry.json.
|
|
4
4
|
Edits here are overwritten on the next commit (molecule's pre-commit hook regenerates).
|
|
5
5
|
To change this document, edit the module-level JSDoc in src/index.ts.
|
|
6
|
-
Generated: 2026-08-
|
|
6
|
+
Generated: 2026-08-14T03:10:30.998Z
|
|
7
7
|
-->
|
|
8
8
|
|
|
9
9
|
# @molecule/app-ide-react
|
|
@@ -245,6 +245,13 @@ interface ChatPanelProps {
|
|
|
245
245
|
onCommit?: () => void
|
|
246
246
|
/** Called when an inline activity card is clicked — should open the Activity panel filtered to this activity. */
|
|
247
247
|
onActivityClick?: (activity: ActivityFromCard) => void
|
|
248
|
+
/**
|
|
249
|
+
* Reports a chat timeline item that threw during render, caught by that item's
|
|
250
|
+
* error boundary. The item degrades to an inline notice either way; this is how the
|
|
251
|
+
* host gets the crash into its telemetry instead of it being visible only to the
|
|
252
|
+
* one user who hit it.
|
|
253
|
+
*/
|
|
254
|
+
onRenderError?: (error: Error, info: ErrorInfo) => void
|
|
248
255
|
/**
|
|
249
256
|
* Called when a user avatar in the chat timeline is clicked — the host opens
|
|
250
257
|
* that user's profile (e.g. molecule.dev's profile modal). Receives the clicked
|
|
@@ -1617,6 +1624,7 @@ function ChatPanel({
|
|
|
1617
1624
|
onFileDeleted,
|
|
1618
1625
|
onCommit,
|
|
1619
1626
|
onActivityClick,
|
|
1627
|
+
onRenderError,
|
|
1620
1628
|
onProfileClick,
|
|
1621
1629
|
onReadyToBuild,
|
|
1622
1630
|
awaitingSandboxBoot,
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-item error boundary for the chat timeline.
|
|
3
|
+
*
|
|
4
|
+
* Everything in the chat timeline is built from data an LLM authored — tool-call
|
|
5
|
+
* inputs, tool outputs, card payloads, streamed markdown. None of it is validated
|
|
6
|
+
* by the type system: a tool schema saying `type: 'string'` is a request to a model,
|
|
7
|
+
* not a guarantee, and a value of the wrong shape reaching JSX throws during render.
|
|
8
|
+
*
|
|
9
|
+
* A throw during render unwinds to the nearest boundary. With only an app-level
|
|
10
|
+
* boundary, one malformed option object blanks the entire IDE — the editor, the
|
|
11
|
+
* preview, the file tree and every other message included — at the moment the user
|
|
12
|
+
* submits their first prompt. That is the difference between a cosmetic defect and
|
|
13
|
+
* an outage, and it is decided entirely by where the boundary sits.
|
|
14
|
+
*
|
|
15
|
+
* So each timeline item renders inside its own boundary: a bad item degrades to one
|
|
16
|
+
* inline notice and every sibling keeps working. The item body is invoked from a
|
|
17
|
+
* CHILD component (`RenderSlot`), not from this component's own render, because a
|
|
18
|
+
* boundary cannot catch what it throws itself — that placement is what extends the
|
|
19
|
+
* protection to synchronous throws in the item's own branching, not just to its
|
|
20
|
+
* descendants.
|
|
21
|
+
*
|
|
22
|
+
* @module
|
|
23
|
+
*/
|
|
24
|
+
import type { ErrorInfo, ReactNode } from 'react';
|
|
25
|
+
import { Component } from 'react';
|
|
26
|
+
interface Props {
|
|
27
|
+
/** Produces the timeline item's element tree. Called during render, below the boundary. */
|
|
28
|
+
render: () => ReactNode;
|
|
29
|
+
/** Reports a caught render error (telemetry). Never throws. */
|
|
30
|
+
onError?: (error: Error, info: ErrorInfo) => void;
|
|
31
|
+
}
|
|
32
|
+
interface State {
|
|
33
|
+
failed: boolean;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Error boundary around a single chat timeline item.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```tsx
|
|
40
|
+
* <ChatItemBoundary key={id} render={() => <MessageItem msg={msg} />} />
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export declare class ChatItemBoundary extends Component<Props, State> {
|
|
44
|
+
state: State;
|
|
45
|
+
/**
|
|
46
|
+
* Switches this item to its fallback after a render throw.
|
|
47
|
+
* @returns The failed state.
|
|
48
|
+
*/
|
|
49
|
+
static getDerivedStateFromError(): State;
|
|
50
|
+
/**
|
|
51
|
+
* Reports the caught error so a malformed item is visible in telemetry rather
|
|
52
|
+
* than only to the one user who hit it.
|
|
53
|
+
* @param error - The thrown error.
|
|
54
|
+
* @param info - React's component stack for the throw.
|
|
55
|
+
*/
|
|
56
|
+
componentDidCatch(error: Error, info: ErrorInfo): void;
|
|
57
|
+
/**
|
|
58
|
+
* Renders the timeline item, or its fallback once the item has failed.
|
|
59
|
+
*
|
|
60
|
+
* @returns The item, or an inline notice when rendering it threw.
|
|
61
|
+
*/
|
|
62
|
+
render(): ReactNode;
|
|
63
|
+
}
|
|
64
|
+
export {};
|
|
65
|
+
//# sourceMappingURL=ChatItemBoundary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChatItemBoundary.d.ts","sourceRoot":"","sources":["../../src/components/ChatItemBoundary.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAO,SAAS,EAAE,MAAM,OAAO,CAAA;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAkBjC,UAAU,KAAK;IACb,2FAA2F;IAC3F,MAAM,EAAE,MAAM,SAAS,CAAA;IACvB,+DAA+D;IAC/D,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,KAAK,IAAI,CAAA;CAClD;AAED,UAAU,KAAK;IACb,MAAM,EAAE,OAAO,CAAA;CAChB;AAED;;;;;;;GAOG;AACH,qBAAa,gBAAiB,SAAQ,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC;IAClD,KAAK,EAAE,KAAK,CAAoB;IAEzC;;;OAGG;IACH,MAAM,CAAC,wBAAwB,IAAI,KAAK;IAIxC;;;;;OAKG;IACM,iBAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,GAAG,IAAI;IAe/D;;;;OAIG;IACM,MAAM,IAAI,SAAS;CAiB7B"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Component } from 'react';
|
|
3
|
+
import { t } from '@molecule/app-i18n';
|
|
4
|
+
import { getLogger } from '@molecule/app-logger';
|
|
5
|
+
import { getClassMap } from '@molecule/app-ui';
|
|
6
|
+
/**
|
|
7
|
+
* Invokes the item's render body as a child of the boundary, so a synchronous throw
|
|
8
|
+
* in that body is caught by the boundary above rather than escaping to the app.
|
|
9
|
+
*
|
|
10
|
+
* @param props - Component props.
|
|
11
|
+
* @param props.render - Produces the item's element tree.
|
|
12
|
+
* @returns The rendered item.
|
|
13
|
+
*/
|
|
14
|
+
function RenderSlot({ render }) {
|
|
15
|
+
return _jsx(_Fragment, { children: render() });
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Error boundary around a single chat timeline item.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```tsx
|
|
22
|
+
* <ChatItemBoundary key={id} render={() => <MessageItem msg={msg} />} />
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export class ChatItemBoundary extends Component {
|
|
26
|
+
state = { failed: false };
|
|
27
|
+
/**
|
|
28
|
+
* Switches this item to its fallback after a render throw.
|
|
29
|
+
* @returns The failed state.
|
|
30
|
+
*/
|
|
31
|
+
static getDerivedStateFromError() {
|
|
32
|
+
return { failed: true };
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Reports the caught error so a malformed item is visible in telemetry rather
|
|
36
|
+
* than only to the one user who hit it.
|
|
37
|
+
* @param error - The thrown error.
|
|
38
|
+
* @param info - React's component stack for the throw.
|
|
39
|
+
*/
|
|
40
|
+
componentDidCatch(error, info) {
|
|
41
|
+
// Log unconditionally: a host that wires no reporter must still leave a trace,
|
|
42
|
+
// or a contained failure becomes an invisible one.
|
|
43
|
+
getLogger().error('Chat timeline item failed to render', {
|
|
44
|
+
error,
|
|
45
|
+
componentStack: info.componentStack,
|
|
46
|
+
});
|
|
47
|
+
try {
|
|
48
|
+
this.props.onError?.(error, info);
|
|
49
|
+
}
|
|
50
|
+
catch (_error) {
|
|
51
|
+
// A failing error reporter must never escalate into a second render throw —
|
|
52
|
+
// the whole point of this boundary is that nothing here can take the app down.
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Renders the timeline item, or its fallback once the item has failed.
|
|
57
|
+
*
|
|
58
|
+
* @returns The item, or an inline notice when rendering it threw.
|
|
59
|
+
*/
|
|
60
|
+
render() {
|
|
61
|
+
if (this.state.failed) {
|
|
62
|
+
const cm = getClassMap();
|
|
63
|
+
return (_jsx("div", { "data-mol-id": "chat-item-render-error", className: cm.cn(cm.textSize('xs'), cm.textMuted), style: { padding: '6px 12px', fontStyle: 'italic' }, children: t('ide.chat.itemRenderError', undefined, {
|
|
64
|
+
defaultValue: "This message couldn't be displayed.",
|
|
65
|
+
}) }));
|
|
66
|
+
}
|
|
67
|
+
return _jsx(RenderSlot, { render: this.props.render });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=ChatItemBoundary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChatItemBoundary.js","sourceRoot":"","sources":["../../src/components/ChatItemBoundary.tsx"],"names":[],"mappings":";AAyBA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEjC,OAAO,EAAE,CAAC,EAAE,MAAM,oBAAoB,CAAA;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAE9C;;;;;;;GAOG;AACH,SAAS,UAAU,CAAC,EAAE,MAAM,EAA+B;IACzD,OAAO,4BAAG,MAAM,EAAE,GAAI,CAAA;AACxB,CAAC;AAaD;;;;;;;GAOG;AACH,MAAM,OAAO,gBAAiB,SAAQ,SAAuB;IAClD,KAAK,GAAU,EAAE,MAAM,EAAE,KAAK,EAAE,CAAA;IAEzC;;;OAGG;IACH,MAAM,CAAC,wBAAwB;QAC7B,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAA;IACzB,CAAC;IAED;;;;;OAKG;IACM,iBAAiB,CAAC,KAAY,EAAE,IAAe;QACtD,+EAA+E;QAC/E,mDAAmD;QACnD,SAAS,EAAE,CAAC,KAAK,CAAC,qCAAqC,EAAE;YACvD,KAAK;YACL,cAAc,EAAE,IAAI,CAAC,cAAc;SACpC,CAAC,CAAA;QACF,IAAI,CAAC;YACH,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;QACnC,CAAC;QAAC,OAAO,MAAM,EAAE,CAAC;YAChB,4EAA4E;YAC5E,+EAA+E;QACjF,CAAC;IACH,CAAC;IAED;;;;OAIG;IACM,MAAM;QACb,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;YACtB,MAAM,EAAE,GAAG,WAAW,EAAE,CAAA;YACxB,OAAO,CACL,6BACc,wBAAwB,EACpC,SAAS,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,EACjD,KAAK,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,YAElD,CAAC,CAAC,0BAA0B,EAAE,SAAS,EAAE;oBACxC,YAAY,EAAE,qCAAqC;iBACpD,CAAC,GACE,CACP,CAAA;QACH,CAAC;QACD,OAAO,KAAC,UAAU,IAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAI,CAAA;IAClD,CAAC;CACF"}
|
|
@@ -120,6 +120,8 @@ export interface ChatInnerProps {
|
|
|
120
120
|
onConversationId?: (id: string) => void;
|
|
121
121
|
/** Called when an inline activity card is clicked — should open the Activity panel filtered to this activity. */
|
|
122
122
|
onActivityClick?: (activity: Activity) => void;
|
|
123
|
+
/** See {@link ChatPanelProps.onRenderError}. */
|
|
124
|
+
onRenderError?: ChatPanelProps['onRenderError'];
|
|
123
125
|
/** Called when a user avatar in the chat timeline is clicked — see {@link ChatPanelProps.onProfileClick}. */
|
|
124
126
|
onProfileClick?: ChatPanelProps['onProfileClick'];
|
|
125
127
|
/** Called on the `ready_to_build` stream event — discovery is done; boot the sandbox. */
|
|
@@ -176,7 +178,7 @@ export interface ChatInnerProps {
|
|
|
176
178
|
* @param props - Component props (see {@link MessageItemProps}).
|
|
177
179
|
* @returns The rendered chat panel element.
|
|
178
180
|
*/
|
|
179
|
-
export declare function ChatPanel({ projectId, endpoint, initialMessage, onInitialMessageSent, activeFile, openTabs, onFileOpen, onFileDoubleClick, onFileDiff, onFileRevert, onFileChange, onFileDeleted, onCommit, onActivityClick, onProfileClick, onReadyToBuild, awaitingSandboxBoot, onClientAction, onTurnComplete, onLoadingChange, onNavigatePreview, onRegisterPushHandler, autoSubmitSignal, initialInputValue, hideConversationMenu, renderConversationHeader, conversationId: controlledConversationId, chatKey: controlledChatKey, onConversationId: controlledOnConversationId, openShareSignal: controlledShareSignal, openReportSignal: controlledReportSignal, openSettingsSignal: controlledSettingsSignal, onManageCustomModels, gitStatusTick, pendingMessage, pendingMessageKey, pendingMessageSuppressUser, pendingMessageUserInitiated, userEditedFile, userEditedFileKey, isPro, buildUpgradeCta, buildHelpUpgradeSection, userAvatar, agentName, productName, version, feedbackUrl, className, }: ChatPanelProps): JSX.Element;
|
|
181
|
+
export declare function ChatPanel({ projectId, endpoint, initialMessage, onInitialMessageSent, activeFile, openTabs, onFileOpen, onFileDoubleClick, onFileDiff, onFileRevert, onFileChange, onFileDeleted, onCommit, onActivityClick, onRenderError, onProfileClick, onReadyToBuild, awaitingSandboxBoot, onClientAction, onTurnComplete, onLoadingChange, onNavigatePreview, onRegisterPushHandler, autoSubmitSignal, initialInputValue, hideConversationMenu, renderConversationHeader, conversationId: controlledConversationId, chatKey: controlledChatKey, onConversationId: controlledOnConversationId, openShareSignal: controlledShareSignal, openReportSignal: controlledReportSignal, openSettingsSignal: controlledSettingsSignal, onManageCustomModels, gitStatusTick, pendingMessage, pendingMessageKey, pendingMessageSuppressUser, pendingMessageUserInitiated, userEditedFile, userEditedFileKey, isPro, buildUpgradeCta, buildHelpUpgradeSection, userAvatar, agentName, productName, version, feedbackUrl, className, }: ChatPanelProps): JSX.Element;
|
|
180
182
|
export declare namespace ChatPanel {
|
|
181
183
|
var displayName: string;
|
|
182
184
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatPanel.d.ts","sourceRoot":"","sources":["../../src/components/ChatPanel.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAa,MAAM,OAAO,CAAA;AAY3C,OAAO,KAAK,EAAa,WAAW,EAAmB,MAAM,uBAAuB,CAAA;
|
|
1
|
+
{"version":3,"file":"ChatPanel.d.ts","sourceRoot":"","sources":["../../src/components/ChatPanel.tsx"],"names":[],"mappings":"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"}
|
|
@@ -22,7 +22,7 @@ import { cachedPromptTokens, formatTokenTotal } from './chat-cost-utilities.js';
|
|
|
22
22
|
import { effortOptionsForModel, nativeEffortName, parseEffortCommand, resolveEffortArg, } from './chat-effort-utilities.js';
|
|
23
23
|
import { buildHelpText } from './chat-help-utilities.js';
|
|
24
24
|
import { effectiveModeModelId, freeTierLockReason, freeTierUsableMode, isModeModelLocked, modeSettingKey, parseModelModeCommand, resolveModeModel, } from './chat-model-mode-utilities.js';
|
|
25
|
-
import { modelUsageRate, sortModels } from './chat-models-utilities.js';
|
|
25
|
+
import { modelHasPeakPricing, modelPeakMultiplier, modelPeakWindowLabels, modelUsageRate, sortModels, } from './chat-models-utilities.js';
|
|
26
26
|
import { formatReportConfirmation, parseReportCommand } from './chat-report-utilities.js';
|
|
27
27
|
import { findScriptByName, formatRunOutput, parseRunCommand, parseScriptsCommand, runSucceeded, } from './chat-scripts-utilities.js';
|
|
28
28
|
import { buildSettingsList, summarizeSounds } from './chat-settings-utilities.js';
|
|
@@ -30,6 +30,7 @@ import { buildShareUrl, DEFAULT_SHARE_ROLE, parseShareCommand, SHARE_ROLES, } fr
|
|
|
30
30
|
import { buildNewSkillTemplate, loadProjectSkills, newSkillPath, parseSkillMeta, pickRelevantSkill, recentUserText, } from './chat-skills-utilities.js';
|
|
31
31
|
import { estimateTurnTokens } from './chat-stream-utilities.js';
|
|
32
32
|
import { ENTRY_TIP, pickIdleTip, shouldShowIdleTip, TIP_IDLE_MS, TIP_MIN_MESSAGES, } from './chat-tips-utilities.js';
|
|
33
|
+
import { ChatItemBoundary } from './ChatItemBoundary.js';
|
|
33
34
|
import { HelpCard } from './HelpCard.js';
|
|
34
35
|
import { Icon } from './Icon.js';
|
|
35
36
|
import { MarkdownContent } from './MarkdownContent.js';
|
|
@@ -1245,7 +1246,7 @@ const MessageItem = memo(function MessageItem(props) {
|
|
|
1245
1246
|
* @param props - Component props (see {@link MessageItemProps}).
|
|
1246
1247
|
* @returns The rendered chat inner component.
|
|
1247
1248
|
*/
|
|
1248
|
-
function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent, isPro, buildUpgradeCta, buildHelpUpgradeSection, activeFile, openTabs, onFileOpen, onFileDoubleClick, onFileDiff, onFileRevert, onFileChange, onFileDeleted, onCommit, onConversationId, onActivityClick, onProfileClick, onReadyToBuild, awaitingSandboxBoot, onClientAction, onTurnComplete, onLoadingChange, onNavigatePreview, onRegisterPushHandler, autoSubmitSignal, openSettingsSignal, onManageCustomModels, openReportSignal, openShareSignal, initialInputValue, pendingMessage, pendingMessageKey, pendingMessageSuppressUser, pendingMessageUserInitiated, userEditedFile, userEditedFileKey, gitStatusTick: externalGitStatusTick, discovery, userAvatar, agentName = DEFAULT_AGENT_NAME, productName = DEFAULT_PRODUCT_NAME, version,
|
|
1249
|
+
function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent, isPro, buildUpgradeCta, buildHelpUpgradeSection, activeFile, openTabs, onFileOpen, onFileDoubleClick, onFileDiff, onFileRevert, onFileChange, onFileDeleted, onCommit, onConversationId, onActivityClick, onRenderError, onProfileClick, onReadyToBuild, awaitingSandboxBoot, onClientAction, onTurnComplete, onLoadingChange, onNavigatePreview, onRegisterPushHandler, autoSubmitSignal, openSettingsSignal, onManageCustomModels, openReportSignal, openShareSignal, initialInputValue, pendingMessage, pendingMessageKey, pendingMessageSuppressUser, pendingMessageUserInitiated, userEditedFile, userEditedFileKey, gitStatusTick: externalGitStatusTick, discovery, userAvatar, agentName = DEFAULT_AGENT_NAME, productName = DEFAULT_PRODUCT_NAME, version,
|
|
1249
1250
|
// feedbackUrl: prop kept for back-compat (callers still pass it), but no longer
|
|
1250
1251
|
// consumed here — its only use was the command-menu footer link removed in P3-21.
|
|
1251
1252
|
}) {
|
|
@@ -4690,7 +4691,22 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
|
|
|
4690
4691
|
case 'custom': {
|
|
4691
4692
|
// App-registered renderer (registerCustomEventCard) builds the copy/actions/tone
|
|
4692
4693
|
// from the raw data — keeping app-specific text out of this shared package.
|
|
4693
|
-
|
|
4694
|
+
//
|
|
4695
|
+
// This runs in a memo ABOVE the timeline's per-item boundaries, so a factory
|
|
4696
|
+
// that throws would take the whole panel down rather than one card — and the
|
|
4697
|
+
// factory is host code reading model-authored `data`, exactly the combination
|
|
4698
|
+
// that caused the 2026-08-14 outage. One unrenderable card must cost one card.
|
|
4699
|
+
let card;
|
|
4700
|
+
try {
|
|
4701
|
+
card = getCustomEventCardFactory(cardEvent.name)?.(cardEvent.data);
|
|
4702
|
+
}
|
|
4703
|
+
catch (error) {
|
|
4704
|
+
logger.error('Custom chat card factory threw — dropping the card', {
|
|
4705
|
+
error,
|
|
4706
|
+
name: cardEvent.name,
|
|
4707
|
+
});
|
|
4708
|
+
return null;
|
|
4709
|
+
}
|
|
4694
4710
|
if (!card)
|
|
4695
4711
|
return null;
|
|
4696
4712
|
return {
|
|
@@ -4849,117 +4865,117 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
|
|
|
4849
4865
|
opacity: 0.7,
|
|
4850
4866
|
}, children: t('ide.chat.showEarlier', undefined, {
|
|
4851
4867
|
defaultValue: 'Show earlier messages',
|
|
4852
|
-
}) }) })), (timeline.length > maxVisibleItems ? timeline.slice(-maxVisibleItems) : timeline).map((item) => {
|
|
4853
|
-
|
|
4854
|
-
|
|
4855
|
-
|
|
4856
|
-
|
|
4857
|
-
|
|
4858
|
-
|
|
4859
|
-
|
|
4860
|
-
|
|
4861
|
-
|
|
4862
|
-
|
|
4863
|
-
|
|
4864
|
-
|
|
4865
|
-
|
|
4866
|
-
|
|
4867
|
-
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
|
|
4874
|
-
|
|
4875
|
-
|
|
4876
|
-
|
|
4877
|
-
|
|
4878
|
-
|
|
4879
|
-
|
|
4880
|
-
|
|
4881
|
-
|
|
4882
|
-
|
|
4883
|
-
|
|
4884
|
-
|
|
4885
|
-
|
|
4886
|
-
|
|
4887
|
-
|
|
4888
|
-
|
|
4889
|
-
|
|
4890
|
-
|
|
4891
|
-
|
|
4892
|
-
|
|
4893
|
-
|
|
4894
|
-
|
|
4895
|
-
|
|
4896
|
-
|
|
4897
|
-
|
|
4898
|
-
|
|
4899
|
-
|
|
4900
|
-
|
|
4901
|
-
|
|
4902
|
-
|
|
4903
|
-
|
|
4904
|
-
|
|
4905
|
-
|
|
4906
|
-
|
|
4907
|
-
|
|
4908
|
-
|
|
4909
|
-
|
|
4868
|
+
}) }) })), (timeline.length > maxVisibleItems ? timeline.slice(-maxVisibleItems) : timeline).map((item) => (_jsx(ChatItemBoundary, { onError: onRenderError, render: () => {
|
|
4869
|
+
if (item.kind === 'commit')
|
|
4870
|
+
return (_jsx(CommitCardItem, { card: item.card, onRevert: handleRevertCommit }, item.card.id));
|
|
4871
|
+
if (item.kind === 'activity')
|
|
4872
|
+
return (_jsx(ActivityCard, { activity: item.card.activity, onActivityClick: onActivityClick }, item.card.id));
|
|
4873
|
+
if (item.kind === 'tip')
|
|
4874
|
+
return (_jsx(TipCard, { text: item.card.text, onDismiss: () => dismissTip(item.card.id) }, item.card.id));
|
|
4875
|
+
if (item.kind === 'system') {
|
|
4876
|
+
if (item.card.variant === 'settings') {
|
|
4877
|
+
// Legacy inline branch — kept so any 'settings' card persisted
|
|
4878
|
+
// before /settings became an overlay still renders. New /settings
|
|
4879
|
+
// invocations open the closeable overlay (see panelOverlay below).
|
|
4880
|
+
return (_jsx(SettingsCard, { settings: computeSettingsList(), onRunCommand: (commandId) => void executeCommand(commandId), onPrefillInput: (input) => setInputAndCursorEnd(`${input} `), isLight: isLight, agentName: agentName }, item.card.id));
|
|
4881
|
+
}
|
|
4882
|
+
if (item.card.variant === 'skills' || item.card.variant === 'skillsCreate') {
|
|
4883
|
+
return (_jsx(SkillsCard, { projectId: projectId, initialQuery: item.card.query ?? '', onLoad: loadSkill, onCreate: createSkill,
|
|
4884
|
+
// The 'skillsCreate' variant opens the card with its "New skill" form
|
|
4885
|
+
// already open (vs plain 'skills', which opens the browser).
|
|
4886
|
+
startCreating: item.card.variant === 'skillsCreate', loadedSkillPaths: loadedSkillPaths, defaultSkillPaths: defaultSkillPaths, onToggleDefault: toggleDefaultSkill, onResetDefault: resetDefaultSkills, defaultsExplicit: defaultSkillsExplicitRef.current, isLight: isLight }, item.card.id));
|
|
4887
|
+
}
|
|
4888
|
+
if (item.card.variant === 'scripts') {
|
|
4889
|
+
return (_jsx(ScriptsCard, { projectId: projectId, initialQuery: item.card.query ?? '', isLight: isLight, agentName: agentName }, item.card.id));
|
|
4890
|
+
}
|
|
4891
|
+
if (item.card.variant === 'help') {
|
|
4892
|
+
// The plan/upgrade blurb is app-specific (pricing, plan names), so the
|
|
4893
|
+
// host supplies it via buildHelpUpgradeSection — this shared package
|
|
4894
|
+
// hardcodes none. Read at render time (like the settings card's list).
|
|
4895
|
+
const upgradeSection = buildHelpUpgradeSection?.();
|
|
4896
|
+
return (_jsx(HelpCard, { isLight: isLight, agentName: agentName, productName: productName, upgradeLines: upgradeSection?.lines, upgradeAction: upgradeSection?.action ?? undefined }, item.card.id));
|
|
4897
|
+
}
|
|
4898
|
+
if (item.card.variant === 'skillsLoaded') {
|
|
4899
|
+
// "🧠 Loaded {{count}} skills" — styled like the plain "🔨 Building your
|
|
4900
|
+
// app" phase notice (centered, muted, xs, emoji baked into the text), but
|
|
4901
|
+
// CLICKABLE: its onClick is created HERE at render time — opening the
|
|
4902
|
+
// /skills browser overlay, exactly what typing /skills does — so it
|
|
4903
|
+
// survives the persistence round-trip (which stores only variant + count +
|
|
4904
|
+
// text, never callbacks). Text restores from the persisted copy; re-derive
|
|
4905
|
+
// from `count` if a caller passed none.
|
|
4906
|
+
const skillsLoadedLabel = item.card.text ||
|
|
4907
|
+
t('ide.chat.skills.loadedCount', { count: item.card.count ?? 0 }, { defaultValue: '🧠 Loaded {{count}} skills' });
|
|
4908
|
+
return (_jsx("div", { style: { textAlign: 'center', marginBottom: TIMELINE_ITEM_GAP }, children: _jsx("button", { type: "button", "data-mol-id": "chat-skills-loaded", onClick: () => openPanelOverlay('skills'), className: cm.cn(cm.textSize('xs'), cm.textMuted), style: {
|
|
4909
|
+
// Plain text like the build-phase notice — no border/fill/pill.
|
|
4910
|
+
background: 'none',
|
|
4911
|
+
border: 'none',
|
|
4912
|
+
margin: 0,
|
|
4913
|
+
padding: '6px 0',
|
|
4914
|
+
fontFamily: 'inherit',
|
|
4915
|
+
cursor: 'pointer',
|
|
4916
|
+
},
|
|
4917
|
+
// Underline on hover is the only clickability hint (it otherwise
|
|
4918
|
+
// reads exactly like the plain phase message).
|
|
4919
|
+
onMouseEnter: (e) => {
|
|
4920
|
+
;
|
|
4921
|
+
e.currentTarget.style.textDecoration = 'underline';
|
|
4922
|
+
}, onMouseLeave: (e) => {
|
|
4923
|
+
;
|
|
4924
|
+
e.currentTarget.style.textDecoration = 'none';
|
|
4925
|
+
}, children: skillsLoadedLabel }) }, item.card.id));
|
|
4926
|
+
}
|
|
4927
|
+
// Every rich variant is handled above; what remains is the plain notice /
|
|
4928
|
+
// tip card (no variant). Narrow to PlainSystemCard so the compiler knows
|
|
4929
|
+
// tone/content/emphasized exist here — and render nothing for any future
|
|
4930
|
+
// unhandled variant rather than mis-rendering it as a plain card.
|
|
4931
|
+
if (item.card.variant !== undefined)
|
|
4932
|
+
return null;
|
|
4933
|
+
// ── Unified tip / notice card ────────────────────────────────────────────
|
|
4934
|
+
// EVERY host notice (upgrade, sign-up, model-intro, pre-alpha, saved-script,
|
|
4935
|
+
// build-degraded) renders through ONE structure so they look consistent: an
|
|
4936
|
+
// icon, a tinted body with a uniform 1px border, and — for action cards — a row
|
|
4937
|
+
// of accent buttons. Only the ACCENT COLOUR + ICON change, by `tone`. Picking a
|
|
4938
|
+
// tone (or `emphasized`, or merely having an action) opts a card in; a card with
|
|
4939
|
+
// none of those stays a plain muted inline line (e.g. a "Now using <model>"
|
|
4940
|
+
// notice). `emphasized` without a tone → the neutral `info` tone.
|
|
4941
|
+
const tipTone = item.card.tone ?? (item.card.emphasized || item.card.action ? 'info' : null);
|
|
4942
|
+
if (tipTone) {
|
|
4943
|
+
// ONE shared treatment for every tone-accented notice — see NoticeCard.
|
|
4944
|
+
// The resource-limit / upgrade banner renders through the same component,
|
|
4945
|
+
// so their icon + buttons stay in lockstep.
|
|
4946
|
+
return (_jsx(NoticeCard, { tone: tipTone, text: item.card.text, content: item.card.content, action: item.card.action, icon: item.card.icon }, item.card.id));
|
|
4947
|
+
}
|
|
4948
|
+
// Plain muted inline notice (no tone / not emphasized / no action) — e.g. a
|
|
4949
|
+
// "Now using <model>" line. Centered for one-liners; left-aligned mono for
|
|
4950
|
+
// multi-line.
|
|
4951
|
+
const isMultiLine = item.card.text.includes('\n');
|
|
4952
|
+
return (_jsx("div", { className: cm.cn(cm.textSize('xs'), cm.textMuted), style: {
|
|
4953
|
+
textAlign: isMultiLine ? 'left' : 'center',
|
|
4954
|
+
padding: isMultiLine ? '8px 12px' : '6px 0',
|
|
4955
|
+
marginBottom: TIMELINE_ITEM_GAP,
|
|
4956
|
+
whiteSpace: isMultiLine ? 'pre-wrap' : undefined,
|
|
4957
|
+
fontFamily: isMultiLine ? 'var(--mol-font-mono, monospace)' : undefined,
|
|
4958
|
+
lineHeight: isMultiLine ? 1.5 : undefined,
|
|
4959
|
+
}, children: item.card.content
|
|
4960
|
+
? item.card.content.map((seg, i) => renderCardSegment(seg, i))
|
|
4961
|
+
: item.card.text }, item.card.id));
|
|
4910
4962
|
}
|
|
4911
|
-
|
|
4912
|
-
//
|
|
4913
|
-
|
|
4914
|
-
|
|
4915
|
-
|
|
4916
|
-
return
|
|
4917
|
-
|
|
4918
|
-
|
|
4919
|
-
|
|
4920
|
-
|
|
4921
|
-
|
|
4922
|
-
|
|
4923
|
-
|
|
4924
|
-
// notice). `emphasized` without a tone → the neutral `info` tone.
|
|
4925
|
-
const tipTone = item.card.tone ?? (item.card.emphasized || item.card.action ? 'info' : null);
|
|
4926
|
-
if (tipTone) {
|
|
4927
|
-
// ONE shared treatment for every tone-accented notice — see NoticeCard.
|
|
4928
|
-
// The resource-limit / upgrade banner renders through the same component,
|
|
4929
|
-
// so their icon + buttons stay in lockstep.
|
|
4930
|
-
return (_jsx(NoticeCard, { tone: tipTone, text: item.card.text, content: item.card.content, action: item.card.action, icon: item.card.icon }, item.card.id));
|
|
4963
|
+
const { msg } = item;
|
|
4964
|
+
// Persisted commit records render as commit cards
|
|
4965
|
+
if (msg.commitRecord) {
|
|
4966
|
+
const files = msg.commitRecord.files.map((f) => typeof f === 'string' ? f : f.path);
|
|
4967
|
+
const hash = msg.commitRecord.hash;
|
|
4968
|
+
return (_jsx(CommitCardItem, { card: {
|
|
4969
|
+
id: msg.id,
|
|
4970
|
+
message: msg.commitRecord.message,
|
|
4971
|
+
files,
|
|
4972
|
+
timestamp: msg.timestamp,
|
|
4973
|
+
status: 'done',
|
|
4974
|
+
hash,
|
|
4975
|
+
}, onRevert: handleRevertCommit }, msg.id));
|
|
4931
4976
|
}
|
|
4932
|
-
|
|
4933
|
-
|
|
4934
|
-
// multi-line.
|
|
4935
|
-
const isMultiLine = item.card.text.includes('\n');
|
|
4936
|
-
return (_jsx("div", { className: cm.cn(cm.textSize('xs'), cm.textMuted), style: {
|
|
4937
|
-
textAlign: isMultiLine ? 'left' : 'center',
|
|
4938
|
-
padding: isMultiLine ? '8px 12px' : '6px 0',
|
|
4939
|
-
marginBottom: TIMELINE_ITEM_GAP,
|
|
4940
|
-
whiteSpace: isMultiLine ? 'pre-wrap' : undefined,
|
|
4941
|
-
fontFamily: isMultiLine ? 'var(--mol-font-mono, monospace)' : undefined,
|
|
4942
|
-
lineHeight: isMultiLine ? 1.5 : undefined,
|
|
4943
|
-
}, children: item.card.content
|
|
4944
|
-
? item.card.content.map((seg, i) => renderCardSegment(seg, i))
|
|
4945
|
-
: item.card.text }, item.card.id));
|
|
4946
|
-
}
|
|
4947
|
-
const { msg } = item;
|
|
4948
|
-
// Persisted commit records render as commit cards
|
|
4949
|
-
if (msg.commitRecord) {
|
|
4950
|
-
const files = msg.commitRecord.files.map((f) => typeof f === 'string' ? f : f.path);
|
|
4951
|
-
const hash = msg.commitRecord.hash;
|
|
4952
|
-
return (_jsx(CommitCardItem, { card: {
|
|
4953
|
-
id: msg.id,
|
|
4954
|
-
message: msg.commitRecord.message,
|
|
4955
|
-
files,
|
|
4956
|
-
timestamp: msg.timestamp,
|
|
4957
|
-
status: 'done',
|
|
4958
|
-
hash,
|
|
4959
|
-
}, onRevert: handleRevertCommit }, msg.id));
|
|
4960
|
-
}
|
|
4961
|
-
return (_jsx(MessageItem, { msg: msg, editingQueuedId: editingQueuedId, editingQueuedText: editingQueuedText, setEditingQueuedId: setEditingQueuedId, setEditingQueuedText: setEditingQueuedText, editQueuedMessage: editQueuedMessage, deleteQueuedMessage: deleteQueuedMessage, sendMessage: sendMessage, handleAskUserResponse: handleAskUserResponse, isLoading: isLoading, streamingStatus: streamingStatus, onNavigatePreview: onNavigatePreview, undoneTcIds: undoneTcIds, handleUndoToggle: handleUndoToggle, onFileOpen: onFileOpen, onFileDoubleClick: onFileDoubleClick, onFileDiff: onFileDiff, handleFileRevert: handleFileRevert, setInputAndCursorEnd: setInputAndCursorEnd, setModelPicker: setModelPicker, userAvatar: userAvatar, onAvatarClick: onUserAvatarClick, discovery: discovery, buildUpgradeCta: buildUpgradeCta }, msg.id));
|
|
4962
|
-
}), error &&
|
|
4977
|
+
return (_jsx(MessageItem, { msg: msg, editingQueuedId: editingQueuedId, editingQueuedText: editingQueuedText, setEditingQueuedId: setEditingQueuedId, setEditingQueuedText: setEditingQueuedText, editQueuedMessage: editQueuedMessage, deleteQueuedMessage: deleteQueuedMessage, sendMessage: sendMessage, handleAskUserResponse: handleAskUserResponse, isLoading: isLoading, streamingStatus: streamingStatus, onNavigatePreview: onNavigatePreview, undoneTcIds: undoneTcIds, handleUndoToggle: handleUndoToggle, onFileOpen: onFileOpen, onFileDoubleClick: onFileDoubleClick, onFileDiff: onFileDiff, handleFileRevert: handleFileRevert, setInputAndCursorEnd: setInputAndCursorEnd, setModelPicker: setModelPicker, userAvatar: userAvatar, onAvatarClick: onUserAvatarClick, discovery: discovery, buildUpgradeCta: buildUpgradeCta }, msg.id));
|
|
4978
|
+
} }, item.kind === 'message' ? item.msg.id : item.card.id))), error &&
|
|
4963
4979
|
(errorMeta?.limitType ? (_jsx(ResourceLimitBanner, { message: error, action: buildUpgradeCta?.({ requiresSignup: errorMeta.requiresSignup }) })) : (_jsx("div", { className: cm.cn(cm.textSize('sm'), cm.sp('p', 2), cm.sp('mb', 2), cm.bgErrorSubtle, cm.textError), style: { borderRadius: '6px' }, children: error }))), (() => {
|
|
4964
4980
|
const showActivity = isLoading || awaitingSandboxBoot;
|
|
4965
4981
|
const streamingMsg = isLoading
|
|
@@ -5479,6 +5495,8 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
|
|
|
5479
5495
|
// region immediately re-rates the row (e.g. DeepSeek V4
|
|
5480
5496
|
// Pro: ×3 native-CN vs ×9 US-rehosted).
|
|
5481
5497
|
const usageRate = modelUsageRate(model, AVAILABLE_MODELS, modelRegion);
|
|
5498
|
+
// Whether the rate above is currently inflated by a peak window.
|
|
5499
|
+
const peakNow = modelPeakMultiplier(model, modelRegion);
|
|
5482
5500
|
const priceColor = usageRate <= 5
|
|
5483
5501
|
? isLight
|
|
5484
5502
|
? 'rgb(22,163,74)'
|
|
@@ -5601,7 +5619,17 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
|
|
|
5601
5619
|
defaultValue: 'your key',
|
|
5602
5620
|
}) })) : (_jsx("span", { style: { color: priceColor }, title: t('ide.chat.models.usageRateHint', undefined, {
|
|
5603
5621
|
defaultValue: 'How fast this model uses your AI allowance, relative to the most economical model',
|
|
5604
|
-
}), children: t('ide.chat.models.usageRateValue', { rate: usageRate }, { defaultValue: '×{{rate}} usage' }) })), model
|
|
5622
|
+
}), children: t('ide.chat.models.usageRateValue', { rate: usageRate }, { defaultValue: '×{{rate}} usage' }) })), !isCustom && modelHasPeakPricing(model, modelRegion) && (_jsxs(_Fragment, { children: [' · ', _jsx("span", { style: {
|
|
5623
|
+
color: peakNow > 1 ? priceColor : undefined,
|
|
5624
|
+
opacity: peakNow > 1 ? 1 : 0.8,
|
|
5625
|
+
}, title: t('ide.chat.models.peakHint', {
|
|
5626
|
+
multiplier: model.peakPricing?.multiplier ?? 2,
|
|
5627
|
+
windows: modelPeakWindowLabels(model).join(', '),
|
|
5628
|
+
}, {
|
|
5629
|
+
defaultValue: 'This model costs ×{{multiplier}} between {{windows}}. It is the normal rate the rest of the day.',
|
|
5630
|
+
}), children: peakNow > 1
|
|
5631
|
+
? t('ide.chat.models.peakNow', { multiplier: model.peakPricing?.multiplier ?? 2 }, { defaultValue: 'peak ×{{multiplier}} now' })
|
|
5632
|
+
: t('ide.chat.models.peakLater', { multiplier: model.peakPricing?.multiplier ?? 2 }, { defaultValue: '×{{multiplier}} at peak hours' }) })] })), model.knowledgeCutoff ? _jsxs(_Fragment, { children: [" \u00B7 ", model.knowledgeCutoff] }) : null] }), (badges.length > 0 || showRegionPill) && (_jsxs("span", { style: {
|
|
5605
5633
|
display: 'flex',
|
|
5606
5634
|
gap: '4px',
|
|
5607
5635
|
flexWrap: 'wrap',
|
|
@@ -6550,7 +6578,7 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
|
|
|
6550
6578
|
* @param props - Component props (see {@link MessageItemProps}).
|
|
6551
6579
|
* @returns The rendered chat panel element.
|
|
6552
6580
|
*/
|
|
6553
|
-
export function ChatPanel({ projectId, endpoint, initialMessage, onInitialMessageSent, activeFile, openTabs, onFileOpen, onFileDoubleClick, onFileDiff, onFileRevert, onFileChange, onFileDeleted, onCommit, onActivityClick, onProfileClick, onReadyToBuild, awaitingSandboxBoot, onClientAction, onTurnComplete, onLoadingChange, onNavigatePreview, onRegisterPushHandler, autoSubmitSignal, initialInputValue, hideConversationMenu, renderConversationHeader = true, conversationId: controlledConversationId, chatKey: controlledChatKey, onConversationId: controlledOnConversationId, openShareSignal: controlledShareSignal, openReportSignal: controlledReportSignal, openSettingsSignal: controlledSettingsSignal, onManageCustomModels, gitStatusTick, pendingMessage, pendingMessageKey, pendingMessageSuppressUser, pendingMessageUserInitiated, userEditedFile, userEditedFileKey, isPro, buildUpgradeCta, buildHelpUpgradeSection, userAvatar, agentName, productName, version, feedbackUrl, className, }) {
|
|
6581
|
+
export function ChatPanel({ projectId, endpoint, initialMessage, onInitialMessageSent, activeFile, openTabs, onFileOpen, onFileDoubleClick, onFileDiff, onFileRevert, onFileChange, onFileDeleted, onCommit, onActivityClick, onRenderError, onProfileClick, onReadyToBuild, awaitingSandboxBoot, onClientAction, onTurnComplete, onLoadingChange, onNavigatePreview, onRegisterPushHandler, autoSubmitSignal, initialInputValue, hideConversationMenu, renderConversationHeader = true, conversationId: controlledConversationId, chatKey: controlledChatKey, onConversationId: controlledOnConversationId, openShareSignal: controlledShareSignal, openReportSignal: controlledReportSignal, openSettingsSignal: controlledSettingsSignal, onManageCustomModels, gitStatusTick, pendingMessage, pendingMessageKey, pendingMessageSuppressUser, pendingMessageUserInitiated, userEditedFile, userEditedFileKey, isPro, buildUpgradeCta, buildHelpUpgradeSection, userAvatar, agentName, productName, version, feedbackUrl, className, }) {
|
|
6554
6582
|
const cm = getClassMap();
|
|
6555
6583
|
const isNarrow = useNarrowViewport();
|
|
6556
6584
|
const isCoarse = useCoarsePointer();
|
|
@@ -6759,7 +6787,7 @@ export function ChatPanel({ projectId, endpoint, initialMessage, onInitialMessag
|
|
|
6759
6787
|
textOverflow: 'ellipsis',
|
|
6760
6788
|
whiteSpace: 'nowrap',
|
|
6761
6789
|
width: '100%',
|
|
6762
|
-
}, children: conv.preview ?? 'New conversation' }), _jsx("span", { className: cm.cn(cm.textMuted, cm.textSize('xs')), style: { opacity: 0.55 }, children: relativeTime(conv.updatedAt) })] }, conv.id)))] }))] })), _jsx(ChatInner, { projectId: projectId, endpoint: chatEndpoint, initialMessage: initialMessage, onInitialMessageSent: onInitialMessageSent, isPro: isPro, buildUpgradeCta: buildUpgradeCta, buildHelpUpgradeSection: buildHelpUpgradeSection, activeFile: activeFile, openTabs: openTabs, onFileOpen: onFileOpen, onFileDoubleClick: onFileDoubleClick, onFileDiff: onFileDiff, onFileRevert: onFileRevert, onFileChange: onFileChange, onFileDeleted: onFileDeleted, onCommit: onCommit, onConversationId: reportConversationId, onActivityClick: onActivityClick, onProfileClick: onProfileClick, onReadyToBuild: onReadyToBuild, awaitingSandboxBoot: awaitingSandboxBoot, onClientAction: onClientAction, onTurnComplete: onTurnComplete, onLoadingChange: onLoadingChange, onNavigatePreview: onNavigatePreview, onRegisterPushHandler: onRegisterPushHandler, autoSubmitSignal: autoSubmitSignal, openSettingsSignal: effectiveSettingsSignal, onManageCustomModels: onManageCustomModels, openReportSignal: effectiveReportSignal, openShareSignal: effectiveShareSignal, initialInputValue: initialInputValue, pendingMessage: pendingMessage, pendingMessageKey: pendingMessageKey, pendingMessageSuppressUser: pendingMessageSuppressUser, pendingMessageUserInitiated: pendingMessageUserInitiated, userEditedFile: userEditedFile, userEditedFileKey: userEditedFileKey, gitStatusTick: gitStatusTick, discovery: hideConversationMenu, userAvatar: userAvatar, agentName: agentName, productName: productName, version: version, feedbackUrl: feedbackUrl }, chatKey)] }));
|
|
6790
|
+
}, children: conv.preview ?? 'New conversation' }), _jsx("span", { className: cm.cn(cm.textMuted, cm.textSize('xs')), style: { opacity: 0.55 }, children: relativeTime(conv.updatedAt) })] }, conv.id)))] }))] })), _jsx(ChatInner, { projectId: projectId, endpoint: chatEndpoint, initialMessage: initialMessage, onInitialMessageSent: onInitialMessageSent, isPro: isPro, buildUpgradeCta: buildUpgradeCta, buildHelpUpgradeSection: buildHelpUpgradeSection, activeFile: activeFile, openTabs: openTabs, onFileOpen: onFileOpen, onFileDoubleClick: onFileDoubleClick, onFileDiff: onFileDiff, onFileRevert: onFileRevert, onFileChange: onFileChange, onFileDeleted: onFileDeleted, onCommit: onCommit, onConversationId: reportConversationId, onActivityClick: onActivityClick, onRenderError: onRenderError, onProfileClick: onProfileClick, onReadyToBuild: onReadyToBuild, awaitingSandboxBoot: awaitingSandboxBoot, onClientAction: onClientAction, onTurnComplete: onTurnComplete, onLoadingChange: onLoadingChange, onNavigatePreview: onNavigatePreview, onRegisterPushHandler: onRegisterPushHandler, autoSubmitSignal: autoSubmitSignal, openSettingsSignal: effectiveSettingsSignal, onManageCustomModels: onManageCustomModels, openReportSignal: effectiveReportSignal, openShareSignal: effectiveShareSignal, initialInputValue: initialInputValue, pendingMessage: pendingMessage, pendingMessageKey: pendingMessageKey, pendingMessageSuppressUser: pendingMessageSuppressUser, pendingMessageUserInitiated: pendingMessageUserInitiated, userEditedFile: userEditedFile, userEditedFileKey: userEditedFileKey, gitStatusTick: gitStatusTick, discovery: hideConversationMenu, userAvatar: userAvatar, agentName: agentName, productName: productName, version: version, feedbackUrl: feedbackUrl }, chatKey)] }));
|
|
6763
6791
|
}
|
|
6764
6792
|
ChatPanel.displayName = 'ChatPanel';
|
|
6765
6793
|
//# sourceMappingURL=ChatPanel.js.map
|