@adecore/agents-react 0.31.9 → 0.31.10

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.
@@ -318,12 +318,24 @@ function changedFilesRow(turn, items) {
318
318
  ...(moved ? { baseMoved: { from: turn.checkpointHead, to: turn.checkpointHeadAfter } } : {})
319
319
  };
320
320
  }
321
+ /*
322
+ * The closing answer of a settled turn. A turn may end on a call the person turned down, as an agent that stops
323
+ * there does: the answer before it closes the turn, and the refused call and its denial stay in sight with it.
324
+ */
321
325
  function lastAssistantRow(rows) {
326
+ const refused = new Set();
322
327
  for (let i = rows.length - 1; i >= 0; i--) {
323
328
  const row = rows[i];
324
329
  if (row.kind === 'assistant') {
325
330
  return row;
326
331
  }
332
+ if (row.kind === 'approval' && row.item.decision === 'deny' && row.item.toolUseId !== null) {
333
+ refused.add(row.item.toolUseId);
334
+ continue;
335
+ }
336
+ if (row.kind === 'work' && refused.has(row.tool.toolUseId)) {
337
+ continue;
338
+ }
327
339
  if (row.kind !== 'note' && !isImageRow(row)) {
328
340
  return null;
329
341
  }
@@ -332,8 +344,9 @@ function lastAssistantRow(rows) {
332
344
  }
333
345
  /*
334
346
  * The rows of a running turn with its latest thought over the call it led to, so what the model
335
- * found does not scroll away behind the next tool line. Nothing when that call follows the thought
336
- * directly, where the thought's own row already shows it, or when a newer thought came after the call.
347
+ * found does not scroll away behind the next tool line. Nothing while no finished call stands between
348
+ * the thought's own row and that call, since the thought still shows there, or when a newer thought
349
+ * came after the call.
337
350
  */
338
351
  function withLiveThought(rows, items) {
339
352
  const thoughtAt = items.findLastIndex((item) => item.kind === 'thinking' && parentOf(item) === null);
@@ -344,8 +357,9 @@ function withLiveThought(rows, items) {
344
357
  const after = new Set(items.slice(thoughtAt + 1).map((item) => item.id));
345
358
  const index = rows.findIndex((row) => row.kind === 'work-live' && after.has(row.tool.id));
346
359
  const call = rows[index];
347
- const previous = rows[index - 1];
348
- if (call?.kind !== 'work-live' || (previous?.kind === 'thinking' && previous.id === thought.id)) {
360
+ const shownAt = rows.findIndex((row) => row.kind === 'thinking' && row.id === thought.id);
361
+ const inSight = shownAt !== -1 && shownAt < index && !rows.slice(shownAt + 1, index).some((row) => row.kind === 'work');
362
+ if (call?.kind !== 'work-live' || inSight) {
349
363
  return rows;
350
364
  }
351
365
  return [...rows.slice(0, index), { kind: 'live-thought', id: `live-thought-${thought.id}`, item: thought, at: call.tool.createdAt }, ...rows.slice(index)];
@@ -4,7 +4,7 @@ import { useChatHost } from '../../../host.js';
4
4
  import { useChatScope } from '../../../scope.js';
5
5
  import { errorCode } from '../../../transport.js';
6
6
  import { useChatActions } from '../../actions.js';
7
- import { rememberChatAccount, rememberChatPreferences, rememberChatSelection } from '../../preferences.js';
7
+ import { rememberChatAccount, rememberChatSelection } from '../../preferences.js';
8
8
  import { composerStopOf } from '../../subagent-list.js';
9
9
  /* What the composer does to the chat rather than to its draft: its settings, a stop, a clear and a compaction. */
10
10
  export function useChatControls({ chatId, info, notice: { setNotice, showError }, onRetarget }) {
@@ -30,14 +30,12 @@ export function useChatControls({ chatId, info, notice: { setNotice, showError }
30
30
  setConfigurationPending(false);
31
31
  });
32
32
  };
33
+ // A mode picked here is this chat's; the default for new chats changes only in the settings.
33
34
  const configure = (patch) => {
34
35
  runConfiguration(() => actions.configure(chatId, patch).then(() => {
35
36
  if (patch.selection) {
36
37
  rememberChatSelection(info.provider, patch.selection);
37
38
  }
38
- if (patch.runtimeMode) {
39
- rememberChatPreferences({ runtimeMode: patch.runtimeMode });
40
- }
41
39
  if (patch.account) {
42
40
  rememberChatAccount(scope.id, info.provider, patch.account);
43
41
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adecore/agents-react",
3
- "version": "0.31.9",
3
+ "version": "0.31.10",
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.9",
71
- "@adecore/editor": "0.31.9",
72
- "@adecore/editor-react": "0.31.9",
73
- "@adecore/intelligent-ui": "0.31.9",
74
- "@adecore/merge": "0.31.9",
70
+ "@adecore/agent-contracts": "0.31.10",
71
+ "@adecore/editor": "0.31.10",
72
+ "@adecore/editor-react": "0.31.10",
73
+ "@adecore/intelligent-ui": "0.31.10",
74
+ "@adecore/merge": "0.31.10",
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.9",
97
+ "@adecore/ui": "^0.31.10",
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.9",
104
+ "@adecore/ui": "0.31.10",
105
105
  "@types/bun": "^1.4.2",
106
106
  "@types/react": "^19.3.0",
107
107
  "@types/react-dom": "^19.3.0",
@@ -409,12 +409,24 @@ function changedFilesRow(turn: ChatTurnItem, items: ChatItem[]): TimelineRow | n
409
409
  };
410
410
  }
411
411
 
412
+ /*
413
+ * The closing answer of a settled turn. A turn may end on a call the person turned down, as an agent that stops
414
+ * there does: the answer before it closes the turn, and the refused call and its denial stay in sight with it.
415
+ */
412
416
  function lastAssistantRow(rows: TimelineRow[]): TimelineRow | null {
417
+ const refused = new Set<string>();
413
418
  for (let i = rows.length - 1; i >= 0; i--) {
414
419
  const row = rows[i]!;
415
420
  if (row.kind === 'assistant') {
416
421
  return row;
417
422
  }
423
+ if (row.kind === 'approval' && row.item.decision === 'deny' && row.item.toolUseId !== null) {
424
+ refused.add(row.item.toolUseId);
425
+ continue;
426
+ }
427
+ if (row.kind === 'work' && refused.has(row.tool.toolUseId)) {
428
+ continue;
429
+ }
418
430
  if (row.kind !== 'note' && !isImageRow(row)) {
419
431
  return null;
420
432
  }
@@ -424,8 +436,9 @@ function lastAssistantRow(rows: TimelineRow[]): TimelineRow | null {
424
436
 
425
437
  /*
426
438
  * The rows of a running turn with its latest thought over the call it led to, so what the model
427
- * found does not scroll away behind the next tool line. Nothing when that call follows the thought
428
- * directly, where the thought's own row already shows it, or when a newer thought came after the call.
439
+ * found does not scroll away behind the next tool line. Nothing while no finished call stands between
440
+ * the thought's own row and that call, since the thought still shows there, or when a newer thought
441
+ * came after the call.
429
442
  */
430
443
  function withLiveThought(rows: TimelineRow[], items: readonly ChatItem[]): TimelineRow[] {
431
444
  const thoughtAt = items.findLastIndex((item) => item.kind === 'thinking' && parentOf(item) === null);
@@ -436,8 +449,9 @@ function withLiveThought(rows: TimelineRow[], items: readonly ChatItem[]): Timel
436
449
  const after = new Set(items.slice(thoughtAt + 1).map((item) => item.id));
437
450
  const index = rows.findIndex((row) => row.kind === 'work-live' && after.has(row.tool.id));
438
451
  const call = rows[index];
439
- const previous = rows[index - 1];
440
- if (call?.kind !== 'work-live' || (previous?.kind === 'thinking' && previous.id === thought.id)) {
452
+ const shownAt = rows.findIndex((row) => row.kind === 'thinking' && row.id === thought.id);
453
+ const inSight = shownAt !== -1 && shownAt < index && !rows.slice(shownAt + 1, index).some((row) => row.kind === 'work');
454
+ if (call?.kind !== 'work-live' || inSight) {
441
455
  return rows;
442
456
  }
443
457
  return [...rows.slice(0, index), { kind: 'live-thought', id: `live-thought-${thought.id}`, item: thought, at: call.tool.createdAt }, ...rows.slice(index)];
@@ -5,7 +5,7 @@ import { useChatHost } from '../../../host';
5
5
  import { useChatScope } from '../../../scope';
6
6
  import { errorCode } from '../../../transport';
7
7
  import { useChatActions } from '../../actions';
8
- import { rememberChatAccount, rememberChatPreferences, rememberChatSelection } from '../../preferences';
8
+ import { rememberChatAccount, rememberChatSelection } from '../../preferences';
9
9
  import { composerStopOf } from '../../subagent-list';
10
10
  import type { ComposerNotice } from './use-notice';
11
11
 
@@ -42,15 +42,13 @@ export function useChatControls({ chatId, info, notice: { setNotice, showError }
42
42
  });
43
43
  };
44
44
 
45
+ // A mode picked here is this chat's; the default for new chats changes only in the settings.
45
46
  const configure = (patch: { selection?: ModelSelection; runtimeMode?: RuntimeMode; account?: string }): void => {
46
47
  runConfiguration(() =>
47
48
  actions.configure(chatId, patch).then(() => {
48
49
  if (patch.selection) {
49
50
  rememberChatSelection(info.provider, patch.selection);
50
51
  }
51
- if (patch.runtimeMode) {
52
- rememberChatPreferences({ runtimeMode: patch.runtimeMode });
53
- }
54
52
  if (patch.account) {
55
53
  rememberChatAccount(scope.id, info.provider, patch.account);
56
54
  }