@adecore/agents-react 0.31.11 → 0.31.12

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.
@@ -11,7 +11,7 @@ import { useChatHost } from '../../../host.js';
11
11
  import { lazyNamed } from '../../../lazy.js';
12
12
  import { useChatActions } from '../../actions.js';
13
13
  import { ChatScopeContext, useChatScope } from '../../../scope.js';
14
- import { useCurrentItem } from '../../../state/chats.js';
14
+ import { useAwaitsApproval, useCurrentItem } from '../../../state/chats.js';
15
15
  import { useTimelineFlash } from '../../timeline-flash.js';
16
16
  import { formatClockDuration, formatElapsedShort } from '@adecore/ui/format';
17
17
  import { Icon, LazyBoundary, MiddleTruncate, Spinner, useTickingText } from '@adecore/ui';
@@ -147,7 +147,9 @@ export function WorkLiveRow({ chatId, tool: derived }) {
147
147
  const shell = shellCommand(tool.name, tool.input);
148
148
  const { commandLooks } = useChatHost();
149
149
  const run = shell === null ? null : matchCommandLook(shell, commandLooks);
150
- return (_jsxs("div", { children: [_jsx(ToggleLine, { icon: run === null ? toolIcon(tool.name) : _jsx(run.look.Mark, { size: 12 }), label: run === null ? tool.name : run.match.label, brand: run?.look.brand, look: run === null ? undefined : { run, chatId }, detail: summary || tool.progress?.description || '', command: summary !== '' && summary === shellCommand(tool.name, tool.input), path: summary !== '' && toolSummaryIsPath(tool.name, tool.input), open: open && opens, onToggle: opens ? () => setOpen((o) => !o) : undefined, trailing: _jsx(RunningFor, { startedAt: toolStartedAt(tool) }), live: true }), open && opens && _jsx(ToolBody, { tool: tool }), tail !== null && !open && (_jsx("pre", { className: "mt-1.5 mb-2 ml-6 max-h-48 overflow-auto rounded-md border border-border bg-surface-raised px-3 py-2 font-mono text-code whitespace-pre-wrap text-chat-output select-text", children: _jsx(AnsiOutput, { text: tail, tailLines: 12 }) }))] }));
150
+ const awaiting = useAwaitsApproval(chatId, tool.toolUseId);
151
+ const { t } = useTranslation('agent-chat');
152
+ return (_jsxs("div", { children: [_jsx(ToggleLine, { icon: run === null ? toolIcon(tool.name) : _jsx(run.look.Mark, { size: 12 }), label: run === null ? tool.name : run.match.label, brand: run?.look.brand, look: run === null ? undefined : { run, chatId }, detail: summary || tool.progress?.description || '', command: summary !== '' && summary === shellCommand(tool.name, tool.input), path: summary !== '' && toolSummaryIsPath(tool.name, tool.input), open: open && opens, onToggle: opens ? () => setOpen((o) => !o) : undefined, trailing: awaiting ? (_jsx("span", { className: "shrink-0 text-xs text-text-faint", children: t('work.awaitingApproval') })) : (_jsx(RunningFor, { startedAt: toolStartedAt(tool) })), live: true }), open && opens && _jsx(ToolBody, { tool: tool }), tail !== null && !open && (_jsx("pre", { className: "mt-1.5 mb-2 ml-6 max-h-48 overflow-auto rounded-md border border-border bg-surface-raised px-3 py-2 font-mono text-code whitespace-pre-wrap text-chat-output select-text", children: _jsx(AnsiOutput, { text: tail, tailLines: 12 }) }))] }));
151
153
  }
152
154
  /* A run of tool calls as one line ("Read 4 files"); opening it lists every call. A run of one look wears its mark and its brand. */
153
155
  export function WorkGroupRow({ tools, summary, look, expanded, onToggle }) {
@@ -183,6 +183,7 @@ declare const _default: {
183
183
  loadingDiff: string;
184
184
  diffUnavailable: string;
185
185
  runningFor: string;
186
+ awaitingApproval: string;
186
187
  forksAfter_one: string;
187
188
  forksAfter_other: string;
188
189
  omitted: {
@@ -183,6 +183,7 @@ export default {
183
183
  loadingDiff: 'Loading diff',
184
184
  diffUnavailable: 'Could not load this diff',
185
185
  runningFor: 'running for {{elapsed}}',
186
+ awaitingApproval: 'waiting for you',
186
187
  forksAfter_one: 'A fork goes on after this turn',
187
188
  forksAfter_other: '{{count}} forks go on after this turn',
188
189
  omitted: {
@@ -183,6 +183,7 @@ declare const _default: {
183
183
  loadingDiff: string;
184
184
  diffUnavailable: string;
185
185
  runningFor: string;
186
+ awaitingApproval: string;
186
187
  forksAfter_one: string;
187
188
  forksAfter_other: string;
188
189
  omitted: {
@@ -183,6 +183,7 @@ export default {
183
183
  loadingDiff: 'Diff laden',
184
184
  diffUnavailable: 'Deze diff kon niet worden geladen',
185
185
  runningFor: 'loopt al {{elapsed}}',
186
+ awaitingApproval: 'wacht op jou',
186
187
  forksAfter_one: 'Een fork gaat verder na deze turn',
187
188
  forksAfter_other: '{{count}} forks gaan verder na deze turn',
188
189
  omitted: {
@@ -22,7 +22,9 @@ function ApprovalDetails({ item }) {
22
22
  const editorPreview = host.code.editor !== undefined;
23
23
  const maxHeight = expanded ? 480 : 176;
24
24
  const input = typeof item.input === 'object' && item.input !== null ? item.input : {};
25
- return (_jsxs(_Fragment, { children: [item.description && _jsx("p", { className: "text-sm text-text-muted", children: item.description }), patches.length + edits.length > 1 && (_jsx("p", { className: "text-xs text-text-muted", children: t('approval.allChanges', { count: patches.length + edits.length }) })), patches.length + edits.length > 0 ? (_jsxs("div", { className: "overflow-hidden rounded-xl bg-surface-sunken", children: [_jsx("div", { className: clsx(editorPreview ? 'overflow-hidden' : 'overflow-auto', !editorPreview && !expanded && 'max-h-44'), children: _jsx(ApprovalReview, { entries: entries, maxHeight: maxHeight }, item.requestId) }), _jsx("div", { className: "flex items-center border-t border-border p-1", children: _jsx(Button, { size: "sm", "aria-expanded": expanded, onClick: () => setExpanded(!expanded), children: expanded ? t('approval.collapseDiff') : t('approval.viewDiff') }) })] })) : typeof input.command === 'string' ? (_jsx(CommandBox, { command: input.command, cwd: typeof input.cwd === 'string' ? input.cwd : undefined })) : (_jsxs("details", { children: [_jsx("summary", { className: "flex h-7 cursor-pointer items-center text-xs text-text-muted", children: t('approval.details') }), _jsx(TextMenu, { children: _jsx("pre", { className: "max-h-64 overflow-auto whitespace-pre-wrap break-words rounded-xl bg-surface-sunken p-3 font-mono text-code text-text select-text", children: JSON.stringify(item.input, null, 2) }) })] }))] }));
25
+ // Some agents describe a command by the command itself, which the box under it already shows.
26
+ const describes = item.description && item.description.trim() !== (typeof input.command === 'string' ? input.command.trim() : null);
27
+ return (_jsxs(_Fragment, { children: [describes && _jsx("p", { className: "text-sm text-text-muted", children: item.description }), patches.length + edits.length > 1 && (_jsx("p", { className: "text-xs text-text-muted", children: t('approval.allChanges', { count: patches.length + edits.length }) })), patches.length + edits.length > 0 ? (_jsxs("div", { className: "overflow-hidden rounded-xl bg-surface-sunken", children: [_jsx("div", { className: clsx(editorPreview ? 'overflow-hidden' : 'overflow-auto', !editorPreview && !expanded && 'max-h-44'), children: _jsx(ApprovalReview, { entries: entries, maxHeight: maxHeight }, item.requestId) }), _jsx("div", { className: "flex items-center border-t border-border p-1", children: _jsx(Button, { size: "sm", "aria-expanded": expanded, onClick: () => setExpanded(!expanded), children: expanded ? t('approval.collapseDiff') : t('approval.viewDiff') }) })] })) : typeof input.command === 'string' ? (_jsx(CommandBox, { command: input.command, cwd: typeof input.cwd === 'string' ? input.cwd : undefined })) : (_jsxs("details", { children: [_jsx("summary", { className: "flex h-7 cursor-pointer items-center text-xs text-text-muted", children: t('approval.details') }), _jsx(TextMenu, { children: _jsx("pre", { className: "max-h-64 overflow-auto whitespace-pre-wrap break-words rounded-xl bg-surface-sunken p-3 font-mono text-code text-text select-text", children: JSON.stringify(item.input, null, 2) }) })] }))] }));
26
28
  }
27
29
  /* A chat's permission request: the diff, the command or the raw input, and the reason a Deny may carry. */
28
30
  export function ApprovalBody({ item, draft, onDraft, denyReason, locked }) {
@@ -46,5 +46,6 @@ export declare const useChats: import("zustand").UseBoundStore<import("zustand")
46
46
  export declare function chatSink(keyOf: (chatId: string) => string): ChatSink;
47
47
  export declare function useChatRow<T>(chatId: string, select: (row: ChatState | undefined) => T): T;
48
48
  export declare function useReportedModels(provider: AgentKind): ReadonlySet<string>;
49
+ export declare function useAwaitsApproval(chatId: string, toolUseId: string): boolean;
49
50
  export declare function useCurrentItem<T extends ChatItem>(chatId: string, derived: T): T;
50
51
  export {};
@@ -243,6 +243,10 @@ export function useReportedModels(provider) {
243
243
  });
244
244
  return useMemo(() => new Set(joined === '' ? [] : joined.split('\n')), [joined]);
245
245
  }
246
+ /* Whether a call still waits on the person's answer to an approval of it, when its clock is not running yet. */
247
+ export function useAwaitsApproval(chatId, toolUseId) {
248
+ return useChatRow(chatId, (row) => waitingRequestsOf(row).some((request) => request.kind === 'approval' && request.toolUseId === toolUseId));
249
+ }
246
250
  /* The item as the thread holds it now, for a row derived from the structure, which a delta leaves alone. */
247
251
  export function useCurrentItem(chatId, derived) {
248
252
  return useChatRow(chatId, (row) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adecore/agents-react",
3
- "version": "0.31.11",
3
+ "version": "0.31.12",
4
4
  "description": "React agent chat threads, composers, approvals, provider accounts and usage views.",
5
5
  "type": "module",
6
6
  "exports": {
@@ -67,11 +67,11 @@
67
67
  "test:visuals": "bun --config=integration.bunfig.toml --conditions=source test ./src/chat/visual-viewport.integration.test.ts"
68
68
  },
69
69
  "dependencies": {
70
- "@adecore/agent-contracts": "0.31.11",
71
- "@adecore/editor": "0.31.11",
72
- "@adecore/editor-react": "0.31.11",
73
- "@adecore/intelligent-ui": "0.31.11",
74
- "@adecore/merge": "0.31.11",
70
+ "@adecore/agent-contracts": "0.31.12",
71
+ "@adecore/editor": "0.31.12",
72
+ "@adecore/editor-react": "0.31.12",
73
+ "@adecore/intelligent-ui": "0.31.12",
74
+ "@adecore/merge": "0.31.12",
75
75
  "@codemirror/commands": "^6.11.1",
76
76
  "@codemirror/language": "^6.12.4",
77
77
  "@codemirror/state": "^6.7.6",
@@ -94,14 +94,14 @@
94
94
  "zustand": "^5.0.15"
95
95
  },
96
96
  "peerDependencies": {
97
- "@adecore/ui": "^0.31.11",
97
+ "@adecore/ui": "^0.31.12",
98
98
  "i18next": "^26.4.2",
99
99
  "react": "^19.3.0",
100
100
  "react-dom": "^19.3.0",
101
101
  "react-i18next": "^17.0.15"
102
102
  },
103
103
  "devDependencies": {
104
- "@adecore/ui": "0.31.11",
104
+ "@adecore/ui": "0.31.12",
105
105
  "@types/bun": "^1.4.2",
106
106
  "@types/react": "^19.3.0",
107
107
  "@types/react-dom": "^19.3.0",
@@ -26,7 +26,7 @@ import { useChatHost, type CommandLook } from '../../../host';
26
26
  import { lazyNamed } from '../../../lazy';
27
27
  import { useChatActions } from '../../actions';
28
28
  import { ChatScopeContext, useChatScope } from '../../../scope';
29
- import { useCurrentItem } from '../../../state/chats';
29
+ import { useAwaitsApproval, useCurrentItem } from '../../../state/chats';
30
30
  import { useTimelineFlash } from '../../timeline-flash';
31
31
  import { formatClockDuration, formatElapsedShort } from '@adecore/ui/format';
32
32
  import { Icon, LazyBoundary, MiddleTruncate, Spinner, useTickingText } from '@adecore/ui';
@@ -378,6 +378,8 @@ export function WorkLiveRow({ chatId, tool: derived }: { chatId: string; tool: C
378
378
  const shell = shellCommand(tool.name, tool.input);
379
379
  const { commandLooks } = useChatHost();
380
380
  const run = shell === null ? null : matchCommandLook(shell, commandLooks);
381
+ const awaiting = useAwaitsApproval(chatId, tool.toolUseId);
382
+ const { t } = useTranslation('agent-chat');
381
383
  return (
382
384
  <div>
383
385
  <ToggleLine
@@ -390,7 +392,13 @@ export function WorkLiveRow({ chatId, tool: derived }: { chatId: string; tool: C
390
392
  path={summary !== '' && toolSummaryIsPath(tool.name, tool.input)}
391
393
  open={open && opens}
392
394
  onToggle={opens ? () => setOpen((o) => !o) : undefined}
393
- trailing={<RunningFor startedAt={toolStartedAt(tool)} />}
395
+ trailing={
396
+ awaiting ? (
397
+ <span className="shrink-0 text-xs text-text-faint">{t('work.awaitingApproval')}</span>
398
+ ) : (
399
+ <RunningFor startedAt={toolStartedAt(tool)} />
400
+ )
401
+ }
394
402
  live
395
403
  />
396
404
  {open && opens && <ToolBody tool={tool} />}
@@ -183,6 +183,7 @@ export default {
183
183
  loadingDiff: 'Loading diff',
184
184
  diffUnavailable: 'Could not load this diff',
185
185
  runningFor: 'running for {{elapsed}}',
186
+ awaitingApproval: 'waiting for you',
186
187
  forksAfter_one: 'A fork goes on after this turn',
187
188
  forksAfter_other: '{{count}} forks go on after this turn',
188
189
  omitted: {
@@ -183,6 +183,7 @@ export default {
183
183
  loadingDiff: 'Diff laden',
184
184
  diffUnavailable: 'Deze diff kon niet worden geladen',
185
185
  runningFor: 'loopt al {{elapsed}}',
186
+ awaitingApproval: 'wacht op jou',
186
187
  forksAfter_one: 'Een fork gaat verder na deze turn',
187
188
  forksAfter_other: '{{count}} forks gaan verder na deze turn',
188
189
  omitted: {
@@ -30,9 +30,11 @@ function ApprovalDetails({ item }: { item: ChatApprovalItem }) {
30
30
  const editorPreview = host.code.editor !== undefined;
31
31
  const maxHeight = expanded ? 480 : 176;
32
32
  const input = typeof item.input === 'object' && item.input !== null ? (item.input as Record<string, unknown>) : {};
33
+ // Some agents describe a command by the command itself, which the box under it already shows.
34
+ const describes = item.description && item.description.trim() !== (typeof input.command === 'string' ? input.command.trim() : null);
33
35
  return (
34
36
  <>
35
- {item.description && <p className="text-sm text-text-muted">{item.description}</p>}
37
+ {describes && <p className="text-sm text-text-muted">{item.description}</p>}
36
38
  {patches.length + edits.length > 1 && (
37
39
  <p className="text-xs text-text-muted">{t('approval.allChanges', { count: patches.length + edits.length })}</p>
38
40
  )}
@@ -347,6 +347,11 @@ export function useReportedModels(provider: AgentKind): ReadonlySet<string> {
347
347
  return useMemo(() => new Set(joined === '' ? [] : joined.split('\n')), [joined]);
348
348
  }
349
349
 
350
+ /* Whether a call still waits on the person's answer to an approval of it, when its clock is not running yet. */
351
+ export function useAwaitsApproval(chatId: string, toolUseId: string): boolean {
352
+ return useChatRow(chatId, (row) => waitingRequestsOf(row).some((request) => request.kind === 'approval' && request.toolUseId === toolUseId));
353
+ }
354
+
350
355
  /* The item as the thread holds it now, for a row derived from the structure, which a delta leaves alone. */
351
356
  export function useCurrentItem<T extends ChatItem>(chatId: string, derived: T): T {
352
357
  return useChatRow(chatId, (row) => {