@kortix/ui 0.14.9 → 0.14.11
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/dist/_vendor/kortix-shared.js +55 -2
- package/dist/_vendor/shared/artifact-comments.d.ts +235 -0
- package/dist/_vendor/shared/channel-descriptors.d.ts +96 -0
- package/dist/_vendor/shared/channel-message.d.ts +13 -2
- package/dist/_vendor/shared/index.d.ts +1 -0
- package/dist/_vendor/shared/runtime-versions.d.ts +9 -0
- package/dist/apps/app-preview-pool.js +19 -2
- package/dist/artifacts/artifact-frame.js +7 -3
- package/dist/customize/sections/component/channel-access-panel.js +4 -4
- package/dist/customize/sections/component/telegram-channel-row.js +7 -5
- package/dist/customize/sections/view/agent-editor-catalog.js +5 -0
- package/dist/customize/sections/view/channels-view.d.ts +2 -1
- package/dist/customize/sections/view/channels-view.js +12 -7
- package/dist/customize/settings/rail.js +9 -0
- package/dist/customize/settings/settings-tabs.d.ts +1 -1
- package/dist/customize/settings/settings-tabs.js +1 -0
- package/dist/customize/settings/tabs/chrome-connections-tab.d.ts +6 -0
- package/dist/customize/settings/tabs/chrome-connections-tab.js +99 -0
- package/dist/customize/settings/tabs/sandbox-template-form.js +8 -1
- package/dist/customize/shared/catalog/catalog-empty-state.d.ts +3 -3
- package/dist/customize/shared/catalog/catalog-empty-state.js +6 -4
- package/dist/files/renderers/image-frame.d.ts +3 -1
- package/dist/files/renderers/image-frame.js +2 -2
- package/dist/files/renderers/show-content-renderer.d.ts +2 -2
- package/dist/files/renderers/show-content-renderer.js +2 -1
- package/dist/i18n/en.d.ts +206 -0
- package/dist/i18n/en.js +219 -13
- package/dist/i18n/ui-catalog/remaining-ui-translation-keys.generated.js +3 -3
- package/dist/internal/apps-and-extensions/apps-modal.d.ts +9 -0
- package/dist/internal/apps-and-extensions/apps-modal.js +107 -0
- package/dist/internal/branding/branding-provider.js +3 -3
- package/dist/internal/chrome/browser-icon.d.ts +24 -0
- package/dist/internal/chrome/browser-icon.js +58 -0
- package/dist/internal/chrome/chrome-card-state.d.ts +16 -0
- package/dist/internal/chrome/chrome-card-state.js +9 -0
- package/dist/internal/chrome/chrome-connect.d.ts +69 -0
- package/dist/internal/chrome/chrome-connect.js +178 -0
- package/dist/internal/chrome/chrome-mock.d.ts +4 -0
- package/dist/internal/chrome/chrome-mock.js +15 -0
- package/dist/internal/chrome/chrome-names.d.ts +15 -0
- package/dist/internal/chrome/chrome-names.js +35 -0
- package/dist/internal/chrome/extension.d.ts +47 -0
- package/dist/internal/chrome/extension.js +91 -0
- package/dist/internal/chrome/use-chrome-offered.d.ts +11 -0
- package/dist/internal/chrome/use-chrome-offered.js +22 -0
- package/dist/internal/connector-logo/connector-logo-source.d.ts +2 -1
- package/dist/internal/connector-logo/connector-logo-source.js +7 -6
- package/dist/internal/hooks/use-notification-center.d.ts +10 -6
- package/dist/internal/hooks/use-notification-center.js +32 -10
- package/dist/internal/icons/edge.d.ts +5 -0
- package/dist/internal/icons/edge.js +10 -0
- package/dist/internal/lib/browser-noise/rules/extensions.js +17 -3
- package/dist/internal/lib/detect-os.d.ts +43 -0
- package/dist/internal/lib/detect-os.js +70 -0
- package/dist/internal/lib/site-metadata.js +4 -4
- package/dist/internal/lib/use-project-feature-flags.js +5 -1
- package/dist/internal/notifications/notification-bell.js +4 -3
- package/dist/internal/notifications/notification-rows.d.ts +1 -1
- package/dist/internal/notifications/notification-rows.js +2 -0
- package/dist/internal/stores/apps-modal-store.d.ts +8 -0
- package/dist/internal/stores/apps-modal-store.js +6 -0
- package/dist/internal/stores/composer-prefill-store.d.ts +12 -5
- package/dist/internal/stores/kortix-computer-store.d.ts +1 -1
- package/dist/markdown/setup-links/approval-decision.js +3 -1
- package/dist/primitives/empty-state.d.ts +2 -2
- package/dist/primitives/empty-state.js +6 -5
- package/dist/primitives/mermaid-renderer.js +1 -1
- package/dist/session/composer/send-stop-control.js +8 -3
- package/dist/session/header/session-site-header.js +3 -1
- package/dist/session/panel/easy/detail-view.js +4 -0
- package/dist/session/panel/mobile-tool-drawer.js +5 -3
- package/dist/session/panel/open-session-quick-view.js +2 -2
- package/dist/session/panel/panel-fallback.js +10 -7
- package/dist/session/panel/session-audit-shared.js +3 -1
- package/dist/session/panel/session-desktop.d.ts +6 -0
- package/dist/session/panel/session-desktop.js +74 -0
- package/dist/session/panel/session-panel-provider.d.ts +1 -0
- package/dist/session/panel/session-panel-provider.js +17 -1
- package/dist/session/panel/shared/use-panel-handoffs.d.ts +2 -2
- package/dist/session/panel/shared/use-panel-handoffs.js +5 -1
- package/dist/session/panel/use-session-panel-layout.js +8 -0
- package/dist/session/participants/session-participants.d.ts +3 -1
- package/dist/session/participants/session-participants.js +2 -2
- package/dist/session/prompts/approval-request.js +2 -0
- package/dist/session/status/session-tab-title.d.ts +1 -1
- package/dist/session/status/session-tab-title.js +1 -1
- package/dist/session/thread/session-chat.js +12 -0
- package/dist/session/thread/session-context-sub-sessions.js +1 -1
- package/dist/session/thread/session-thread.d.ts +13 -1
- package/dist/session/thread/session-thread.js +15 -5
- package/dist/session/thread/session-transcript-class.d.ts +5 -1
- package/dist/session/thread/session-transcript-class.js +5 -1
- package/dist/session/tool/tools/image-gen-tool.d.ts +1 -1
- package/dist/session/tool/tools/image-gen-tool.js +21 -11
- package/dist/session/turn/user-message.d.ts +7 -5
- package/dist/session/turn/user-message.js +14 -8
- package/dist/styles.css +1 -1
- package/dist/workspace/session-workspace.js +24 -5
- package/dist/workspace/sessions/session-label-badges.js +2 -1
- package/dist/workspace/sidebar/footer/project-chrome-nav.d.ts +10 -0
- package/dist/workspace/sidebar/footer/project-chrome-nav.js +56 -0
- package/dist/workspace/sidebar/project-sidebar.js +5 -1
- package/package.json +43 -3
- package/skills/kortix-ui/references/modules.md +1 -1
|
@@ -52,7 +52,7 @@ function WithOneThread({ source, id, rest, pricingLookup, acc, children, }) {
|
|
|
52
52
|
}
|
|
53
53
|
/**
|
|
54
54
|
* Loads a sub-agent's thread into the store, as the sub-agent's own view does (`useSessionSync`
|
|
55
|
-
* with `savedChild`):
|
|
55
|
+
* with `savedChild`): the session's log, then the runtime's. The section mounts one per requested
|
|
56
56
|
* id (a row that scrolled into view, or "Load all"), outside the tree, so collapsing a row
|
|
57
57
|
* does not unload its children. Reports whether its last runtime read failed.
|
|
58
58
|
*/
|
|
@@ -11,6 +11,9 @@
|
|
|
11
11
|
* Alone, it has no side panel: its "open in the panel" actions (Preview, file
|
|
12
12
|
* chips, Terminal, Browser) open an overlay (`SessionPanelFallback`). Inside
|
|
13
13
|
* `SessionWorkspace` they open in the side panel.
|
|
14
|
+
*
|
|
15
|
+
* A host that just created the session passes `firstPrompt`: the prompt shows
|
|
16
|
+
* at once, as the turn the transcript will draw, while the computer boots.
|
|
14
17
|
*/
|
|
15
18
|
import type { UseSessionResult } from '@kortix/sdk/react';
|
|
16
19
|
import '../tool/tools/register.js';
|
|
@@ -32,6 +35,15 @@ export interface SessionThreadProps {
|
|
|
32
35
|
id: number;
|
|
33
36
|
text: string;
|
|
34
37
|
} | null;
|
|
38
|
+
/**
|
|
39
|
+
* The first prompt of a session this host just created, as sent. Drawn at
|
|
40
|
+
* once (the prompt and the agent's Thinking row) while the computer boots,
|
|
41
|
+
* then handed to the transcript without a jump. Pass it only for that
|
|
42
|
+
* fresh session: the transcript draws its prompts from then on.
|
|
43
|
+
*/
|
|
44
|
+
firstPrompt?: string;
|
|
45
|
+
/** `compact`: tighter gutters for a narrow column (a side sheet). Default: the session page's. */
|
|
46
|
+
density?: 'default' | 'compact';
|
|
35
47
|
className?: string;
|
|
36
48
|
}
|
|
37
|
-
export declare function SessionThread({ session, hideHeader, readOnly, composerPlaceholder, quote, className, }: SessionThreadProps): import("react").JSX.Element;
|
|
49
|
+
export declare function SessionThread({ session, hideHeader, readOnly, composerPlaceholder, quote, firstPrompt, density, className, }: SessionThreadProps): import("react").JSX.Element;
|
|
@@ -1,20 +1,30 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useContext } from 'react';
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useContext, useEffect } from 'react';
|
|
4
4
|
import { cn } from '../../lib/utils.js';
|
|
5
5
|
import { ProjectScope } from '../../internal/project-scope.js';
|
|
6
|
+
import { useFirstPromptPreviewStore } from '../composer/stores/session-composer-handoff-store.js';
|
|
6
7
|
import { ProviderPoolDraftBoundary } from '../overrides/provider-pool-draft-context.js';
|
|
7
8
|
import { SessionPanelFallback } from '../panel/panel-fallback.js';
|
|
8
9
|
import { SessionChat } from './session-chat.js';
|
|
9
10
|
import { SessionStartingLoader } from '../status/session-starting-loader.js';
|
|
11
|
+
import { OptimisticTurn } from './optimistic-turn.js';
|
|
12
|
+
import { SESSION_TRANSCRIPT_CLASS } from './session-transcript-class.js';
|
|
10
13
|
import { ThreadBootRows } from './thread-boot-rows.js';
|
|
11
14
|
import { TranscriptRowsContext } from './transcript-rows.js';
|
|
12
15
|
import '../tool/tools/register.js';
|
|
13
|
-
export function SessionThread({ session, hideHeader = false, readOnly = false, composerPlaceholder, quote, className, }) {
|
|
16
|
+
export function SessionThread({ session, hideHeader = false, readOnly = false, composerPlaceholder, quote, firstPrompt, density = 'default', className, }) {
|
|
14
17
|
const { projectId, sessionId, runtimeSessionId } = session;
|
|
15
18
|
const rows = useContext(TranscriptRowsContext) !== null;
|
|
16
|
-
|
|
19
|
+
// The same stand-in the instant session shell hands `SessionChat`: it draws
|
|
20
|
+
// the prompt until its transcript has it, then forgets it.
|
|
21
|
+
const bootPrompt = useFirstPromptPreviewStore((state) => state.previewBySession[sessionId]?.text ?? null) ?? (firstPrompt?.trim() || null);
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
if (firstPrompt?.trim())
|
|
24
|
+
useFirstPromptPreviewStore.getState().setFirstPromptPreview(sessionId, firstPrompt, []);
|
|
25
|
+
}, [sessionId, firstPrompt]);
|
|
26
|
+
return (_jsx(ProjectScope, { projectId: projectId, sessionId: sessionId, children: _jsx(ProviderPoolDraftBoundary, { identity: `${projectId}/${sessionId}`, children: _jsxs("div", { "data-slot": "session-thread", "data-density": density, className: cn('group/thread relative flex h-full min-h-0 flex-col', className), children: [runtimeSessionId ? (_jsx(SessionChat, { sessionId: runtimeSessionId, projectSessionId: sessionId, projectId: projectId, sessionState: session, hideHeader: hideHeader, readOnly: readOnly, composerPlaceholder: composerPlaceholder, hostQuote: quote }, runtimeSessionId)) : rows ? (
|
|
17
27
|
// A channel thread: its prompt, the agent's busy row and the reply
|
|
18
28
|
// box from the first frame, while the computer comes up.
|
|
19
|
-
_jsx(ThreadBootRows, { projectId: projectId, sessionId: sessionId, composerPlaceholder: composerPlaceholder, readOnly: readOnly })) : (_jsx(SessionStartingLoader, { projectId: projectId, sessionId: sessionId })), _jsx(SessionPanelFallback, { projectId: projectId, projectSessionId: sessionId, runtimeSessionId: runtimeSessionId })] }) }) }));
|
|
29
|
+
_jsx(ThreadBootRows, { projectId: projectId, sessionId: sessionId, composerPlaceholder: composerPlaceholder, readOnly: readOnly })) : bootPrompt ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "scrollbar-hide min-h-0 flex-1 overflow-y-auto", children: _jsx("div", { className: SESSION_TRANSCRIPT_CLASS, children: _jsx(OptimisticTurn, { text: bootPrompt, deferPreview: true, sessionId: sessionId }) }) }), _jsx("div", { className: "shrink-0", children: _jsx(SessionStartingLoader, { projectId: projectId, sessionId: sessionId }) })] })) : (_jsx(SessionStartingLoader, { projectId: projectId, sessionId: sessionId })), _jsx(SessionPanelFallback, { projectId: projectId, projectSessionId: sessionId, runtimeSessionId: runtimeSessionId })] }) }) }));
|
|
20
30
|
}
|
|
@@ -15,5 +15,9 @@
|
|
|
15
15
|
* Its own module with no imports, so a surface that only needs the column (the
|
|
16
16
|
* first chat on project home) does not pull `session-body.tsx`'s action panel
|
|
17
17
|
* into its bundle. `session-body.tsx` re-exports it for the session surfaces.
|
|
18
|
+
*
|
|
19
|
+
* Inside a compact `SessionThread` (a narrow side column) the conversation's
|
|
20
|
+
* gutters and top inset tighten; the composer keeps its own. The gutters then
|
|
21
|
+
* match the composer's (`px-4`), so messages line up with the input card's edges.
|
|
18
22
|
*/
|
|
19
|
-
export declare const SESSION_TRANSCRIPT_CLASS = "mx-auto w-full max-w-3xl min-w-0 px-7 pt-6";
|
|
23
|
+
export declare const SESSION_TRANSCRIPT_CLASS = "mx-auto w-full max-w-3xl min-w-0 px-7 pt-6 group-data-[density=compact]/thread:px-4 group-data-[density=compact]/thread:pt-4";
|
|
@@ -15,5 +15,9 @@
|
|
|
15
15
|
* Its own module with no imports, so a surface that only needs the column (the
|
|
16
16
|
* first chat on project home) does not pull `session-body.tsx`'s action panel
|
|
17
17
|
* into its bundle. `session-body.tsx` re-exports it for the session surfaces.
|
|
18
|
+
*
|
|
19
|
+
* Inside a compact `SessionThread` (a narrow side column) the conversation's
|
|
20
|
+
* gutters and top inset tighten; the composer keeps its own. The gutters then
|
|
21
|
+
* match the composer's (`px-4`), so messages line up with the input card's edges.
|
|
18
22
|
*/
|
|
19
|
-
export const SESSION_TRANSCRIPT_CLASS = 'mx-auto w-full max-w-3xl min-w-0 px-7 pt-6';
|
|
23
|
+
export const SESSION_TRANSCRIPT_CLASS = 'mx-auto w-full max-w-3xl min-w-0 px-7 pt-6 group-data-[density=compact]/thread:px-4 group-data-[density=compact]/thread:pt-4';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { ToolProps } from '../shared/types.js';
|
|
2
|
-
export declare function ImageGenTool({ call }: ToolProps): import("react").JSX.Element;
|
|
2
|
+
export declare function ImageGenTool({ call }: ToolProps): import("react").JSX.Element | null;
|
|
@@ -125,9 +125,10 @@ function ImageGenFrame({ image, seed, busy, model, fill, }) {
|
|
|
125
125
|
useKortixComputerStore.getState().setIsExpanded(true);
|
|
126
126
|
}
|
|
127
127
|
: undefined;
|
|
128
|
-
return (
|
|
129
|
-
|
|
130
|
-
|
|
128
|
+
return (_jsx(ImageFrame, { className: "group", aspectRatio: image.aspectRatio, fill: fill, maxHeight: fill ? undefined : IMAGE_MAX_HEIGHT, openLabel: image.prompt ? t('openFullScreenPrompt', { prompt: image.prompt }) : t('openFullScreen'), src: src, alt: image.prompt || t('generating'), pending: generating || (!src && !blobError), label: generating ? (busy) : blobError ? (_jsx(ImageUnavailable, { onRetry: retry })) : !src ? (_jsx(BusyLabel, { seed: seed, label: t('loading') })) : null, onOpen: openFullScreen, naturalRatio: naturalRatio, onNaturalSize: onNaturalSize, children: src && openFullScreen ? (
|
|
129
|
+
// The one hint that the image opens full screen, on hover only; the whole frame is the button.
|
|
130
|
+
// A child of the frame: a tall image narrows the frame, and the hint stays on its corner.
|
|
131
|
+
_jsx("span", { "data-image-gen-expand": "", "aria-hidden": "true", className: "bg-popover text-foreground pointer-events-none absolute top-1.5 right-1.5 flex size-6 items-center justify-center rounded-md opacity-0 shadow-xs transition-opacity duration-fast group-focus-within:opacity-100 group-hover:opacity-100", children: _jsx(ArrowsOutSimpleIcon, { className: "size-3.5" }) })) : null }));
|
|
131
132
|
}
|
|
132
133
|
/**
|
|
133
134
|
* The tallest a lone image or the bento may be (R33). The box narrows to
|
|
@@ -161,6 +162,8 @@ const cappedWidth = (rect) => `min(100%, calc(${IMAGE_MAX_HEIGHT} * ${rect}))`;
|
|
|
161
162
|
* Five or more images (R38): ONE grid of six columns whose rows are the
|
|
162
163
|
* bento patterns (`imageGenGrid().rows`: 5 = 3+2, 8 = 4+4, …). Every tile sits
|
|
163
164
|
* in the same grid, placed by line numbers, so a tile is never re-parented.
|
|
165
|
+
* A strip (portrait tiles, `imageGenGrid().strip`) uses this grid at any count,
|
|
166
|
+
* with twelve columns: each row is its tiles side by side, one track tall.
|
|
164
167
|
*
|
|
165
168
|
* The grid is as wide as its tallest row allows under the cap (`width`), and
|
|
166
169
|
* each row is exactly `width / rects[k]` tall (`rects[k]` = its tile ratio ×
|
|
@@ -171,19 +174,21 @@ const cappedWidth = (rect) => `min(100%, calc(${IMAGE_MAX_HEIGHT} * ${rect}))`;
|
|
|
171
174
|
* summed below 1, e.g. 16:9 tiles.) A two-track row subtracts the gap between
|
|
172
175
|
* its tracks, so a large tile spanning both is the row's height.
|
|
173
176
|
*/
|
|
174
|
-
function gridPlacement(rows, rects) {
|
|
177
|
+
function gridPlacement(rows, rects, strip) {
|
|
175
178
|
const width = `min(100cqw, ${IMAGE_MAX_HEIGHT} * ${Math.min(...rects)})`;
|
|
176
179
|
const tracks = [];
|
|
177
180
|
const places = [];
|
|
178
181
|
rows.forEach((count, row) => {
|
|
179
182
|
const track = tracks.length + 1;
|
|
180
183
|
const height = `${width} / ${rects[row]}`;
|
|
181
|
-
if (count === 2)
|
|
184
|
+
if (strip || count === 2)
|
|
182
185
|
tracks.push(`calc(${height})`);
|
|
183
186
|
else
|
|
184
187
|
tracks.push(`calc((${height} - var(--spacing)) / 2)`, `calc((${height} - var(--spacing)) / 2)`);
|
|
185
188
|
for (let i = 0; i < count; i++) {
|
|
186
|
-
if (
|
|
189
|
+
if (strip)
|
|
190
|
+
places.push({ gridColumn: `${1 + (12 / count) * i} / span ${12 / count}`, gridRow: `${track}` });
|
|
191
|
+
else if (count === 2)
|
|
187
192
|
places.push({ gridColumn: `${1 + 3 * i} / span 3`, gridRow: `${track}` });
|
|
188
193
|
else if (count === 4)
|
|
189
194
|
places.push({ gridColumn: `${1 + 3 * (i % 2)} / span 3`, gridRow: `${track + Math.floor(i / 2)}` });
|
|
@@ -205,13 +210,17 @@ export function ImageGenTool({ call }) {
|
|
|
205
210
|
const views = useMemo(() => (run ? run.map(sessionLogOpenCall) : [call]).map((one) => imageGenView(one, inTurn ? live : undefined)), [run, call, inTurn, live]);
|
|
206
211
|
const grid = useMemo(() => imageGenGrid(views), [views]);
|
|
207
212
|
const view = views[0];
|
|
208
|
-
|
|
213
|
+
// One tile: a lone image, or one left beside calls the image cap refused.
|
|
214
|
+
const solo = grid.tiles.length === 1;
|
|
209
215
|
// One fix per card, even when several frames failed for the same reason.
|
|
210
216
|
const repairable = views.find((one) => one.error?.connectModel)?.error ??
|
|
211
217
|
views.flatMap((one) => one.images).find((image) => image.error?.connectModel)?.error;
|
|
212
218
|
const action = repairable ? _jsx(ConnectAction, { code: repairable.code, provider: repairable.provider }) : null;
|
|
213
219
|
// The card carries no prompt and no model (R29): the frames are the content,
|
|
214
220
|
// their status (busy, loading, an error) the only text.
|
|
221
|
+
// The image cap refused every call before any request: nothing was asked for, so nothing to show.
|
|
222
|
+
if (!grid.tiles.length)
|
|
223
|
+
return null;
|
|
215
224
|
if (views.length === 1 && !view.images.length) {
|
|
216
225
|
// The whole call failed or stopped.
|
|
217
226
|
return (_jsx("div", { className: "w-full max-w-md", children: _jsx(FailureNote, { error: view.error, action: action }) }));
|
|
@@ -235,14 +244,15 @@ export function ImageGenTool({ call }) {
|
|
|
235
244
|
return (_jsxs("figure", { className: "flex w-full flex-col gap-2", children: [frame(grid.tiles[0]), action ? _jsx("div", { className: "flex flex-col items-start", children: action }) : null] }));
|
|
236
245
|
}
|
|
237
246
|
const count = grid.tiles.length;
|
|
238
|
-
const bento = grid.rows.length === 1 ? BENTO[count] : null;
|
|
247
|
+
const bento = !grid.strip && grid.rows.length === 1 ? BENTO[count] : null;
|
|
248
|
+
// A row's rectangle over its tile ratio: a strip row is its tiles side by side.
|
|
239
249
|
const rowRects = grid.rows.map((size, row) => {
|
|
240
250
|
const firstTile = grid.tiles[grid.rows.slice(0, row).reduce((sum, n) => sum + n, 0)];
|
|
241
|
-
return ratioValue(views[firstTile.call].aspectRatio) * BENTO[size].scale;
|
|
251
|
+
return ratioValue(views[firstTile.call].aspectRatio) * (grid.strip ? size : BENTO[size].scale);
|
|
242
252
|
});
|
|
243
|
-
const placed = bento ? null : gridPlacement(grid.rows, rowRects);
|
|
253
|
+
const placed = bento ? null : gridPlacement(grid.rows, rowRects, grid.strip);
|
|
244
254
|
return (
|
|
245
255
|
// An inline-size container: the merged grid sizes its rows from its width (`cqw`).
|
|
246
|
-
_jsxs("figure", { className: cn('flex w-full flex-col gap-2', !bento && '@container'), children: [_jsx("div", { ...(bento ? { 'data-image-gen-bento': count } : { 'data-image-gen-grid': grid.rows.join('+') }), className: cn('grid min-h-0 w-full gap-1', bento ? bento.grid : 'grid-cols-6'), style: placed ? placed.style : { aspectRatio: rowRects[0], width: cappedWidth(rowRects[0]) }, children: grid.tiles.map((tile, i) => (_jsx("div", { "data-image-gen-tile": i, className: cn('min-h-0 min-w-0', bento && i === 0 && bento.first), style: placed?.places[i], children: frame(tile) }, tileKey(tile, i)))) }), action ? _jsx("div", { className: "flex flex-col items-start", children: action }) : null] }));
|
|
256
|
+
_jsxs("figure", { className: cn('flex w-full flex-col gap-2', !bento && '@container'), children: [_jsx("div", { ...(bento ? { 'data-image-gen-bento': count } : { 'data-image-gen-grid': grid.rows.join('+'), ...(grid.strip && { 'data-image-gen-strip': '' }) }), className: cn('grid min-h-0 w-full gap-1', bento ? bento.grid : grid.strip ? 'grid-cols-12' : 'grid-cols-6'), style: placed ? placed.style : { aspectRatio: rowRects[0], width: cappedWidth(rowRects[0]) }, children: grid.tiles.map((tile, i) => (_jsx("div", { "data-image-gen-tile": i, className: cn('min-h-0 min-w-0', bento && i === 0 && bento.first), style: placed?.places[i], children: frame(tile) }, tileKey(tile, i)))) }), action ? _jsx("div", { className: "flex flex-col items-start", children: action }) : null] }));
|
|
247
257
|
}
|
|
248
258
|
ToolRegistry.register('image-gen', ImageGenTool);
|
|
@@ -29,13 +29,15 @@ export declare function ChannelOrigin({ info, platform }: {
|
|
|
29
29
|
}): import("react").JSX.Element;
|
|
30
30
|
/**
|
|
31
31
|
* A message that arrived from a chat channel (Slack / Microsoft Teams /
|
|
32
|
-
* Telegram): a source pill — mark, platform, sender — over the
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
32
|
+
* Telegram): a source pill — mark, platform, sender — over the files the
|
|
33
|
+
* sender sent (the strip a composer upload gets) and the same bubble a typed
|
|
34
|
+
* message gets. Every `@name` in the text (`@Kortix`, `@KortixDev`, `@here`)
|
|
35
|
+
* is a `MentionChip`, the chip the composer draws, static because a channel
|
|
36
|
+
* mention opens nothing here. Exported for `channel-message-card.test.tsx`.
|
|
36
37
|
*/
|
|
37
|
-
export declare function ChannelMessage({ info, actions, }: {
|
|
38
|
+
export declare function ChannelMessage({ info, attachments, actions, }: {
|
|
38
39
|
info: ChannelMessageInfo;
|
|
40
|
+
attachments?: NormalizedAttachment[];
|
|
39
41
|
actions?: React.ReactNode;
|
|
40
42
|
}): import("react").JSX.Element;
|
|
41
43
|
export interface NormalizedAttachment {
|
|
@@ -13,7 +13,7 @@ import { fetchSessionAttachment, isSessionAttachmentRef, } from '@kortix/sdk';
|
|
|
13
13
|
/** Moved from session-chat.tsx (`UserMessageRow`) so the turn module owns the
|
|
14
14
|
* user-message card. Full-width card, no reference chips. */
|
|
15
15
|
import { useTranslations } from '../../i18n/index.js';
|
|
16
|
-
import { expandPastedContent, neutralizePastedTags, sanitizePromptUploadFilename, serializePromptWithPastes, splitPastedContent, } from '../../_vendor/kortix-shared.js';
|
|
16
|
+
import { channelPromptTail, isChannelFileLabel, expandPastedContent, neutralizePastedTags, sanitizePromptUploadFilename, serializePromptWithPastes, splitPastedContent, } from '../../_vendor/kortix-shared.js';
|
|
17
17
|
import { useContext, useEffect, useMemo, useRef, useState } from 'react';
|
|
18
18
|
import { PencilSimpleIcon, AlarmIcon, ChatsTeardropIcon, LightningIcon, } from '@phosphor-icons/react';
|
|
19
19
|
import { CopyButton } from '../../markdown/copy-button.js';
|
|
@@ -99,15 +99,16 @@ export function ChannelOrigin({ info, platform }) {
|
|
|
99
99
|
}
|
|
100
100
|
/**
|
|
101
101
|
* A message that arrived from a chat channel (Slack / Microsoft Teams /
|
|
102
|
-
* Telegram): a source pill — mark, platform, sender — over the
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
102
|
+
* Telegram): a source pill — mark, platform, sender — over the files the
|
|
103
|
+
* sender sent (the strip a composer upload gets) and the same bubble a typed
|
|
104
|
+
* message gets. Every `@name` in the text (`@Kortix`, `@KortixDev`, `@here`)
|
|
105
|
+
* is a `MentionChip`, the chip the composer draws, static because a channel
|
|
106
|
+
* mention opens nothing here. Exported for `channel-message-card.test.tsx`.
|
|
106
107
|
*/
|
|
107
|
-
export function ChannelMessage({ info, actions, }) {
|
|
108
|
+
export function ChannelMessage({ info, attachments = [], actions, }) {
|
|
108
109
|
const tI18nComplete = useTranslations('hardcodedUi.i18nComplete');
|
|
109
110
|
const platform = channelPlatformLabel(info.platform, tI18nComplete);
|
|
110
|
-
return (_jsxs("div", { className: "flex flex-col items-end gap-1.5", children: [_jsx(SourcePill, { mark: _jsx(ChannelBrandMark, { platform: info.platform, className: "size-3 shrink-0" }), source: platform, sourceColor: CHANNEL_BRAND_COLOR[info.platform], sender: info.userName, card: _jsx(ChannelOrigin, { info: info, platform: platform }) }), info.messageText && (_jsx("div", { className: cn(BUBBLE_SURFACE, 'max-w-[80%]'), children: _jsx("div", { className: BUBBLE_TEXT, children: buildMentionSegments({ text: info.messageText }).map((segment, i) => segment.type ? (_jsx(MentionChip, { kind: "user", label: segment.text.slice(1) }, i)) : (_jsx("span", { children: segment.text }, i))) }) })), actions] }));
|
|
111
|
+
return (_jsxs("div", { className: "flex flex-col items-end gap-1.5", children: [_jsx(SourcePill, { mark: _jsx(ChannelBrandMark, { platform: info.platform, className: "size-3 shrink-0" }), source: platform, sourceColor: CHANNEL_BRAND_COLOR[info.platform], sender: info.userName, card: _jsx(ChannelOrigin, { info: info, platform: platform }) }), _jsx(MessageAttachments, { attachments: attachments }), info.messageText && !(attachments.length > 0 && isChannelFileLabel(info.messageText)) && (_jsx("div", { className: cn(BUBBLE_SURFACE, 'max-w-[80%]'), children: _jsx("div", { className: BUBBLE_TEXT, children: buildMentionSegments({ text: info.messageText }).map((segment, i) => segment.type ? (_jsx(MentionChip, { kind: "user", label: segment.text.slice(1) }, i)) : (_jsx("span", { children: segment.text }, i))) }) })), actions] }));
|
|
111
112
|
}
|
|
112
113
|
/**
|
|
113
114
|
* A prompt the platform wrote — a reminder fire or a trigger fire — drawn the
|
|
@@ -900,6 +901,11 @@ export function UserMessage({ message, author, showAuthor, agentNames, commandIn
|
|
|
900
901
|
// scaffolds these prompts with ids and turn instructions the person never
|
|
901
902
|
// typed, so the card shows only the platform, the sender, and their words.
|
|
902
903
|
const channelMessageInfo = useMemo(() => parseChannelMessage(rawText), [rawText]);
|
|
904
|
+
// Its files: the `<file>` tags Kortix wrote after the sender's text, and nothing else. A tag the sender
|
|
905
|
+
// typed is text; the image block pi records for a tag repeats it, and names no path when the sender typed one.
|
|
906
|
+
const channelAttachments = useMemo(() => channelMessageInfo
|
|
907
|
+
? normalizeAttachments([], parseFileReferences(channelPromptTail(rawText, channelMessageInfo.platform)).files)
|
|
908
|
+
: [], [channelMessageInfo, rawText]);
|
|
903
909
|
// Detect trigger_event in user message
|
|
904
910
|
const triggerEventInfo = useMemo(() => parseTriggerEvent(rawText), [rawText]);
|
|
905
911
|
// A reminder fire: platform-written `[REMINDER …]` header + the reminder text.
|
|
@@ -1061,7 +1067,7 @@ export function UserMessage({ message, author, showAuthor, agentNames, commandIn
|
|
|
1061
1067
|
}
|
|
1062
1068
|
// Channel messages (Slack / Microsoft Teams / Telegram): a branded card with the sender
|
|
1063
1069
|
if (channelMessageInfo) {
|
|
1064
|
-
return _jsx(ChannelMessage, { info: channelMessageInfo, actions: actions });
|
|
1070
|
+
return _jsx(ChannelMessage, { info: channelMessageInfo, attachments: channelAttachments, actions: actions });
|
|
1065
1071
|
}
|
|
1066
1072
|
if (reminderInfo) {
|
|
1067
1073
|
return _jsx(ReminderMessage, { info: reminderInfo, actions: actions });
|