@parallelworks/ui 0.68.0 → 0.70.0

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 CHANGED
@@ -714,6 +714,10 @@ glyph per meaning across the apps.
714
714
  named value and `ReportIcon` a report to open.
715
715
  `WorkspaceMountIcon` is storage mounted into a workspace and
716
716
  `CloudNetworkIcon` the private network hosts attach to.
717
+ `VerifiedIcon` marks a verified item, publisher or domain, while
718
+ `SuccessIcon` is a run that succeeded. `OwnerIcon` is who owns a resource
719
+ and `DefaultIcon` the one used when nothing else is chosen, while
720
+ `FeaturedIcon` marks an item picked out to show first.
717
721
  `NamespaceIcon`, `CommandShellIcon` and `QuickActionIcon` were
718
722
  `KubernetesNamespaceIcon`, `PowershellIcon` and `ZapIcon`; the old names
719
723
  still work but are deprecated.
@@ -858,6 +862,18 @@ The chat's links (each conversation, a new chat, attachments, and the
858
862
  these links, so `navigation` handles only the moves that aren't clicks, such as
859
863
  keyboard shortcuts.
860
864
 
865
+ `ChatThread` is `SessionView` bound to the chat provider. A host with its own
866
+ transcript, such as an agent session fed by an event stream, renders
867
+ `SessionView` with its messages, streaming and queued messages, and callbacks:
868
+ `onSend`, and `turn` (`running`, `onStop`) for a turn the provider doesn't run.
869
+ What it leaves out it doesn't offer: `onEdit`, `onRegenerate`, `onRetry` and
870
+ `onNavigateBranch` turn on editing, regenerating, retrying and branches.
871
+ Escape stops the running turn either way. `queueDelivery` says when a queued
872
+ message reaches the model, per message when it takes a function. `composer`
873
+ passes `ChatInput`'s props; `ComposerControls` takes `model` and `allocation`
874
+ as a `BoundSetting` for a session that owns its own, and `tools={false}` keeps
875
+ the chat's tools out of a composer they don't apply to.
876
+
861
877
  `ChatLayout sidebarMode="auto"` shows the conversation list as a drawer over
862
878
  the thread when the chat is narrower than `drawerBelowPx` (`DRAWER_BELOW_PX`, 896, by default),
863
879
  measured on the chat's own box; `"drawer"` always does, and `"inline"` (the
@@ -1,3 +1,9 @@
1
+ import type { BoundSetting } from '../types.js';
1
2
  /** Which allocation an organization model bills, with its spend so far. Shows
2
3
  * only for an organization model, and picks the first allocation for it. */
3
- export default function AllocationSelector(): import("react").JSX.Element | null;
4
+ export default function AllocationSelector({ model, allocation, }?: {
5
+ /** The model a session owns, which decides whether it bills an allocation. */
6
+ model?: string | null | undefined;
7
+ /** The allocation a session owns, in place of the chat's own selection. */
8
+ allocation?: BoundSetting | undefined;
9
+ }): import("react").JSX.Element | null;
@@ -15,22 +15,28 @@ var dollars = new Intl.NumberFormat(void 0, {
15
15
  var money = (amount) => dollars.format(amount);
16
16
  /** Which allocation an organization model bills, with its spend so far. Shows
17
17
  * only for an organization model, and picks the first allocation for it. */
18
- function AllocationSelector() {
19
- const { adapter, selectedProvider, selectedAllocation, setSelectedAllocation } = useChat();
18
+ function AllocationSelector({ model, allocation } = {}) {
19
+ const chat = useChat();
20
20
  const t = useChatConfig().strings.allocationPicker;
21
+ const { adapter } = chat;
22
+ const bound = allocation !== void 0;
23
+ const selectedProvider = bound ? model ?? null : chat.selectedProvider;
24
+ const selectedAllocation = bound ? allocation.value ?? null : chat.selectedAllocation;
21
25
  const isOrgProvider = isOrgModel(selectedProvider);
22
26
  const allocationsAdapter = adapter.allocations;
23
27
  const { data: allocations } = useSWR(isOrgProvider && allocationsAdapter ? ["ai-chat-allocations"] : null, () => allocationsAdapter?.list());
24
28
  const first = allocations?.[0];
25
29
  useEffect(() => {
30
+ if (bound) return;
26
31
  if (!isOrgProvider) {
27
- if (selectedAllocation) setSelectedAllocation(null);
28
- } else if (first && !selectedAllocation) setSelectedAllocation(first.name);
32
+ if (selectedAllocation) chat.setSelectedAllocation(null);
33
+ } else if (first && !selectedAllocation) chat.setSelectedAllocation(first.name);
29
34
  }, [
35
+ bound,
30
36
  isOrgProvider,
31
37
  first,
32
38
  selectedAllocation,
33
- setSelectedAllocation
39
+ chat.setSelectedAllocation
34
40
  ]);
35
41
  if (!isOrgProvider || !allocations?.length) return null;
36
42
  const selected = allocations.find((a) => a.name === selectedAllocation);
@@ -43,7 +49,8 @@ function AllocationSelector() {
43
49
  label: a.name
44
50
  })),
45
51
  value: selectedAllocation,
46
- onValueChange: setSelectedAllocation,
52
+ disabled: !!allocation?.disabled,
53
+ onValueChange: (name) => bound ? name && allocation.onChange(name) : chat.setSelectedAllocation(name),
47
54
  trigger: /* @__PURE__ */ jsxs("button", {
48
55
  type: "button",
49
56
  className: chipClassName,
@@ -42,6 +42,9 @@ interface ChatInputProps {
42
42
  onStop: () => void;
43
43
  stopping?: boolean;
44
44
  };
45
+ /** False where the chat's tools do not apply, such as starting an agent
46
+ * session, which brings its own. */
47
+ tools?: boolean;
45
48
  pastes?: ComposerPastes | undefined;
46
49
  ref?: Ref<ChatInputHandle> | undefined;
47
50
  }
@@ -49,5 +52,5 @@ export interface ChatInputHandle {
49
52
  addFiles: (files: FileList | File[]) => void;
50
53
  focus: () => void;
51
54
  }
52
- export default function ChatInput({ onSend, disabled, placeholder, conversationId, onEditLastMessage, allowEmpty, attachments: attachmentsWanted, requireModel, inputLabel, sendLabel, sendTestId, slash, notices, activity, context, reserveContext, settingsLeft, settingsRight, hint, turn, pastes, ref, }: ChatInputProps): import("react").JSX.Element;
55
+ export default function ChatInput({ onSend, disabled, placeholder, conversationId, onEditLastMessage, allowEmpty, attachments: attachmentsWanted, requireModel, inputLabel, sendLabel, sendTestId, slash, notices, activity, context, reserveContext, settingsLeft, settingsRight, hint, turn, tools: toolsAllowed, pastes, ref, }: ChatInputProps): import("react").JSX.Element;
53
56
  export {};
@@ -58,7 +58,7 @@ function fitToContent(el) {
58
58
  el.style.height = `${el.scrollHeight}px`;
59
59
  }
60
60
  var draftsSwept = false;
61
- function ChatInput({ onSend, disabled = false, placeholder, conversationId, onEditLastMessage, allowEmpty = false, attachments: attachmentsWanted = true, requireModel = true, inputLabel, sendLabel, sendTestId, slash, notices, activity, context, reserveContext = false, settingsLeft, settingsRight = /* @__PURE__ */ jsx(ComposerControls, {}), hint, turn, pastes, ref }) {
61
+ function ChatInput({ onSend, disabled = false, placeholder, conversationId, onEditLastMessage, allowEmpty = false, attachments: attachmentsWanted = true, requireModel = true, inputLabel, sendLabel, sendTestId, slash, notices, activity, context, reserveContext = false, settingsLeft, settingsRight = /* @__PURE__ */ jsx(ComposerControls, {}), hint, turn, tools: toolsAllowed = true, pastes, ref }) {
62
62
  const [input, setInput] = useState(() => readDraft(conversationId));
63
63
  useEffect(() => {
64
64
  if (!draftsSwept) {
@@ -186,7 +186,7 @@ function ChatInput({ onSend, disabled = false, placeholder, conversationId, onEd
186
186
  if (pastes && handleTextPaste(e.clipboardData.getData("text/plain"))) e.preventDefault();
187
187
  };
188
188
  const { isDragging, dragHandlers } = useDragDrop({ onFilesDropped: handleFilesDropped });
189
- const toolsAvailable = !turn && tools.length > 0;
189
+ const toolsAvailable = toolsAllowed && !turn && tools.length > 0;
190
190
  const toolbar = attachmentsAvailable || toolsAvailable || !!settingsRight;
191
191
  const action = isStreaming && !input.trim() ? /* @__PURE__ */ jsx("button", {
192
192
  type: "button",
@@ -275,7 +275,7 @@ function ChatInput({ onSend, disabled = false, placeholder, conversationId, onEd
275
275
  attachmentsOpen: showAttachments && attachmentsAvailable,
276
276
  onToggleAttachments: attachmentsAvailable ? () => setShowAttachments(!showAttachments) : void 0,
277
277
  disabled,
278
- withTools: !turn
278
+ withTools: toolsAllowed && !turn
279
279
  }), /* @__PURE__ */ jsxs("div", {
280
280
  className: "ml-auto flex min-w-0 items-center gap-1",
281
281
  children: [/* @__PURE__ */ jsx("div", {
@@ -85,19 +85,57 @@ function ChatMessage({ message, allMessages, isStreaming = false, latest = false
85
85
  const maxHeight = 200;
86
86
  e.target.style.height = `${Math.min(e.target.scrollHeight, maxHeight)}px`;
87
87
  };
88
- const hasParts = !!message.parts?.length;
89
- if (hasParts && !message.content) return /* @__PURE__ */ jsx("div", {
90
- className: cx("group py-3 w-full", !flush && "px-4"),
91
- children: /* @__PURE__ */ jsx(AgentMessageParts, {
92
- message,
93
- isStreaming,
94
- onApprovalAnswer
95
- })
88
+ const timestamp = parseTimestamp(message.timestamp);
89
+ const totalTokens = message.tokensUsed?.total_tokens;
90
+ const meta = (timestamp || !isUser && (message.model || totalTokens)) && /* @__PURE__ */ jsxs("span", {
91
+ className: cx("chat-meta flex items-center gap-2 ml-2 text-xs tabular-nums theme-muted-text transition-opacity duration-150 select-none", "opacity-0 group-focus-within:opacity-100 group-hover:opacity-100"),
92
+ children: [
93
+ /* @__PURE__ */ jsx(RelativeTime, { value: timestamp }),
94
+ !isUser && message.model && /* @__PURE__ */ jsx("span", { children: message.model }),
95
+ !isUser && totalTokens ? /* @__PURE__ */ jsx("span", {
96
+ title: message.tokensUsed?.prompt_tokens !== void 0 && message.tokensUsed?.completion_tokens !== void 0 ? t.tokensBreakdown(message.tokensUsed.prompt_tokens, message.tokensUsed.completion_tokens) : void 0,
97
+ children: t.tokens(totalTokens)
98
+ }) : null
99
+ ]
96
100
  });
101
+ const hasParts = !!message.parts?.length;
102
+ if (hasParts && !message.content) {
103
+ const said = message.parts?.flatMap((p) => p.kind === "text" && p.text.trim() ? [p.text.trim()] : []).join("\n\n");
104
+ return /* @__PURE__ */ jsxs("div", {
105
+ className: cx("group py-3 w-full", !flush && "px-4"),
106
+ children: [/* @__PURE__ */ jsx(AgentMessageParts, {
107
+ message,
108
+ isStreaming,
109
+ onApprovalAnswer
110
+ }), !isUser && !isStreaming && (said || onRegenerate || meta) && /* @__PURE__ */ jsxs("div", {
111
+ className: "chat-actions -ml-1.5 mt-2 flex items-center gap-0.5",
112
+ children: [
113
+ said && /* @__PURE__ */ jsx(CopyButton, {
114
+ text: said,
115
+ label: t.copyLabel,
116
+ quiet: true,
117
+ size: "md",
118
+ className: actionClasses
119
+ }),
120
+ onRegenerate && /* @__PURE__ */ jsx(IconButton, {
121
+ label: t.regenerate,
122
+ onClick: () => onRegenerate(message.id),
123
+ size: "md",
124
+ className: actionClasses,
125
+ icon: /* @__PURE__ */ jsx(RetryIcon, {})
126
+ }),
127
+ onNavigateBranch && /* @__PURE__ */ jsx(BranchNavigator, {
128
+ messages: allMessages,
129
+ currentMessageId: message.id,
130
+ onNavigate: onNavigateBranch
131
+ }),
132
+ meta
133
+ ]
134
+ })]
135
+ });
136
+ }
97
137
  if (isTool) return null;
98
138
  if (!isUser && !message.content && message.toolCalls?.length) return null;
99
- const timestamp = parseTimestamp(message.timestamp);
100
- const totalTokens = message.tokensUsed?.total_tokens;
101
139
  const collapsed = !isUser && collapsible && !expanded && !isStreaming && !latest;
102
140
  return /* @__PURE__ */ jsx("div", {
103
141
  role: "none",
@@ -246,17 +284,7 @@ function ChatMessage({ message, allMessages, isStreaming = false, latest = false
246
284
  currentMessageId: message.id,
247
285
  onNavigate: onNavigateBranch
248
286
  }),
249
- (timestamp || !isUser && (message.model || totalTokens)) && /* @__PURE__ */ jsxs("span", {
250
- className: cx("chat-meta flex items-center gap-2 ml-2 text-xs tabular-nums theme-muted-text transition-opacity duration-150 select-none", "opacity-0 group-focus-within:opacity-100 group-hover:opacity-100"),
251
- children: [
252
- /* @__PURE__ */ jsx(RelativeTime, { value: timestamp }),
253
- !isUser && message.model && /* @__PURE__ */ jsx("span", { children: message.model }),
254
- !isUser && totalTokens ? /* @__PURE__ */ jsx("span", {
255
- title: message.tokensUsed?.prompt_tokens !== void 0 && message.tokensUsed?.completion_tokens !== void 0 ? t.tokensBreakdown(message.tokensUsed.prompt_tokens, message.tokensUsed.completion_tokens) : void 0,
256
- children: t.tokens(totalTokens)
257
- }) : null
258
- ]
259
- })
287
+ meta
260
288
  ]
261
289
  })
262
290
  ]
@@ -1,5 +1,6 @@
1
1
  import { type ReactNode } from 'react';
2
2
  import type { ApprovalAnswerValue, ChatMessage as Message } from '../types.js';
3
+ export type QueueDelivery = 'afterReply' | 'nextStep';
3
4
  interface ChatMessageListProps {
4
5
  messages: Message[];
5
6
  allMessages: Message[];
@@ -13,8 +14,9 @@ interface ChatMessageListProps {
13
14
  canRemoveQueued?: (id: string) => boolean;
14
15
  /** When a queued message reaches the model: once the running reply
15
16
  * finishes (the chat provider's queue), or between the agent's steps for a
16
- * host that steers the turn in progress. */
17
- queueDelivery?: 'afterReply' | 'nextStep';
17
+ * host that steers the turn in progress. A host with both kinds says which
18
+ * each message is. */
19
+ queueDelivery?: QueueDelivery | ((messageId: string) => QueueDelivery);
18
20
  editingMessageId?: string | null | undefined;
19
21
  showAuthor?: boolean;
20
22
  currentUsername?: string;
@@ -253,7 +253,7 @@ function ChatMessageList({ messages, allMessages, streamingMessage: streamingMes
253
253
  }, "streaming"),
254
254
  queuedMessages?.map((msg) => {
255
255
  const removable = canRemoveQueued?.(msg.id) ?? true;
256
- const status = !removable ? strings.queue.handedOver : queueDelivery === "nextStep" ? strings.queue.waitingNextStep : strings.queue.waiting;
256
+ const status = !removable ? strings.queue.handedOver : (typeof queueDelivery === "function" ? queueDelivery(msg.id) : queueDelivery) === "nextStep" ? strings.queue.waitingNextStep : strings.queue.waiting;
257
257
  return /* @__PURE__ */ jsxs("div", {
258
258
  className: cx("animate-chat-enter", removable && "chat-queued"),
259
259
  children: [/* @__PURE__ */ jsx(ChatMessage_default, {
@@ -1,19 +1,14 @@
1
1
  import { useChatConfig } from "../core/config.js";
2
2
  import { useChat } from "../core/ChatProvider.js";
3
3
  import BlockedGroupBanner from "./BlockedGroupBanner.js";
4
- import useDragDrop from "../core/useDragDrop.js";
5
4
  import { ComposerControls, ComposerUsage, ConnectToolsLink } from "./ComposerChrome.js";
6
- import DragOverlay from "./DragOverlay.js";
7
- import ChatInput from "./ChatInput.js";
8
5
  import ProviderIssueBanner from "./ProviderIssueBanner.js";
9
6
  import { ShareButton } from "./ShareDialog.js";
10
- import ChatMessageList from "./ChatMessageList.js";
7
+ import SessionView from "./SessionView.js";
11
8
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
12
- import { useCallback, useEffect, useMemo, useRef, useState } from "react";
9
+ import { useCallback, useEffect, useMemo, useRef } from "react";
13
10
  //#region src/ai/components/ChatThread.tsx
14
11
  function ChatThread({ conversationId }) {
15
- const chatInputRef = useRef(null);
16
- const [editingState, setEditingState] = useState(null);
17
12
  const { adapter, currentUser, currentConversation, loadConversation, loadProviders, sendMessage, retryMessage, isLoadingConversation, navigateToBranch, queuedMessages, removeQueuedMessage } = useChat();
18
13
  const { slots, strings } = useChatConfig();
19
14
  const requestedConversationIdRef = useRef(null);
@@ -28,98 +23,46 @@ function ChatThread({ conversationId }) {
28
23
  loadConversation,
29
24
  loadProviders
30
25
  ]);
31
- const handleSendMessage = useCallback((content, attachmentIds, attachmentMeta) => {
26
+ const messages = currentConversation?.messages ?? [];
27
+ const canWrite = currentConversation?.canCollaborate !== false;
28
+ const onSend = useCallback((content, attachmentIds, attachmentMeta) => {
32
29
  sendMessage(content, attachmentIds, void 0, attachmentMeta);
33
30
  }, [sendMessage]);
34
- const handleEditMessage = useCallback((messageId) => {
35
- const message = (currentConversation?.messages || []).find((m) => m.id === messageId);
36
- if (message && message.role === "user") setEditingState({
37
- messageId: message.id,
38
- parentId: message.parentId || null
39
- });
40
- }, [currentConversation?.messages]);
41
- const handleSaveEdit = useCallback((_messageId, content) => {
42
- if (!editingState) return;
43
- sendMessage(content, void 0, editingState.parentId || void 0);
44
- setEditingState(null);
45
- }, [sendMessage, editingState]);
46
- const handleCancelEdit = useCallback(() => {
47
- setEditingState(null);
48
- }, []);
49
- const handleEditLastMessage = useCallback(() => {
50
- const lastUserMessage = (currentConversation?.messages || []).findLast((m) => m.role === "user");
51
- if (lastUserMessage) handleEditMessage(lastUserMessage.id);
52
- }, [currentConversation?.messages, handleEditMessage]);
53
- const handleNavigateBranch = useCallback((messageId) => {
54
- navigateToBranch?.(messageId);
55
- }, [navigateToBranch]);
56
- const handleRegenerateMessage = useCallback((messageId) => {
57
- const conversationMessages = currentConversation?.messages || [];
58
- const assistantMessage = conversationMessages.find((m) => m.id === messageId);
59
- if (assistantMessage?.role !== "assistant") return;
60
- const userMessage = conversationMessages.find((m) => m.id === assistantMessage.parentId);
61
- if (userMessage?.role !== "user") return;
62
- sendMessage(userMessage.content || "", userMessage.attachments?.map((a) => a.id), userMessage.parentId || void 0);
63
- }, [currentConversation?.messages, sendMessage]);
64
- const handleRetryMessage = useCallback((messageId) => {
65
- retryMessage(messageId);
66
- }, [retryMessage]);
67
- const handleFilesDropped = useCallback((files) => {
68
- chatInputRef.current?.addFiles(files);
69
- }, []);
70
- const { isDragging, dragHandlers } = useDragDrop({ onFilesDropped: handleFilesDropped });
71
- const attachmentsAvailable = !!adapter.attachments;
72
- const messages = currentConversation?.messages || [];
31
+ const onEdit = useCallback((message, content) => {
32
+ sendMessage(content, void 0, message.parentId || void 0);
33
+ }, [sendMessage]);
34
+ const onRegenerate = useCallback((messageId) => {
35
+ const reply = messages.find((m) => m.id === messageId);
36
+ const asked = messages.find((m) => m.id === reply?.parentId);
37
+ if (reply?.role !== "assistant" || asked?.role !== "user") return;
38
+ sendMessage(asked.content || "", asked.attachments?.map((a) => a.id), asked.parentId || void 0);
39
+ }, [messages, sendMessage]);
73
40
  const showAuthor = useMemo(() => {
74
41
  return new Set(messages.flatMap((m) => m.author ? [m.author.username] : [])).size > 1 || currentConversation?.isOwner === false;
75
42
  }, [messages, currentConversation?.isOwner]);
76
- if (isLoadingConversation && !currentConversation) return /* @__PURE__ */ jsxs("div", {
77
- className: "flex flex-col h-full bg-(--theme-panel-bg)",
78
- children: [/* @__PURE__ */ jsx("div", { className: "flex-1" }), /* @__PURE__ */ jsx(ChatInput, {
79
- ref: chatInputRef,
80
- onSend: handleSendMessage,
81
- disabled: true,
82
- conversationId,
83
- settingsLeft: /* @__PURE__ */ jsx(ConnectToolsLink, {}),
43
+ return /* @__PURE__ */ jsx(SessionView, {
44
+ sessionKey: conversationId,
45
+ messages,
46
+ queuedMessages,
47
+ onRemoveQueued: removeQueuedMessage,
48
+ onSend,
49
+ ...canWrite ? {
50
+ onEdit,
51
+ onRegenerate,
52
+ onRetry: (id) => void retryMessage(id)
53
+ } : {},
54
+ onNavigateBranch: navigateToBranch,
55
+ showAuthor,
56
+ currentUsername: currentUser.username,
57
+ loading: isLoadingConversation && !currentConversation,
58
+ dropFiles: !!adapter.attachments,
59
+ banners: /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(BlockedGroupBanner, {}), /* @__PURE__ */ jsx(ProviderIssueBanner, {})] }),
60
+ composer: {
61
+ disabled: isLoadingConversation || !canWrite,
62
+ ...canWrite ? {} : { placeholder: strings.thread.viewOnly },
63
+ settingsLeft: /* @__PURE__ */ jsxs(Fragment, { children: [currentConversation && currentConversation.isOwner !== false && /* @__PURE__ */ jsx(ShareButton, { conversationId }), /* @__PURE__ */ jsx(ConnectToolsLink, {})] }),
84
64
  settingsRight: /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(ComposerUsage, { children: slots.composerUsage }), /* @__PURE__ */ jsx(ComposerControls, {})] })
85
- })]
86
- });
87
- return /* @__PURE__ */ jsx("div", {
88
- className: "flex h-full relative bg-(--theme-panel-bg)",
89
- children: /* @__PURE__ */ jsxs("div", {
90
- className: "flex-1 flex flex-col min-w-0",
91
- ...attachmentsAvailable ? dragHandlers : {},
92
- children: [
93
- isDragging && attachmentsAvailable && /* @__PURE__ */ jsx(DragOverlay, { className: "rounded-lg" }),
94
- /* @__PURE__ */ jsx(BlockedGroupBanner, {}),
95
- /* @__PURE__ */ jsx(ProviderIssueBanner, {}),
96
- /* @__PURE__ */ jsx(ChatMessageList, {
97
- messages,
98
- allMessages: messages,
99
- queuedMessages,
100
- onRemoveQueued: removeQueuedMessage,
101
- editingMessageId: editingState?.messageId,
102
- showAuthor,
103
- currentUsername: currentUser.username,
104
- onNavigateBranch: handleNavigateBranch,
105
- onEditMessage: currentConversation?.canCollaborate !== false ? handleEditMessage : void 0,
106
- onRegenerateMessage: currentConversation?.canCollaborate !== false ? handleRegenerateMessage : void 0,
107
- onRetryMessage: currentConversation?.canCollaborate !== false ? handleRetryMessage : void 0,
108
- onSaveEdit: handleSaveEdit,
109
- onCancelEdit: handleCancelEdit,
110
- inputElement: /* @__PURE__ */ jsx(ChatInput, {
111
- ref: chatInputRef,
112
- onSend: handleSendMessage,
113
- disabled: isLoadingConversation || currentConversation?.canCollaborate === false,
114
- placeholder: currentConversation?.canCollaborate === false ? strings.thread.viewOnly : void 0,
115
- conversationId,
116
- onEditLastMessage: handleEditLastMessage,
117
- settingsLeft: /* @__PURE__ */ jsxs(Fragment, { children: [currentConversation?.isOwner !== false && /* @__PURE__ */ jsx(ShareButton, { conversationId }), /* @__PURE__ */ jsx(ConnectToolsLink, {})] }),
118
- settingsRight: /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(ComposerUsage, { children: slots.composerUsage }), /* @__PURE__ */ jsx(ComposerControls, {})] })
119
- })
120
- })
121
- ]
122
- })
65
+ }
123
66
  });
124
67
  }
125
68
  //#endregion
@@ -1,4 +1,5 @@
1
1
  import type { ReactNode } from 'react';
2
+ import type { BoundSetting } from '../types.js';
2
3
  /** Where the turn runs, sitting above the composer the way the terminal shows
3
4
  * it: the machine, the workspace, and whatever else names the place. */
4
5
  export declare function ComposerContext({ children }: {
@@ -19,8 +20,12 @@ export declare function ComposerUsage({ children }: {
19
20
  }): import("react").JSX.Element | null;
20
21
  /** The two selectors every surface carries, reading as text beside whatever
21
22
  * the surface puts next to them. */
22
- export declare function ComposerControls({ targetSession }: {
23
+ export declare function ComposerControls({ targetSession, model, allocation, }: {
23
24
  targetSession?: string | null | undefined;
25
+ /** A session's own model and allocation, for a session that keeps them
26
+ * apart from the chat's selection. */
27
+ model?: BoundSetting | undefined;
28
+ allocation?: BoundSetting | undefined;
24
29
  }): import("react").JSX.Element;
25
30
  /** Where the reader manages the providers behind the model picker, at the
26
31
  * foot of a conversation list. */
@@ -40,8 +40,14 @@ function ComposerUsage({ children }) {
40
40
  }
41
41
  /** The two selectors every surface carries, reading as text beside whatever
42
42
  * the surface puts next to them. */
43
- function ComposerControls({ targetSession }) {
44
- return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(ModelSelector, { targetSession }), /* @__PURE__ */ jsx(AllocationSelector, {})] });
43
+ function ComposerControls({ targetSession, model, allocation }) {
44
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(ModelSelector, {
45
+ targetSession,
46
+ model
47
+ }), /* @__PURE__ */ jsx(AllocationSelector, { ...allocation ? {
48
+ allocation,
49
+ model: model ? model.value : void 0
50
+ } : {} })] });
45
51
  }
46
52
  /** Where the reader manages the providers behind the model picker, at the
47
53
  * foot of a conversation list. */
@@ -1,8 +1,11 @@
1
+ import type { BoundSetting } from '../types.js';
1
2
  export declare function getProviderKeyFromModelId(modelId: string): string;
2
3
  /** Picks the model a conversation runs on, grouped by provider. Sessions that
3
4
  * are still connecting or not responding show as headings with their status,
4
5
  * so the reader sees why their models are missing. */
5
- export default function ModelSelector({ targetSession, }: {
6
+ export default function ModelSelector({ targetSession, model, }: {
6
7
  /** A session, as "owner:name", whose models the reader is waiting for. */
7
8
  targetSession?: string | null | undefined;
9
+ /** The model a session owns, in place of the chat's own selection. */
10
+ model?: BoundSetting | undefined;
8
11
  }): import("react").JSX.Element;
@@ -50,11 +50,12 @@ function groupModelsByProvider(models) {
50
50
  /** Picks the model a conversation runs on, grouped by provider. Sessions that
51
51
  * are still connecting or not responding show as headings with their status,
52
52
  * so the reader sees why their models are missing. */
53
- function ModelSelector({ targetSession }) {
54
- const { providers, models, unreachableSessions, providerIssues, selectedProvider, setSelectedProvider, isLoadingModels, hasLoadedModels, modelsError, refreshModels, currentUser } = useChat();
53
+ function ModelSelector({ targetSession, model }) {
54
+ const { providers, models, unreachableSessions, providerIssues, selectedProvider: chatSelection, setSelectedProvider, isLoadingModels, hasLoadedModels, modelsError, refreshModels, currentUser } = useChat();
55
55
  const { strings } = useChatConfig();
56
56
  const { common } = useStrings();
57
57
  const t = strings.modelPicker;
58
+ const selectedProvider = model ? model.value ?? null : chatSelection;
58
59
  const targetSessionFound = !!targetSession && models.some((m) => m.id.startsWith(`session:${targetSession}/`));
59
60
  const targetSessionStatus = !targetSession ? null : isLoadingModels ? "connecting" : hasLoadedModels && !targetSessionFound ? "offline" : null;
60
61
  const groups = useMemo(() => {
@@ -128,8 +129,8 @@ function ModelSelector({ targetSession }) {
128
129
  placeholder: t.search,
129
130
  items: groups,
130
131
  value: selectedProvider,
131
- onValueChange: (id) => id && setSelectedProvider(id),
132
- disabled: groups.length === 0,
132
+ onValueChange: (id) => id && (model ? model.onChange(id) : setSelectedProvider(id)),
133
+ disabled: groups.length === 0 || !!model?.disabled,
133
134
  triggerTooltip: issue ? `${issueLabel(strings.providerIssue, issue)} \u2014 ${issueDetail(strings.providerIssue, issue)}` : void 0,
134
135
  trigger: /* @__PURE__ */ jsxs("button", {
135
136
  type: "button",
@@ -0,0 +1,56 @@
1
+ import { type ComponentProps, type ReactNode } from 'react';
2
+ import type { ApprovalAnswerValue, AttachmentMeta, ChatMessage as Message } from '../types.js';
3
+ import ChatInput from './ChatInput.js';
4
+ import ChatMessageList from './ChatMessageList.js';
5
+ type ComposerProps = Omit<ComponentProps<typeof ChatInput>, 'ref' | 'onSend' | 'turn' | 'conversationId' | 'onEditLastMessage'>;
6
+ type ListProps = ComponentProps<typeof ChatMessageList>;
7
+ export interface SessionViewProps {
8
+ /** Keys the composer's draft, so each conversation or session keeps its own. */
9
+ sessionKey: string;
10
+ messages: Message[];
11
+ /** Every message branch navigation and turn attribution look through;
12
+ * defaults to `messages`. */
13
+ allMessages?: Message[];
14
+ streamingMessage?: Message | null;
15
+ queuedMessages?: Message[];
16
+ onRemoveQueued?: (id: string) => void;
17
+ canRemoveQueued?: (id: string) => boolean;
18
+ queueDelivery?: ListProps['queueDelivery'];
19
+ /** A turn the chat provider does not run, such as an agent session's: it
20
+ * drives the composer's Stop and Escape in place of the provider's stream. */
21
+ turn?: {
22
+ running: boolean;
23
+ onStop: () => void;
24
+ stopping?: boolean;
25
+ };
26
+ onSend: (content: string, attachmentIds?: string[], attachmentMeta?: AttachmentMeta) => void;
27
+ /** Resends an edited user message as a new branch. Without it, messages
28
+ * cannot be edited. */
29
+ onEdit?: (message: Message, content: string) => void;
30
+ onRegenerate?: (messageId: string) => void;
31
+ onRetry?: (messageId: string) => void;
32
+ onNavigateBranch?: (messageId: string) => void;
33
+ onApprovalAnswer?: (id: string, answer: ApprovalAnswerValue) => void;
34
+ showAuthor?: boolean;
35
+ currentUsername?: string;
36
+ /** Shown above the transcript, such as a blocked allocation or an
37
+ * unreachable machine. */
38
+ banners?: ReactNode;
39
+ /** In place of the transcript, such as a failed load with a way to retry. */
40
+ error?: ReactNode;
41
+ /** Still loading the first messages: the transcript stays empty and the
42
+ * composer disabled. */
43
+ loading?: boolean;
44
+ /** Files dropped anywhere on the view go to the composer's attachments. */
45
+ dropFiles?: boolean;
46
+ footer?: ReactNode;
47
+ label?: string;
48
+ flush?: boolean;
49
+ workingIndicator?: boolean;
50
+ composer?: ComposerProps;
51
+ }
52
+ /** One conversation or agent session: its transcript, with the composer at
53
+ * the foot of the scrolling column. The host binds its own data and actions;
54
+ * what it leaves out (editing, regenerating, branches) the view leaves out. */
55
+ export default function SessionView({ sessionKey, messages, allMessages, streamingMessage, queuedMessages, onRemoveQueued, canRemoveQueued, queueDelivery, turn, onSend, onEdit, onRegenerate, onRetry, onNavigateBranch, onApprovalAnswer, showAuthor, currentUsername, banners, error, loading, dropFiles, footer, label, flush, workingIndicator, composer, }: SessionViewProps): import("react").JSX.Element;
56
+ export {};
@@ -0,0 +1,99 @@
1
+ import { useChat } from "../core/ChatProvider.js";
2
+ import useDragDrop from "../core/useDragDrop.js";
3
+ import DragOverlay from "./DragOverlay.js";
4
+ import ChatInput from "./ChatInput.js";
5
+ import { escapeClosesLayer } from "../core/useKeyboardShortcuts.js";
6
+ import ChatMessageList from "./ChatMessageList.js";
7
+ import { jsx, jsxs } from "react/jsx-runtime";
8
+ import { useCallback, useEffect, useRef, useState } from "react";
9
+ //#region src/ai/components/SessionView.tsx
10
+ /** One conversation or agent session: its transcript, with the composer at
11
+ * the foot of the scrolling column. The host binds its own data and actions;
12
+ * what it leaves out (editing, regenerating, branches) the view leaves out. */
13
+ function SessionView({ sessionKey, messages, allMessages, streamingMessage, queuedMessages, onRemoveQueued, canRemoveQueued, queueDelivery, turn, onSend, onEdit, onRegenerate, onRetry, onNavigateBranch, onApprovalAnswer, showAuthor, currentUsername, banners, error, loading = false, dropFiles = false, footer, label, flush, workingIndicator, composer }) {
14
+ const inputRef = useRef(null);
15
+ const [editingId, setEditingId] = useState(null);
16
+ const { isStreaming: providerStreaming, stopStreaming } = useChat();
17
+ const running = turn ? turn.running : providerStreaming;
18
+ const stop = turn ? turn.onStop : stopStreaming;
19
+ useEffect(() => {
20
+ if (!running) return;
21
+ const onKeyDown = (e) => {
22
+ if (e.key === "Escape" && !e.defaultPrevented && !escapeClosesLayer(e.target)) stop();
23
+ };
24
+ window.addEventListener("keydown", onKeyDown);
25
+ return () => window.removeEventListener("keydown", onKeyDown);
26
+ }, [running, stop]);
27
+ const editable = (id) => messages.find((m) => m.id === id && m.role === "user");
28
+ const startEdit = useCallback((id) => {
29
+ if (messages.some((m) => m.id === id && m.role === "user")) setEditingId(id);
30
+ }, [messages]);
31
+ const editLast = useCallback(() => {
32
+ const last = messages.findLast((m) => m.role === "user");
33
+ if (last) setEditingId(last.id);
34
+ }, [messages]);
35
+ const onFilesDropped = useCallback((files) => {
36
+ inputRef.current?.addFiles(files);
37
+ }, []);
38
+ const { isDragging, dragHandlers } = useDragDrop({ onFilesDropped });
39
+ const input = /* @__PURE__ */ jsx(ChatInput, {
40
+ ref: inputRef,
41
+ ...composer,
42
+ onSend,
43
+ conversationId: sessionKey,
44
+ disabled: loading || !!composer?.disabled,
45
+ ...turn ? { turn } : {},
46
+ ...onEdit ? { onEditLastMessage: editLast } : {}
47
+ });
48
+ if (loading && !error) return /* @__PURE__ */ jsxs("div", {
49
+ className: "flex h-full flex-col bg-(--theme-panel-bg)",
50
+ children: [
51
+ banners,
52
+ /* @__PURE__ */ jsx("div", { className: "flex-1" }),
53
+ input
54
+ ]
55
+ });
56
+ return /* @__PURE__ */ jsx("div", {
57
+ className: "relative flex h-full bg-(--theme-panel-bg)",
58
+ children: /* @__PURE__ */ jsxs("div", {
59
+ className: "flex min-w-0 flex-1 flex-col",
60
+ ...dropFiles ? dragHandlers : {},
61
+ children: [
62
+ isDragging && dropFiles && /* @__PURE__ */ jsx(DragOverlay, { className: "rounded-lg" }),
63
+ banners,
64
+ error ?? /* @__PURE__ */ jsx(ChatMessageList, {
65
+ messages,
66
+ allMessages: allMessages ?? messages,
67
+ ...streamingMessage !== void 0 ? { streamingMessage } : {},
68
+ ...queuedMessages ? { queuedMessages } : {},
69
+ ...onRemoveQueued ? { onRemoveQueued } : {},
70
+ ...canRemoveQueued ? { canRemoveQueued } : {},
71
+ ...queueDelivery ? { queueDelivery } : {},
72
+ ...turn ? { isStreaming: turn.running } : {},
73
+ editingMessageId: editingId,
74
+ ...showAuthor !== void 0 ? { showAuthor } : {},
75
+ ...currentUsername ? { currentUsername } : {},
76
+ ...onNavigateBranch ? { onNavigateBranch } : {},
77
+ onEditMessage: onEdit ? startEdit : void 0,
78
+ onSaveEdit: (id, content) => {
79
+ const message = editable(id);
80
+ if (message && onEdit) onEdit(message, content);
81
+ setEditingId(null);
82
+ },
83
+ onCancelEdit: () => setEditingId(null),
84
+ onRegenerateMessage: onRegenerate,
85
+ onRetryMessage: onRetry,
86
+ ...onApprovalAnswer ? { onApprovalAnswer } : {},
87
+ ...footer ? { footer } : {},
88
+ ...label ? { label } : {},
89
+ ...flush ? { flush } : {},
90
+ ...workingIndicator !== void 0 ? { workingIndicator } : {},
91
+ inputElement: input
92
+ }),
93
+ error && input
94
+ ]
95
+ })
96
+ });
97
+ }
98
+ //#endregion
99
+ export { SessionView as default };
@@ -44,10 +44,6 @@ function useKeyboardShortcuts(options = {}) {
44
44
  if (!enabled) return;
45
45
  const handleKeyDown = (e) => {
46
46
  const cmdKey = isMac() ? e.metaKey : e.ctrlKey;
47
- if (e.key === "Escape") {
48
- if (!escapeClosesLayer(e.target)) handleStopGeneration();
49
- return;
50
- }
51
47
  if (cmdKey && e.shiftKey && e.key === "O") {
52
48
  e.preventDefault();
53
49
  handleNewConversation();
@@ -69,8 +65,7 @@ function useKeyboardShortcuts(options = {}) {
69
65
  }, [
70
66
  enabled,
71
67
  handleNewConversation,
72
- handleCopyLastResponse,
73
- handleStopGeneration
68
+ handleCopyLastResponse
74
69
  ]);
75
70
  return {
76
71
  getLastUserMessage,
@@ -21,6 +21,7 @@ export { type ConversationGroupKey, groupConversationsByDate, useConversationAct
21
21
  export { default as DragOverlay } from './components/DragOverlay.js';
22
22
  export { default as ModelSelector, getProviderKeyFromModelId, } from './components/ModelSelector.js';
23
23
  export { default as ProviderIssueBanner } from './components/ProviderIssueBanner.js';
24
+ export { default as SessionView, type SessionViewProps } from './components/SessionView.js';
24
25
  export { default as ShareDialog, ShareButton, } from './components/ShareDialog.js';
25
26
  export { type SlashCommandOption, type SlashMenuConfig, slashMatches, } from './components/SlashMenu.js';
26
27
  export type { ComposerPastes, PasteUploadResult, } from './components/usePasteCards.js';
package/dist/ai/index.js CHANGED
@@ -43,6 +43,7 @@ import ChatSidebar from "./components/ChatSidebar.js";
43
43
  import ChatLayout, { CHAT_COLUMN_SCOPE, ConversationLayout, DRAWER_BELOW_PX } from "./components/ChatLayout.js";
44
44
  import ChatMessage_default from "./components/ChatMessage.js";
45
45
  import ChatMessageList from "./components/ChatMessageList.js";
46
+ import SessionView from "./components/SessionView.js";
46
47
  import ChatThread from "./components/ChatThread.js";
47
48
  import { NoticeBar, NoticeCard, OutputCard } from "./ui/Notice.js";
48
- export { AGENT_COLOR_NAMES, ActivityLine, AgentMessageParts, AllocationSelector, ApprovalBlock, AttachmentManager, AttachmentUpload, BlockedGroupBanner, BranchNavigator, CHAT_COLUMN_SCOPE, ChatAdapterError, ChatEmptyState, ChatInput, ChatLayout, ChatMessageList, ChatMessage_default as ChatMessageView, ChatProvider, ChatSidebar, ChatStage, ChatThread, ComposerContext, ComposerControls, ComposerSettings, ComposerUsage, ConnectToolsLink, ConversationLayout, ConversationSidebar, DEFAULT_PERMISSION_MODE, DRAWER_BELOW_PX, DragOverlay, FOCUS_SIDEBAR_SEARCH_EVENT, INTERRUPTED_NOTICE, KeyboardShortcutsProvider, MAX_EDIT_DIFF_LINES, MAX_WRITE_DIFF_LINES, ManageProvidersLink, ModelSelector, NAMED_PERMISSION_MODES, NoticeBar, NoticeCard, OutputCard, PermissionPicker, ProviderIssueBanner, RenameDialog, ShareButton, ShareDialog, SidebarGroupHeading, SidebarPanel, SidebarRailItem, SidebarRow, SidebarRowTitle, SidebarToggle, agentColorHex, agentTypeLabel, applyPartDelta, askQuestionFromArgs, bashExitCode, chatReducer, clampPermissionMode, classifyPseudoUserMessage, clip, computeEditDiff, computeWriteRows, defaultChatStrings, defaultToolStrings, editSummary, finalizeParts, firstNonEmptyLine, fullToolArgs, getGreeting, getProviderKeyFromModelId, groupConversationsByDate, hiddenTranscriptTool, initialState, interruptionNotice, isEditDiffTool, isGroupableTool, isMac, isNamedPermissionMode, isOrgModel, languageForPath, lineDelta, parseEditArgs, parseSubagentNotice, pasteInlineMaxBytes, permissionModesUpTo, planFromArgs, providerIssueFor, resolveChatConfig, resultFailed, rollupSentence, sanitizeLabel, sanitizePanelText, sidebarDrawerProps, slashMatches, subagentDeliveryLine, summarizeToolArgs, taskCallFromArgs, thinkingHeading, tokenizeDiffLines, toolHeaderFor, toolSummary, useChat, useChatConfig, useChatStream, useConversationActions, useDragDrop, useKeyboardShortcuts, useRowDialogs, wordEmphasisRanges };
49
+ export { AGENT_COLOR_NAMES, ActivityLine, AgentMessageParts, AllocationSelector, ApprovalBlock, AttachmentManager, AttachmentUpload, BlockedGroupBanner, BranchNavigator, CHAT_COLUMN_SCOPE, ChatAdapterError, ChatEmptyState, ChatInput, ChatLayout, ChatMessageList, ChatMessage_default as ChatMessageView, ChatProvider, ChatSidebar, ChatStage, ChatThread, ComposerContext, ComposerControls, ComposerSettings, ComposerUsage, ConnectToolsLink, ConversationLayout, ConversationSidebar, DEFAULT_PERMISSION_MODE, DRAWER_BELOW_PX, DragOverlay, FOCUS_SIDEBAR_SEARCH_EVENT, INTERRUPTED_NOTICE, KeyboardShortcutsProvider, MAX_EDIT_DIFF_LINES, MAX_WRITE_DIFF_LINES, ManageProvidersLink, ModelSelector, NAMED_PERMISSION_MODES, NoticeBar, NoticeCard, OutputCard, PermissionPicker, ProviderIssueBanner, RenameDialog, SessionView, ShareButton, ShareDialog, SidebarGroupHeading, SidebarPanel, SidebarRailItem, SidebarRow, SidebarRowTitle, SidebarToggle, agentColorHex, agentTypeLabel, applyPartDelta, askQuestionFromArgs, bashExitCode, chatReducer, clampPermissionMode, classifyPseudoUserMessage, clip, computeEditDiff, computeWriteRows, defaultChatStrings, defaultToolStrings, editSummary, finalizeParts, firstNonEmptyLine, fullToolArgs, getGreeting, getProviderKeyFromModelId, groupConversationsByDate, hiddenTranscriptTool, initialState, interruptionNotice, isEditDiffTool, isGroupableTool, isMac, isNamedPermissionMode, isOrgModel, languageForPath, lineDelta, parseEditArgs, parseSubagentNotice, pasteInlineMaxBytes, permissionModesUpTo, planFromArgs, providerIssueFor, resolveChatConfig, resultFailed, rollupSentence, sanitizeLabel, sanitizePanelText, sidebarDrawerProps, slashMatches, subagentDeliveryLine, summarizeToolArgs, taskCallFromArgs, thinkingHeading, tokenizeDiffLines, toolHeaderFor, toolSummary, useChat, useChatConfig, useChatStream, useConversationActions, useDragDrop, useKeyboardShortcuts, useRowDialogs, wordEmphasisRanges };
@@ -1,3 +1,10 @@
1
+ /** A turn setting a session owns, shown in place of the chat's own selection. */
2
+ export interface BoundSetting {
3
+ value: string | null | undefined;
4
+ onChange: (value: string) => void;
5
+ /** The session cannot take a change right now, such as while it is unreachable. */
6
+ disabled?: boolean | undefined;
7
+ }
1
8
  export interface ChatUser {
2
9
  id: string;
3
10
  username: string;
package/dist/icons.d.ts CHANGED
@@ -62,6 +62,7 @@ export declare const ConnectIcon: IconType;
62
62
  export declare const ContractIcon: IconType;
63
63
  export declare const CopyIcon: IconType;
64
64
  export declare const CustomizeIcon: IconType;
65
+ export declare const DefaultIcon: IconType;
65
66
  export declare const DefinitionIcon: IconType;
66
67
  export declare const DeprovisionIcon: IconType;
67
68
  export declare const DesktopIcon: IconType;
@@ -175,6 +176,7 @@ export declare const NotRunningIcon: IconType;
175
176
  export declare const OnboardingIcon: IconType;
176
177
  export declare const OpenInNewGraphIcon: IconType;
177
178
  export declare const OrganizationIcon: IconType;
179
+ export declare const OwnerIcon: IconType;
178
180
  export declare const PartnerIcon: IconType;
179
181
  export declare const PasswordIcon: IconType;
180
182
  export declare const PauseIcon: IconType;
@@ -269,6 +271,7 @@ export declare const UserIcon: IconType;
269
271
  export declare const UsersIcon: IconType;
270
272
  export declare const UserWorkspaceIcon: IconType;
271
273
  export declare const VariableIcon: IconType;
274
+ export declare const VerifiedIcon: IconType;
272
275
  export declare const VideoIcon: IconType;
273
276
  export declare const WarningIcon: IconType;
274
277
  export declare const WebhookIcon: IconType;
package/dist/icons.js CHANGED
@@ -84,6 +84,7 @@ var ConnectIcon = /* @__PURE__ */ drawn("M5.5 2v3M10.5 2v3M3.5 5h9v2.5a4.5 4.5 0
84
84
  var ContractIcon = /* @__PURE__ */ drawn("M12.5 6.25V4.75L9.5 1.75h-5a1 1 0 0 0-1 1v10.5a1 1 0 0 0 1 1h2.25M9.5 1.75v3h3M5.5 11h1.5M8.25 14.25l.5-2.25 4-4a1.06 1.06 0 0 1 1.5 1.5l-4 4Z");
85
85
  var CopyIcon = /* @__PURE__ */ drawn("M6.5 5.5h6a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1h-6a1 1 0 0 1-1-1v-6a1 1 0 0 1 1-1ZM10.5 5.5v-2a1 1 0 0 0-1-1h-6a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2");
86
86
  var CustomizeIcon = /* @__PURE__ */ drawn("M8 14A6 6 0 1 1 14 8c0 1.5-1.25 2.25-2.5 2.25H10.5a1.5 1.5 0 0 0-1.1 2.5c.6.65.1 1.25-1.4 1.25ZM5 7.4a0.6 0.6 0 1 0 0 1.2a0.6 0.6 0 0 0 0-1.2ZM6.25 4.15a0.6 0.6 0 1 0 0 1.2a0.6 0.6 0 0 0 0-1.2ZM9.75 4.15a0.6 0.6 0 1 0 0 1.2a0.6 0.6 0 0 0 0-1.2Z");
87
+ var DefaultIcon = /* @__PURE__ */ drawn("M4.5 2.25h7v11.5L8 11.25l-3.5 2.5Z");
87
88
  var DefinitionIcon = /* @__PURE__ */ drawn("M9.5 1.75h-5a1 1 0 0 0-1 1v10.5a1 1 0 0 0 1 1h7a1 1 0 0 0 1-1V4.75ZM9.5 1.75v3h3M5.75 7.25h2.5M7.75 9.75h2.5M7.75 12.25h1.5");
88
89
  var DeprovisionIcon = /* @__PURE__ */ drawn("M3.5 2.5h9a1 1 0 0 1 1 1v2.5a1 1 0 0 1-1 1h-9a1 1 0 0 1-1-1v-2.5a1 1 0 0 1 1-1ZM5 4.75h.01M3.5 9h4.25a1 1 0 0 1 1 1v2.5a1 1 0 0 1-1 1h-4.25a1 1 0 0 1-1-1v-2.5a1 1 0 0 1 1-1ZM5 11.25h.01M10.25 12.25h4");
89
90
  var DesktopIcon = /* @__PURE__ */ drawn("M3.5 2.5h9a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1h-9a1 1 0 0 1-1-1v-6a1 1 0 0 1 1-1ZM5.5 13.5h5M8 10.5v3");
@@ -197,6 +198,7 @@ var NotRunningIcon = /* @__PURE__ */ drawn("M8 14A6 6 0 1 0 8 2a6 6 0 0 0 0 12Z"
197
198
  var OnboardingIcon = /* @__PURE__ */ drawn("M1.75 14h3.5v-3.5h3.5V7h3.5V2.5M9.75 4.75 12.25 2.25l2.5 2.5");
198
199
  var OpenInNewGraphIcon = /* @__PURE__ */ drawn("M7 2h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1ZM3 10h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1v-2a1 1 0 0 1 1-1ZM8 6v2M4 10V8.75A.75.75 0 0 1 4.75 8h4.75M11.25 10.25h3v3M14.25 10.25l-4 4");
199
200
  var OrganizationIcon = /* @__PURE__ */ drawn("M5 13.75V3.25a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v10.5M5 7H3.25a1 1 0 0 0-1 1v4.75a1 1 0 0 0 1 1h9.5a1 1 0 0 0 1-1V6a1 1 0 0 0-1-1H11M7 5.25h2M7 8.25h2M7 13.75v-1.75a1 1 0 0 1 2 0v1.75");
201
+ var OwnerIcon = /* @__PURE__ */ drawn("M6.5 7.75a2.75 2.75 0 1 0 0-5.5 2.75 2.75 0 0 0 0 5.5ZM2 13.75c.55-2.35 2.4-3.75 4.5-3.75.8 0 1.5.15 2.1.45M11.5 12.75a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3ZM12.6 12.6l1.9 1.9M13.75 13.75l-1 1");
200
202
  var PartnerIcon = /* @__PURE__ */ drawn("M2.5 2.5 2 9.25l3.9 3.9a.9.9 0 0 0 1.8-1.8M2.5 3.25h4.75M13.5 2.5l.5 6.75h-1.25M9.25 9.25l1.5 1.5a.9.9 0 0 0 1.8-1.8l-2.35-2.35a1.8 1.8 0 0 0-2.55 0l-.55.55a.9.9 0 0 1-1.8-1.8l1.7-1.7a3.5 3.5 0 0 1 4.25-.5l.3.15a1.2 1.2 0 0 0 .85.15l1.1-.25");
201
203
  var PasswordIcon = /* @__PURE__ */ drawn("M2.9 7.25a0.6 0.6 0 1 0 1.2 0a0.6 0.6 0 1 0 -1.2 0M7.4 7.25a0.6 0.6 0 1 0 1.2 0a0.6 0.6 0 1 0 -1.2 0M11.9 7.25a0.6 0.6 0 1 0 1.2 0a0.6 0.6 0 1 0 -1.2 0M1.75 11.5h12.5");
202
204
  var PauseIcon = /* @__PURE__ */ drawn("M5.5 3.25v9.5M10.5 3.25v9.5");
@@ -291,6 +293,7 @@ var UserIcon = /* @__PURE__ */ drawn("M8 8a2.75 2.75 0 1 0 0-5.5A2.75 2.75 0 0 0
291
293
  var UsersIcon = /* @__PURE__ */ drawn("M6 7.5a2.25 2.25 0 1 0 0-4.5 2.25 2.25 0 0 0 0 4.5ZM1.75 13c.5-2 2.1-3.25 4.25-3.25S9.75 11 10.25 13M10.5 3.1a2.25 2.25 0 0 1 0 4.3M11.75 9.9c1.2.45 2.1 1.5 2.5 3.1");
292
294
  var UserWorkspaceIcon = /* @__PURE__ */ drawn("M3.5 2.5h9a1 1 0 0 1 1 1v9a1 1 0 0 1-1 1h-9a1 1 0 0 1-1-1v-9a1 1 0 0 1 1-1ZM5 5.5l2 2-2 2M8 10.5h3");
293
295
  var VariableIcon = /* @__PURE__ */ drawn("M4.75 2.5C3.25 4 2.5 6 2.5 8s.75 4 2.25 5.5M11.25 2.5c1.5 1.5 2.25 3.5 2.25 5.5s-.75 4-2.25 5.5M6 6l4 4M10 6l-4 4");
296
+ var VerifiedIcon = /* @__PURE__ */ drawn("M8 1.75L9.91 3.38L12.42 3.58L12.62 6.09L14.25 8L12.62 9.91L12.42 12.42L9.91 12.62L8 14.25L6.09 12.62L3.58 12.42L3.38 9.91L1.75 8L3.38 6.09L3.58 3.58L6.09 3.38ZM5.5 8.25 7.15 9.9 10.5 6.25");
294
297
  var VideoIcon = /* @__PURE__ */ drawn("M2.75 4h6.75a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1H2.75a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1ZM10.5 9l3.15 2.1a.4.4 0 0 0 .6-.35v-5.5a.4.4 0 0 0-.6-.35L10.5 7");
295
298
  var WarningIcon = /* @__PURE__ */ drawn("M7.13 2.5a1 1 0 0 1 1.74 0l5.5 9.75a1 1 0 0 1-.87 1.5H2.5a1 1 0 0 1-.87-1.5ZM8 6.5v2.75M8 11.25h.01");
296
299
  var WebhookIcon = /* @__PURE__ */ drawn("M11.75 11.13H8.01c-.69 0-1.22.59-1.55 1.19A2.5 2.5 0 0 1 1.75 11.13c.01-.44.13-.88.36-1.25M4.25 11.13l1.96-3.61c.33-.61.06-1.36-.31-1.94a2.5 2.5 0 1 1 4.31-2.54M8 4.25l1.96 3.58c.33.61 1.1.8 1.79.8a2.5 2.5 0 0 1 0 5");
@@ -308,4 +311,4 @@ var PowershellIcon = CommandShellIcon;
308
311
  /** @deprecated Renamed QuickActionIcon, which says what it means. */
309
312
  var ZapIcon = QuickActionIcon;
310
313
  //#endregion
311
- export { APIIcon, AccessIcon, AddAllocationIcon, AddIcon, AddProjectIcon, AddUserIcon, AgentIcon, AiProviderIcon, AllocationIcon, ArchiveIcon, ArrowDownIcon, ArrowLeftIcon, ArrowRightIcon, ArrowUpIcon, ArticleIcon, AttachmentIcon, AuthenticationIcon, BannerIcon, BillingIcon, BriefcaseIcon, BucketIcon, BuildWorkflowIcon, CalendarIcon, CancelIcon, CelebrateIcon, CertificateIcon, ChangesRequestedIcon, ChartIcon, ChatIcon, CheckIcon, ChevronDoubleDownIcon, ChevronDoubleUpIcon, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, ChevronUpIcon, ClipboardCheckIcon, ClockIcon, CloseIcon, CloudIcon, CloudNetworkIcon, ClusterIcon, CodeIcon, CollapseIcon, ColumnsIcon, CommandShellIcon, CommentIcon, CommitIcon, ComputeIcon, ConfigIcon, ConnectIcon, ContractIcon, CopyIcon, CustomizeIcon, DefinitionIcon, DeprovisionIcon, DesktopIcon, DestroyIcon, DeviceIcon, DirectoryIcon, DirectorySyncIcon, DisableCostIcon, DisableUserIcon, DisconnectIcon, DiskIcon, DisplayIcon, DownloadIcon, DragHandleIcon, DuplicateIcon, EditIcon, EditorIcon, EducationIcon, EnableCostIcon, EnableUserIcon, EndpointIcon, ErrorCheckmark, ErrorIcon, EventsIcon, ExpandIcon, ExpandVerticalIcon, ExpiredIcon, ExpiringIcon, ExpressionIcon, ExternalLinkIcon, EyeIcon, EyeOffIcon, FailIcon, FavoriteIcon, FavoriteOutlineIcon, FeaturedIcon, FileIcon, FileTextIcon, FilesIcon, FilesystemIcon, FilterClearIcon, FilterIcon, FlaggedIcon, FlaskIcon, FolderIcon, FolderOpenIcon, FolderTreeIcon, ForbiddenIcon, ForkIcon, GearsIcon, GlobeIcon, GovernmentIcon, GraphIcon, GridIcon, HealthMonitoringIcon, HelpIcon, HistoryIcon, HomeIcon, IdCardIcon, ImageIcon, ImpersonateIcon, InboxIcon, IndexIcon, InfoIcon, InfrastructureLayersIcon, InputFormIcon, InstallIcon, InstanceIcon, InstanceTypeIcon, IpAddressIcon, IssueIcon, JobIcon, JsonIcon, KeyIcon, KeyboardIcon, KubernetesNamespaceIcon, LanguageIcon, LegalIcon, LibraryIcon, LicenseIcon, LinkIcon, ListViewIcon, LoadingIcon, LockIcon, LogsIcon, MFAIcon, MachineImageIcon, MailFailedIcon, MailIcon, MailVerifiedIcon, MapPinIcon, MarketplaceIcon, MatrixIcon, MegaphoneIcon, MigrationIcon, MinimizeIcon, MinusIcon, MlIcon, MoneyIcon, MoonIcon, MoreIcon, MusicIcon, MuteIcon, NamespaceIcon, NavigationIcon, NetworkInterfaceIcon, NetworkShareIcon, NewChatIcon, NodeIcon, NotRunningIcon, NotebookIcon, NotificationIcon, OnboardingIcon, OpenInNewGraphIcon, OrganizationIcon, PartnerIcon, PasswordIcon, PauseIcon, PdfIcon, PendingIcon, PhoneIcon, PieChartIcon, PinFilledIcon, PinIcon, PowerIcon, PowershellIcon, PreviewIcon, PrintIcon, ProjectIcon, ProvisionIcon, PublishIcon, PullRequestIcon, QRCodeIcon, QueueIcon, QuickActionIcon, QuotaIcon, RedoIcon, RefreshIcon, ReleaseIcon, RemoveIcon, RemoveUserIcon, RenameIcon, RenewIcon, ReportIcon, ResetIcon, ResetLayoutIcon, ResourceGroupIcon, ResourceIcon, RestartIcon, RestoreIcon, RetryIcon, RevokeIcon, RoleIcon, RollbackIcon, RunWorkflowIcon, RunningIcon, RunsIcon, SaveIcon, SchedulerIcon, ScriptIcon, SearchIcon, SendIcon, ServiceIcon, SessionIcon, SettingsIcon, ShareIcon, SharedIcon, ShieldIcon, ShieldOffIcon, ShrinkIcon, SidebarCloseIcon, SidebarIcon, SidebarOpenIcon, SignInIcon, SignOutIcon, SkipIcon, SnapshotIcon, SortDownIcon, SortUnsortedIcon, SortUpIcon, SparklesIcon, SplitIcon, SpreadsheetIcon, StartIcon, StopIcon, StorageIcon, SubdomainIcon, SuccessCheckmark, SuccessIcon, SummaryIcon, SunIcon, SupportIcon, SwapIcon, TagIcon, TerminalIcon, ThinkingIcon, TodoIcon, TokenIcon, ToolsIcon, TrashIcon, TunnelIcon, UndoIcon, UnfavoriteIcon, UnlinkIcon, UnmuteIcon, UnsplitIcon, UploadIcon, UserIcon, UserWorkspaceIcon, UsersIcon, VariableIcon, VideoIcon, WarningIcon, WebhookIcon, WorkerIcon, WorkflowIcon, WorkloadIcon, WorkspaceMountIcon, ZapIcon, ZipIcon, ZoomInIcon, ZoomOutIcon };
314
+ export { APIIcon, AccessIcon, AddAllocationIcon, AddIcon, AddProjectIcon, AddUserIcon, AgentIcon, AiProviderIcon, AllocationIcon, ArchiveIcon, ArrowDownIcon, ArrowLeftIcon, ArrowRightIcon, ArrowUpIcon, ArticleIcon, AttachmentIcon, AuthenticationIcon, BannerIcon, BillingIcon, BriefcaseIcon, BucketIcon, BuildWorkflowIcon, CalendarIcon, CancelIcon, CelebrateIcon, CertificateIcon, ChangesRequestedIcon, ChartIcon, ChatIcon, CheckIcon, ChevronDoubleDownIcon, ChevronDoubleUpIcon, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, ChevronUpIcon, ClipboardCheckIcon, ClockIcon, CloseIcon, CloudIcon, CloudNetworkIcon, ClusterIcon, CodeIcon, CollapseIcon, ColumnsIcon, CommandShellIcon, CommentIcon, CommitIcon, ComputeIcon, ConfigIcon, ConnectIcon, ContractIcon, CopyIcon, CustomizeIcon, DefaultIcon, DefinitionIcon, DeprovisionIcon, DesktopIcon, DestroyIcon, DeviceIcon, DirectoryIcon, DirectorySyncIcon, DisableCostIcon, DisableUserIcon, DisconnectIcon, DiskIcon, DisplayIcon, DownloadIcon, DragHandleIcon, DuplicateIcon, EditIcon, EditorIcon, EducationIcon, EnableCostIcon, EnableUserIcon, EndpointIcon, ErrorCheckmark, ErrorIcon, EventsIcon, ExpandIcon, ExpandVerticalIcon, ExpiredIcon, ExpiringIcon, ExpressionIcon, ExternalLinkIcon, EyeIcon, EyeOffIcon, FailIcon, FavoriteIcon, FavoriteOutlineIcon, FeaturedIcon, FileIcon, FileTextIcon, FilesIcon, FilesystemIcon, FilterClearIcon, FilterIcon, FlaggedIcon, FlaskIcon, FolderIcon, FolderOpenIcon, FolderTreeIcon, ForbiddenIcon, ForkIcon, GearsIcon, GlobeIcon, GovernmentIcon, GraphIcon, GridIcon, HealthMonitoringIcon, HelpIcon, HistoryIcon, HomeIcon, IdCardIcon, ImageIcon, ImpersonateIcon, InboxIcon, IndexIcon, InfoIcon, InfrastructureLayersIcon, InputFormIcon, InstallIcon, InstanceIcon, InstanceTypeIcon, IpAddressIcon, IssueIcon, JobIcon, JsonIcon, KeyIcon, KeyboardIcon, KubernetesNamespaceIcon, LanguageIcon, LegalIcon, LibraryIcon, LicenseIcon, LinkIcon, ListViewIcon, LoadingIcon, LockIcon, LogsIcon, MFAIcon, MachineImageIcon, MailFailedIcon, MailIcon, MailVerifiedIcon, MapPinIcon, MarketplaceIcon, MatrixIcon, MegaphoneIcon, MigrationIcon, MinimizeIcon, MinusIcon, MlIcon, MoneyIcon, MoonIcon, MoreIcon, MusicIcon, MuteIcon, NamespaceIcon, NavigationIcon, NetworkInterfaceIcon, NetworkShareIcon, NewChatIcon, NodeIcon, NotRunningIcon, NotebookIcon, NotificationIcon, OnboardingIcon, OpenInNewGraphIcon, OrganizationIcon, OwnerIcon, PartnerIcon, PasswordIcon, PauseIcon, PdfIcon, PendingIcon, PhoneIcon, PieChartIcon, PinFilledIcon, PinIcon, PowerIcon, PowershellIcon, PreviewIcon, PrintIcon, ProjectIcon, ProvisionIcon, PublishIcon, PullRequestIcon, QRCodeIcon, QueueIcon, QuickActionIcon, QuotaIcon, RedoIcon, RefreshIcon, ReleaseIcon, RemoveIcon, RemoveUserIcon, RenameIcon, RenewIcon, ReportIcon, ResetIcon, ResetLayoutIcon, ResourceGroupIcon, ResourceIcon, RestartIcon, RestoreIcon, RetryIcon, RevokeIcon, RoleIcon, RollbackIcon, RunWorkflowIcon, RunningIcon, RunsIcon, SaveIcon, SchedulerIcon, ScriptIcon, SearchIcon, SendIcon, ServiceIcon, SessionIcon, SettingsIcon, ShareIcon, SharedIcon, ShieldIcon, ShieldOffIcon, ShrinkIcon, SidebarCloseIcon, SidebarIcon, SidebarOpenIcon, SignInIcon, SignOutIcon, SkipIcon, SnapshotIcon, SortDownIcon, SortUnsortedIcon, SortUpIcon, SparklesIcon, SplitIcon, SpreadsheetIcon, StartIcon, StopIcon, StorageIcon, SubdomainIcon, SuccessCheckmark, SuccessIcon, SummaryIcon, SunIcon, SupportIcon, SwapIcon, TagIcon, TerminalIcon, ThinkingIcon, TodoIcon, TokenIcon, ToolsIcon, TrashIcon, TunnelIcon, UndoIcon, UnfavoriteIcon, UnlinkIcon, UnmuteIcon, UnsplitIcon, UploadIcon, UserIcon, UserWorkspaceIcon, UsersIcon, VariableIcon, VerifiedIcon, VideoIcon, WarningIcon, WebhookIcon, WorkerIcon, WorkflowIcon, WorkloadIcon, WorkspaceMountIcon, ZapIcon, ZipIcon, ZoomInIcon, ZoomOutIcon };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parallelworks/ui",
3
- "version": "0.68.0",
3
+ "version": "0.70.0",
4
4
  "description": "React UI components: a theme contract, icons, brand logos, primitives, lists, forms, a job graph, a code editor, a log viewer, a file explorer and an AI chat, each on its own subpath",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {