@jini-ai/chat 0.6.15-rc.2 → 0.6.15
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/core/accepted-input.js +20 -11
- package/dist/core/ag-ui/entry.js +3 -1
- package/dist/core/agent-plugin-chat-state.js +3 -1
- package/dist/core/assistant-client/ag-ui-transport.js +1 -1
- package/dist/core/assistant-client/attachment-liveness.js +1 -1
- package/dist/core/assistant-client/durable-run-subscription.js +2 -1
- package/dist/core/assistant-client/transport.js +13 -7
- package/dist/core/assistant-content.js +2 -1
- package/dist/core/composer-history.js +2 -1
- package/dist/core/durable-projection.js +2 -1
- package/dist/core/durable-runs/continuation.js +2 -1
- package/dist/core/messages.d.ts +5 -1
- package/dist/core/partial-json.js +18 -9
- package/dist/core/persistence/title.d.ts +1 -1
- package/dist/core/persistence/title.js +25 -7
- package/dist/core/question-form/normalize.js +1 -1
- package/dist/core/question-form/scan.js +25 -15
- package/dist/core/question-form/secret-answers.js +2 -1
- package/dist/core/run-activity.js +8 -4
- package/dist/core/run-events/entry.js +6 -2
- package/dist/core/transcript.js +13 -6
- package/dist/core/turn-usage.js +7 -2
- package/dist/core/user-text-redaction.d.ts +2 -5
- package/dist/core/user-text-redaction.js +3 -3
- package/dist/core/util/manifest.js +13 -11
- package/dist/core/util/markdown-context.d.ts +14 -0
- package/dist/core/util/markdown-context.js +42 -4
- package/dist/core/util/markup-attributes.js +1 -1
- package/dist/core/util/parser.js +7 -7
- package/dist/core/util/pointer.js +22 -6
- package/dist/core/util/recover.js +5 -8
- package/dist/core/util/strip.js +12 -15
- package/dist/core/util/validate.js +30 -18
- package/dist/embed-widget/browser/lazy-loader.js +16 -12
- package/dist/embed-widget/react/dialog.hooks.js +2 -2
- package/dist/embed-widget/react/embed.js +1 -1
- package/dist/embed-widget/react/header.hooks.js +1 -1
- package/dist/embed-widget/transports/fetch-sse.js +2 -1
- package/dist/embed-widget/vanilla/index.js +19 -12
- package/dist/embed-widget/vanilla/state.js +4 -2
- package/dist/react/components/AttachmentPreviewModal.hooks.js +2 -1
- package/dist/react/components/ChatSettingsDialog.js +18 -9
- package/dist/react/components/Composer.js +5 -4
- package/dist/react/components/ConversationList.js +5 -4
- package/dist/react/components/Markdown.js +29 -26
- package/dist/react/components/McpUiSurfaceCard.js +2 -1
- package/dist/react/components/MessageList.hooks.js +3 -2
- package/dist/react/components/MessageRow.js +23 -7
- package/dist/react/components/MessageRow.usage.js +3 -1
- package/dist/react/components/QuestionForm.js +4 -5
- package/dist/react/components/SentAttachment.js +4 -1
- package/dist/react/components/TodoCard.js +9 -1
- package/dist/react/components/ToolCard.js +8 -7
- package/dist/react/components/composer-discovery.js +8 -8
- package/dist/react/features/chat-pane/components/AgentPluginUsage.js +1 -2
- package/dist/react/features/chat-pane/components/AgentRuntimePicker.d.ts +1 -1
- package/dist/react/features/chat-pane/components/AgentRuntimePicker.js +15 -5
- package/dist/react/features/chat-pane/components/ChatPane.js +4 -2
- package/dist/react/features/chat-pane/components/RuntimeDropUp.js +1 -1
- package/dist/react/features/chat-pane/create-daemon-attachment-uploader.js +1 -1
- package/dist/react/features/chat-pane/hooks/useAgentRuntimePicker.hooks.js +2 -2
- package/dist/react/features/chat-pane/hooks/useChatPane.hooks.js +4 -2
- package/dist/react/features/chat-pane/hooks/useChatPaneAgentControl.hooks.js +2 -2
- package/dist/react/features/chat-pane/hooks/useChatPaneControlsHeight.hooks.js +1 -1
- package/dist/react/features/chat-pane/hooks/useChatPaneRuntimeInventory.hooks.js +2 -2
- package/dist/react/features/chat-pane/hooks/useChatPaneWorkingDirectory.hooks.js +2 -2
- package/dist/react/features/chat-pane/hooks/useRuntimeDropUp.hooks.js +2 -2
- package/dist/react/features/chat-pane/model-options.js +4 -2
- package/dist/react/features/chat-pane/styles.d.ts +1 -1
- package/dist/react/features/chat-pane/styles.js +26 -3
- package/dist/react/features/chat-pane/types.d.ts +8 -0
- package/dist/react/hooks/assistant-chats.js +22 -8
- package/dist/react/hooks/useArtifactStream.js +2 -1
- package/dist/react/hooks/useComposer.js +2 -2
- package/dist/react/hooks/useComposerHistoryKeys.hooks.js +2 -2
- package/dist/react/hooks/useConversation.js +9 -4
- package/dist/react/hooks/useExtEventGroups.js +4 -2
- package/dist/react/hooks/useLatestOperation.js +2 -1
- package/dist/react/hooks/useQuestionForms.js +32 -22
- package/dist/react/hooks/useRunStream.js +4 -2
- package/dist/react/message-blocks.js +4 -2
- package/dist/react/styles/reference.css +9 -0
- package/dist/server/durable-runs/recover.js +13 -5
- package/dist/server/run-finalizer/entry.js +1 -0
- package/dist/store/runtime/chat-history-store.js +9 -3
- package/dist/store/runtime/durable-run-store.js +34 -24
- package/dist/store/runtime/run-ledger.js +7 -4
- package/dist/store/sql/boundary.js +3 -1
- package/dist/store/sql/cursor.js +8 -3
- package/dist/store/sql/store.js +36 -28
- package/package.json +15 -15
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
const RUNNING_TITLE_CLASS = ' shimmer-text';
|
|
2
3
|
/**
|
|
3
4
|
* @module ToolCard
|
|
4
5
|
*
|
|
@@ -146,19 +147,19 @@ function DelegatedToolCard({ name, input, result, runStreaming, runSucceeded })
|
|
|
146
147
|
const args = isDelegatedWrapperToolName({ name: name }) ? wrapper.input : input;
|
|
147
148
|
const target = primaryTarget(args);
|
|
148
149
|
const isRunning = runStreaming && !result;
|
|
149
|
-
return (_jsx(ExpandableCard, { className: "op-jini-tool", call: { input: args ?? {}, result: result, runStreaming: runStreaming, runSucceeded: runSucceeded }, head: _jsxs(_Fragment, { children: [_jsx(ResultBadge, { result: result, runStreaming: runStreaming, runSucceeded: runSucceeded }), _jsxs("span", { className: `op-title${isRunning ?
|
|
150
|
+
return (_jsx(ExpandableCard, { className: "op-jini-tool", call: { input: args ?? {}, result: result, runStreaming: runStreaming, runSucceeded: runSucceeded }, head: _jsxs(_Fragment, { children: [_jsx(ResultBadge, { result: result, runStreaming: runStreaming, runSucceeded: runSucceeded }), _jsxs("span", { className: `op-title${isRunning ? RUNNING_TITLE_CLASS : ''}`, children: [t('Tool call'), " \u00B7 ", humanizeToolId(toolId)] }), target ? _jsx("span", { className: "op-meta", children: headSummary({ text: target }) }) : null] }), after: _jsx(FileErrorDetail, { result: result }), children: _jsx(ToolCallDetail, { input: args ?? {}, result: result, runStreaming: runStreaming, runSucceeded: runSucceeded, children: _jsx(ToolResultMedia, { result: result }) }) }));
|
|
150
151
|
}
|
|
151
152
|
function SearchToolsCard({ input, result, runStreaming, runSucceeded }) {
|
|
152
153
|
const t = useT();
|
|
153
154
|
const obj = (input ?? {});
|
|
154
155
|
const isRunning = runStreaming && !result;
|
|
155
|
-
return (_jsx(ExpandableCard, { className: "op-jini-tool", call: { input: input, result: result, runStreaming: runStreaming, runSucceeded: runSucceeded }, head: _jsxs(_Fragment, { children: [_jsx(ResultBadge, { result: result, runStreaming: runStreaming, runSucceeded: runSucceeded }), _jsx("span", { className: `op-title${isRunning ?
|
|
156
|
+
return (_jsx(ExpandableCard, { className: "op-jini-tool", call: { input: input, result: result, runStreaming: runStreaming, runSucceeded: runSucceeded }, head: _jsxs(_Fragment, { children: [_jsx(ResultBadge, { result: result, runStreaming: runStreaming, runSucceeded: runSucceeded }), _jsx("span", { className: `op-title${isRunning ? RUNNING_TITLE_CLASS : ''}`, children: t('Search tools') }), obj.query ? _jsx("span", { className: "op-meta", children: obj.query }) : null] }), after: _jsx(FileErrorDetail, { result: result }), children: _jsx(ToolCallDetail, { input: input, result: result, runStreaming: runStreaming, runSucceeded: runSucceeded }) }));
|
|
156
157
|
}
|
|
157
158
|
function DescribeToolCard({ input, result, runStreaming, runSucceeded }) {
|
|
158
159
|
const t = useT();
|
|
159
160
|
const obj = (input ?? {});
|
|
160
161
|
const isRunning = runStreaming && !result;
|
|
161
|
-
return (_jsx(ExpandableCard, { className: "op-jini-tool", call: { input: input, result: result, runStreaming: runStreaming, runSucceeded: runSucceeded }, head: _jsxs(_Fragment, { children: [_jsx(ResultBadge, { result: result, runStreaming: runStreaming, runSucceeded: runSucceeded }), _jsx("span", { className: `op-title${isRunning ?
|
|
162
|
+
return (_jsx(ExpandableCard, { className: "op-jini-tool", call: { input: input, result: result, runStreaming: runStreaming, runSucceeded: runSucceeded }, head: _jsxs(_Fragment, { children: [_jsx(ResultBadge, { result: result, runStreaming: runStreaming, runSucceeded: runSucceeded }), _jsx("span", { className: `op-title${isRunning ? RUNNING_TITLE_CLASS : ''}`, children: t('Describe tool') }), obj.id ? _jsx("span", { className: "op-meta", children: obj.id }) : null] }), after: _jsx(FileErrorDetail, { result: result }), children: _jsx(ToolCallDetail, { input: input, result: result, runStreaming: runStreaming, runSucceeded: runSucceeded }) }));
|
|
162
163
|
}
|
|
163
164
|
function OpenInTabButton({ filePath, ctx }) {
|
|
164
165
|
const t = useT();
|
|
@@ -184,7 +185,7 @@ function FileWriteCard({ input, result, runStreaming, runSucceeded, ctx }) {
|
|
|
184
185
|
const baseName = file.split('/').pop();
|
|
185
186
|
const lines = typeof obj.content === 'string' ? obj.content.split('\n').length : null;
|
|
186
187
|
const isRunning = runStreaming && !result;
|
|
187
|
-
return (_jsxs(ExpandableCard, { className: "op-file", call: { input: input, result: result, runStreaming: runStreaming, runSucceeded: runSucceeded }, head: _jsxs(_Fragment, { children: [_jsx(ResultBadge, { result: result, runStreaming: runStreaming, runSucceeded: runSucceeded }), _jsx("span", { className: `op-title${isRunning ?
|
|
188
|
+
return (_jsxs(ExpandableCard, { className: "op-file", call: { input: input, result: result, runStreaming: runStreaming, runSucceeded: runSucceeded }, head: _jsxs(_Fragment, { children: [_jsx(ResultBadge, { result: result, runStreaming: runStreaming, runSucceeded: runSucceeded }), _jsx("span", { className: `op-title${isRunning ? RUNNING_TITLE_CLASS : ''}`, children: t('Write') }), _jsxs("span", { className: "op-meta", children: [baseName, lines !== null ? ` · ${t('{n} lines', { n: lines })}` : ''] })] }), after: _jsx(FileErrorDetail, { result: result }), children: [_jsxs("div", { className: "op-card-detail op-card-file-detail", children: [_jsx("code", { className: "op-path", children: file }), _jsx(OpenInTabButton, { filePath: file, ctx: ctx })] }), _jsx(ToolCallDetail, { input: input, result: result, runStreaming: runStreaming, runSucceeded: runSucceeded })] }));
|
|
188
189
|
}
|
|
189
190
|
function FileEditCard({ input, result, runStreaming, runSucceeded, ctx }) {
|
|
190
191
|
const t = useT();
|
|
@@ -194,7 +195,7 @@ function FileEditCard({ input, result, runStreaming, runSucceeded, ctx }) {
|
|
|
194
195
|
const baseName = file.split('/').pop();
|
|
195
196
|
const editCount = Array.isArray(obj.edits) ? obj.edits.length : 1;
|
|
196
197
|
const isRunning = runStreaming && !result;
|
|
197
|
-
return (_jsxs(ExpandableCard, { className: "op-file", call: { input: input, result: result, runStreaming: runStreaming, runSucceeded: runSucceeded }, head: _jsxs(_Fragment, { children: [_jsx(ResultBadge, { result: result, runStreaming: runStreaming, runSucceeded: runSucceeded }), _jsx("span", { className: `op-title${isRunning ?
|
|
198
|
+
return (_jsxs(ExpandableCard, { className: "op-file", call: { input: input, result: result, runStreaming: runStreaming, runSucceeded: runSucceeded }, head: _jsxs(_Fragment, { children: [_jsx(ResultBadge, { result: result, runStreaming: runStreaming, runSucceeded: runSucceeded }), _jsx("span", { className: `op-title${isRunning ? RUNNING_TITLE_CLASS : ''}`, children: t('Edit') }), _jsxs("span", { className: "op-meta", children: [baseName, " \u00B7 ", editCount, " ", editCount === 1 ? t('change') : t('changes')] })] }), after: _jsx(FileErrorDetail, { result: result }), children: [_jsxs("div", { className: "op-card-detail op-card-file-detail", children: [_jsx("code", { className: "op-path", children: file }), _jsx(OpenInTabButton, { filePath: file, ctx: ctx })] }), _jsx(ToolCallDetail, { input: input, result: result, runStreaming: runStreaming, runSucceeded: runSucceeded })] }));
|
|
198
199
|
}
|
|
199
200
|
function FileReadCard({ input, result, runStreaming, runSucceeded, ctx }) {
|
|
200
201
|
const t = useT();
|
|
@@ -203,7 +204,7 @@ function FileReadCard({ input, result, runStreaming, runSucceeded, ctx }) {
|
|
|
203
204
|
// See OpenInTabButton's baseName comment: `.split('/').pop()` is never undefined.
|
|
204
205
|
const baseName = file.split('/').pop();
|
|
205
206
|
const isRunning = runStreaming && !result;
|
|
206
|
-
return (_jsxs(ExpandableCard, { className: "op-file", call: { input: input, result: result, runStreaming: runStreaming, runSucceeded: runSucceeded }, head: _jsxs(_Fragment, { children: [_jsx(ResultBadge, { result: result, runStreaming: runStreaming, runSucceeded: runSucceeded }), _jsx("span", { className: `op-title${isRunning ?
|
|
207
|
+
return (_jsxs(ExpandableCard, { className: "op-file", call: { input: input, result: result, runStreaming: runStreaming, runSucceeded: runSucceeded }, head: _jsxs(_Fragment, { children: [_jsx(ResultBadge, { result: result, runStreaming: runStreaming, runSucceeded: runSucceeded }), _jsx("span", { className: `op-title${isRunning ? RUNNING_TITLE_CLASS : ''}`, children: t('Read') }), _jsx("span", { className: "op-meta", children: baseName })] }), after: _jsx(FileErrorDetail, { result: result }), children: [_jsxs("div", { className: "op-card-detail op-card-file-detail", children: [_jsx("code", { className: "op-path", children: file }), _jsx(OpenInTabButton, { filePath: file, ctx: ctx })] }), _jsx(ToolCallDetail, { input: input, result: result, runStreaming: runStreaming, runSucceeded: runSucceeded })] }));
|
|
207
208
|
}
|
|
208
209
|
function BashCard({ input, result, runStreaming, runSucceeded }) {
|
|
209
210
|
const t = useT();
|
|
@@ -211,7 +212,7 @@ function BashCard({ input, result, runStreaming, runSucceeded }) {
|
|
|
211
212
|
const command = obj.command ?? '';
|
|
212
213
|
const desc = obj.description;
|
|
213
214
|
const isRunning = runStreaming && !result;
|
|
214
|
-
return (_jsx(ExpandableCard, { className: "op-bash", call: { input: input, result: result, runStreaming: runStreaming, runSucceeded: runSucceeded }, head: _jsxs(_Fragment, { children: [_jsx(ResultBadge, { result: result, runStreaming: runStreaming, runSucceeded: runSucceeded }), _jsx("span", { className: `op-title${isRunning ?
|
|
215
|
+
return (_jsx(ExpandableCard, { className: "op-bash", call: { input: input, result: result, runStreaming: runStreaming, runSucceeded: runSucceeded }, head: _jsxs(_Fragment, { children: [_jsx(ResultBadge, { result: result, runStreaming: runStreaming, runSucceeded: runSucceeded }), _jsx("span", { className: `op-title${isRunning ? RUNNING_TITLE_CLASS : ''}`, children: t('Bash') }), desc ? _jsx("span", { className: "op-meta op-desc", children: desc }) : null] }), children: _jsx(ToolCallDetail, { input: command, result: result, runStreaming: runStreaming, runSucceeded: runSucceeded }) }));
|
|
215
216
|
}
|
|
216
217
|
function GlobCard({ input, result, runStreaming, runSucceeded }) {
|
|
217
218
|
const t = useT();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const SLASH_QUERY_RE = /^\/([^\s/]*)(
|
|
1
|
+
const SLASH_QUERY_RE = /^\/([^\s/]*)(\s+)?/;
|
|
2
2
|
/**
|
|
3
3
|
* Open Design's active slash-token rule (`/^\/([^\s/]*)$/`), extended to admit one optional
|
|
4
4
|
* trailing argument while staying anchored end-to-end. The command segment itself is unchanged —
|
|
@@ -9,13 +9,13 @@ export function parseComposerSlashQuery({ draft }) {
|
|
|
9
9
|
const match = SLASH_QUERY_RE.exec(draft);
|
|
10
10
|
if (!match)
|
|
11
11
|
return null;
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
return { command: command, argument: separator === undefined ? null :
|
|
12
|
+
// Group 1 always participates, including the empty command; without a separator the entire
|
|
13
|
+
// draft must be the command. With one, the greedy separator consumes all leading whitespace.
|
|
14
|
+
// This preserves the whole-draft grammar without overlapping separator/rest repetitions.
|
|
15
|
+
const [, command, separator] = match;
|
|
16
|
+
if (separator === undefined && match[0].length !== draft.length)
|
|
17
|
+
return null;
|
|
18
|
+
return { command: command, argument: separator === undefined ? null : draft.slice(match[0].length) };
|
|
19
19
|
}
|
|
20
20
|
/**
|
|
21
21
|
* Once a separator has been typed, only an item whose declared `command` exactly equals the typed
|
|
@@ -28,14 +28,13 @@ function resolveAgentPluginStrip({ messages }, { conversationId }) {
|
|
|
28
28
|
/** One per-chat usage strip; removing a name persists its exclusion for future turns. */
|
|
29
29
|
export function AgentPluginUsage({ conversationId, messages }) {
|
|
30
30
|
const t = useT();
|
|
31
|
-
const [
|
|
31
|
+
const [, setRevision] = useState(0);
|
|
32
32
|
useEffect(() => {
|
|
33
33
|
const refresh = () => setRevision(value => value + 1);
|
|
34
34
|
window.addEventListener(AGENT_PLUGIN_STATE_CHANGED, refresh);
|
|
35
35
|
window.addEventListener('storage', refresh);
|
|
36
36
|
return () => { window.removeEventListener(AGENT_PLUGIN_STATE_CHANGED, refresh); window.removeEventListener('storage', refresh); };
|
|
37
37
|
}, []);
|
|
38
|
-
void revision;
|
|
39
38
|
const strip = resolveAgentPluginStrip({ messages }, { conversationId });
|
|
40
39
|
if (!strip)
|
|
41
40
|
return null;
|
|
@@ -10,5 +10,5 @@ export declare function runtimeAgentStatus({ agent }: {
|
|
|
10
10
|
* @complexity Time: O(n) in the runtime inventory; space: O(n) for ordering.
|
|
11
11
|
* @overallScore 100/100
|
|
12
12
|
*/
|
|
13
|
-
export declare function AgentRuntimePicker({ agents, value, onChange, onRescan, scanning, daemonOnline, placement, executionMode, apiModeAvailable, onExecutionModeChange, byokRuntime, onByokModelChange, agentIconBasePath, }: AgentRuntimePickerProps): import("react").JSX.Element;
|
|
13
|
+
export declare function AgentRuntimePicker({ agents, nativeToolPolicy, value, onChange, onRescan, scanning, daemonOnline, placement, executionMode, apiModeAvailable, onExecutionModeChange, byokRuntime, onByokModelChange, agentIconBasePath, }: AgentRuntimePickerProps): import("react").JSX.Element;
|
|
14
14
|
//# sourceMappingURL=AgentRuntimePicker.d.ts.map
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { jsx as _jsx,
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { pickerModelValue, pickerCatalogNote, pickerModelOptions, shortModelLabel } from '../model-options.js';
|
|
3
3
|
import { createPortal } from 'react-dom';
|
|
4
4
|
import { AgentIcon, RemixIcon, SearchableModelSelect } from '@jini-ai/ui';
|
|
5
|
+
import { assessNativeToolPolicy } from '@jini-ai/agent-runtime/native-tool-policy';
|
|
5
6
|
import { useT } from '../../../hooks/context.js';
|
|
6
7
|
import { definedProps } from '../../../util/defined-props.js';
|
|
7
8
|
import { RuntimeDropUp } from './RuntimeDropUp.js';
|
|
@@ -17,8 +18,17 @@ export function runtimeAgentStatus({ agent }) {
|
|
|
17
18
|
return 'Installed · sign-in required';
|
|
18
19
|
return agent.version ?? 'Installed';
|
|
19
20
|
}
|
|
21
|
+
/** Selection preflight uses the launch assessor; it never substitutes for enforcement. */
|
|
22
|
+
function NativeToolPolicyWarning({ agent, policy, isApi }) {
|
|
23
|
+
const t = useT();
|
|
24
|
+
if (!agent || isApi)
|
|
25
|
+
return null;
|
|
26
|
+
const warning = policy ? assessNativeToolPolicy({ def: agent, policy }) : null;
|
|
27
|
+
return _jsxs(_Fragment, { children: [agent.fullCliAccessNote ? _jsx("p", { children: t(agent.fullCliAccessNote) }) : null, warning ? _jsx("p", { role: "alert", children: t(warning) }) : null] });
|
|
28
|
+
}
|
|
20
29
|
function RuntimeModeButtons({ executionMode, daemonOnline, apiModeAvailable, onExecutionModeChange, t, }) {
|
|
21
|
-
|
|
30
|
+
const localModeLabel = executionMode === 'local' ? t('active') : '';
|
|
31
|
+
return (_jsxs(_Fragment, { children: [_jsxs("button", { type: "button", className: `jini-runtime-mode${executionMode === 'local' ? ' is-active' : ''}`, disabled: !daemonOnline && executionMode !== 'local', onClick: () => onExecutionModeChange?.('local'), children: [_jsx(RemixIcon, { name: "terminal-box-line", size: 18 }), _jsx("span", { children: t('Use Local CLI') }), _jsx("span", { className: "jini-runtime-mode__meta", children: !daemonOnline ? t('offline') : localModeLabel }), executionMode === 'local' ? (_jsx(RemixIcon, { name: "check-line", size: 19, className: "jini-runtime-check" })) : null] }), _jsxs("button", { type: "button", className: `jini-runtime-mode${executionMode === 'api' ? ' is-active' : ''}`, disabled: !apiModeAvailable, onClick: () => onExecutionModeChange?.('api'), children: [_jsx(RemixIcon, { name: "link", size: 18 }), _jsx("span", { children: t('Use API · BYOK') }), !apiModeAvailable ? _jsx("span", { className: "jini-runtime-mode__meta", children: t('not configured') }) : null, executionMode === 'api' ? (_jsx(RemixIcon, { name: "check-line", size: 19, className: "jini-runtime-check" })) : null] })] }));
|
|
22
32
|
}
|
|
23
33
|
function RuntimeAgentList({ orderedAgents, value, onChange, agentIconBasePath, t, }) {
|
|
24
34
|
if (orderedAgents.length === 0) {
|
|
@@ -27,7 +37,7 @@ function RuntimeAgentList({ orderedAgents, value, onChange, agentIconBasePath, t
|
|
|
27
37
|
return (_jsx(_Fragment, { children: orderedAgents.map((agent) => {
|
|
28
38
|
const active = agent.id === value.agentId;
|
|
29
39
|
const status = runtimeAgentStatus({ agent: agent });
|
|
30
|
-
return (_jsxs("button", { type: "button", role: "radio", "aria-checked": active, className: `jini-runtime-agent${active ? ' is-active' : ''}`, "aria-current": active ? 'true' : undefined, "aria-label": `${agent.name} · ${status}`, onClick: () => onChange(defaultChatPaneSelection({ agent: agent })), children: [_jsx(AgentIcon, { id: agent.id, size: 20, className: "jini-runtime-agent-icon", ...definedProps({ source: { basePath: agentIconBasePath } }) }),
|
|
40
|
+
return (_jsxs("button", { type: "button", role: "radio", "aria-checked": active, className: `jini-runtime-agent${active ? ' is-active' : ''}`, "aria-current": active ? 'true' : undefined, "aria-label": `${agent.name} · ${status}`, onClick: () => onChange(defaultChatPaneSelection({ agent: agent })), children: [_jsx(AgentIcon, { id: agent.id, size: 20, className: "jini-runtime-agent-icon", ...definedProps({ source: { basePath: agentIconBasePath } }) }), _jsxs("span", { className: "jini-runtime-agent__copy", children: [_jsx("strong", { children: agent.name }), agent.fullCliAccessNote ? _jsx("small", { children: t(agent.fullCliAccessNote) }) : null] }), agent.supportsTools === false ? (_jsx("span", { className: "jini-runtime-agent__badge", title: t("This CLI has no MCP support, so it cannot use this app's tools."), children: t('No tools') })) : null, _jsx("span", { className: "jini-runtime-agent__status", children: active ? t('selected') : status }), active ? (_jsx(RemixIcon, { name: "check-line", size: 19, className: "jini-runtime-check" })) : null] }, agent.id));
|
|
31
41
|
}) }));
|
|
32
42
|
}
|
|
33
43
|
/**
|
|
@@ -127,7 +137,7 @@ function RuntimePopover({ picker, value, onChange, onRescan, scanning, daemonOnl
|
|
|
127
137
|
* @complexity Time: O(n) in the runtime inventory; space: O(n) for ordering.
|
|
128
138
|
* @overallScore 100/100
|
|
129
139
|
*/
|
|
130
|
-
export function AgentRuntimePicker({ agents, value, onChange, onRescan, scanning = false, daemonOnline = true, placement = 'up', executionMode = 'local', apiModeAvailable = false, onExecutionModeChange, byokRuntime, onByokModelChange,
|
|
140
|
+
export function AgentRuntimePicker({ agents, nativeToolPolicy, value, onChange, onRescan, scanning = false, daemonOnline = true, placement = 'up', executionMode = 'local', apiModeAvailable = false, onExecutionModeChange, byokRuntime, onByokModelChange,
|
|
131
141
|
// No default here (was '/agent-icons'): omitted means "let AgentIcon fall back to its own
|
|
132
142
|
// bundled icon set" — see AgentIcon.tsx's BUNDLED_ICON_URLS. A host that still wants to vendor
|
|
133
143
|
// its own asset directory can pass this explicitly, same as before.
|
|
@@ -140,6 +150,6 @@ agentIconBasePath, }) {
|
|
|
140
150
|
// operator on BYOK saw a CLI named as "selected" and a model reading "Default (CLI config)"
|
|
141
151
|
// while their messages went to a provider over an API key.
|
|
142
152
|
const isApi = executionMode === 'api';
|
|
143
|
-
return (_jsxs("div", { className: "jini-runtime-picker", children: [_jsx(RuntimeTrigger, { picker: picker, isApi: isApi, byokRuntime: byokRuntime, agentIconBasePath: agentIconBasePath, t: t }), isApi ? null : (_jsx(RuntimeBarMenus, { selectedAgent: picker.selectedAgent, value: value, onChange: onChange, modelLabel: picker.modelLabel, t: t })), _jsx(RuntimePopover, { picker: picker, value: value, onChange: onChange, onRescan: onRescan, scanning: scanning, daemonOnline: daemonOnline, executionMode: executionMode, apiModeAvailable: apiModeAvailable, onExecutionModeChange: onExecutionModeChange, byokRuntime: byokRuntime, onByokModelChange: onByokModelChange, agentIconBasePath: agentIconBasePath, t: t })] }));
|
|
153
|
+
return (_jsxs("div", { className: "jini-runtime-picker", children: [_jsx(RuntimeTrigger, { picker: picker, isApi: isApi, byokRuntime: byokRuntime, agentIconBasePath: agentIconBasePath, t: t }), isApi ? null : (_jsx(RuntimeBarMenus, { selectedAgent: picker.selectedAgent, value: value, onChange: onChange, modelLabel: picker.modelLabel, t: t })), _jsx(NativeToolPolicyWarning, { agent: picker.selectedAgent, policy: nativeToolPolicy, isApi: isApi }), _jsx(RuntimePopover, { picker: picker, value: value, onChange: onChange, onRescan: onRescan, scanning: scanning, daemonOnline: daemonOnline, executionMode: executionMode, apiModeAvailable: apiModeAvailable, onExecutionModeChange: onExecutionModeChange, byokRuntime: byokRuntime, onByokModelChange: onByokModelChange, agentIconBasePath: agentIconBasePath, t: t })] }));
|
|
144
154
|
}
|
|
145
155
|
//# sourceMappingURL=AgentRuntimePicker.js.map
|
|
@@ -25,7 +25,8 @@ function defaultHeader(title, onReset, t) {
|
|
|
25
25
|
return (_jsxs("div", { className: "jini-chat-pane__header", children: [_jsxs("div", { className: "jini-chat-pane__heading", children: [_jsx("span", { className: "jini-chat-pane__eyebrow", children: t('Workspace chat') }), _jsx("h1", { className: "jini-chat-pane__title", children: title ?? t('Chat') })] }), _jsx("button", { type: "button", className: "jini-chat-pane__new-thread", onClick: onReset, children: t('New thread') })] }));
|
|
26
26
|
}
|
|
27
27
|
function chatPaneClassName(variant, className) {
|
|
28
|
-
|
|
28
|
+
const suffix = className ? ' ' + className : '';
|
|
29
|
+
return `jini-chat-pane jini-chat-pane--${variant}${suffix}`;
|
|
29
30
|
}
|
|
30
31
|
function resolveRuntimeAccessView(runtimeAccess, injectedAgents, scanningAgents, daemonOnline, onRescanAgents, inventory) {
|
|
31
32
|
if (runtimeAccess === undefined) {
|
|
@@ -268,7 +269,7 @@ function useComposerHandlePublisher({ pane }, { composerHandle }) {
|
|
|
268
269
|
composerDraftRef.current = pane.composer.draft;
|
|
269
270
|
useEffect(() => {
|
|
270
271
|
if (!composerHandle)
|
|
271
|
-
return;
|
|
272
|
+
return undefined;
|
|
272
273
|
composerHandle.current = {
|
|
273
274
|
insertText: (text) => {
|
|
274
275
|
pane.composer.setDraft(appendComposerDiscovery({ draft: composerDraftRef.current, insertText: text }));
|
|
@@ -396,6 +397,7 @@ export function ChatPane(props) {
|
|
|
396
397
|
onExecutionModeChange: p.onExecutionModeChange,
|
|
397
398
|
byokRuntime: p.byokRuntime,
|
|
398
399
|
onByokModelChange: p.onByokModelChange,
|
|
400
|
+
nativeToolPolicy: p.nativeToolPolicy,
|
|
399
401
|
} }) })),
|
|
400
402
|
}, { leadingAccessory: p.leadingAccessory });
|
|
401
403
|
const { rootRef, controlsRef } = useChatPaneControlsHeight();
|
|
@@ -33,7 +33,7 @@ export function RuntimeDropUp({ label, valueLabel, triggerLabel, value, options,
|
|
|
33
33
|
if (tipVisible)
|
|
34
34
|
tip.show();
|
|
35
35
|
};
|
|
36
|
-
return (_jsxs(_Fragment, { children: [_jsxs("button", { ref: triggerRef, type: "button", className:
|
|
36
|
+
return (_jsxs(_Fragment, { children: [_jsxs("button", { ref: triggerRef, type: "button", className: 'jini-runtime-dropup-trigger' + (className ? ' ' + className : ''), "aria-label": `${label}: ${valueLabel}`, "aria-haspopup": "menu", "aria-expanded": open, "aria-controls": menuId, ...(shortened ? {} : { title: valueLabel }), onClick: () => {
|
|
37
37
|
tip.hide();
|
|
38
38
|
toggleOpen();
|
|
39
39
|
}, onKeyDown: (event) => {
|
|
@@ -179,7 +179,7 @@ export function createDaemonAttachmentUploader({ baseUrl, fetch }, options = {})
|
|
|
179
179
|
const controller = new AbortController();
|
|
180
180
|
const unlinkParentAbort = linkParentAbort({ controller, parent: uploadOptions?.signal });
|
|
181
181
|
const timeout = globalThis.setTimeout(() => controller.abort(new DOMException('Attachment upload timed out', 'TimeoutError')), timeoutMs);
|
|
182
|
-
const uploaded =
|
|
182
|
+
const uploaded = Array.from({ length: files.length }, () => undefined);
|
|
183
183
|
const settled = () => uploaded.filter((attachment) => attachment !== undefined);
|
|
184
184
|
// The failure is captured rather than rethrown from inside the `try`, so that the timer/listener
|
|
185
185
|
// teardown in `finally` has exactly two reachable paths (the turn succeeded, or it did not)
|
|
@@ -175,7 +175,7 @@ export function useAgentRuntimePicker({ agents, value, placement, t, executionMo
|
|
|
175
175
|
}, []);
|
|
176
176
|
useEffect(() => {
|
|
177
177
|
if (!open)
|
|
178
|
-
return;
|
|
178
|
+
return undefined;
|
|
179
179
|
const closeOnOutsidePointer = (event) => {
|
|
180
180
|
const target = event.target;
|
|
181
181
|
if (triggerRef.current?.contains(target)
|
|
@@ -207,7 +207,7 @@ export function useAgentRuntimePicker({ agents, value, placement, t, executionMo
|
|
|
207
207
|
}, [focusTrigger, open]);
|
|
208
208
|
useEffect(() => {
|
|
209
209
|
if (!open)
|
|
210
|
-
return;
|
|
210
|
+
return undefined;
|
|
211
211
|
const update = () => {
|
|
212
212
|
const rect = triggerRef.current?.getBoundingClientRect();
|
|
213
213
|
const bounds = triggerRef.current?.closest('.jini-composer')?.getBoundingClientRect();
|
|
@@ -393,8 +393,7 @@ export function useChatPane(options) {
|
|
|
393
393
|
if (inputId === undefined)
|
|
394
394
|
composer.addAttachment(attachment);
|
|
395
395
|
else
|
|
396
|
-
setQueuedInputs(inputs =>
|
|
397
|
-
? { ...input, attachments: [...input.attachments, attachment] } : input));
|
|
396
|
+
setQueuedInputs(inputs => attachQueuedInput({ inputs, inputId, attachment }));
|
|
398
397
|
if (file)
|
|
399
398
|
cacheAttachmentPreviewSource({ path: attachment.path, file });
|
|
400
399
|
},
|
|
@@ -840,4 +839,7 @@ export function useChatPane(options) {
|
|
|
840
839
|
reset,
|
|
841
840
|
};
|
|
842
841
|
}
|
|
842
|
+
function attachQueuedInput({ inputs, inputId, attachment }) {
|
|
843
|
+
return inputs.map(input => input.id === inputId ? { ...input, attachments: [...input.attachments, attachment] } : input);
|
|
844
|
+
}
|
|
843
845
|
//# sourceMappingURL=useChatPane.hooks.js.map
|
|
@@ -67,7 +67,7 @@ async function selectAgentAction(pane, input) {
|
|
|
67
67
|
}
|
|
68
68
|
if (agent.available === false) {
|
|
69
69
|
throw new Error(`agent "${agentId}" is not available on this machine`
|
|
70
|
-
+
|
|
70
|
+
+ (agent.diagnostic === undefined ? '' : ` (${agent.diagnostic})`));
|
|
71
71
|
}
|
|
72
72
|
const model = optionalStringField(input, 'model');
|
|
73
73
|
const reasoning = optionalStringField(input, 'reasoning');
|
|
@@ -191,7 +191,7 @@ export function useChatPaneAgentControl({ pane }, options = {}) {
|
|
|
191
191
|
const hasBridgeAccess = options.bridgeAccess !== undefined;
|
|
192
192
|
useEffect(() => {
|
|
193
193
|
if (!enabled)
|
|
194
|
-
return;
|
|
194
|
+
return undefined;
|
|
195
195
|
const cleanups = [];
|
|
196
196
|
// Not registered unless the host opted in: see `webmcp`'s own doc for why this path cannot be
|
|
197
197
|
// gated and therefore must not be on by default.
|
|
@@ -42,7 +42,7 @@ export function useChatPaneControlsHeight() {
|
|
|
42
42
|
const root = rootRef.current;
|
|
43
43
|
const controls = controlsRef.current;
|
|
44
44
|
if (!root || !controls || typeof ResizeObserver !== 'function')
|
|
45
|
-
return;
|
|
45
|
+
return undefined;
|
|
46
46
|
const observer = new ResizeObserver((entries) => {
|
|
47
47
|
// Only `controls` is observed, so a notification carries at most one entry: `slice(0, 1)`
|
|
48
48
|
// reads it without a branch for the empty list the ResizeObserver spec never delivers.
|
|
@@ -111,7 +111,7 @@ export function useChatPaneRuntimeInventory({ access, initialAgents = EMPTY_AGEN
|
|
|
111
111
|
}, [access, health, reloadIfUnanswered, retry]);
|
|
112
112
|
useEffect(() => {
|
|
113
113
|
if (!access)
|
|
114
|
-
return;
|
|
114
|
+
return undefined;
|
|
115
115
|
retry.reset();
|
|
116
116
|
void loadAgents(false);
|
|
117
117
|
// Health polls only while the tab is visible: a hidden tab stops its timer, and showing it
|
|
@@ -157,7 +157,7 @@ export function useChatPaneRuntimeInventory({ access, initialAgents = EMPTY_AGEN
|
|
|
157
157
|
}, [access, health, inventory, loadAgents, pollIntervalMs, refreshStatus, retry]);
|
|
158
158
|
useEffect(() => {
|
|
159
159
|
if (!access)
|
|
160
|
-
return;
|
|
160
|
+
return undefined;
|
|
161
161
|
// The status check on becoming visible belongs to the polling effect above; this one only
|
|
162
162
|
// retries an unanswered inventory load (and, on focus, checks status too).
|
|
163
163
|
const onFocus = () => {
|
|
@@ -43,7 +43,7 @@ export function useChatPaneWorkingDirectory(options) {
|
|
|
43
43
|
}, []);
|
|
44
44
|
useEffect(() => {
|
|
45
45
|
if (observedDirectoryRef.current === workingDirectory)
|
|
46
|
-
return;
|
|
46
|
+
return undefined;
|
|
47
47
|
observedDirectoryRef.current = workingDirectory;
|
|
48
48
|
operation.supersede();
|
|
49
49
|
const access = options.workingDirectoryAccess;
|
|
@@ -51,7 +51,7 @@ export function useChatPaneWorkingDirectory(options) {
|
|
|
51
51
|
if (workingDirectory === null || !access) {
|
|
52
52
|
setWorkingDirectoryInvalid(false);
|
|
53
53
|
setWorkingDirectoryPending(false);
|
|
54
|
-
return;
|
|
54
|
+
return undefined;
|
|
55
55
|
}
|
|
56
56
|
let validationSettled = false;
|
|
57
57
|
setWorkingDirectoryPending(true);
|
|
@@ -56,7 +56,7 @@ export function useRuntimeDropUp({ width }) {
|
|
|
56
56
|
}, []);
|
|
57
57
|
useEffect(() => {
|
|
58
58
|
if (!open)
|
|
59
|
-
return;
|
|
59
|
+
return undefined;
|
|
60
60
|
const closeOnOutsidePointer = (event) => {
|
|
61
61
|
const target = event.target;
|
|
62
62
|
if (triggerRef.current?.contains(target) || menuRef.current?.contains(target))
|
|
@@ -77,7 +77,7 @@ export function useRuntimeDropUp({ width }) {
|
|
|
77
77
|
}, [closeToTrigger, open]);
|
|
78
78
|
useEffect(() => {
|
|
79
79
|
if (!open)
|
|
80
|
-
return;
|
|
80
|
+
return undefined;
|
|
81
81
|
const update = () => {
|
|
82
82
|
const rect = triggerRef.current?.getBoundingClientRect();
|
|
83
83
|
const bounds = triggerRef.current?.closest('.jini-composer')?.getBoundingClientRect();
|
|
@@ -51,7 +51,8 @@ const RAW_MODEL_ID = /^(?:[a-z0-9._-]+\/)*[a-z0-9][a-z0-9._-]*(?:\[[^\]]*\])?$/;
|
|
|
51
51
|
const BRAND_CASING = { gpt: 'GPT' };
|
|
52
52
|
function prettifyRawModelId(id) {
|
|
53
53
|
// A routing prefix ("anthropic/") is the full name's job; the bar names only the model.
|
|
54
|
-
|
|
54
|
+
// The caller proved RAW_MODEL_ID, so the first '[' can only start its trailing context suffix.
|
|
55
|
+
const tokens = id.slice(id.lastIndexOf('/') + 1).split('[', 1)[0].split(/[-_]+/).filter((token) => token && !/^\d{8}$/.test(token));
|
|
55
56
|
const words = [];
|
|
56
57
|
for (const token of tokens) {
|
|
57
58
|
const previous = words[words.length - 1];
|
|
@@ -78,7 +79,8 @@ export function shortModelLabel({ label, agentId }, { max = 16 } = {}) {
|
|
|
78
79
|
const vendors = (agentId && BAR_VENDOR_WORDS[agentId]) || [];
|
|
79
80
|
const dropVendor = words.length > 1 && vendors.includes(words[0].toLowerCase());
|
|
80
81
|
// A display name with no vendor word to drop is shown as the catalog wrote it.
|
|
81
|
-
const
|
|
82
|
+
const normalized = raw ? words.join(' ') : trimmed;
|
|
83
|
+
const short = dropVendor ? words.slice(1).join(' ') : normalized;
|
|
82
84
|
return short.length > max ? `${short.slice(0, max - 1).trimEnd()}…` : short;
|
|
83
85
|
}
|
|
84
86
|
//# sourceMappingURL=model-options.js.map
|