@ezychat/web 0.1.47 → 0.1.48

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.
@@ -1,11 +1,16 @@
1
+ import type { TFunction } from 'i18next';
1
2
  import { type AiDocument } from '@ezychat/shared';
3
+ /** An AI agent API error in the admin's language (`ai.agents.errors.*`); others as usual. */
4
+ export declare function agentErrorMessage(error: unknown, t: TFunction<'admin'>): string;
2
5
  /**
3
- * Business context as a list of items (uploaded files and text content), like a project
4
- * knowledge panel: search, multi-select delete, and Add ▾ (upload or text). Items belong to the
5
- * AI member, so `ensureMember` saves a draft member first when there is none yet.
6
+ * The Business context of ONE agent as a list of items (uploaded files and text content), like a
7
+ * project knowledge panel: search, the Internal filter, multi-select delete, and Add ▾ (upload or
8
+ * text). An Internal item helps the agent decide and is never told to customers.
6
9
  */
7
- export declare function AiContextPanel({ documents, ensureMember, disabled, }: {
10
+ export declare function AiContextPanel({ agentId, documents, disabled, }: {
11
+ agentId: number;
8
12
  documents: AiDocument[];
9
- ensureMember: () => Promise<boolean>;
10
13
  disabled?: boolean;
11
14
  }): import("react").JSX.Element;
15
+ /** "Internal" badge: used to decide, never told to customers. */
16
+ export declare function InternalBadge(): import("react").JSX.Element;
@@ -1,13 +1,17 @@
1
- import { type AiEditField } from '@ezychat/shared';
1
+ import { type AiAgentPreset, type AiEditField } from '@ezychat/shared';
2
2
  /**
3
3
  * Edit with AI: the admin describes a change to one box, reviews the suggested rewrite as a line
4
4
  * diff and applies it to the page's draft. Applying never saves; the page's Save does.
5
5
  */
6
- export declare function AiEditDialog({ field, current, open, onOpenChange, onApply, }: {
6
+ export declare function AiEditDialog({ field, current, open, onOpenChange, onApply, agentId, preset, }: {
7
7
  field: AiEditField;
8
8
  /** The box's current (possibly unsaved) text. */
9
9
  current: string;
10
10
  open: boolean;
11
11
  onOpenChange: (open: boolean) => void;
12
12
  onApply: (text: string) => void;
13
+ /** The agent whose Business context informs the rewrite (none: the inbox-1 agent). */
14
+ agentId?: number;
15
+ /** The agent's preset, so a FAQ agent is not pushed toward sales. */
16
+ preset?: AiAgentPreset;
13
17
  }): import("react").JSX.Element;
@@ -1 +1,7 @@
1
+ /**
2
+ * Members ▸ AI agent: `/admin/members/ai/:agentId` edits one agent; `/admin/members/ai/new?preset=`
3
+ * creates one. Name, starting point, Business context (with Internal items), Try it, the role and
4
+ * hand-over rules, the fixed safety rules, and in an edition with several inboxes the inbox and
5
+ * Delete.
6
+ */
1
7
  export declare function AiMemberPage(): import("react").JSX.Element;
@@ -1,8 +1,13 @@
1
1
  import type { AiKnowledgeDraft } from './ai-status';
2
2
  /**
3
3
  * Asks the AI a test question with the page's current (possibly unsaved) name and instructions;
4
- * the server answers from the saved Business context items.
4
+ * the server answers from the saved Business context items of `agentId` (none: the inbox-1 agent).
5
+ * `ready` false: the AI connection does not work yet, so asking is off.
5
6
  */
6
- export declare function AiTryIt({ draft }: {
7
+ export declare function AiTryIt({ draft, agentId, ready, onAnswered, }: {
7
8
  draft: AiKnowledgeDraft;
9
+ agentId?: number;
10
+ ready?: boolean;
11
+ /** Called after the model answered a test question (the agent page's Next steps). */
12
+ onAnswered?: () => void;
8
13
  }): import("react").JSX.Element;
@@ -0,0 +1,8 @@
1
+ import { type LucideIcon } from 'lucide-react';
2
+ import type { AiAgentPreset } from '@ezychat/shared';
3
+ /** The icon of each agent preset (picker, badges). */
4
+ export declare const PRESET_ICON: Record<AiAgentPreset, LucideIcon>;
5
+ /** "Sales agent", "FAQ agent", "Custom agent". */
6
+ export declare function PresetBadge({ preset }: Readonly<{
7
+ preset: AiAgentPreset;
8
+ }>): import("react").JSX.Element;
@@ -0,0 +1,6 @@
1
+ import type { AiMemberStatus } from '@ezychat/shared';
2
+ /**
3
+ * Where "set up the AI agent" links go: the only agent's page, a new agent while there is none, or
4
+ * Members (which lists every agent) when there are several.
5
+ */
6
+ export declare function aiAgentsPath(status: Pick<AiMemberStatus, 'agents'>): string;
@@ -1,4 +1,5 @@
1
- import type { AiDocument, AiMemberStatus, AiSettings } from '@ezychat/shared';
1
+ import type { TFunction } from 'i18next';
2
+ import { type AiAgentPreset, type AiDocument, type AiMemberStatus, type AiSettings } from '@ezychat/shared';
2
3
  /** Only the official ChatGPT sign-in hosts may be opened from the app. */
3
4
  export declare function officialLoginUrl(raw: string | null): string | null;
4
5
  /** The saved connection can answer customers right now. */
@@ -10,3 +11,16 @@ export type AiKnowledgeDraft = Pick<AiSettings, 'displayName' | 'instructions'>
10
11
  export declare function hasKnowledge(documents: readonly AiDocument[]): boolean;
11
12
  export type AiPill = 'off' | 'on' | 'needsConnection' | 'needsKnowledge';
12
13
  export declare function memberPill(status: AiMemberStatus): AiPill;
14
+ export type PresetTexts = {
15
+ instructions: string;
16
+ handoffRules: string;
17
+ };
18
+ type PresetField = keyof PresetTexts;
19
+ /** A preset's starting texts in the admin's language (`ai.defaults.<preset>.*`); Custom is blank. */
20
+ export declare function presetDefaults(preset: AiAgentPreset, t: TFunction<'admin'>): PresetTexts;
21
+ /**
22
+ * True when `text` is an unedited starting text of any preset: the English one the server keeps,
23
+ * or the copy in any language whose catalog is loaded. A blank text is never a default.
24
+ */
25
+ export declare function isPresetDefault(text: string, field: PresetField): boolean;
26
+ export {};
@@ -1,4 +1,6 @@
1
- import { type AiMemberBody, type AiConnectionBody, type AiContextPatchBody, type AiContextTextBody, type AiEditBody } from '@ezychat/shared';
1
+ import { type QueryClient } from '@tanstack/react-query';
2
+ import { z } from 'zod';
3
+ import { type AiAgentBody, type AiMemberBody, type AiConnectionBody, type AiContextPatchBody, type AiContextTextBody, type AiEditBody } from '@ezychat/shared';
2
4
  export declare const aiMemberKey: readonly ["ai-member"];
3
5
  export declare function useAiMember(): import("@tanstack/react-query").UseQueryResult<{
4
6
  member: {
@@ -12,6 +14,8 @@ export declare function useAiMember(): import("@tanstack/react-query").UseQueryR
12
14
  locale: "en" | "ms" | "zh-CN" | null;
13
15
  kind?: "human" | "ai" | undefined;
14
16
  aiRole?: "sales" | undefined;
17
+ aiAgentId?: number | undefined;
18
+ aiDeleted?: boolean | undefined;
15
19
  inboxIds?: number[] | undefined;
16
20
  } | null;
17
21
  settings: {
@@ -37,7 +41,18 @@ export declare function useAiMember(): import("@tanstack/react-query").UseQueryR
37
41
  characters: number;
38
42
  createdAt: number;
39
43
  updatedAt: number;
44
+ internal: boolean;
40
45
  }[];
46
+ agents: {
47
+ id: number;
48
+ userId: number;
49
+ displayName: string;
50
+ enabled: boolean;
51
+ preset: "sales" | "custom" | "faq";
52
+ inboxId: number | null;
53
+ documentCount: number;
54
+ }[];
55
+ maxAgents: number;
41
56
  }, Error>;
42
57
  /** One Business context item with its text (full for text items, a preview for files). */
43
58
  export declare function useAiDocument(id: number | null): import("@tanstack/react-query").UseQueryResult<{
@@ -48,6 +63,7 @@ export declare function useAiDocument(id: number | null): import("@tanstack/reac
48
63
  characters: number;
49
64
  createdAt: number;
50
65
  updatedAt: number;
66
+ internal: boolean;
51
67
  text: string;
52
68
  truncated: boolean;
53
69
  }, Error>;
@@ -65,14 +81,17 @@ export declare function useAiTest(): import("@tanstack/react-query").UseMutation
65
81
  reply: string | null;
66
82
  error: string | null;
67
83
  }, Error, void, unknown>;
68
- /** Try it: answers from the page's current knowledge; never touches chats or WhatsApp. */
84
+ /**
85
+ * Try it: answers from the page's current knowledge; never touches chats or WhatsApp. With
86
+ * `agentId` the answer uses that agent's saved items (and its path); without, the inbox-1 agent.
87
+ */
69
88
  export declare function useAiTry(): import("@tanstack/react-query").UseMutationResult<{
70
89
  ok: boolean;
71
90
  reply: string | null;
72
91
  action: "answer" | "ask_resolution" | "resolve" | "handoff" | "no_reply" | null;
73
92
  model: string | null;
74
93
  error: string | null;
75
- handoffReason?: "asked_for_human" | "missing_facts" | "sensitive" | "needs_action" | "business_rule" | "unsupported_message" | "ai_unavailable" | "lookup_failed" | null | undefined;
94
+ handoffReason?: "asked_for_human" | "missing_facts" | "sensitive" | "needs_action" | "business_rule" | "unsupported_message" | "ai_unavailable" | "lookup_failed" | "confidential_leak" | null | undefined;
76
95
  lookups?: {
77
96
  title: string;
78
97
  sourceLabel: string;
@@ -88,10 +107,13 @@ export declare function useAiTry(): import("@tanstack/react-query").UseMutationR
88
107
  instructions: string;
89
108
  handoffRules?: string | undefined;
90
109
  };
110
+ agentId?: number | undefined;
91
111
  }, unknown>;
92
- /** Edit with AI: a suggested rewrite of one box; nothing is saved (the page's Save does that). */
93
- /** Edit with AI. Pass a signal so closing the popup stops the (paid) model call. */
94
- export declare function useAiEdit(): import("@tanstack/react-query").UseMutationResult<{
112
+ /**
113
+ * Edit with AI: a suggested rewrite of one box; nothing is saved (the page's Save does that).
114
+ * Pass a signal so closing the popup stops the (paid) model call. `agentId`: whose items inform it.
115
+ */
116
+ export declare function useAiEdit(agentId?: number): import("@tanstack/react-query").UseMutationResult<{
95
117
  ok: boolean;
96
118
  text: string | null;
97
119
  error: string | null;
@@ -147,6 +169,8 @@ export declare function useAiMemberAction(): import("@tanstack/react-query").Use
147
169
  locale: "en" | "ms" | "zh-CN" | null;
148
170
  kind?: "human" | "ai" | undefined;
149
171
  aiRole?: "sales" | undefined;
172
+ aiAgentId?: number | undefined;
173
+ aiDeleted?: boolean | undefined;
150
174
  inboxIds?: number[] | undefined;
151
175
  } | null;
152
176
  settings: {
@@ -172,5 +196,167 @@ export declare function useAiMemberAction(): import("@tanstack/react-query").Use
172
196
  characters: number;
173
197
  createdAt: number;
174
198
  updatedAt: number;
199
+ internal: boolean;
200
+ }[];
201
+ agents: {
202
+ id: number;
203
+ userId: number;
204
+ displayName: string;
205
+ enabled: boolean;
206
+ preset: "sales" | "custom" | "faq";
207
+ inboxId: number | null;
208
+ documentCount: number;
175
209
  }[];
210
+ maxAgents: number;
176
211
  }, Error, AiMemberAction, unknown>;
212
+ /** `GET /api/ai/agents` and `DELETE /api/ai/agents/:agentId`: every agent and the edition limit. */
213
+ export declare const AiAgentList: z.ZodObject<{
214
+ agents: z.ZodArray<z.ZodObject<{
215
+ id: z.ZodNumber;
216
+ userId: z.ZodNumber;
217
+ displayName: z.ZodString;
218
+ enabled: z.ZodBoolean;
219
+ preset: z.ZodEnum<{
220
+ sales: "sales";
221
+ custom: "custom";
222
+ faq: "faq";
223
+ }>;
224
+ inboxId: z.ZodNullable<z.ZodNumber>;
225
+ documentCount: z.ZodNumber;
226
+ }, z.core.$strip>>;
227
+ maxAgents: z.ZodNumber;
228
+ }, z.core.$strip>;
229
+ export type AiAgentList = z.infer<typeof AiAgentList>;
230
+ export declare const aiAgentsKey: readonly ["ai-agents"];
231
+ export declare const aiAgentKey: (agentId: number) => readonly ["ai-agent", number];
232
+ /** One item with its text, under its agent (the agent is part of the key and of the path). */
233
+ export declare const aiAgentDocumentKey: (agentId: number, id: number) => readonly ["ai-document", number, number];
234
+ export declare function useAiAgents(): import("@tanstack/react-query").UseQueryResult<{
235
+ agents: {
236
+ id: number;
237
+ userId: number;
238
+ displayName: string;
239
+ enabled: boolean;
240
+ preset: "sales" | "custom" | "faq";
241
+ inboxId: number | null;
242
+ documentCount: number;
243
+ }[];
244
+ maxAgents: number;
245
+ }, Error>;
246
+ /** One agent with its settings and items; `null` (a new agent) reads nothing. */
247
+ export declare function useAiAgent(agentId: number | null): import("@tanstack/react-query").UseQueryResult<{
248
+ agent: {
249
+ id: number;
250
+ userId: number;
251
+ displayName: string;
252
+ enabled: boolean;
253
+ preset: "sales" | "custom" | "faq";
254
+ inboxId: number | null;
255
+ documentCount: number;
256
+ };
257
+ settings: {
258
+ displayName: string;
259
+ mode: "api" | "chatgpt";
260
+ enabled: boolean;
261
+ model: string;
262
+ instructions: string;
263
+ handoffRules?: string | undefined;
264
+ };
265
+ documents: {
266
+ id: number;
267
+ name: string;
268
+ kind: "text" | "file";
269
+ size: number;
270
+ characters: number;
271
+ createdAt: number;
272
+ updatedAt: number;
273
+ internal: boolean;
274
+ }[];
275
+ }, Error>;
276
+ /** One Business context item of an agent with its text (full for text, a preview for files). */
277
+ export declare function useAiAgentDocument(agentId: number, id: number | null): import("@tanstack/react-query").UseQueryResult<{
278
+ id: number;
279
+ name: string;
280
+ kind: "text" | "file";
281
+ size: number;
282
+ characters: number;
283
+ createdAt: number;
284
+ updatedAt: number;
285
+ internal: boolean;
286
+ text: string;
287
+ truncated: boolean;
288
+ }, Error>;
289
+ export type AiAgentAction = {
290
+ kind: 'create';
291
+ body: AiAgentBody;
292
+ } | {
293
+ kind: 'save';
294
+ body: AiAgentBody;
295
+ } | {
296
+ kind: 'delete';
297
+ } | {
298
+ kind: 'upload';
299
+ file: File;
300
+ internal?: boolean;
301
+ } | {
302
+ kind: 'addText';
303
+ body: AiContextTextBody;
304
+ } | {
305
+ kind: 'updateText';
306
+ id: number;
307
+ body: AiContextPatchBody;
308
+ } | {
309
+ kind: 'remove';
310
+ id: number;
311
+ } | {
312
+ kind: 'removeMany';
313
+ ids: number[];
314
+ }
315
+ /** Binds the agent to an inbox (Admin → Inboxes' route); null frees the inbox it answers now. */
316
+ | {
317
+ kind: 'setInbox';
318
+ inboxId: number | null;
319
+ };
320
+ /** Everything that shows agents: the list, every agent, the old AI member view, members, inboxes. */
321
+ export declare function refreshAgents(qc: QueryClient): void;
322
+ /** Changes one agent (or creates one with `agentId` null) and its Business context items. */
323
+ export declare function useAiAgentAction(agentId: number | null): import("@tanstack/react-query").UseMutationResult<{
324
+ agents: {
325
+ id: number;
326
+ userId: number;
327
+ displayName: string;
328
+ enabled: boolean;
329
+ preset: "sales" | "custom" | "faq";
330
+ inboxId: number | null;
331
+ documentCount: number;
332
+ }[];
333
+ maxAgents: number;
334
+ } | {
335
+ agent: {
336
+ id: number;
337
+ userId: number;
338
+ displayName: string;
339
+ enabled: boolean;
340
+ preset: "sales" | "custom" | "faq";
341
+ inboxId: number | null;
342
+ documentCount: number;
343
+ };
344
+ settings: {
345
+ displayName: string;
346
+ mode: "api" | "chatgpt";
347
+ enabled: boolean;
348
+ model: string;
349
+ instructions: string;
350
+ handoffRules?: string | undefined;
351
+ };
352
+ documents: {
353
+ id: number;
354
+ name: string;
355
+ kind: "text" | "file";
356
+ size: number;
357
+ characters: number;
358
+ createdAt: number;
359
+ updatedAt: number;
360
+ internal: boolean;
361
+ }[];
362
+ }, Error, AiAgentAction, unknown>;
@@ -16,10 +16,12 @@ export declare function useCreateInbox(): import("@tanstack/react-query").UseMut
16
16
  lastError: string | null;
17
17
  };
18
18
  removed: boolean;
19
+ aiAgentId: number | null;
19
20
  memberIds?: number[] | undefined;
20
21
  }, Error, {
21
22
  name: string;
22
23
  memberIds?: number[] | undefined;
24
+ aiAgentId?: number | null | undefined;
23
25
  }, unknown>;
24
26
  export declare function useUpdateInbox(): import("@tanstack/react-query").UseMutationResult<{
25
27
  id: number;
@@ -37,6 +39,7 @@ export declare function useUpdateInbox(): import("@tanstack/react-query").UseMut
37
39
  lastError: string | null;
38
40
  };
39
41
  removed: boolean;
42
+ aiAgentId: number | null;
40
43
  memberIds?: number[] | undefined;
41
44
  }, Error, {
42
45
  id: number;
@@ -61,5 +64,7 @@ export declare function useSetUserInboxes(userId: number): import("@tanstack/rea
61
64
  locale: "en" | "ms" | "zh-CN" | null;
62
65
  kind?: "human" | "ai" | undefined;
63
66
  aiRole?: "sales" | undefined;
67
+ aiAgentId?: number | undefined;
68
+ aiDeleted?: boolean | undefined;
64
69
  inboxIds?: number[] | undefined;
65
70
  }, Error, number[], unknown>;
@@ -68,6 +68,8 @@ export declare function useMe(): import("@tanstack/react-query").UseQueryResult<
68
68
  locale: "en" | "ms" | "zh-CN" | null;
69
69
  kind?: "human" | "ai" | undefined;
70
70
  aiRole?: "sales" | undefined;
71
+ aiAgentId?: number | undefined;
72
+ aiDeleted?: boolean | undefined;
71
73
  inboxIds?: number[] | undefined;
72
74
  } | null, Error>;
73
75
  export declare function useSetupStatus(): import("@tanstack/react-query").UseQueryResult<{
@@ -90,6 +92,8 @@ export declare function useLogin(): import("@tanstack/react-query").UseMutationR
90
92
  locale: "en" | "ms" | "zh-CN" | null;
91
93
  kind?: "human" | "ai" | undefined;
92
94
  aiRole?: "sales" | undefined;
95
+ aiAgentId?: number | undefined;
96
+ aiDeleted?: boolean | undefined;
93
97
  inboxIds?: number[] | undefined;
94
98
  } | null, Error, {
95
99
  username: string;
@@ -113,6 +117,8 @@ export declare function useSetMyLocale(): import("@tanstack/react-query").UseMut
113
117
  locale: "en" | "ms" | "zh-CN" | null;
114
118
  kind?: "human" | "ai" | undefined;
115
119
  aiRole?: "sales" | undefined;
120
+ aiAgentId?: number | undefined;
121
+ aiDeleted?: boolean | undefined;
116
122
  inboxIds?: number[] | undefined;
117
123
  }, Error, "en" | "ms" | "zh-CN" | null, unknown>;
118
124
  export declare function useChangePassword(): import("@tanstack/react-query").UseMutationResult<unknown, Error, {
@@ -460,6 +466,8 @@ export declare function useUsers(opts?: {
460
466
  locale: "en" | "ms" | "zh-CN" | null;
461
467
  kind?: "human" | "ai" | undefined;
462
468
  aiRole?: "sales" | undefined;
469
+ aiAgentId?: number | undefined;
470
+ aiDeleted?: boolean | undefined;
463
471
  inboxIds?: number[] | undefined;
464
472
  }[], Error>;
465
473
  /** Public team-member fields every logged-in user may see (`GET /api/users/directory`). */
@@ -479,6 +487,8 @@ export declare function useUserDirectory(opts?: {
479
487
  inboxIds: "all" | number[];
480
488
  kind?: "human" | "ai" | undefined;
481
489
  aiRole?: "sales" | undefined;
490
+ aiAgentId?: number | undefined;
491
+ aiDeleted?: boolean | undefined;
482
492
  }[], Error>;
483
493
  export declare function useCreateUser(): import("@tanstack/react-query").UseMutationResult<{
484
494
  id: number;
@@ -491,6 +501,8 @@ export declare function useCreateUser(): import("@tanstack/react-query").UseMuta
491
501
  locale: "en" | "ms" | "zh-CN" | null;
492
502
  kind?: "human" | "ai" | undefined;
493
503
  aiRole?: "sales" | undefined;
504
+ aiAgentId?: number | undefined;
505
+ aiDeleted?: boolean | undefined;
494
506
  inboxIds?: number[] | undefined;
495
507
  }, Error, {
496
508
  username: string;
@@ -509,6 +521,8 @@ export declare function usePatchUser(): import("@tanstack/react-query").UseMutat
509
521
  locale: "en" | "ms" | "zh-CN" | null;
510
522
  kind?: "human" | "ai" | undefined;
511
523
  aiRole?: "sales" | undefined;
524
+ aiAgentId?: number | undefined;
525
+ aiDeleted?: boolean | undefined;
512
526
  inboxIds?: number[] | undefined;
513
527
  }, Error, {
514
528
  id: number;
@@ -555,6 +569,7 @@ export declare function useInboxes(opts?: {
555
569
  lastError: string | null;
556
570
  };
557
571
  removed: boolean;
572
+ aiAgentId: number | null;
558
573
  memberIds?: number[] | undefined;
559
574
  }[];
560
575
  maxInboxes: number;
@@ -0,0 +1,18 @@
1
+ import { type ReactNode } from 'react';
2
+ import type { AiAgentPreset } from '@ezychat/shared';
3
+ /** The AI agent whose page an extension section (`agentSections`) is rendered on. */
4
+ export interface AgentSectionInfo {
5
+ agentId: number;
6
+ displayName: string;
7
+ preset: AiAgentPreset;
8
+ }
9
+ /** Wraps the extension sections of one agent page (core use only). */
10
+ export declare function AgentSectionProvider({ value, children, }: {
11
+ value: AgentSectionInfo;
12
+ children: ReactNode;
13
+ }): import("react").JSX.Element;
14
+ /**
15
+ * Inside an `agentSections` element: the agent whose page shows it (id, saved name and preset).
16
+ * Null anywhere else.
17
+ */
18
+ export declare function useAgentSection(): AgentSectionInfo | null;
@@ -2,3 +2,4 @@ export * from './types';
2
2
  export { WebExtensionsProvider, useWebExtensions } from './context';
3
3
  export { registerExtensionCatalogs, useExtensionTranslation, type ExtensionTranslate, } from './i18n';
4
4
  export { ExtensionBoundary, extensionRoutes } from './routes';
5
+ export { AgentSectionProvider, useAgentSection, type AgentSectionInfo } from './agent-section';