@nextclaw/ui 0.15.0 → 0.15.1

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.
Files changed (99) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/assets/{api-DLtsiBKm.js → api-b1R9VdeH.js} +1 -1
  3. package/dist/assets/{appearance-settings-page-CtkeYXux.js → appearance-settings-page-D2O9pch9.js} +1 -1
  4. package/dist/assets/{book-open-BQwWBDKb.js → book-open-B77lQ2Tg.js} +1 -1
  5. package/dist/assets/{channels-list-page-Cv8o9Hxg.js → channels-list-page-DcsIQc6A.js} +2 -2
  6. package/dist/assets/chat-page-CZ7WxPir.js +1 -0
  7. package/dist/assets/{config-split-page-EidRBpP2.js → config-split-page-BWQ6_Raq.js} +1 -1
  8. package/dist/assets/{confirm-dialog-iIJFFp2T.js → confirm-dialog-C-NXSioX.js} +1 -1
  9. package/dist/assets/desktop-update-config-usHpXugP.js +1 -0
  10. package/dist/assets/{dist-CBxWOazz.js → dist-YtoqU-AT.js} +1 -1
  11. package/dist/assets/{dist-D2eZC3OR.js → dist-jdGmbb6w.js} +1 -1
  12. package/dist/assets/doc-browser-B_Tf9n70.js +1 -0
  13. package/dist/assets/{doc-browser-B76XOXmW.js → doc-browser-BdZPFOVa.js} +1 -1
  14. package/dist/assets/{doc-browser-context-Sv-044Cl.js → doc-browser-context-DwokemUn.js} +1 -1
  15. package/dist/assets/{es2015-DhQo_oS6.js → es2015-bNpL2LKy.js} +1 -1
  16. package/dist/assets/{external-link-CM5dnUI6.js → external-link-BM6fk8q-.js} +1 -1
  17. package/dist/assets/{i18n-provider-di1waTGX.js → i18n-provider-CntWolRA.js} +1 -1
  18. package/dist/assets/index-BIcEw90u.js +104 -0
  19. package/dist/assets/index-BiNSTKTU.css +1 -0
  20. package/dist/assets/loader-circle-MBgNSVIH.js +1 -0
  21. package/dist/assets/{mcp-marketplace-page-C_MVQUbT.js → mcp-marketplace-page-CLmUstLN.js} +1 -1
  22. package/dist/assets/mcp-marketplace-page-rZkmWPMy.js +1 -0
  23. package/dist/assets/{model-config-page-Cdr9P6TQ.js → model-config-page-Di0ySJD2.js} +1 -1
  24. package/dist/assets/plus-vDqW5Kxp.js +1 -0
  25. package/dist/assets/{provider-scoped-model-input-g1WkGiJ8.js → provider-scoped-model-input-Cm_a4GHf.js} +1 -1
  26. package/dist/assets/providers-config-page-BAf2W0MV.js +1 -0
  27. package/dist/assets/{react-DjpzoZXB.js → react-BN8uzPnp.js} +1 -1
  28. package/dist/assets/{refresh-cw-DaTv3zxE.js → refresh-cw-BpVcFPmJ.js} +1 -1
  29. package/dist/assets/remote-CLQ0IBM8.js +1 -0
  30. package/dist/assets/rotate-cw-CvNBv7_w.js +1 -0
  31. package/dist/assets/{runtime-config-page-CfTqh1nv.js → runtime-config-page-CflvvoDc.js} +1 -1
  32. package/dist/assets/{save-BZof1uie.js → save-BpFW5fpk.js} +1 -1
  33. package/dist/assets/{search-MxAarS_g.js → search-D0uO7enf.js} +1 -1
  34. package/dist/assets/{search-config-page-Dm8daYny.js → search-config-page-D0klFUXd.js} +1 -1
  35. package/dist/assets/{secrets-config-page-D8AbcR05.js → secrets-config-page-dVZ631Wp.js} +1 -1
  36. package/dist/assets/security-config-C5gnlkuj.js +1 -0
  37. package/dist/assets/{select-D7GcNP0z.js → select-Bh-CrA4p.js} +1 -1
  38. package/dist/assets/{setting-row-CuozlnJd.js → setting-row-BJfCHRcb.js} +1 -1
  39. package/dist/assets/settings-2-Blzi1vr6.js +1 -0
  40. package/dist/assets/{side-dock-BcLau5S_.js → side-dock-ZdaSrQVB.js} +1 -1
  41. package/dist/assets/{skeleton-shfmXuYp.js → skeleton-BLlEzebZ.js} +1 -1
  42. package/dist/assets/{switch-C1BWMU5c.js → switch-CFLJFNSd.js} +1 -1
  43. package/dist/assets/{tag-chip-DCUrQUCP.js → tag-chip-CzGihiQx.js} +1 -1
  44. package/dist/assets/{tooltip-DfAHHA76.js → tooltip-CdcrBjrC.js} +1 -1
  45. package/dist/assets/{use-config-DAdbT5QJ.js → use-config-CVPgsBmU.js} +1 -1
  46. package/dist/assets/{use-confirm-dialog-eWcJ6V-s.js → use-confirm-dialog-CSeBk9SF.js} +1 -1
  47. package/dist/assets/x-BF2KQ--V.js +1 -0
  48. package/dist/index.html +26 -26
  49. package/package.json +9 -9
  50. package/src/features/agents/components/__tests__/agents-page.test.tsx +135 -2
  51. package/src/features/agents/components/agent-advanced-config-fields.tsx +70 -0
  52. package/src/features/agents/components/agent-details-dialog.tsx +398 -0
  53. package/src/features/agents/components/agent-dialogs.tsx +20 -47
  54. package/src/features/agents/components/agents-page.tsx +76 -10
  55. package/src/features/agents/types/agent-form.types.ts +21 -0
  56. package/src/features/agents/utils/agent-form.utils.ts +39 -0
  57. package/src/features/chat/components/conversation/__tests__/chat-conversation-header-section.test.tsx +132 -1
  58. package/src/features/chat/components/conversation/chat-conversation-header-section.tsx +8 -0
  59. package/src/features/chat/components/conversation/chat-conversation-header.tsx +7 -3
  60. package/src/features/chat/features/conversation/components/__tests__/session-conversation-area.test.tsx +18 -3
  61. package/src/features/chat/features/message/components/__tests__/chat-message-list.container.test.tsx +1 -1
  62. package/src/features/chat/features/ncp/hooks/__tests__/use-ncp-agent-runtime.test.tsx +23 -1
  63. package/src/features/chat/features/ncp/hooks/__tests__/use-ncp-session-list-view.test.tsx +74 -0
  64. package/src/features/chat/features/ncp/hooks/use-ncp-session-list-view.ts +3 -2
  65. package/src/features/chat/features/session/components/session-header/chat-session-title-switcher.tsx +294 -0
  66. package/src/features/chat/features/session/utils/__tests__/chat-session-display.utils.test.ts +15 -1
  67. package/src/features/chat/features/session/utils/__tests__/ncp-session-adapter.utils.test.ts +24 -4
  68. package/src/features/chat/features/session/utils/chat-session-display.utils.ts +3 -0
  69. package/src/features/chat/features/session/utils/ncp-session-adapter.utils.ts +1 -0
  70. package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-file-preview.test.tsx +34 -0
  71. package/src/features/chat/features/workspace/components/chat-session-workspace-file-preview.tsx +1 -7
  72. package/src/features/chat/features/workspace/utils/__tests__/chat-workspace-panel-view-model.utils.test.ts +46 -0
  73. package/src/features/chat/managers/__tests__/chat-thread.manager.test.ts +47 -0
  74. package/src/features/chat/managers/chat-thread.manager.ts +8 -2
  75. package/src/features/system-status/components/__tests__/desktop-update-config.test.tsx +97 -5
  76. package/src/features/system-status/components/desktop-update-config.tsx +91 -2
  77. package/src/features/system-status/utils/update-release-notes.utils.ts +94 -0
  78. package/src/shared/lib/api/ncp-session.types.ts +1 -1
  79. package/src/shared/lib/api/types.ts +12 -3
  80. package/src/shared/lib/i18n/locales/en-US/agents.json +41 -0
  81. package/src/shared/lib/i18n/locales/en-US/chat.json +3 -0
  82. package/src/shared/lib/i18n/locales/en-US/desktop-update.json +8 -0
  83. package/src/shared/lib/i18n/locales/zh-CN/agents.json +41 -0
  84. package/src/shared/lib/i18n/locales/zh-CN/chat.json +3 -0
  85. package/src/shared/lib/i18n/locales/zh-CN/desktop-update.json +8 -0
  86. package/dist/assets/chat-page-BtA7H1Ea.js +0 -1
  87. package/dist/assets/desktop-update-config-C6n_TB1r.js +0 -1
  88. package/dist/assets/doc-browser-DBnj9UMB.js +0 -1
  89. package/dist/assets/ellipsis-2uzhypw5.js +0 -1
  90. package/dist/assets/index-CBRP-7-a.css +0 -1
  91. package/dist/assets/index-Z1fYpbNd.js +0 -104
  92. package/dist/assets/loader-circle-BjmN5DeJ.js +0 -1
  93. package/dist/assets/mcp-marketplace-page-CoZIiD6G.js +0 -1
  94. package/dist/assets/plus-3ztRZD_l.js +0 -1
  95. package/dist/assets/providers-config-page-CWlO7J4A.js +0 -1
  96. package/dist/assets/remote-CKWZfVVB.js +0 -1
  97. package/dist/assets/rotate-cw-CHcaRUDz.js +0 -1
  98. package/dist/assets/security-config-Ds0LsJmo.js +0 -1
  99. package/dist/assets/x-DqL1mYLC.js +0 -1
@@ -1,6 +1,7 @@
1
1
  import { render, screen } from '@testing-library/react';
2
2
  import userEvent from '@testing-library/user-event';
3
- import { beforeEach, describe, expect, it, vi } from 'vitest';
3
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
4
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
4
5
  import { useRuntimeUpdateStore } from '@/features/system-status';
5
6
  import { DesktopUpdateConfig } from '@/features/system-status/components/desktop-update-config';
6
7
  import { setLanguage } from '@/shared/lib/i18n';
@@ -26,6 +27,22 @@ vi.mock('@/features/system-status', async () => {
26
27
  };
27
28
  });
28
29
 
30
+ function renderDesktopUpdateConfig() {
31
+ const queryClient = new QueryClient({
32
+ defaultOptions: {
33
+ queries: {
34
+ gcTime: 0,
35
+ retry: false
36
+ }
37
+ }
38
+ });
39
+ return render(
40
+ <QueryClientProvider client={queryClient}>
41
+ <DesktopUpdateConfig />
42
+ </QueryClientProvider>
43
+ );
44
+ }
45
+
29
46
  describe('DesktopUpdateConfig', () => {
30
47
  beforeEach(() => {
31
48
  setLanguage('zh');
@@ -60,7 +77,7 @@ describe('DesktopUpdateConfig', () => {
60
77
  availableVersion: '0.18.2-beta.1',
61
78
  downloadedVersion: null,
62
79
  minimumHostVersion: null,
63
- releaseNotesUrl: 'https://example.com/release-notes',
80
+ releaseNotesUrl: null,
64
81
  lastCheckedAt: '2026-04-13T12:00:00.000Z',
65
82
  progress: null,
66
83
  canAutoDownload: false,
@@ -77,8 +94,12 @@ describe('DesktopUpdateConfig', () => {
77
94
  });
78
95
  });
79
96
 
97
+ afterEach(() => {
98
+ vi.unstubAllGlobals();
99
+ });
100
+
80
101
  it('renders current channel information and beta guidance', () => {
81
- render(<DesktopUpdateConfig />);
102
+ renderDesktopUpdateConfig();
82
103
 
83
104
  expect(mocks.start).not.toHaveBeenCalled();
84
105
  expect(mocks.stop).not.toHaveBeenCalled();
@@ -93,7 +114,7 @@ describe('DesktopUpdateConfig', () => {
93
114
  it('sends the newly selected release channel to the desktop update manager', async () => {
94
115
  const user = userEvent.setup();
95
116
 
96
- render(<DesktopUpdateConfig />);
117
+ renderDesktopUpdateConfig();
97
118
 
98
119
  await user.click(screen.getByRole('combobox'));
99
120
  await user.click(screen.getByRole('option', { name: 'Stable' }));
@@ -118,9 +139,80 @@ describe('DesktopUpdateConfig', () => {
118
139
  : null
119
140
  }));
120
141
 
121
- render(<DesktopUpdateConfig />);
142
+ renderDesktopUpdateConfig();
122
143
 
123
144
  expect(screen.getByText('正在下载 50%')).toBeTruthy();
124
145
  expect(screen.getByText('50 B / 100 B')).toBeTruthy();
125
146
  });
147
+
148
+ it('loads structured release notes from the docs JSON endpoint', async () => {
149
+ const fetchMock = vi.fn(async () => new Response(JSON.stringify({
150
+ schemaVersion: 1,
151
+ product: 'NextClaw',
152
+ version: '0.22.0',
153
+ sections: [
154
+ {
155
+ kind: 'feature',
156
+ title: {
157
+ 'zh-CN': '功能',
158
+ 'en-US': 'Features'
159
+ },
160
+ items: [
161
+ {
162
+ title: {
163
+ 'zh-CN': '更新前查看内容',
164
+ 'en-US': 'Review before updating'
165
+ },
166
+ body: {
167
+ 'zh-CN': '更新提示可以直接展示本版本的结构化说明。',
168
+ 'en-US': 'The update prompt can show structured notes for this version.'
169
+ }
170
+ }
171
+ ]
172
+ },
173
+ {
174
+ kind: 'fix',
175
+ title: {
176
+ 'zh-CN': '修复',
177
+ 'en-US': 'Fixes'
178
+ },
179
+ items: [
180
+ {
181
+ title: {
182
+ 'zh-CN': '附件发送修复',
183
+ 'en-US': 'Attachment delivery fix'
184
+ }
185
+ }
186
+ ]
187
+ }
188
+ ]
189
+ }), {
190
+ headers: { 'content-type': 'application/json' },
191
+ status: 200
192
+ }));
193
+ vi.stubGlobal('fetch', fetchMock);
194
+ useRuntimeUpdateStore.setState((state) => ({
195
+ ...state,
196
+ snapshot: state.snapshot
197
+ ? {
198
+ ...state.snapshot,
199
+ status: 'update-available',
200
+ availableVersion: '0.22.0',
201
+ releaseNotesUrl: 'https://docs.nextclaw.io/zh/notes/2026-07-05-nextclaw-v0-22-0'
202
+ }
203
+ : null
204
+ }));
205
+
206
+ renderDesktopUpdateConfig();
207
+
208
+ expect(await screen.findByText('更新前查看内容')).toBeTruthy();
209
+ expect(screen.getByText('修复')).toBeTruthy();
210
+ expect(fetchMock).toHaveBeenCalledWith(
211
+ 'https://docs.nextclaw.io/release-notes/nextclaw-v0.22.0.json',
212
+ expect.objectContaining({
213
+ cache: 'no-store',
214
+ headers: { accept: 'application/json' }
215
+ })
216
+ );
217
+ });
126
218
  });
@@ -1,4 +1,5 @@
1
1
  import type { UpdateSnapshot } from '@nextclaw/shared';
2
+ import { useQuery } from '@tanstack/react-query';
2
3
  import { runtimeUpdateManager, useRuntimeUpdateStore } from '@/features/system-status';
3
4
  import { Button } from '@/shared/components/ui/button';
4
5
  import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/shared/components/ui/card';
@@ -6,9 +7,16 @@ import { Label } from '@/shared/components/ui/label';
6
7
  import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/shared/components/ui/select';
7
8
  import { Switch } from '@/shared/components/ui/switch';
8
9
  import { PageHeader, PageLayout } from '@/app/components/layout/page-layout';
9
- import { formatDateTime, t } from '@/shared/lib/i18n';
10
+ import { formatDateTime, getLanguage, t } from '@/shared/lib/i18n';
10
11
  import { cn } from '@/shared/lib/utils';
11
12
  import { hostCapabilityManager } from '@/shared/lib/host-capabilities';
13
+ import {
14
+ fetchReleaseNotesData,
15
+ readReleaseNotesText,
16
+ resolveReleaseNotesDataUrl,
17
+ type ReleaseNotesLocale,
18
+ type ReleaseNotesSection
19
+ } from '@/features/system-status/utils/update-release-notes.utils';
12
20
  import { Download, ExternalLink, RefreshCw, RotateCw } from 'lucide-react';
13
21
 
14
22
  const STATUS_LABEL_KEYS: Record<string, string> = {
@@ -21,6 +29,13 @@ const STATUS_LABEL_KEYS: Record<string, string> = {
21
29
  failed: 'desktopUpdatesStatusFailed',
22
30
  };
23
31
 
32
+ const RELEASE_NOTES_KIND_LABEL_KEYS: Record<string, string> = {
33
+ feature: 'desktopUpdatesReleaseNotesFeature',
34
+ enhancement: 'desktopUpdatesReleaseNotesEnhancement',
35
+ fix: 'desktopUpdatesReleaseNotesFix',
36
+ compatibility: 'desktopUpdatesReleaseNotesCompatibility'
37
+ };
38
+
24
39
  function StatusBadge({ status }: { status: string }) {
25
40
  return <span className={cn('inline-flex rounded-full px-3 py-1 text-xs font-medium ring-1', getStatusTone(status))}>{getStatusLabel(status)}</span>;
26
41
  }
@@ -117,6 +132,80 @@ function getStatusTone(status: string): string {
117
132
  return 'bg-gray-100 text-gray-700 ring-gray-200';
118
133
  }
119
134
 
135
+ function getReleaseNotesLocale(): ReleaseNotesLocale {
136
+ return getLanguage() === 'zh' ? 'zh-CN' : 'en-US';
137
+ }
138
+
139
+ function getReleaseNotesSectionTitle(section: ReleaseNotesSection, locale: ReleaseNotesLocale): string {
140
+ const title = readReleaseNotesText(section.title, locale);
141
+ return title ?? t(RELEASE_NOTES_KIND_LABEL_KEYS[section.kind] ?? 'desktopUpdatesReleaseNotesEnhancement');
142
+ }
143
+
144
+ function ReleaseNotesPreview({ snapshot }: { snapshot: UpdateSnapshot }) {
145
+ const dataUrl = resolveReleaseNotesDataUrl(snapshot);
146
+ const locale = getReleaseNotesLocale();
147
+ const releaseNotesQuery = useQuery({
148
+ queryKey: ['runtime-release-notes', dataUrl],
149
+ queryFn: async () => await fetchReleaseNotesData(dataUrl ?? ''),
150
+ enabled: Boolean(dataUrl),
151
+ retry: false,
152
+ staleTime: 5 * 60 * 1000
153
+ });
154
+ const payload = releaseNotesQuery.data;
155
+ const title = readReleaseNotesText(payload?.title, locale) ?? t('desktopUpdatesReleaseNotesPreviewTitle');
156
+ const summary = readReleaseNotesText(payload?.summary, locale) ?? t('desktopUpdatesReleaseNotesPreviewDescription');
157
+
158
+ if (!snapshot.releaseNotesUrl) {
159
+ return null;
160
+ }
161
+
162
+ return (
163
+ <Card>
164
+ <CardHeader>
165
+ <div className="flex flex-wrap items-start justify-between gap-3">
166
+ <div className="space-y-1">
167
+ <CardTitle>{title}</CardTitle>
168
+ <CardDescription>{summary}</CardDescription>
169
+ </div>
170
+ <Button variant="ghost" onClick={() => void hostCapabilityManager.openExternalUrl(snapshot.releaseNotesUrl ?? '')}>
171
+ <ExternalLink className="mr-2 h-4 w-4" />
172
+ {t('desktopUpdatesReleaseNotes')}
173
+ </Button>
174
+ </div>
175
+ </CardHeader>
176
+ <CardContent className="space-y-4">
177
+ {releaseNotesQuery.isLoading ? (
178
+ <p className="text-sm text-gray-500">{t('desktopUpdatesReleaseNotesPreviewLoading')}</p>
179
+ ) : null}
180
+ {!dataUrl || releaseNotesQuery.isError ? (
181
+ <p className="text-sm text-gray-500">{t('desktopUpdatesReleaseNotesPreviewUnavailable')}</p>
182
+ ) : null}
183
+ {payload ? (
184
+ <div className="grid gap-4 md:grid-cols-2">
185
+ {payload.sections.map((section) => (
186
+ <div key={section.kind} className="rounded-xl border border-gray-200 bg-gray-50/60 p-4">
187
+ <p className="text-sm font-semibold text-gray-900">{getReleaseNotesSectionTitle(section, locale)}</p>
188
+ <ul className="mt-3 space-y-3">
189
+ {section.items.map((item, index) => {
190
+ const itemTitle = readReleaseNotesText(item.title, locale);
191
+ const itemBody = readReleaseNotesText(item.body, locale);
192
+ return (
193
+ <li key={`${itemTitle ?? section.kind}-${index}`} className="space-y-1">
194
+ {itemTitle ? <p className="text-sm font-medium text-gray-800">{itemTitle}</p> : null}
195
+ {itemBody ? <p className="text-sm leading-5 text-gray-600">{itemBody}</p> : null}
196
+ </li>
197
+ );
198
+ })}
199
+ </ul>
200
+ </div>
201
+ ))}
202
+ </div>
203
+ ) : null}
204
+ </CardContent>
205
+ </Card>
206
+ );
207
+ }
208
+
120
209
  function RuntimeUpdateUnavailableState() {
121
210
  return (
122
211
  <PageLayout className="space-y-6">
@@ -192,6 +281,7 @@ export function DesktopUpdateConfig() {
192
281
  {snapshot.errorMessage && snapshot.status !== 'blocked' ? <div className="rounded-2xl border border-red-200 bg-red-50/70 p-4 text-sm text-red-700">{snapshot.errorMessage}</div> : null}
193
282
  </CardContent>
194
283
  </Card>
284
+ <ReleaseNotesPreview snapshot={snapshot} />
195
285
  <Card>
196
286
  <CardHeader>
197
287
  <CardTitle>{t('desktopUpdatesPreferencesTitle')}</CardTitle>
@@ -250,7 +340,6 @@ export function DesktopUpdateConfig() {
250
340
  <RotateCw className={cn('mr-2 h-4 w-4', isApplying && 'animate-spin')} />
251
341
  {t('runtimeUpdatesApplyNow')}
252
342
  </Button>
253
- {snapshot.releaseNotesUrl ? <Button variant="ghost" onClick={() => void hostCapabilityManager.openExternalUrl(snapshot.releaseNotesUrl ?? '')}><ExternalLink className="mr-2 h-4 w-4" />{t('desktopUpdatesReleaseNotes')}</Button> : null}
254
343
  </CardContent>
255
344
  </Card>
256
345
  </PageLayout>
@@ -0,0 +1,94 @@
1
+ import type { UpdateSnapshot } from '@nextclaw/shared';
2
+
3
+ export type ReleaseNotesLocale = 'zh-CN' | 'en-US';
4
+
5
+ export type ReleaseNotesText = Partial<Record<ReleaseNotesLocale, string>>;
6
+
7
+ export type ReleaseNotesItem = {
8
+ title: ReleaseNotesText;
9
+ body?: ReleaseNotesText;
10
+ };
11
+
12
+ export type ReleaseNotesSection = {
13
+ kind: string;
14
+ title?: ReleaseNotesText;
15
+ items: ReleaseNotesItem[];
16
+ };
17
+
18
+ export type ReleaseNotesPayload = {
19
+ title?: ReleaseNotesText;
20
+ summary?: ReleaseNotesText;
21
+ sections: ReleaseNotesSection[];
22
+ };
23
+
24
+ export function readReleaseNotesText(
25
+ value: ReleaseNotesText | undefined,
26
+ locale: ReleaseNotesLocale
27
+ ): string | null {
28
+ const fallbackLocale = locale === 'zh-CN' ? 'en-US' : 'zh-CN';
29
+ const text = value?.[locale]?.trim() || value?.[fallbackLocale]?.trim();
30
+ return text || null;
31
+ }
32
+
33
+ export function resolveReleaseNotesDataUrl(snapshot: UpdateSnapshot): string | null {
34
+ const releaseNotesUrl = snapshot.releaseNotesUrl?.trim();
35
+ const version = (snapshot.availableVersion ?? snapshot.downloadedVersion)?.trim();
36
+ if (!releaseNotesUrl || !version || !/^[0-9A-Za-z.-]+$/.test(version)) {
37
+ return null;
38
+ }
39
+
40
+ try {
41
+ return new URL(`/release-notes/nextclaw-v${version}.json`, releaseNotesUrl).toString();
42
+ } catch {
43
+ return null;
44
+ }
45
+ }
46
+
47
+ function isRecord(value: unknown): value is Record<string, unknown> {
48
+ return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
49
+ }
50
+
51
+ function isReleaseNotesText(value: unknown): value is ReleaseNotesText {
52
+ if (!isRecord(value)) {
53
+ return false;
54
+ }
55
+ return typeof value['zh-CN'] === 'string' || typeof value['en-US'] === 'string';
56
+ }
57
+
58
+ function isReleaseNotesItem(value: unknown): value is ReleaseNotesItem {
59
+ if (!isRecord(value) || !isReleaseNotesText(value.title)) {
60
+ return false;
61
+ }
62
+ return value.body === undefined || isReleaseNotesText(value.body);
63
+ }
64
+
65
+ function isReleaseNotesSection(value: unknown): value is ReleaseNotesSection {
66
+ return isRecord(value)
67
+ && typeof value.kind === 'string'
68
+ && Array.isArray(value.items)
69
+ && value.items.every(isReleaseNotesItem)
70
+ && (value.title === undefined || isReleaseNotesText(value.title));
71
+ }
72
+
73
+ function isReleaseNotesPayload(value: unknown): value is ReleaseNotesPayload {
74
+ return isRecord(value)
75
+ && Array.isArray(value.sections)
76
+ && value.sections.every(isReleaseNotesSection)
77
+ && (value.title === undefined || isReleaseNotesText(value.title))
78
+ && (value.summary === undefined || isReleaseNotesText(value.summary));
79
+ }
80
+
81
+ export async function fetchReleaseNotesData(url: string): Promise<ReleaseNotesPayload> {
82
+ const response = await fetch(url, {
83
+ cache: 'no-store',
84
+ headers: { accept: 'application/json' }
85
+ });
86
+ if (!response.ok) {
87
+ throw new Error(`Release notes request failed with HTTP ${response.status}.`);
88
+ }
89
+ const payload: unknown = await response.json();
90
+ if (!isReleaseNotesPayload(payload)) {
91
+ throw new Error('Release notes payload has an unsupported shape.');
92
+ }
93
+ return payload;
94
+ }
@@ -32,7 +32,7 @@ export type SessionContextWindowView = {
32
32
  };
33
33
 
34
34
  export type SessionActivityPreviewView = {
35
- state: "running" | "completed" | "failed" | "idle";
35
+ state: "running" | "completed" | "failed" | "cancelled" | "idle";
36
36
  timestamp: string;
37
37
  statusText?: string;
38
38
  replyText?: string;
@@ -56,6 +56,9 @@ export type BootstrapStatusView = {
56
56
  };
57
57
 
58
58
  export type ThinkingLevel = "off" | "minimal" | "low" | "medium" | "high" | "adaptive" | "xhigh";
59
+ export type AgentModelsView = Record<string, {
60
+ params: Record<string, unknown>;
61
+ } & Record<string, unknown>>;
59
62
 
60
63
  export type ProviderInstanceView = {
61
64
  providerId: string;
@@ -253,11 +256,13 @@ export type AgentProfileView = {
253
256
  workspace?: string;
254
257
  model?: string;
255
258
  runtime?: string;
256
- runtimeConfig?: Record<string, unknown>;
259
+ runtimeConfig?: Record<string, unknown> | null;
257
260
  engine?: string;
258
261
  engineConfig?: Record<string, unknown>;
259
262
  thinkingDefault?: ThinkingLevel;
263
+ models?: AgentModelsView;
260
264
  contextTokens?: number;
265
+ reservedContextTokens?: number;
261
266
  maxToolIterations?: number;
262
267
  builtIn?: boolean;
263
268
  };
@@ -270,7 +275,8 @@ export type AgentCreateRequest = {
270
275
  home?: string;
271
276
  model?: string;
272
277
  runtime?: string;
273
- runtimeConfig?: Record<string, unknown>;
278
+ runtimeConfig?: Record<string, unknown> | null;
279
+ contextTokens?: number | null;
274
280
  };
275
281
 
276
282
  export type AgentUpdateRequest = {
@@ -279,7 +285,8 @@ export type AgentUpdateRequest = {
279
285
  avatar?: string;
280
286
  model?: string;
281
287
  runtime?: string;
282
- runtimeConfig?: Record<string, unknown>;
288
+ runtimeConfig?: Record<string, unknown> | null;
289
+ contextTokens?: number | null;
283
290
  };
284
291
 
285
292
  export type AgentDeleteResult = {
@@ -523,7 +530,9 @@ export type ConfigView = {
523
530
  engine?: string;
524
531
  engineConfig?: Record<string, unknown>;
525
532
  thinkingDefault?: ThinkingLevel;
533
+ models?: AgentModelsView;
526
534
  contextTokens?: number;
535
+ reservedContextTokens?: number;
527
536
  maxToolIterations?: number;
528
537
  };
529
538
  runtimes?: {
@@ -19,12 +19,52 @@
19
19
  "agentsRuntimeSelectPlaceholder": "Select runtime",
20
20
  "agentsRuntimeUnavailableHelp": "This runtime is no longer available in the current list. Switch to an installed and available runtime.",
21
21
  "agentsCreateAction": "Create Agent",
22
+ "agentsViewDetailsAction": "View details",
22
23
  "agentsEditAction": "Edit",
23
24
  "agentsEditDialogTitle": "Edit agent identity",
24
25
  "agentsEditDialogDescription": "Update the name, role description, and avatar. The agent ID and home directory stay stable to protect existing memory, skills, and sessions.",
25
26
  "agentsEditHomeReadonly": "Home directory stays unchanged",
26
27
  "agentsEditHomeReadonlyHint": "Use a dedicated config migration flow to move the home directory and avoid losing agent context unexpectedly.",
27
28
  "agentsEditSaveAction": "Save edits",
29
+ "agentsAdvancedConfigToggle": "Advanced configuration",
30
+ "agentsAdvancedConfigDescription": "Leave a field empty to inherit the default configuration; filled values become overrides for this agent.",
31
+ "agentsAdvancedInheritOption": "Inherit default",
32
+ "agentsAdvancedInheritPlaceholder": "Empty inherits default",
33
+ "agentsAdvancedContextTokensLabel": "Context window size",
34
+ "agentsAdvancedReservedContextTokensLabel": "Reserved context size",
35
+ "agentsAdvancedMaxToolIterationsLabel": "Max tool iterations",
36
+ "agentsAdvancedThinkingDefaultLabel": "Default thinking level",
37
+ "agentsAdvancedRuntimeConfigLabel": "Runtime config JSON",
38
+ "agentsAdvancedModelsLabel": "Model overrides JSON",
39
+ "agentsAdvancedJsonPlaceholder": "Leave empty to inherit defaults; enter a JSON object when filled",
40
+ "agentsAdvancedInvalidNumberError": "Advanced numeric fields must contain a valid number",
41
+ "agentsAdvancedInvalidJsonError": "Advanced JSON parsing failed",
42
+ "agentsAdvancedJsonObjectError": "Advanced JSON must be an object",
43
+ "agentsAdvancedParseFailed": "Failed to parse advanced configuration",
44
+ "agentsDetailsDialogTitle": "Agent details",
45
+ "agentsDetailsDialogDescription": "View this agent's visible identity, runtime, and context configuration.",
46
+ "agentsDetailsEditAction": "Edit",
47
+ "agentsDetailsIdentitySection": "Identity",
48
+ "agentsDetailsRuntimeSection": "Runtime",
49
+ "agentsDetailsContextSection": "Context",
50
+ "agentsDetailsBehaviorSection": "Behavior",
51
+ "agentsDetailsFieldId": "Agent ID",
52
+ "agentsDetailsFieldDisplayName": "Display name",
53
+ "agentsDetailsFieldDescription": "Role description",
54
+ "agentsDetailsFieldWorkspace": "Home directory",
55
+ "agentsDetailsFieldAvatar": "Avatar",
56
+ "agentsDetailsFieldModel": "Model",
57
+ "agentsDetailsFieldRuntime": "Runtime",
58
+ "agentsDetailsFieldRuntimeConfig": "Runtime config",
59
+ "agentsDetailsFieldContextTokens": "Context window size",
60
+ "agentsDetailsFieldReservedContextTokens": "Reserved context size",
61
+ "agentsDetailsFieldMaxToolIterations": "Max tool iterations",
62
+ "agentsDetailsFieldThinkingDefault": "Default thinking level",
63
+ "agentsDetailsFieldModelOverrides": "Model overrides",
64
+ "agentsDetailsInheritedDefault": "Inherited default",
65
+ "agentsDetailsAgentOverride": "Agent override",
66
+ "agentsDetailsEmptyValue": "No description",
67
+ "agentsDetailsUnsetValue": "Not set",
28
68
  "agentsRemoveAction": "Remove",
29
69
  "agentsNewChat": "New Chat",
30
70
  "agentsLoading": "Loading agents...",
@@ -38,6 +78,7 @@
38
78
  "agentsCardBuiltInSummary": "The built-in main agent, ideal as the default entry and coordinating collaborator.",
39
79
  "agentsCardCustomSummary": "A dedicated identity with its own memory, skills, and role style.",
40
80
  "agentsCardRuntimeLabel": "Runtime",
81
+ "agentsCardContextTokensLabel": "Context",
41
82
  "agentsCardHomeLabel": "Home Directory",
42
83
  "agentsCardAvatarLabel": "Avatar",
43
84
  "agentsCardStartChat": "Start Chat",
@@ -29,6 +29,9 @@
29
29
  "chatProviderSetupTitle": "Configure a Provider First",
30
30
  "chatProviderSetupDescription": "No models are available yet. Configure and save at least one provider, then return to start chatting.",
31
31
  "chatSessionLabel": "Current Session",
32
+ "chatSessionSwitch": "Switch session",
33
+ "chatSessionSwitcherTitle": "Recent sessions",
34
+ "chatSessionSwitcherNoResults": "No matching sessions",
32
35
  "chatNoSession": "No session selected",
33
36
  "chatHistoryLoading": "Loading session history...",
34
37
  "chatBackToParent": "Back to parent",
@@ -75,6 +75,14 @@
75
75
  "desktopUpdatesDownloadNow": "Download Update",
76
76
  "desktopUpdatesApplyNow": "Restart to Update",
77
77
  "desktopUpdatesReleaseNotes": "Release Notes",
78
+ "desktopUpdatesReleaseNotesPreviewTitle": "What's New",
79
+ "desktopUpdatesReleaseNotesPreviewDescription": "Review the main changes in this version before updating.",
80
+ "desktopUpdatesReleaseNotesPreviewLoading": "Loading release notes...",
81
+ "desktopUpdatesReleaseNotesPreviewUnavailable": "Structured release notes could not be loaded in the app. Open the full notes instead.",
82
+ "desktopUpdatesReleaseNotesFeature": "Features",
83
+ "desktopUpdatesReleaseNotesEnhancement": "Enhancements",
84
+ "desktopUpdatesReleaseNotesFix": "Fixes",
85
+ "desktopUpdatesReleaseNotesCompatibility": "Defaults and Compatibility",
78
86
  "desktopUpdatesLoadFailed": "Failed to load update state",
79
87
  "desktopUpdatesCheckFailed": "Failed to check for updates",
80
88
  "desktopUpdatesDownloadFailed": "Failed to download update",
@@ -19,12 +19,52 @@
19
19
  "agentsRuntimeSelectPlaceholder": "选择 Runtime",
20
20
  "agentsRuntimeUnavailableHelp": "当前 Runtime 已不在可用列表中;建议改选一个已安装且可用的 Runtime。",
21
21
  "agentsCreateAction": "创建 Agent",
22
+ "agentsViewDetailsAction": "查看详情",
22
23
  "agentsEditAction": "编辑",
23
24
  "agentsEditDialogTitle": "编辑 Agent 身份",
24
25
  "agentsEditDialogDescription": "更新名称、角色描述与头像。Agent ID 与主目录保持稳定,避免影响既有记忆、技能与会话。",
25
26
  "agentsEditHomeReadonly": "主目录保持不变",
26
27
  "agentsEditHomeReadonlyHint": "如需迁移主目录,请走独立配置迁移流程,避免意外丢失 Agent 上下文。",
27
28
  "agentsEditSaveAction": "保存编辑",
29
+ "agentsAdvancedConfigToggle": "高级配置",
30
+ "agentsAdvancedConfigDescription": "留空会继承默认配置;填写后会成为这个 Agent 的专属覆盖。",
31
+ "agentsAdvancedInheritOption": "继承默认",
32
+ "agentsAdvancedInheritPlaceholder": "留空继承默认",
33
+ "agentsAdvancedContextTokensLabel": "上下文窗口大小",
34
+ "agentsAdvancedReservedContextTokensLabel": "预留上下文大小",
35
+ "agentsAdvancedMaxToolIterationsLabel": "最大工具迭代次数",
36
+ "agentsAdvancedThinkingDefaultLabel": "默认思考强度",
37
+ "agentsAdvancedRuntimeConfigLabel": "Runtime 配置 JSON",
38
+ "agentsAdvancedModelsLabel": "模型覆盖 JSON",
39
+ "agentsAdvancedJsonPlaceholder": "留空继承默认;填写时请输入 JSON 对象",
40
+ "agentsAdvancedInvalidNumberError": "高级配置里的数字必须是有效数字",
41
+ "agentsAdvancedInvalidJsonError": "高级配置 JSON 解析失败",
42
+ "agentsAdvancedJsonObjectError": "高级配置 JSON 必须是对象",
43
+ "agentsAdvancedParseFailed": "高级配置解析失败",
44
+ "agentsDetailsDialogTitle": "Agent 详情",
45
+ "agentsDetailsDialogDescription": "查看这个 Agent 当前可见的身份、运行时与上下文配置。",
46
+ "agentsDetailsEditAction": "编辑",
47
+ "agentsDetailsIdentitySection": "身份",
48
+ "agentsDetailsRuntimeSection": "运行",
49
+ "agentsDetailsContextSection": "上下文",
50
+ "agentsDetailsBehaviorSection": "行为",
51
+ "agentsDetailsFieldId": "Agent ID",
52
+ "agentsDetailsFieldDisplayName": "显示名称",
53
+ "agentsDetailsFieldDescription": "角色描述",
54
+ "agentsDetailsFieldWorkspace": "主目录",
55
+ "agentsDetailsFieldAvatar": "头像",
56
+ "agentsDetailsFieldModel": "模型",
57
+ "agentsDetailsFieldRuntime": "Runtime",
58
+ "agentsDetailsFieldRuntimeConfig": "Runtime 配置",
59
+ "agentsDetailsFieldContextTokens": "上下文窗口大小",
60
+ "agentsDetailsFieldReservedContextTokens": "预留上下文大小",
61
+ "agentsDetailsFieldMaxToolIterations": "最大工具迭代次数",
62
+ "agentsDetailsFieldThinkingDefault": "默认思考强度",
63
+ "agentsDetailsFieldModelOverrides": "模型覆盖",
64
+ "agentsDetailsInheritedDefault": "继承默认",
65
+ "agentsDetailsAgentOverride": "Agent 覆盖",
66
+ "agentsDetailsEmptyValue": "暂无描述",
67
+ "agentsDetailsUnsetValue": "未设置",
28
68
  "agentsRemoveAction": "移除",
29
69
  "agentsNewChat": "新建会话",
30
70
  "agentsLoading": "正在加载 Agent...",
@@ -38,6 +78,7 @@
38
78
  "agentsCardBuiltInSummary": "系统主 Agent,适合作为默认入口与总控协作者。",
39
79
  "agentsCardCustomSummary": "专属 Agent 身份,可沉淀自己的记忆、技能与角色风格。",
40
80
  "agentsCardRuntimeLabel": "Runtime",
81
+ "agentsCardContextTokensLabel": "上下文",
41
82
  "agentsCardHomeLabel": "主目录",
42
83
  "agentsCardAvatarLabel": "Avatar",
43
84
  "agentsCardStartChat": "开始对话",
@@ -29,6 +29,9 @@
29
29
  "chatProviderSetupTitle": "开始前先配置提供商",
30
30
  "chatProviderSetupDescription": "你还没有可用模型。先在提供商页面配置并保存至少一个 Provider 后,再回来开始对话。",
31
31
  "chatSessionLabel": "当前会话",
32
+ "chatSessionSwitch": "切换会话",
33
+ "chatSessionSwitcherTitle": "最近会话",
34
+ "chatSessionSwitcherNoResults": "没有匹配的会话",
32
35
  "chatNoSession": "未选择会话",
33
36
  "chatHistoryLoading": "加载会话历史中...",
34
37
  "chatBackToParent": "返回父会话",
@@ -75,6 +75,14 @@
75
75
  "desktopUpdatesDownloadNow": "下载更新",
76
76
  "desktopUpdatesApplyNow": "立即重启更新",
77
77
  "desktopUpdatesReleaseNotes": "查看更新说明",
78
+ "desktopUpdatesReleaseNotesPreviewTitle": "本次更新",
79
+ "desktopUpdatesReleaseNotesPreviewDescription": "更新前可以先查看这个版本的主要变化。",
80
+ "desktopUpdatesReleaseNotesPreviewLoading": "正在读取更新说明...",
81
+ "desktopUpdatesReleaseNotesPreviewUnavailable": "暂时无法在应用内读取结构化更新说明,可以打开完整说明。",
82
+ "desktopUpdatesReleaseNotesFeature": "功能",
83
+ "desktopUpdatesReleaseNotesEnhancement": "增强",
84
+ "desktopUpdatesReleaseNotesFix": "修复",
85
+ "desktopUpdatesReleaseNotesCompatibility": "默认行为与兼容性",
78
86
  "desktopUpdatesLoadFailed": "读取更新状态失败",
79
87
  "desktopUpdatesCheckFailed": "检查更新失败",
80
88
  "desktopUpdatesDownloadFailed": "下载更新失败",
@@ -1 +0,0 @@
1
- import{h as e,p as t,r as n,u as r,v as i}from"./react-DjpzoZXB.js";import{C as a,T as o,w as s}from"./side-dock-BcLau5S_.js";import{Nt as c,ft as l,jt as u}from"./api-DLtsiBKm.js";import{c as d,l as f,n as p,r as m}from"./switch-C1BWMU5c.js";import{a as h,i as g,n as _,o as v,r as y,s as b}from"./confirm-dialog-iIJFFp2T.js";import{a as x,i as S,n as C,r as w,t as T}from"./select-D7GcNP0z.js";import{t as E}from"./provider-scoped-model-input-g1WkGiJ8.js";import{i as D}from"./i18n-provider-di1waTGX.js";import{t as ee}from"./ellipsis-2uzhypw5.js";import{t as O}from"./plus-3ztRZD_l.js";import{n as te}from"./skeleton-shfmXuYp.js";import{t as k}from"./use-confirm-dialog-eWcJ6V-s.js";import{t as ne}from"./tag-chip-DCUrQUCP.js";import{A as re,B as ie,D as ae,E as oe,F as se,H as ce,M as A,N as le,O as ue,P as j,R as de,T as M,U as N,_t as P,a as F,at as I,ct as L,d as R,f as z,ft as B,i as V,j as H,k as fe,m as pe,n as U,o as me,r as W,rt as he,s as ge,t as _e,ut as ve,z as G}from"./index-Z1fYpbNd.js";import{l as K,t as q,u as J}from"./use-config-DAdbT5QJ.js";var Y=i(e(),1),X=t(),Z=Y.forwardRef(({className:e,...t},n)=>(0,X.jsx)(`textarea`,{className:r(`flex min-h-28 w-full rounded-xl border border-border bg-card px-3.5 py-2.5 text-sm text-foreground placeholder:text-muted-foreground/55 placeholder:font-normal focus:outline-none focus:ring-1 focus:ring-primary/40 focus:border-primary/50 transition-colors disabled:cursor-not-allowed disabled:opacity-50`,e),ref:n,...t}));Z.displayName=`Textarea`;function ye(e){return{displayName:e.displayName??``,description:e.description??``,avatar:e.avatar??``,model:e.model??``,runtime:e.runtime??e.engine??``}}function be(e){let{runtimeOptions:t,currentRuntime:n}=e,r=n.trim();if(!r)return t;let i=A(r);return t.some(e=>e.value===i)?t:[...t,{value:i,label:j(i),icon:null,ready:!1,reason:`unavailable`,reasonMessage:null,supportedModels:void 0,recommendedModel:null,cta:null}].sort((e,t)=>e.value===`native`?-1:t.value===`native`?1:e.value.localeCompare(t.value))}function xe({value:e,disabled:t=!1,runtimeOptions:r,defaultRuntime:i,onChange:a}){let o=e.trim()?A(e):``,s=be({runtimeOptions:r,currentRuntime:e}),c=s.find(e=>e.value===o)??null,l=c?.reasonMessage?.trim()||(c?.ready===!1?n(`agentsRuntimeUnavailableHelp`):``);return(0,X.jsxs)(`div`,{className:`space-y-2`,children:[(0,X.jsxs)(T,{value:o||i,onValueChange:e=>a(e===i?``:e),disabled:t,children:[(0,X.jsx)(S,{"aria-label":n(`agentsCardRuntimeLabel`),className:`rounded-xl`,children:(0,X.jsx)(x,{placeholder:n(`agentsRuntimeSelectPlaceholder`)})}),(0,X.jsx)(C,{className:`rounded-xl`,children:s.map(e=>(0,X.jsx)(w,{value:e.value,disabled:e.ready===!1&&e.value!==o,className:`rounded-lg`,children:e.label},e.value))})]}),l?(0,X.jsx)(`p`,{className:`text-xs text-gray-500`,children:l}):null]})}function Se({agent:e,pending:t,providerCatalog:n,runtimeOptions:r,defaultRuntime:i,onOpenChange:a,onSubmit:o}){return(0,X.jsx)(_,{open:e!==null,onOpenChange:a,children:e?(0,X.jsx)(Ce,{agent:e,pending:t,providerCatalog:n,runtimeOptions:r,defaultRuntime:i,onOpenChange:a,onSubmit:o},e.id):null})}function Ce(e){let{agent:t,pending:r,providerCatalog:i,runtimeOptions:a,defaultRuntime:o,onOpenChange:s,onSubmit:l}=e,[u,d]=(0,Y.useState)(ye(t));return(0,X.jsxs)(y,{className:`flex max-h-[calc(100vh-2rem)] flex-col overflow-hidden border-none bg-[linear-gradient(180deg,#fff9f1_0%,#ffffff_24%)] p-0 sm:max-h-[760px] sm:max-w-xl`,children:[(0,X.jsx)(`div`,{className:`shrink-0 border-b border-[#f0e2c8] px-6 py-6`,children:(0,X.jsxs)(v,{className:`text-left`,children:[(0,X.jsx)(b,{children:n(`agentsEditDialogTitle`)}),(0,X.jsx)(g,{children:n(`agentsEditDialogDescription`)})]})}),(0,X.jsx)(`div`,{className:`min-h-0 flex-1 overflow-y-auto overscroll-contain px-6 py-6`,children:(0,X.jsxs)(`div`,{className:`space-y-4`,children:[(0,X.jsx)(D,{tone:`warning`,title:n(`agentsEditHomeReadonly`),description:n(`agentsEditHomeReadonlyHint`),children:(0,X.jsx)(`div`,{className:`break-all text-sm text-amber-950`,children:t.workspace??`-`})}),(0,X.jsxs)(`div`,{className:`grid gap-4 md:grid-cols-2`,children:[(0,X.jsx)(c,{value:u.displayName,onChange:e=>d(t=>({...t,displayName:e.target.value})),placeholder:n(`agentsFormNamePlaceholder`)}),(0,X.jsx)(Z,{value:u.description,onChange:e=>d(t=>({...t,description:e.target.value})),placeholder:n(`agentsFormDescriptionPlaceholder`),rows:4,className:`md:col-span-2`}),(0,X.jsx)(c,{value:u.avatar,onChange:e=>d(t=>({...t,avatar:e.target.value})),placeholder:n(`agentsFormAvatarPlaceholder`)}),(0,X.jsx)(E,{value:u.model,onChange:e=>d(t=>({...t,model:e})),providerCatalog:i,disabled:r,className:`md:col-span-2`}),(0,X.jsx)(xe,{value:u.runtime,onChange:e=>d(t=>({...t,runtime:e})),runtimeOptions:a,defaultRuntime:o,disabled:r})]})]})}),(0,X.jsxs)(h,{className:`shrink-0 border-t border-[#f1e7d4] px-6 py-5`,children:[(0,X.jsx)(f,{type:`button`,variant:`ghost`,onClick:()=>s(!1),disabled:r,children:n(`cancel`)}),(0,X.jsxs)(f,{type:`button`,variant:`primary`,className:`rounded-2xl px-5`,onClick:()=>l(t.id,u),disabled:r,children:[(0,X.jsx)(L,{className:`mr-2 h-4 w-4`}),n(`agentsEditSaveAction`)]})]})]})}var we=`请直接创建一个默认示例 Agent,不要问我问题。创建完成后,简单告诉我它能做什么。`;function Te(e){let{agentCount:t,onCreate:r}=e;return(0,X.jsxs)(`section`,{className:`flex flex-col gap-3 border-b border-gray-200 pb-4 sm:flex-row sm:items-end sm:justify-between`,children:[(0,X.jsxs)(`div`,{className:`min-w-0 space-y-1`,children:[(0,X.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,X.jsx)(`h1`,{className:`text-xl font-semibold text-gray-950`,children:n(`agentsHeroEyebrow`)}),(0,X.jsx)(`span`,{className:`rounded-full border border-gray-200 bg-white px-2 py-0.5 text-xs font-medium text-gray-500`,children:t})]}),(0,X.jsx)(`p`,{className:`max-w-2xl text-sm leading-6 text-gray-500`,children:n(`agentsHeroDescription`)})]}),(0,X.jsxs)(f,{type:`button`,variant:`primary`,className:`h-9 shrink-0 rounded-xl px-4 text-sm font-semibold`,onClick:r,children:[(0,X.jsx)(O,{className:`mr-2 h-4 w-4`}),n(`agentsCreateButton`)]})]})}function Q(e){let{icon:t,label:n,disabled:i=!1,destructive:a=!1,onClick:o}=e;return(0,X.jsxs)(`button`,{type:`button`,className:r(`flex w-full items-center gap-2 rounded-lg px-3 py-2 text-left text-sm transition-colors disabled:cursor-not-allowed disabled:opacity-50`,a?`text-destructive hover:bg-destructive/10`:`text-gray-700 hover:bg-gray-100`),onClick:o,disabled:i,children:[(0,X.jsx)(t,{className:`h-4 w-4 shrink-0`}),(0,X.jsx)(`span`,{children:n})]})}function Ee(e){let{agent:t,runtimeOptions:r,defaultRuntimeLabel:i,updatePending:a,deletePending:o,onStartChat:s,onEdit:c,onDelete:l}=e,u=t.runtime?.trim()||t.engine?.trim()||``,d=u?r.find(e=>e.value===A(u))?.label??j(u):i;return(0,X.jsx)(p,{className:`group overflow-hidden border border-gray-200 bg-white shadow-none transition-colors duration-200 hover:border-gray-300`,children:(0,X.jsxs)(m,{className:`relative flex h-full flex-col gap-3 px-3.5 py-3.5`,children:[(0,X.jsxs)(`div`,{className:`flex items-start gap-2.5 pr-16`,children:[(0,X.jsx)(re,{agentId:t.id,displayName:t.displayName,avatarUrl:t.avatarUrl,className:`h-9 w-9 shrink-0`}),(0,X.jsxs)(`div`,{className:`min-w-0 flex-1 space-y-0.5`,children:[(0,X.jsxs)(`div`,{className:`flex min-w-0 items-center gap-2`,children:[(0,X.jsx)(`div`,{className:`truncate text-sm font-semibold text-gray-950`,children:t.displayName?.trim()||t.id}),t.builtIn?(0,X.jsxs)(ne,{tone:`warning`,className:`h-5 gap-1 border-amber-200 bg-amber-50 px-1.5 text-[10px] text-amber-700`,children:[(0,X.jsx)(I,{className:`h-3 w-3`}),n(`agentsCardBuiltInTag`)]}):null]}),(0,X.jsxs)(`div`,{className:`truncate text-xs text-gray-400`,children:[`@`,t.id]})]})]}),(0,X.jsxs)(`div`,{className:`absolute right-2.5 top-2.5 flex items-center gap-1 opacity-100 transition-opacity md:opacity-0 md:group-hover:opacity-100 md:group-focus-within:opacity-100`,children:[(0,X.jsx)(f,{type:`button`,variant:`ghost`,size:`icon`,className:`h-8 w-8 rounded-lg text-gray-400 hover:text-gray-800`,"aria-label":n(`agentsCardStartChat`),title:n(`agentsCardStartChat`),onClick:s,children:(0,X.jsx)(ve,{className:`h-4 w-4`})}),(0,X.jsxs)(ie,{children:[(0,X.jsx)(N,{asChild:!0,children:(0,X.jsx)(f,{type:`button`,variant:`ghost`,size:`icon`,className:`h-8 w-8 rounded-lg text-gray-400 hover:text-gray-800`,"aria-label":n(`chatSessionMoreActions`),title:n(`chatSessionMoreActions`),children:(0,X.jsx)(ee,{className:`h-4 w-4`})})}),(0,X.jsxs)(ce,{align:`end`,className:`w-44 p-1.5`,children:[(0,X.jsx)(Q,{icon:L,label:n(`agentsEditAction`),onClick:c,disabled:a}),t.builtIn?null:(0,X.jsx)(Q,{icon:he,label:n(`agentsRemoveAction`),onClick:l,disabled:o,destructive:!0})]})]})]}),(0,X.jsx)(`p`,{className:`line-clamp-2 min-h-10 text-sm leading-5 text-gray-600`,children:t.description?.trim()||(t.builtIn?n(`agentsCardBuiltInSummary`):n(`agentsCardCustomSummary`))}),(0,X.jsxs)(`div`,{className:`mt-auto grid gap-2 border-t border-gray-100 pt-2 text-xs text-gray-500`,children:[(0,X.jsxs)(`div`,{className:`flex min-w-0 items-center gap-2`,children:[(0,X.jsx)(te,{className:`h-3.5 w-3.5 shrink-0 text-gray-300`}),(0,X.jsx)(`span`,{className:`truncate`,children:d})]}),(0,X.jsxs)(`div`,{className:`flex min-w-0 items-center gap-2`,children:[(0,X.jsx)(B,{className:`h-3.5 w-3.5 shrink-0 text-gray-300`}),(0,X.jsx)(`span`,{className:`truncate`,children:t.workspace??`-`})]})]})]})})}function De(){let e=G(),t=U(),r=s(),i=ae(),a=q(),o=J(),c=K(),l=W(),u=fe(),h=ue(),[g,_]=(0,Y.useState)(null),v=(0,Y.useMemo)(()=>i.data?.agents??[],[i.data?.agents]),y=(0,Y.useMemo)(()=>[...v].sort((e,t)=>Number(!!t.builtIn)-Number(!!e.builtIn)||e.id.localeCompare(t.id)),[v]),b=(0,Y.useMemo)(()=>pe({config:a.data,providersView:o.data,templatesView:c.data,onlyConfigured:!0}),[a.data,o.data,c.data]),x=(0,Y.useMemo)(()=>H(l.data?.options??[]),[l.data?.options]),S=(0,Y.useMemo)(()=>A(l.data?.defaultType??`native`),[l.data?.defaultType]),C=(0,Y.useMemo)(()=>x.find(e=>e.value===S)?.label??j(S),[S,x]),w=e=>{_(e)},T=async(e,t)=>{await u.mutateAsync({agentId:e,data:{displayName:t.displayName,description:t.description,avatar:t.avatar,model:t.model,...t.runtime.trim()?{runtime:t.runtime.trim()}:{runtime:``}}}),_(null)},E=t=>{e.chatSessionListManager.startAgentDraftChat(t.id,le(t,S))},D=()=>{r(`/chat`),t.chatDraftIntentManager.requestDraft(we)};return(0,X.jsxs)(d,{className:`space-y-5`,children:[(0,X.jsx)(Te,{agentCount:v.length,onCreate:D}),(0,X.jsx)(`div`,{className:`grid gap-4 md:grid-cols-2 xl:grid-cols-3`,children:i.isLoading?(0,X.jsx)(p,{className:`md:col-span-2 xl:col-span-3 border-dashed border-[#d9dce3] bg-white/70`,children:(0,X.jsx)(m,{className:`py-14 text-center text-sm text-gray-500`,children:n(`agentsLoading`)})}):y.length===0?(0,X.jsx)(p,{className:`md:col-span-2 xl:col-span-3 overflow-hidden border-dashed border-[#d9dce3] bg-[linear-gradient(135deg,#fff7ea_0%,#f4fbff_100%)]`,children:(0,X.jsxs)(m,{className:`flex min-h-[240px] flex-col items-center justify-center px-6 py-14 text-center`,children:[(0,X.jsx)(`div`,{className:`mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-white/80 shadow-[0_18px_44px_rgba(0,0,0,0.08)]`,children:(0,X.jsx)(P,{className:`h-8 w-8 text-[#d39a3b]`})}),(0,X.jsx)(`div`,{className:`text-lg font-semibold text-[#2f2212]`,children:n(`agentsEmpty`)}),(0,X.jsx)(`p`,{className:`mt-2 max-w-md text-sm leading-6 text-[#78644d]`,children:n(`agentsEmptyDescription`)}),(0,X.jsxs)(f,{type:`button`,variant:`primary`,className:`mt-5 rounded-2xl px-5`,onClick:D,children:[(0,X.jsx)(O,{className:`mr-2 h-4 w-4`}),n(`agentsCreateButton`)]})]})}):y.map(e=>(0,X.jsx)(Ee,{agent:e,runtimeOptions:x,defaultRuntimeLabel:C,updatePending:u.isPending,deletePending:h.isPending,onStartChat:()=>E(e),onEdit:()=>w(e),onDelete:()=>h.mutate({agentId:e.id})},e.id))}),(0,X.jsx)(Se,{agent:g,pending:u.isPending,providerCatalog:b,runtimeOptions:x,defaultRuntime:S,onOpenChange:e=>{!e&&!u.isPending&&_(null)},onSubmit:T})]})}function $(e){let{view:t,routeSessionKey:n,syncRouteSessionSelection:r}=e;(0,Y.useEffect)(()=>{r({isChatView:t===`chat`,routeSessionKey:n})},[n,r,t])}function Oe({view:e,confirmDialog:t}){let{isMobile:n}=z();return(0,X.jsxs)(`div`,{className:`h-full flex`,children:[n?null:(0,X.jsx)(me,{}),e===`chat`?n?(0,X.jsx)(ge,{}):(0,X.jsx)(R,{}):(0,X.jsx)(`section`,{className:`flex-1 min-h-0 overflow-hidden bg-background`,children:e===`cron`?(0,X.jsx)(`div`,{className:`h-full overflow-auto custom-scrollbar`,children:(0,X.jsx)(`div`,{className:`mx-auto w-full max-w-[min(1120px,100%)] px-4 py-4 sm:px-6 sm:py-5`,children:(0,X.jsx)(se,{})})}):e===`agents`?(0,X.jsx)(`div`,{className:`h-full overflow-auto custom-scrollbar`,children:(0,X.jsx)(`div`,{className:`mx-auto w-full max-w-[min(1180px,100%)] px-4 py-4 sm:px-6 sm:py-5`,children:(0,X.jsx)(De,{})})}):(0,X.jsx)(`div`,{className:`h-full overflow-hidden`,children:(0,X.jsx)(`div`,{className:`mx-auto flex h-full min-h-0 w-full max-w-[min(1120px,100%)] flex-col px-4 py-4 sm:px-6 sm:py-5`,children:(0,X.jsx)(_e,{forcedType:`skills`})})})}),t]})}function ke(e){let t=G(),n=q(),r=J(),i=K(),a=oe({limit:200}),o=W(),s=e.sessionKey?.trim()||`draft-session`,c=M({sessionId:s});(0,Y.useEffect)(()=>{t.chatQueryManager.syncSnapshot({configQuery:n,providersQuery:r,providerTemplatesQuery:i,sessionsQuery:a,sessionTypesQuery:o,sessionSkillsSessionId:s,sessionSkillsQuery:c})},[n,t.chatQueryManager,r,s,c,a,o,i])}function Ae(){let e=G();(0,Y.useEffect)(()=>l.eventBus.on(u.uiShowContent,t=>{e.chatThreadManager.handleUiShowContentEvent(t)}),[e])}function je(){let{sessionId:e}=o(),t=(0,Y.useMemo)(()=>F(e),[e]);return{routeSessionKey:t,sessionKey:t??void 0}}function Me(){let e=G(),{confirm:t,ConfirmDialog:n}=k(),r=a(),i=s();return(0,Y.useEffect)(()=>{e.chatUiManager.syncState({pathname:r.pathname}),e.chatUiManager.bindActions({navigate:i,confirm:t})},[t,r.pathname,i,e]),(0,X.jsx)(n,{})}function Ne({view:e}){let t=U(),[n]=(0,Y.useState)(()=>new V(t));return(0,X.jsx)(de,{presenter:n,children:(0,X.jsx)(Pe,{view:e})})}function Pe({view:e}){let t=G(),n=Me(),{routeSessionKey:r,sessionKey:i}=je();return ke({sessionKey:i??null}),$({view:e,routeSessionKey:r,syncRouteSessionSelection:t.chatSessionListManager.syncRouteSessionSelection}),Ae(),(0,X.jsx)(Oe,{view:e,confirmDialog:n})}function Fe({view:e}){return(0,X.jsx)(Ne,{view:e})}export{Fe as ChatPage};