@nextclaw/ui 0.9.13 → 0.9.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.
Files changed (48) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/assets/ChannelsList-Cu_hLbps.js +1 -0
  3. package/dist/assets/{ChatPage-B9dHVmrV.js → ChatPage-Dmpau_7n.js} +2 -2
  4. package/dist/assets/{DocBrowser-S-1-qnZQ.js → DocBrowser-C3ijFxFF.js} +1 -1
  5. package/dist/assets/{LogoBadge-t1JzzCtI.js → LogoBadge-BgjXmBcw.js} +1 -1
  6. package/dist/assets/{MarketplacePage-CzIHYJpM.js → MarketplacePage-CAIdEiw8.js} +1 -1
  7. package/dist/assets/{McpMarketplacePage-BTJdjNQ1.js → McpMarketplacePage-DPtH1xcY.js} +1 -1
  8. package/dist/assets/ModelConfig-D-pqArCg.js +1 -0
  9. package/dist/assets/{ProvidersList-BOQArFRk.js → ProvidersList-DnWsJqMQ.js} +1 -1
  10. package/dist/assets/{RemoteAccessPage-CYNQ53xu.js → RemoteAccessPage-BrXq-x0-.js} +1 -1
  11. package/dist/assets/{RuntimeConfig-B0B73pye.js → RuntimeConfig-UE9VaFO7.js} +1 -1
  12. package/dist/assets/{SearchConfig-CKy2QkAP.js → SearchConfig-CP-RM3V3.js} +1 -1
  13. package/dist/assets/{SecretsConfig-BpZLUu88.js → SecretsConfig-CfN_bazs.js} +1 -1
  14. package/dist/assets/{SessionsConfig-CoFI6Fa2.js → SessionsConfig-CgkKzKGv.js} +1 -1
  15. package/dist/assets/{chat-message-D3jZIASl.js → chat-message-CGL3sMsS.js} +1 -1
  16. package/dist/assets/index-D4alkESd.js +8 -0
  17. package/dist/assets/{label-BOvIOmQx.js → label-CbOSodIL.js} +1 -1
  18. package/dist/assets/{page-layout-PG3cwSpz.js → page-layout-BtDnyNLf.js} +1 -1
  19. package/dist/assets/{popover-BB-kINz7.js → popover-DGlUjPQc.js} +1 -1
  20. package/dist/assets/{security-config-Bb6l-viE.js → security-config-D6Bs1yoK.js} +1 -1
  21. package/dist/assets/{skeleton-CLSc5FYO.js → skeleton-BLV99JbX.js} +1 -1
  22. package/dist/assets/{status-dot-Behu7kDZ.js → status-dot-C8vM3IN1.js} +1 -1
  23. package/dist/assets/{switch-CvNG9775.js → switch-AuwUiga3.js} +1 -1
  24. package/dist/assets/{tabs-custom-CUdBQO_7.js → tabs-custom-CTS7SaFG.js} +1 -1
  25. package/dist/assets/{useConfirmDialog-CLLe2uIJ.js → useConfirmDialog-DrMAdNfN.js} +1 -1
  26. package/dist/index.html +1 -1
  27. package/dist/logos/weixin.svg +5 -0
  28. package/package.json +3 -3
  29. package/public/logos/weixin.svg +5 -0
  30. package/src/api/config.ts +4 -2
  31. package/src/components/chat/chat-stream/transport.ts +42 -2
  32. package/src/components/config/ChannelForm.tsx +1 -122
  33. package/src/components/config/ChannelsList.test.tsx +127 -0
  34. package/src/components/config/ChannelsList.tsx +2 -1
  35. package/src/components/config/ModelConfig.tsx +1 -4
  36. package/src/components/config/channel-form-fields.ts +131 -0
  37. package/src/lib/i18n.channels.ts +52 -0
  38. package/src/lib/i18n.ts +2 -43
  39. package/src/lib/logos.ts +1 -0
  40. package/src/transport/app-client.ts +6 -22
  41. package/src/transport/local.transport.ts +4 -3
  42. package/src/transport/remote.transport.ts +7 -2
  43. package/src/transport/sse-stream.test.ts +54 -0
  44. package/src/transport/sse-stream.ts +3 -17
  45. package/dist/assets/ChannelsList-bROKR37R.js +0 -1
  46. package/dist/assets/ModelConfig-BD4o3Kna.js +0 -1
  47. package/dist/assets/index-CmGwUgcl.js +0 -8
  48. package/src/components/config/ModelConfig.test.tsx +0 -78
package/src/lib/i18n.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { CHANNEL_LABELS } from './i18n.channels';
1
2
  import { MARKETPLACE_LABELS } from './i18n.marketplace';
2
3
  import { REMOTE_LABELS } from './i18n.remote';
3
4
 
@@ -312,49 +313,7 @@ export const LABELS: Record<string, { zh: string; en: string }> = {
312
313
  leaveBlankToKeepUnchanged: { zh: '留空则保持不变', en: 'Leave blank to keep unchanged' },
313
314
 
314
315
  // Channel
315
- channelsPageTitle: { zh: '消息渠道', en: 'Message Channels' },
316
- channelsPageDescription: { zh: '在一个页面中连续筛选、切换并配置各个消息渠道。', en: 'Filter, switch, and configure messaging channels in one continuous workspace.' },
317
- channelsLoading: { zh: '加载渠道中...', en: 'Loading channels...' },
318
- channelsTabEnabled: { zh: '已启用', en: 'Enabled' },
319
- channelsTabAll: { zh: '全部渠道', en: 'All Channels' },
320
- channelsFilterPlaceholder: { zh: '搜索渠道', en: 'Search channels' },
321
- channelsNoMatch: { zh: '没有匹配的渠道', en: 'No matching channels' },
322
- channelsSelectTitle: { zh: '选择左侧渠道开始配置', en: 'Select a channel from the left to configure' },
323
- channelsSelectDescription: { zh: '你可以连续切换多个渠道并逐个保存配置。', en: 'Switch between channels continuously and save each configuration.' },
324
- channelsFormDescription: { zh: '配置消息渠道参数', en: 'Configure message channel parameters' },
325
- channelsEmptyTitle: { zh: '暂无启用渠道', en: 'No channels enabled' },
326
- channelsEmptyDescription: { zh: '启用一个消息渠道以开始接收消息。', en: 'Enable a messaging channel to start receiving messages.' },
327
- channelDescriptionDefault: { zh: '配置该通信渠道', en: 'Configure this communication channel' },
328
- channelDescTelegram: { zh: '连接 Telegram 机器人以进行即时消息收发', en: 'Connect with Telegram bots for instant messaging' },
329
- channelDescSlack: { zh: '接入 Slack 工作区进行团队协作消息处理', en: 'Integrate with Slack workspaces for team collaboration' },
330
- channelDescEmail: { zh: '通过邮件协议收发消息', en: 'Send and receive messages via email protocols' },
331
- channelDescWebhook: { zh: '接收 HTTP Webhook 以支持自定义集成', en: 'Receive HTTP webhooks for custom integrations' },
332
- channelDescDiscord: { zh: '将 Discord 机器人连接到你的社区服务器', en: 'Connect Discord bots to your community servers' },
333
- channelDescFeishu: { zh: '企业消息与协作平台接入', en: 'Enterprise messaging and collaboration platform' },
334
- configureMessageChannelParameters: { zh: '配置消息渠道参数', en: 'Configure message channel parameters' },
335
- channelsGuideTitle: { zh: '查看指南', en: 'View Guide' },
336
- allowFrom: { zh: '允许来源', en: 'Allow From' },
337
- token: { zh: 'Token', en: 'Token' },
338
- botToken: { zh: 'Bot Token', en: 'Bot Token' },
339
- appToken: { zh: 'App Token', en: 'App Token' },
340
- appId: { zh: 'App ID', en: 'App ID' },
341
- corpId: { zh: '企业 ID', en: 'Corp ID' },
342
- agentId: { zh: '应用 Agent ID', en: 'Agent ID' },
343
- appSecret: { zh: 'App Secret', en: 'App Secret' },
344
- markdownSupport: { zh: 'Markdown 支持', en: 'Markdown Support' },
345
- clientId: { zh: 'Client ID', en: 'Client ID' },
346
- clientSecret: { zh: 'Client Secret', en: 'Client Secret' },
347
- encryptKey: { zh: '加密密钥', en: 'Encrypt Key' },
348
- verificationToken: { zh: '验证令牌', en: 'Verification Token' },
349
- bridgeUrl: { zh: '桥接 URL', en: 'Bridge URL' },
350
- gatewayUrl: { zh: '网关 URL', en: 'Gateway URL' },
351
- proxy: { zh: '代理', en: 'Proxy' },
352
- intents: { zh: 'Intents', en: 'Intents' },
353
- mode: { zh: '模式', en: 'Mode' },
354
- webhookPath: { zh: 'Webhook 路径', en: 'Webhook Path' },
355
- callbackPort: { zh: '回调端口', en: 'Callback Port' },
356
- callbackPath: { zh: '回调路径', en: 'Callback Path' },
357
- groupPolicy: { zh: '群组策略', en: 'Group Policy' },
316
+ ...CHANNEL_LABELS,
358
317
  consentGranted: { zh: '同意条款', en: 'Consent Granted' },
359
318
  imapHost: { zh: 'IMAP 服务器', en: 'IMAP Host' },
360
319
  imapPort: { zh: 'IMAP 端口', en: 'IMAP Port' },
package/src/lib/logos.ts CHANGED
@@ -9,6 +9,7 @@ const CHANNEL_LOGOS: LogoMap = {
9
9
  feishu: "feishu.svg",
10
10
  dingtalk: "dingtalk.svg",
11
11
  wecom: "wecom.svg",
12
+ weixin: "weixin.svg",
12
13
  mochat: "mochat.svg",
13
14
  email: "email.svg"
14
15
  };
@@ -4,11 +4,6 @@ import { RemoteSessionMultiplexTransport } from './remote.transport';
4
4
  import type { AppTransport, RemoteRuntimeInfo, RequestInput, StreamInput, StreamSession } from './transport.types';
5
5
 
6
6
  const REMOTE_RUNTIME_PATH = '/_remote/runtime';
7
- const DEFAULT_REMOTE_RUNTIME: RemoteRuntimeInfo = {
8
- mode: 'remote',
9
- protocolVersion: 1,
10
- wsPath: '/_remote/ws'
11
- };
12
7
 
13
8
  async function resolveRuntime(apiBase: string): Promise<AppTransport> {
14
9
  const runtimeUrl = `${apiBase.replace(/\/$/, '')}${REMOTE_RUNTIME_PATH}`;
@@ -27,28 +22,17 @@ async function resolveRuntime(apiBase: string): Promise<AppTransport> {
27
22
  return new LocalAppTransport({ apiBase });
28
23
  }
29
24
 
30
- const contentType = response.headers.get('content-type')?.toLowerCase() ?? '';
31
- if (!contentType.includes('application/json')) {
32
- return response.status >= 400
33
- ? new RemoteSessionMultiplexTransport(DEFAULT_REMOTE_RUNTIME, apiBase)
34
- : new LocalAppTransport({ apiBase });
35
- }
36
-
37
- let payload: { ok?: boolean; data?: RemoteRuntimeInfo } | null = null;
38
- try {
39
- payload = await response.json() as { ok?: boolean; data?: RemoteRuntimeInfo };
40
- } catch {
41
- return response.status >= 400
42
- ? new RemoteSessionMultiplexTransport(DEFAULT_REMOTE_RUNTIME, apiBase)
43
- : new LocalAppTransport({ apiBase });
44
- }
45
-
25
+ const payload = await response.json() as { ok?: boolean; data?: RemoteRuntimeInfo };
46
26
  if (response.ok && payload.ok && payload.data?.mode === 'remote') {
47
27
  return new RemoteSessionMultiplexTransport(payload.data, apiBase);
48
28
  }
49
29
 
50
30
  if (response.status >= 400) {
51
- return new RemoteSessionMultiplexTransport(DEFAULT_REMOTE_RUNTIME, apiBase);
31
+ return new RemoteSessionMultiplexTransport({
32
+ mode: 'remote',
33
+ protocolVersion: 1,
34
+ wsPath: '/_remote/ws'
35
+ }, apiBase);
52
36
  }
53
37
 
54
38
  return new LocalAppTransport({ apiBase });
@@ -101,6 +101,7 @@ class LocalRealtimeGateway {
101
101
 
102
102
  export class LocalAppTransport implements AppTransport {
103
103
  private readonly realtimeGateway: LocalRealtimeGateway;
104
+ private readonly apiBase: string;
104
105
 
105
106
  constructor(
106
107
  private readonly options: {
@@ -108,8 +109,8 @@ export class LocalAppTransport implements AppTransport {
108
109
  wsPath?: string;
109
110
  } = {}
110
111
  ) {
111
- const apiBase = options.apiBase ?? API_BASE;
112
- this.realtimeGateway = new LocalRealtimeGateway(resolveTransportWebSocketUrl(apiBase, options.wsPath ?? '/ws'));
112
+ this.apiBase = options.apiBase ?? API_BASE;
113
+ this.realtimeGateway = new LocalRealtimeGateway(resolveTransportWebSocketUrl(this.apiBase, options.wsPath ?? '/ws'));
113
114
  }
114
115
 
115
116
  async request<T>(input: RequestInput): Promise<T> {
@@ -135,7 +136,7 @@ export class LocalAppTransport implements AppTransport {
135
136
  }
136
137
 
137
138
  const finished = (async () => {
138
- const response = await fetch(`${API_BASE}${input.path}`, {
139
+ const response = await fetch(`${this.apiBase}${input.path}`, {
139
140
  method: input.method,
140
141
  credentials: 'include',
141
142
  headers: {
@@ -14,7 +14,7 @@ type RemoteBrowserFrame =
14
14
  | { type: 'response'; id: string; status: number; body?: unknown }
15
15
  | { type: 'request.error'; id: string; message: string; code?: string }
16
16
  | { type: 'stream.event'; streamId: string; event: string; payload?: unknown }
17
- | { type: 'stream.end'; streamId: string; result?: unknown }
17
+ | { type: 'stream.end'; streamId: string }
18
18
  | { type: 'stream.error'; streamId: string; message: string; code?: string }
19
19
  | { type: 'event'; event: AppEvent }
20
20
  | { type: 'connection.error'; message: string; code?: string };
@@ -31,6 +31,7 @@ type PendingRequest = {
31
31
 
32
32
  type PendingStream = {
33
33
  onEvent: StreamInput['onEvent'];
34
+ finalResult: unknown;
34
35
  resolve: (value: unknown) => void;
35
36
  reject: (error: Error) => void;
36
37
  };
@@ -131,6 +132,7 @@ export class RemoteSessionMultiplexTransport implements AppTransport {
131
132
 
132
133
  this.pendingStreams.set(streamId, {
133
134
  onEvent: input.onEvent,
135
+ finalResult: undefined,
134
136
  resolve: (value) => {
135
137
  if (settled) {
136
138
  return;
@@ -351,6 +353,9 @@ export class RemoteSessionMultiplexTransport implements AppTransport {
351
353
  }
352
354
  if (frame.type === 'stream.event') {
353
355
  try {
356
+ if (frame.event === 'final') {
357
+ pending.finalResult = frame.payload;
358
+ }
354
359
  pending.onEvent({ name: frame.event, payload: frame.payload });
355
360
  } catch (error) {
356
361
  this.pendingStreams.delete(frame.streamId);
@@ -360,7 +365,7 @@ export class RemoteSessionMultiplexTransport implements AppTransport {
360
365
  }
361
366
  this.pendingStreams.delete(frame.streamId);
362
367
  if (frame.type === 'stream.end') {
363
- pending.resolve(frame.result);
368
+ pending.resolve(pending.finalResult);
364
369
  return;
365
370
  }
366
371
  pending.reject(new Error(frame.message));
@@ -0,0 +1,54 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { readSseStreamResult } from './sse-stream';
3
+
4
+ function createSseResponse(frames: string[]): Response {
5
+ const payload = new TextEncoder().encode(frames.join(''));
6
+ const stream = new ReadableStream<Uint8Array>({
7
+ start(controller) {
8
+ controller.enqueue(payload);
9
+ controller.close();
10
+ }
11
+ });
12
+ return new Response(stream, {
13
+ status: 200,
14
+ headers: {
15
+ 'content-type': 'text/event-stream; charset=utf-8'
16
+ }
17
+ });
18
+ }
19
+
20
+ function encodeFrame(event: string, payload: unknown): string {
21
+ return `event: ${event}\ndata: ${JSON.stringify(payload)}\n\n`;
22
+ }
23
+
24
+ describe('readSseStreamResult', () => {
25
+ it('preserves final frames for callers while still resolving with the final payload', async () => {
26
+ const events: Array<{ name: string; payload?: unknown }> = [];
27
+ const response = createSseResponse([
28
+ encodeFrame('ncp-event', { type: 'message.text-delta', payload: { delta: 'hello' } }),
29
+ encodeFrame('final', { sessionId: 's1', reply: 'hello' })
30
+ ]);
31
+
32
+ const result = await readSseStreamResult(response, (event) => {
33
+ events.push(event);
34
+ });
35
+
36
+ expect(result).toEqual({ sessionId: 's1', reply: 'hello' });
37
+ expect(events.map((event) => event.name)).toEqual(['ncp-event', 'final']);
38
+ });
39
+
40
+ it('allows passthrough SSE streams to end without a final frame', async () => {
41
+ const events: Array<{ name: string; payload?: unknown }> = [];
42
+ const response = createSseResponse([
43
+ encodeFrame('ncp-event', { type: 'message.text-delta', payload: { delta: 'hello' } }),
44
+ encodeFrame('ncp-event', { type: 'run.finished', payload: { sessionId: 's1' } })
45
+ ]);
46
+
47
+ const result = await readSseStreamResult(response, (event) => {
48
+ events.push(event);
49
+ });
50
+
51
+ expect(result).toBeUndefined();
52
+ expect(events.map((event) => event.name)).toEqual(['ncp-event', 'ncp-event']);
53
+ });
54
+ });
@@ -1,6 +1,6 @@
1
1
  import type { StreamEvent } from './transport.types';
2
2
 
3
- type SseErrorPayload = { message?: string } | string | undefined;
3
+ type FinalResultSink = (value: unknown) => void;
4
4
 
5
5
  function parseSseFrame(frame: string): StreamEvent | null {
6
6
  const lines = frame.split('\n');
@@ -36,16 +36,10 @@ function parseSseFrame(frame: string): StreamEvent | null {
36
36
  return { name, payload };
37
37
  }
38
38
 
39
- function readSseErrorMessage(payload: SseErrorPayload, fallback: string): string {
40
- return typeof payload === 'string'
41
- ? payload
42
- : payload?.message ?? fallback;
43
- }
44
-
45
39
  function processSseFrame(
46
40
  rawFrame: string,
47
41
  onEvent: (event: StreamEvent) => void,
48
- setFinalResult: (value: unknown) => void
42
+ setFinalResult: FinalResultSink
49
43
  ): void {
50
44
  const frame = parseSseFrame(rawFrame);
51
45
  if (!frame) {
@@ -53,10 +47,6 @@ function processSseFrame(
53
47
  }
54
48
  if (frame.name === 'final') {
55
49
  setFinalResult(frame.payload);
56
- return;
57
- }
58
- if (frame.name === 'error') {
59
- throw new Error(readSseErrorMessage(frame.payload as SseErrorPayload, 'chat stream failed'));
60
50
  }
61
51
  onEvent(frame);
62
52
  }
@@ -64,7 +54,7 @@ function processSseFrame(
64
54
  function flushBufferedFrames(
65
55
  bufferState: { value: string },
66
56
  onEvent: (event: StreamEvent) => void,
67
- setFinalResult: (value: unknown) => void
57
+ setFinalResult: FinalResultSink
68
58
  ): void {
69
59
  let boundary = bufferState.value.indexOf('\n\n');
70
60
  while (boundary !== -1) {
@@ -86,7 +76,6 @@ export async function readSseStreamResult<TFinal>(
86
76
  const decoder = new TextDecoder();
87
77
  const bufferState = { value: '' };
88
78
  let finalResult: unknown = undefined;
89
-
90
79
  try {
91
80
  while (true) {
92
81
  const { value, done } = await reader.read();
@@ -107,8 +96,5 @@ export async function readSseStreamResult<TFinal>(
107
96
  reader.releaseLock();
108
97
  }
109
98
 
110
- if (finalResult === undefined) {
111
- throw new Error('stream ended without final event');
112
- }
113
99
  return finalResult as TFinal;
114
100
  }
@@ -1 +0,0 @@
1
- import{r as v,j as a,X as Z,a3 as ee,e as T,K as ae,aq as te,b1 as se,b2 as ne,b3 as le,a0 as re,G as oe,ai as ce,H as ie}from"./vendor-TJ2hy_Lv.js";import{t as e,c as I,Z as me,u as q,a as $,b as H,$ as pe,a0 as de,I as D,S as be,e as ue,f as xe,g as ye,h as ge,B as E}from"./index-CmGwUgcl.js";import{L as he}from"./label-BOvIOmQx.js";import{S as fe}from"./switch-CvNG9775.js";import{S as K}from"./status-dot-Behu7kDZ.js";import{L as J}from"./LogoBadge-t1JzzCtI.js";import{h as _}from"./config-hints-CApS3K_7.js";import{c as we,b as ve,a as je,C as ke}from"./config-layout-BHnOoweL.js";import{T as Se}from"./tabs-custom-CUdBQO_7.js";import{P as Ce,a as Ne}from"./page-layout-PG3cwSpz.js";function Pe({value:t,onChange:m,className:i,placeholder:r=""}){const[o,u]=v.useState(""),d=x=>{x.key==="Enter"&&o.trim()?(x.preventDefault(),m([...t,o.trim()]),u("")):x.key==="Backspace"&&!o&&t.length>0&&m(t.slice(0,-1))},g=x=>{m(t.filter((j,h)=>h!==x))};return a.jsxs("div",{className:I("flex flex-wrap gap-2 p-2 border rounded-md min-h-[42px]",i),children:[t.map((x,j)=>a.jsxs("span",{className:"inline-flex items-center gap-1 px-2 py-1 bg-primary text-primary-foreground rounded text-sm",children:[x,a.jsx("button",{type:"button",onClick:()=>g(j),className:"hover:text-red-300 transition-colors",children:a.jsx(Z,{className:"h-3 w-3"})})]},j)),a.jsx("input",{type:"text",value:o,onChange:x=>u(x.target.value),onKeyDown:d,className:"flex-1 outline-none min-w-[100px] bg-transparent text-sm",placeholder:r||e("enterTag")})]})}function z(t){var r,o;const m=me();return((r=t.tutorialUrls)==null?void 0:r[m])||((o=t.tutorialUrls)==null?void 0:o.default)||t.tutorialUrl}const Ie={telegram:"telegram.svg",slack:"slack.svg",discord:"discord.svg",whatsapp:"whatsapp.svg",qq:"qq.svg",feishu:"feishu.svg",dingtalk:"dingtalk.svg",wecom:"wecom.svg",mochat:"mochat.svg",email:"email.svg"};function Fe(t,m){const i=m.toLowerCase(),r=t[i];return r?`/logos/${r}`:null}function Y(t){return Fe(Ie,t)}const B=[{value:"pairing",label:"pairing"},{value:"allowlist",label:"allowlist"},{value:"open",label:"open"},{value:"disabled",label:"disabled"}],G=[{value:"open",label:"open"},{value:"allowlist",label:"allowlist"},{value:"disabled",label:"disabled"}],Te=[{value:"off",label:"off"},{value:"partial",label:"partial"},{value:"block",label:"block"},{value:"progress",label:"progress"}],De=t=>t.includes("token")||t.includes("secret")||t.includes("password")?a.jsx(ae,{className:"h-3.5 w-3.5 text-gray-500"}):t.includes("url")||t.includes("host")?a.jsx(te,{className:"h-3.5 w-3.5 text-gray-500"}):t.includes("email")||t.includes("mail")?a.jsx(se,{className:"h-3.5 w-3.5 text-gray-500"}):t.includes("id")||t.includes("from")?a.jsx(ne,{className:"h-3.5 w-3.5 text-gray-500"}):t==="enabled"||t==="consentGranted"?a.jsx(le,{className:"h-3.5 w-3.5 text-gray-500"}):a.jsx(re,{className:"h-3.5 w-3.5 text-gray-500"});function R(){return{telegram:[{name:"enabled",type:"boolean",label:e("enabled")},{name:"token",type:"password",label:e("botToken")},{name:"allowFrom",type:"tags",label:e("allowFrom")},{name:"proxy",type:"text",label:e("proxy")},{name:"accountId",type:"text",label:e("accountId")},{name:"dmPolicy",type:"select",label:e("dmPolicy"),options:B},{name:"groupPolicy",type:"select",label:e("groupPolicy"),options:G},{name:"groupAllowFrom",type:"tags",label:e("groupAllowFrom")},{name:"requireMention",type:"boolean",label:e("requireMention")},{name:"mentionPatterns",type:"tags",label:e("mentionPatterns")},{name:"groups",type:"json",label:e("groupRulesJson")}],discord:[{name:"enabled",type:"boolean",label:e("enabled")},{name:"token",type:"password",label:e("botToken")},{name:"allowBots",type:"boolean",label:e("allowBotMessages")},{name:"allowFrom",type:"tags",label:e("allowFrom")},{name:"gatewayUrl",type:"text",label:e("gatewayUrl")},{name:"intents",type:"number",label:e("intents")},{name:"proxy",type:"text",label:e("proxy")},{name:"mediaMaxMb",type:"number",label:e("attachmentMaxSizeMb")},{name:"streaming",type:"select",label:e("streamingMode"),options:Te},{name:"draftChunk",type:"json",label:e("draftChunkingJson")},{name:"textChunkLimit",type:"number",label:e("textChunkLimit")},{name:"accountId",type:"text",label:e("accountId")},{name:"dmPolicy",type:"select",label:e("dmPolicy"),options:B},{name:"groupPolicy",type:"select",label:e("groupPolicy"),options:G},{name:"groupAllowFrom",type:"tags",label:e("groupAllowFrom")},{name:"requireMention",type:"boolean",label:e("requireMention")},{name:"mentionPatterns",type:"tags",label:e("mentionPatterns")},{name:"groups",type:"json",label:e("groupRulesJson")}],whatsapp:[{name:"enabled",type:"boolean",label:e("enabled")},{name:"bridgeUrl",type:"text",label:e("bridgeUrl")},{name:"allowFrom",type:"tags",label:e("allowFrom")}],feishu:[{name:"enabled",type:"boolean",label:e("enabled")},{name:"appId",type:"text",label:e("appId")},{name:"appSecret",type:"password",label:e("appSecret")},{name:"encryptKey",type:"password",label:e("encryptKey")},{name:"verificationToken",type:"password",label:e("verificationToken")},{name:"allowFrom",type:"tags",label:e("allowFrom")}],dingtalk:[{name:"enabled",type:"boolean",label:e("enabled")},{name:"clientId",type:"text",label:e("clientId")},{name:"clientSecret",type:"password",label:e("clientSecret")},{name:"allowFrom",type:"tags",label:e("allowFrom")}],wecom:[{name:"enabled",type:"boolean",label:e("enabled")},{name:"corpId",type:"text",label:e("corpId")},{name:"agentId",type:"text",label:e("agentId")},{name:"secret",type:"password",label:e("secret")},{name:"token",type:"password",label:e("token")},{name:"callbackPort",type:"number",label:e("callbackPort")},{name:"callbackPath",type:"text",label:e("callbackPath")},{name:"allowFrom",type:"tags",label:e("allowFrom")}],slack:[{name:"enabled",type:"boolean",label:e("enabled")},{name:"mode",type:"text",label:e("mode")},{name:"webhookPath",type:"text",label:e("webhookPath")},{name:"allowBots",type:"boolean",label:e("allowBotMessages")},{name:"botToken",type:"password",label:e("botToken")},{name:"appToken",type:"password",label:e("appToken")}],email:[{name:"enabled",type:"boolean",label:e("enabled")},{name:"consentGranted",type:"boolean",label:e("consentGranted")},{name:"imapHost",type:"text",label:e("imapHost")},{name:"imapPort",type:"number",label:e("imapPort")},{name:"imapUsername",type:"text",label:e("imapUsername")},{name:"imapPassword",type:"password",label:e("imapPassword")},{name:"fromAddress",type:"email",label:e("fromAddress")}],mochat:[{name:"enabled",type:"boolean",label:e("enabled")},{name:"baseUrl",type:"text",label:e("baseUrl")},{name:"clawToken",type:"password",label:e("clawToken")},{name:"agentUserId",type:"text",label:e("agentUserId")},{name:"allowFrom",type:"tags",label:e("allowFrom")}],qq:[{name:"enabled",type:"boolean",label:e("enabled")},{name:"appId",type:"text",label:e("appId")},{name:"secret",type:"password",label:e("appSecret")},{name:"markdownSupport",type:"boolean",label:e("markdownSupport")},{name:"allowFrom",type:"tags",label:e("allowFrom")}]}}function A(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}function V(t,m){const i={...t};for(const[r,o]of Object.entries(m)){const u=i[r];if(A(u)&&A(o)){i[r]=V(u,o);continue}i[r]=o}return i}function Ae(t,m){const i=t.split("."),r={};let o=r;for(let u=0;u<i.length-1;u+=1){const d=i[u];o[d]={},o=o[d]}return o[i[i.length-1]]=m,r}function Le({channelName:t}){var O,U;const{data:m}=q(),{data:i}=$(),{data:r}=H(),o=pe(),u=de(),[d,g]=v.useState({}),[x,j]=v.useState({}),[h,f]=v.useState(null),k=t?m==null?void 0:m.channels[t]:null,w=t?R()[t]??[]:[],c=r==null?void 0:r.uiHints,p=t?`channels.${t}`:null,S=((O=r==null?void 0:r.actions)==null?void 0:O.filter(s=>s.scope===p))??[],C=t&&(((U=_(`channels.${t}`,c))==null?void 0:U.label)??t),P=i==null?void 0:i.channels.find(s=>s.name===t),F=P?z(P):void 0;v.useEffect(()=>{if(k){g({...k});const s={};(t?R()[t]??[]:[]).filter(l=>l.type==="json").forEach(l=>{const y=k[l.name];s[l.name]=JSON.stringify(y??{},null,2)}),j(s)}else g({}),j({})},[k,t]);const N=(s,n)=>{g(l=>({...l,[s]:n}))},L=s=>{if(s.preventDefault(),!t)return;const n={...d};for(const l of w){if(l.type!=="password")continue;const y=n[l.name];(typeof y!="string"||y.length===0)&&delete n[l.name]}for(const l of w){if(l.type!=="json")continue;const y=x[l.name]??"";try{n[l.name]=y.trim()?JSON.parse(y):{}}catch{T.error(`${e("invalidJson")}: ${l.name}`);return}}o.mutate({channel:t,data:n})},Q=s=>{if(!s||!t)return;const n=s.channels;if(!A(n))return;const l=n[t];A(l)&&g(y=>V(y,l))},W=async s=>{if(!(!t||!p)){f(s.id);try{let n={...d};s.saveBeforeRun&&(n={...n,...s.savePatch??{}},g(n),await o.mutateAsync({channel:t,data:n}));const l=await u.mutateAsync({actionId:s.id,data:{scope:p,draftConfig:Ae(p,n)}});Q(l.patch),l.ok?T.success(l.message||e("success")):T.error(l.message||e("error"))}catch(n){const l=n instanceof Error?n.message:String(n);T.error(`${e("error")}: ${l}`)}finally{f(null)}}};if(!t||!P||!k)return a.jsx("div",{className:we,children:a.jsxs("div",{children:[a.jsx("h3",{className:"text-base font-semibold text-gray-900",children:e("channelsSelectTitle")}),a.jsx("p",{className:"mt-2 text-sm text-gray-500",children:e("channelsSelectDescription")})]})});const M=!!k.enabled;return a.jsxs("div",{className:ve,children:[a.jsx("div",{className:"border-b border-gray-100 px-6 py-5",children:a.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[a.jsxs("div",{className:"min-w-0",children:[a.jsxs("div",{className:"flex items-center gap-3",children:[a.jsx(J,{name:t,src:Y(t),className:I("h-9 w-9 rounded-lg border",M?"border-primary/30 bg-white":"border-gray-200/70 bg-white"),imgClassName:"h-5 w-5 object-contain",fallback:a.jsx("span",{className:"text-sm font-semibold uppercase text-gray-500",children:t[0]})}),a.jsx("h3",{className:"truncate text-lg font-semibold text-gray-900 capitalize",children:C})]}),a.jsx("p",{className:"mt-2 text-sm text-gray-500",children:e("channelsFormDescription")}),F&&a.jsxs("a",{href:F,className:"mt-2 inline-flex items-center gap-1.5 text-xs text-primary transition-colors hover:text-primary-hover",children:[a.jsx(ee,{className:"h-3.5 w-3.5"}),e("channelsGuideTitle")]})]}),a.jsx(K,{status:M?"active":"inactive",label:M?e("statusActive"):e("statusInactive")})]})}),a.jsxs("form",{onSubmit:L,className:"flex min-h-0 flex-1 flex-col",children:[a.jsx("div",{className:"min-h-0 flex-1 space-y-6 overflow-y-auto overscroll-contain px-6 py-5",children:w.map(s=>{const n=t?_(`channels.${t}.${s.name}`,c):void 0,l=(n==null?void 0:n.label)??s.label,y=n==null?void 0:n.placeholder;return a.jsxs("div",{className:"space-y-2.5",children:[a.jsxs(he,{htmlFor:s.name,className:"flex items-center gap-2 text-sm font-medium text-gray-900",children:[De(s.name),l]}),s.type==="boolean"&&a.jsxs("div",{className:"flex items-center justify-between rounded-xl bg-gray-50 p-3",children:[a.jsx("span",{className:"text-sm text-gray-500",children:d[s.name]?e("enabled"):e("disabled")}),a.jsx(fe,{id:s.name,checked:d[s.name]||!1,onCheckedChange:b=>N(s.name,b),className:"data-[state=checked]:bg-emerald-500"})]}),(s.type==="text"||s.type==="email")&&a.jsx(D,{id:s.name,type:s.type,value:d[s.name]||"",onChange:b=>N(s.name,b.target.value),placeholder:y,className:"rounded-xl"}),s.type==="password"&&a.jsx(D,{id:s.name,type:"password",value:d[s.name]||"",onChange:b=>N(s.name,b.target.value),placeholder:y??e("leaveBlankToKeepUnchanged"),className:"rounded-xl"}),s.type==="number"&&a.jsx(D,{id:s.name,type:"number",value:d[s.name]||0,onChange:b=>N(s.name,parseInt(b.target.value,10)||0),placeholder:y,className:"rounded-xl"}),s.type==="tags"&&a.jsx(Pe,{value:d[s.name]||[],onChange:b=>N(s.name,b)}),s.type==="select"&&a.jsxs(be,{value:d[s.name]||"",onValueChange:b=>N(s.name,b),children:[a.jsx(ue,{className:"rounded-xl",children:a.jsx(xe,{})}),a.jsx(ye,{children:(s.options??[]).map(b=>a.jsx(ge,{value:b.value,children:b.label},b.value))})]}),s.type==="json"&&a.jsx("textarea",{id:s.name,value:x[s.name]??"{}",onChange:b=>j(X=>({...X,[s.name]:b.target.value})),className:"min-h-[120px] w-full resize-none rounded-lg border border-gray-200 bg-white px-3 py-2 text-xs font-mono"})]},s.name)})}),a.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3 border-t border-gray-100 px-6 py-4",children:[a.jsx("div",{className:"flex flex-wrap items-center gap-2",children:S.filter(s=>s.trigger==="manual").map(s=>a.jsx(E,{type:"button",onClick:()=>W(s),disabled:o.isPending||!!h,variant:"secondary",children:h===s.id?e("connecting"):s.title},s.id))}),a.jsx(E,{type:"submit",disabled:o.isPending||!!h,children:o.isPending?e("saving"):e("save")})]})]})]})}const Me={telegram:"channelDescTelegram",slack:"channelDescSlack",email:"channelDescEmail",webhook:"channelDescWebhook",discord:"channelDescDiscord",feishu:"channelDescFeishu"};function Ke(){const{data:t}=q(),{data:m}=$(),{data:i}=H(),[r,o]=v.useState("enabled"),[u,d]=v.useState(),[g,x]=v.useState(""),j=i==null?void 0:i.uiHints,h=m==null?void 0:m.channels,f=t==null?void 0:t.channels,k=[{id:"enabled",label:e("channelsTabEnabled"),count:(h??[]).filter(c=>{var p;return(p=f==null?void 0:f[c.name])==null?void 0:p.enabled}).length},{id:"all",label:e("channelsTabAll"),count:(h??[]).length}],w=v.useMemo(()=>{const c=g.trim().toLowerCase();return(h??[]).filter(p=>{var C;const S=((C=f==null?void 0:f[p.name])==null?void 0:C.enabled)||!1;return r==="enabled"?S:!0}).filter(p=>c?(p.displayName||p.name).toLowerCase().includes(c)||p.name.toLowerCase().includes(c):!0)},[r,f,h,g]);return v.useEffect(()=>{if(w.length===0){d(void 0);return}w.some(p=>p.name===u)||d(w[0].name)},[w,u]),!t||!m?a.jsx("div",{className:"p-8 text-gray-400",children:e("channelsLoading")}):a.jsxs(Ce,{className:"xl:flex xl:h-full xl:min-h-0 xl:flex-col xl:pb-0",children:[a.jsx(Ne,{title:e("channelsPageTitle"),description:e("channelsPageDescription")}),a.jsxs("div",{className:I(ke,"xl:min-h-0 xl:flex-1"),children:[a.jsxs("section",{className:je,children:[a.jsx("div",{className:"border-b border-gray-100 px-4 pt-4",children:a.jsx(Se,{tabs:k,activeTab:r,onChange:o,className:"mb-0"})}),a.jsx("div",{className:"border-b border-gray-100 px-4 py-3",children:a.jsxs("div",{className:"relative",children:[a.jsx(oe,{className:"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-gray-400"}),a.jsx(D,{value:g,onChange:c=>x(c.target.value),placeholder:e("channelsFilterPlaceholder"),className:"h-10 rounded-xl pl-9"})]})}),a.jsxs("div",{className:"min-h-0 flex-1 space-y-2 overflow-y-auto overscroll-contain p-3",children:[w.map(c=>{const p=t.channels[c.name],S=(p==null?void 0:p.enabled)||!1,C=_(`channels.${c.name}`,j),P=z(c),F=(C==null?void 0:C.help)||e(Me[c.name]||"channelDescriptionDefault"),N=u===c.name;return a.jsx("button",{type:"button",onClick:()=>d(c.name),className:I("w-full rounded-xl border p-2.5 text-left transition-all",N?"border-primary/30 bg-primary-50/40 shadow-sm":"border-gray-200/70 bg-white hover:border-gray-300 hover:bg-gray-50/70"),children:a.jsxs("div",{className:"flex items-start justify-between gap-3",children:[a.jsxs("div",{className:"flex min-w-0 items-center gap-3",children:[a.jsx(J,{name:c.name,src:Y(c.name),className:I("h-10 w-10 rounded-lg border",S?"border-primary/30 bg-white":"border-gray-200/70 bg-white"),imgClassName:"h-5 w-5 object-contain",fallback:a.jsx("span",{className:"text-sm font-semibold uppercase text-gray-500",children:c.name[0]})}),a.jsxs("div",{className:"min-w-0",children:[a.jsx("p",{className:"truncate text-sm font-semibold text-gray-900",children:c.displayName||c.name}),a.jsx("p",{className:"line-clamp-1 text-[11px] text-gray-500",children:F})]})]}),a.jsxs("div",{className:"flex items-center gap-2",children:[P&&a.jsx("a",{href:P,onClick:L=>L.stopPropagation(),className:"inline-flex h-7 w-7 items-center justify-center rounded-md text-gray-300 transition-colors hover:bg-gray-100/70 hover:text-gray-500",title:e("channelsGuideTitle"),children:a.jsx(ce,{className:"h-3.5 w-3.5"})}),a.jsx(K,{status:S?"active":"inactive",label:S?e("statusActive"):e("statusInactive"),className:"min-w-[56px] justify-center"})]})]})},c.name)}),w.length===0&&a.jsxs("div",{className:"flex h-full min-h-[220px] flex-col items-center justify-center rounded-xl border border-dashed border-gray-200 bg-gray-50/70 py-10 text-center",children:[a.jsx("div",{className:"mb-3 flex h-10 w-10 items-center justify-center rounded-lg bg-white",children:a.jsx(ie,{className:"h-5 w-5 text-gray-300"})}),a.jsx("p",{className:"text-sm font-medium text-gray-700",children:e("channelsNoMatch")})]})]})]}),a.jsx(Le,{channelName:u})]})]})}export{Ke as ChannelsList};
@@ -1 +0,0 @@
1
- import{r as n,j as e,ac as W,v as z,F as q,a3 as G,ad as K,ae as Y}from"./vendor-TJ2hy_Lv.js";import{I as A,c as L,u as $,a as J,b as Q,d as X,t as m,C as U,S as Z,e as H,f as ee,g as se,h as te,D as ae,B as re}from"./index-CmGwUgcl.js";import{L as R}from"./label-BOvIOmQx.js";import{S as u}from"./skeleton-CLSc5FYO.js";import{h as _}from"./config-hints-CApS3K_7.js";import{b as le,f as oe,t as F,c as ne}from"./provider-models-BOeNnjk9.js";import{P as ce,a as ie}from"./page-layout-PG3cwSpz.js";function de(c){const r=new Set;for(const p of c){const x=p.trim();x.length>0&&r.add(x)}return[...r]}function me({id:c,value:r,onChange:p,options:x,disabled:i=!1,placeholder:T,className:k,inputClassName:v,emptyText:j,createText:b,maxItems:N=Number.POSITIVE_INFINITY,onEnter:M}){const[o,l]=n.useState(!1);n.useEffect(()=>{i&&o&&l(!1)},[i,o]);const h=n.useMemo(()=>de(x),[x]),d=r.trim().toLowerCase(),a=n.useMemo(()=>{const s=h.map((f,w)=>({option:f,index:w}));d.length>0&&s.sort((f,w)=>{const S=f.option.toLowerCase(),P=w.option.toLowerCase(),D=S===d?0:S.startsWith(d)?1:S.includes(d)?2:3,I=P===d?0:P.startsWith(d)?1:P.includes(d)?2:3;return D!==I?D-I:f.index-w.index});const g=s.map(f=>f.option);return Number.isFinite(N)?g.slice(0,Math.max(1,N)):g},[h,d,N]),C=r.trim().length>0&&h.some(s=>s===r.trim());return e.jsxs("div",{className:L("relative",k),onBlur:()=>{setTimeout(()=>l(!1),120)},children:[e.jsx(A,{id:c,value:r,disabled:i,onFocus:()=>{i||l(!0)},onChange:s=>{p(s.target.value),!o&&!i&&l(!0)},onKeyDown:s=>{s.key==="Enter"&&(M&&(s.preventDefault(),M()),l(!1))},placeholder:T,className:L("pr-10",v)}),e.jsx("button",{type:"button",onMouseDown:s=>s.preventDefault(),onClick:()=>l(s=>!s),disabled:i,className:L("absolute inset-y-0 right-0 inline-flex w-10 items-center justify-center",i?"cursor-not-allowed text-gray-300":"text-gray-400 hover:text-gray-600"),"aria-label":"toggle model options",children:e.jsx(W,{className:"h-4 w-4"})}),o&&!i&&e.jsx("div",{className:"absolute z-20 mt-1 w-full overflow-hidden rounded-xl border border-gray-200 bg-white shadow-lg",children:e.jsxs("div",{className:"max-h-60 overflow-y-auto py-1",children:[!C&&r.trim().length>0&&e.jsxs("button",{type:"button",onMouseDown:s=>s.preventDefault(),onClick:()=>{p(r.trim()),l(!1)},className:"flex w-full items-center gap-2 px-3 py-2 text-left text-sm hover:bg-gray-50",children:[e.jsx(z,{className:"h-4 w-4 text-transparent"}),e.jsx("span",{className:"truncate text-gray-700",children:b?b.replace("{value}",r.trim()):r.trim()})]}),a.map(s=>e.jsxs("button",{type:"button",onMouseDown:g=>g.preventDefault(),onClick:()=>{p(s),l(!1)},className:"flex w-full items-center gap-2 px-3 py-2 text-left text-sm hover:bg-gray-50",children:[e.jsx(z,{className:L("h-4 w-4",s===r.trim()?"text-primary":"text-transparent")}),e.jsx("span",{className:"truncate text-gray-700",children:s})]},s)),a.length===0&&r.trim().length===0&&e.jsx("div",{className:"px-3 py-2 text-sm text-gray-500",children:j??"No models available"})]})})]})}function Ne(){const{data:c,isLoading:r}=$(),{data:p}=J(),{data:x}=Q(),i=X(),[T,k]=n.useState(""),[v,j]=n.useState(""),[b,N]=n.useState(""),M=x==null?void 0:x.uiHints,o=_("agents.defaults.model",M),l=_("agents.defaults.workspace",M),h=n.useMemo(()=>le({meta:p,config:c,onlyConfigured:!0}),[c,p]),d=n.useMemo(()=>new Map(h.map(t=>[t.name,t])),[h]),a=d.get(T),C=(a==null?void 0:a.name)??"",s=n.useMemo(()=>(a==null?void 0:a.aliases)??[],[a]),g=n.useMemo(()=>(a==null?void 0:a.models)??[],[a]);n.useEffect(()=>{var E,B;if(!((E=c==null?void 0:c.agents)!=null&&E.defaults))return;const t=(c.agents.defaults.model||"").trim(),y=oe(t,h)??"",V=((B=d.get(y))==null?void 0:B.aliases)??[];k(y),j(y?F(t,V):""),N(c.agents.defaults.workspace||"")},[c,h,d]);const f=n.useMemo(()=>{const t=new Set;for(const O of g){const y=O.trim();y&&t.add(y)}return[...t]},[g]),w=n.useMemo(()=>{if(!a)return"";const t=F(v,s);return t?ne(a.prefix,t):""},[v,a,s]),S=m("modelIdentifierHelp")||(o==null?void 0:o.help)||"",P=t=>{k(t),j("")},D=t=>{if(!a){j("");return}j(F(t,s))},I=t=>{t.preventDefault(),i.mutate({model:w,workspace:b})};return r?e.jsxs("div",{className:"max-w-2xl space-y-6",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(u,{className:"h-8 w-32"}),e.jsx(u,{className:"h-4 w-48"})]}),e.jsxs(U,{className:"rounded-2xl border-gray-200 p-6",children:[e.jsxs("div",{className:"flex items-center gap-4 mb-6",children:[e.jsx(u,{className:"h-12 w-12 rounded-xl"}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(u,{className:"h-5 w-24"}),e.jsx(u,{className:"h-3 w-32"})]})]}),e.jsx(u,{className:"h-4 w-20 mb-2"}),e.jsx(u,{className:"h-10 w-full rounded-xl"})]}),e.jsxs(U,{className:"rounded-2xl border-gray-200 p-6",children:[e.jsx(u,{className:"h-5 w-24 mb-2"}),e.jsx(u,{className:"h-10 w-full rounded-xl"})]})]}):e.jsxs(ce,{children:[e.jsx(ie,{title:m("modelPageTitle"),description:m("modelPageDescription")}),e.jsxs("form",{onSubmit:I,className:"space-y-8",children:[e.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-8",children:[e.jsxs("div",{className:"p-8 rounded-2xl bg-white border border-gray-200 shadow-card",children:[e.jsxs("div",{className:"flex items-center gap-4 mb-8",children:[e.jsx("div",{className:"h-10 w-10 rounded-xl bg-primary flex items-center justify-center text-white",children:e.jsx(q,{className:"h-5 w-5"})}),e.jsx("h3",{className:"text-lg font-bold text-gray-900",children:m("defaultModel")})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(R,{htmlFor:"model",className:"text-xs font-semibold text-gray-500 uppercase tracking-wider",children:(o==null?void 0:o.label)??"Model Name"}),e.jsxs("div",{className:"flex flex-col gap-2 sm:flex-row sm:items-center",children:[e.jsx("div",{className:"sm:w-[38%] sm:min-w-[170px]",children:e.jsxs(Z,{value:C,onValueChange:P,children:[e.jsx(H,{className:"h-10 w-full rounded-xl",children:e.jsx(ee,{placeholder:m("providersSelectPlaceholder")})}),e.jsx(se,{children:h.map(t=>e.jsx(te,{value:t.name,children:t.displayName},t.name))})]})}),e.jsx("span",{className:"hidden h-10 items-center justify-center leading-none text-lg font-semibold text-gray-300 sm:inline-flex",children:"/"}),e.jsx(me,{id:"model",value:v,onChange:D,options:f,disabled:!C,placeholder:(o==null?void 0:o.placeholder)??"gpt-5.1",className:"sm:flex-1",inputClassName:"h-10 rounded-xl",emptyText:m("modelPickerNoOptions"),createText:m("modelPickerUseCustom")},C)]}),e.jsx("p",{className:"text-xs text-gray-400",children:S}),e.jsx("p",{className:"text-xs text-gray-500",children:m("modelInputCustomHint")}),e.jsxs("a",{href:`${ae}/guide/model-selection`,className:"inline-flex items-center gap-1.5 text-xs text-primary hover:text-primary-hover transition-colors",children:[e.jsx(G,{className:"h-3.5 w-3.5"}),m("channelsGuideTitle")]})]})]}),e.jsxs("div",{className:"p-8 rounded-2xl bg-white border border-gray-200 shadow-card",children:[e.jsxs("div",{className:"flex items-center gap-4 mb-8",children:[e.jsx("div",{className:"h-10 w-10 rounded-xl bg-primary flex items-center justify-center text-white",children:e.jsx(K,{className:"h-5 w-5"})}),e.jsx("h3",{className:"text-lg font-bold text-gray-900",children:m("workspace")})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(R,{htmlFor:"workspace",className:"text-xs font-semibold text-gray-500 uppercase tracking-wider",children:(l==null?void 0:l.label)??"Default Path"}),e.jsx(A,{id:"workspace",value:b,onChange:t=>N(t.target.value),placeholder:(l==null?void 0:l.placeholder)??"/path/to/workspace",className:"rounded-xl"})]})]})]}),e.jsx("div",{className:"flex justify-end pt-4",children:e.jsx(re,{type:"submit",disabled:i.isPending,size:"lg",children:i.isPending?e.jsx(Y,{className:"h-5 w-5 animate-spin"}):m("saveChanges")})})]})]})}export{Ne as ModelConfig};