@aigentyc/chat-sdk 0.2.5 → 0.3.0

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 (101) hide show
  1. package/bin/aigentyc.mjs +10 -4
  2. package/bin/lib/skill.mjs +84 -0
  3. package/claude-skill/README.md +32 -0
  4. package/claude-skill/aigentyc-chat-sdk/SKILL.md +339 -0
  5. package/context7.json +1 -1
  6. package/dist/ChatInterface-B0zbA3Lm.d.cts +64 -0
  7. package/dist/ChatInterface-f8ftS56n.d.ts +64 -0
  8. package/dist/{SlotsContext-CBtt36al.d.ts → SlotsContext-BjiX1mRx.d.ts} +17 -2
  9. package/dist/{SlotsContext-CHvISDJT.d.cts → SlotsContext-CEOBjzfh.d.cts} +17 -2
  10. package/dist/ai-elements.cjs +114 -393
  11. package/dist/ai-elements.cjs.map +1 -1
  12. package/dist/ai-elements.d.cts +2 -31
  13. package/dist/ai-elements.d.ts +2 -31
  14. package/dist/ai-elements.js +9 -291
  15. package/dist/ai-elements.js.map +1 -1
  16. package/dist/{chunk-5QSXB6UL.cjs → chunk-3HGOLNGG.cjs} +13 -4
  17. package/dist/chunk-3HGOLNGG.cjs.map +1 -0
  18. package/dist/{chunk-KVEJAPWA.js → chunk-3KSMOHNY.js} +48 -62
  19. package/dist/chunk-3KSMOHNY.js.map +1 -0
  20. package/dist/chunk-4WOBNRRB.cjs +540 -0
  21. package/dist/chunk-4WOBNRRB.cjs.map +1 -0
  22. package/dist/chunk-7AZMWPKX.cjs +35 -0
  23. package/dist/chunk-7AZMWPKX.cjs.map +1 -0
  24. package/dist/chunk-B27JIQ4Z.js +528 -0
  25. package/dist/chunk-B27JIQ4Z.js.map +1 -0
  26. package/dist/{chunk-J2K7EJYP.cjs → chunk-BPV66QNM.cjs} +6 -4
  27. package/dist/chunk-BPV66QNM.cjs.map +1 -0
  28. package/dist/{chunk-FYPJSHCL.js → chunk-FPQ3UCCJ.js} +6 -4
  29. package/dist/chunk-FPQ3UCCJ.js.map +1 -0
  30. package/dist/{chunk-7L4FS6G7.js → chunk-JHWSG5IB.js} +17 -3
  31. package/dist/chunk-JHWSG5IB.js.map +1 -0
  32. package/dist/{chunk-4FBVV64J.js → chunk-M4YRNNGB.js} +13 -4
  33. package/dist/chunk-M4YRNNGB.js.map +1 -0
  34. package/dist/{chunk-QDFPJJ5Y.cjs → chunk-OU5OZKYH.cjs} +50 -65
  35. package/dist/chunk-OU5OZKYH.cjs.map +1 -0
  36. package/dist/{chunk-MC6QDYB6.cjs → chunk-PPCGZ5MP.cjs} +166 -67
  37. package/dist/chunk-PPCGZ5MP.cjs.map +1 -0
  38. package/dist/{chunk-U3FXVLUK.js → chunk-PQCGQ32Q.js} +84 -4
  39. package/dist/chunk-PQCGQ32Q.js.map +1 -0
  40. package/dist/{chunk-FOZXDUSZ.js → chunk-SWKWHBBN.js} +151 -54
  41. package/dist/chunk-SWKWHBBN.js.map +1 -0
  42. package/dist/{chunk-DMGYQ6NN.cjs → chunk-TLGZSXTU.cjs} +86 -6
  43. package/dist/chunk-TLGZSXTU.cjs.map +1 -0
  44. package/dist/{chunk-C24QG43M.cjs → chunk-TZ7EM3EG.cjs} +17 -2
  45. package/dist/chunk-TZ7EM3EG.cjs.map +1 -0
  46. package/dist/chunk-XEAAB5ZM.js +32 -0
  47. package/dist/chunk-XEAAB5ZM.js.map +1 -0
  48. package/dist/components.cjs +31 -52
  49. package/dist/components.cjs.map +1 -1
  50. package/dist/components.d.cts +4 -34
  51. package/dist/components.d.ts +4 -34
  52. package/dist/components.js +18 -42
  53. package/dist/components.js.map +1 -1
  54. package/dist/core.d.cts +2 -2
  55. package/dist/core.d.ts +2 -2
  56. package/dist/hooks.cjs +6 -6
  57. package/dist/hooks.d.cts +2 -2
  58. package/dist/hooks.d.ts +2 -2
  59. package/dist/hooks.js +2 -2
  60. package/dist/i18n.d.cts +1 -1
  61. package/dist/i18n.d.ts +1 -1
  62. package/dist/index.cjs +45 -23
  63. package/dist/index.cjs.map +1 -1
  64. package/dist/index.d.cts +51 -6
  65. package/dist/index.d.ts +51 -6
  66. package/dist/index.js +17 -10
  67. package/dist/index.js.map +1 -1
  68. package/dist/llms-full.txt +194 -14
  69. package/dist/message-feedback-BFh3-qym.d.cts +92 -0
  70. package/dist/message-feedback-cWR0NVok.d.ts +92 -0
  71. package/dist/normalize-KzCLLqpU.d.cts +42 -0
  72. package/dist/normalize-KzCLLqpU.d.ts +42 -0
  73. package/dist/styles.css +1 -1
  74. package/dist/theme.d.cts +1 -1
  75. package/dist/theme.d.ts +1 -1
  76. package/dist/tools.cjs +14 -5
  77. package/dist/tools.d.cts +3 -2
  78. package/dist/tools.d.ts +3 -2
  79. package/dist/tools.js +3 -2
  80. package/dist/{types-DKJ_-nbG.d.cts → types-DlNwk-bG.d.cts} +33 -3
  81. package/dist/{types-DKJ_-nbG.d.ts → types-DlNwk-bG.d.ts} +33 -3
  82. package/dist/ui.cjs +45 -45
  83. package/dist/ui.js +2 -2
  84. package/llms.txt +175 -5
  85. package/package.json +2 -1
  86. package/dist/chunk-4FBVV64J.js.map +0 -1
  87. package/dist/chunk-5QSXB6UL.cjs.map +0 -1
  88. package/dist/chunk-7L4FS6G7.js.map +0 -1
  89. package/dist/chunk-A7PCSWIK.js +0 -219
  90. package/dist/chunk-A7PCSWIK.js.map +0 -1
  91. package/dist/chunk-C24QG43M.cjs.map +0 -1
  92. package/dist/chunk-DMGYQ6NN.cjs.map +0 -1
  93. package/dist/chunk-FOZXDUSZ.js.map +0 -1
  94. package/dist/chunk-FYPJSHCL.js.map +0 -1
  95. package/dist/chunk-J2K7EJYP.cjs.map +0 -1
  96. package/dist/chunk-KVEJAPWA.js.map +0 -1
  97. package/dist/chunk-MC6QDYB6.cjs.map +0 -1
  98. package/dist/chunk-QDFPJJ5Y.cjs.map +0 -1
  99. package/dist/chunk-RTVEBPAJ.cjs +0 -230
  100. package/dist/chunk-RTVEBPAJ.cjs.map +0 -1
  101. package/dist/chunk-U3FXVLUK.js.map +0 -1
package/bin/aigentyc.mjs CHANGED
@@ -3,12 +3,14 @@
3
3
  * aigentyc — CLI router for @aigentyc/chat-sdk.
4
4
  *
5
5
  * Subcommands:
6
- * doctor diagnose install / config issues
7
- * add integrate the SDK into an existing project
6
+ * doctor diagnose install / config issues
7
+ * add integrate the SDK into an existing project
8
+ * skill install drop the Claude Code skill into .claude/skills/
8
9
  *
9
10
  * Usage:
10
11
  * npx @aigentyc/chat-sdk add
11
12
  * npx @aigentyc/chat-sdk doctor
13
+ * npx @aigentyc/chat-sdk skill install
12
14
  * npx @aigentyc/chat-sdk → shows help
13
15
  */
14
16
 
@@ -21,8 +23,9 @@ const HELP = `
21
23
  npx @aigentyc/chat-sdk <command>
22
24
 
23
25
  Commands:
24
- add Integrate the SDK into an existing Vite/Next/CRA project
25
- doctor Diagnose install + configuration
26
+ add Integrate the SDK into an existing Vite/Next/CRA project
27
+ doctor Diagnose install + configuration
28
+ skill install Install Claude Code skill into .claude/skills/
26
29
 
27
30
  Docs: https://www.npmjs.com/package/@aigentyc/chat-sdk
28
31
  `;
@@ -38,6 +41,9 @@ if (sub === "doctor") {
38
41
  } else if (sub === "add") {
39
42
  const { run } = await import("./lib/add.mjs");
40
43
  await run();
44
+ } else if (sub === "skill") {
45
+ const { run } = await import("./lib/skill.mjs");
46
+ await run(process.argv.slice(3));
41
47
  } else {
42
48
  console.error(`\n Unknown command: ${sub}`);
43
49
  console.log(HELP);
@@ -0,0 +1,84 @@
1
+ /**
2
+ * `aigentyc skill install` — drop the Claude Code skill for this SDK
3
+ * into the user's project at `.claude/skills/aigentyc-chat-sdk/`.
4
+ *
5
+ * The skill is bundled in the npm package at `claude-skill/aigentyc-chat-sdk/`
6
+ * (see package.json "files" entry). This command just copies it into place
7
+ * so any Claude Code / Claude Desktop session running in that workspace can
8
+ * pick it up automatically.
9
+ */
10
+
11
+ import { cp, mkdir, stat } from "node:fs/promises";
12
+ import { existsSync } from "node:fs";
13
+ import { dirname, join, resolve } from "node:path";
14
+ import { fileURLToPath } from "node:url";
15
+
16
+ const __dirname = dirname(fileURLToPath(import.meta.url));
17
+ // bin/lib/skill.mjs -> up to package root
18
+ const PKG_ROOT = resolve(__dirname, "..", "..");
19
+ const SKILL_SRC = resolve(PKG_ROOT, "claude-skill", "aigentyc-chat-sdk");
20
+
21
+ const HELP = `
22
+ aigentyc skill install [--force] [--global]
23
+
24
+ Installs the Claude Code skill for @aigentyc/chat-sdk.
25
+
26
+ Flags:
27
+ --force Overwrite existing skill if present
28
+ --global Install to ~/.claude/skills/ (default: ./.claude/skills/)
29
+
30
+ After install, any Claude Code / Claude Desktop session in this workspace
31
+ will auto-load the skill for help with this SDK.
32
+ `;
33
+
34
+ export async function run(argv = []) {
35
+ const sub = argv[0];
36
+ if (sub === "--help" || sub === "-h") {
37
+ console.log(HELP);
38
+ return;
39
+ }
40
+
41
+ if (sub !== "install") {
42
+ console.error(`\n Unknown skill subcommand: ${sub ?? "(none)"}`);
43
+ console.log(HELP);
44
+ process.exit(2);
45
+ }
46
+
47
+ const flags = new Set(argv.slice(1).filter((a) => a.startsWith("--")));
48
+ const force = flags.has("--force");
49
+ const globalInstall = flags.has("--global");
50
+
51
+ // Target dir
52
+ const rootDir = globalInstall
53
+ ? resolve(process.env.HOME || "~", ".claude", "skills")
54
+ : resolve(process.cwd(), ".claude", "skills");
55
+ const target = join(rootDir, "aigentyc-chat-sdk");
56
+
57
+ if (!existsSync(SKILL_SRC)) {
58
+ console.error(
59
+ `\n ✖ Can't find skill source at: ${SKILL_SRC}\n` +
60
+ ` (Are you running from a checkout, or an old SDK version? Reinstall with \`npm install @aigentyc/chat-sdk@latest\`.)\n`,
61
+ );
62
+ process.exit(1);
63
+ }
64
+
65
+ if (existsSync(target)) {
66
+ if (!force) {
67
+ console.error(
68
+ `\n ✖ Skill already installed at:\n ${target}\n\n` +
69
+ ` Re-run with --force to overwrite, or delete the folder first.\n`,
70
+ );
71
+ process.exit(1);
72
+ }
73
+ }
74
+
75
+ await mkdir(rootDir, { recursive: true });
76
+ await cp(SKILL_SRC, target, { recursive: true });
77
+
78
+ const size = await stat(target);
79
+ console.log(
80
+ `\n ✓ Installed @aigentyc/chat-sdk skill to:\n ${target}\n\n` +
81
+ ` Claude Code / Desktop will now auto-load help for this SDK.\n` +
82
+ (size.isDirectory() ? "" : ""),
83
+ );
84
+ }
@@ -0,0 +1,32 @@
1
+ # Claude Code skill for @aigentyc/chat-sdk
2
+
3
+ This folder ships inside the npm package so developers using the SDK can install the skill into their Claude Code / Claude Desktop workspace.
4
+
5
+ ## Install in an existing project
6
+
7
+ ```bash
8
+ npx @aigentyc/chat-sdk skill install
9
+ ```
10
+
11
+ Drops the skill into `./.claude/skills/aigentyc-chat-sdk/`. Any Claude Code session running in that workspace then gets automatic help with the SDK — slot patterns, auth setup, troubleshooting, headless hook recipes, etc.
12
+
13
+ Flags:
14
+ - `--force` — overwrite an existing install
15
+ - `--global` — install to `~/.claude/skills/` so every project sees it
16
+
17
+ ## Auto-install (new projects)
18
+
19
+ `npm create aigentyc-chat@latest my-app` drops the skill into the scaffolded project automatically. No separate step.
20
+
21
+ ## What the skill covers
22
+
23
+ - Decision tree: `<Chat>` vs `<ChatWidget>` vs `<ChatProvider>` vs `useAigentycChat()`
24
+ - Required setup (the three props + CSS import + `apiKey` gotcha)
25
+ - Slots: full list, the `tools` vs `toolRenderers` confusion, type-safe override pattern
26
+ - Theming / dark mode
27
+ - Tool rendering + `normalizeToolRows` helper
28
+ - Event callbacks
29
+ - Troubleshooting table
30
+ - Rules (do / don't)
31
+
32
+ Content is a superset of `llms.txt`, formatted for Claude Code's progressive-disclosure skill model.
@@ -0,0 +1,339 @@
1
+ ---
2
+ name: aigentyc-chat-sdk
3
+ description: Expert help for building apps with @aigentyc/chat-sdk — the React 19 SDK for embedding Aigentyc-powered AI chat. Trigger when the user imports `@aigentyc/chat-sdk`, mentions `<Chat />` or `<ChatWidget />`, asks how to embed a chat widget, customize slots, theme, tools, handle auth (`apiKey`, 401 errors), or use `useAigentycChat` headless hook.
4
+ ---
5
+
6
+ # @aigentyc/chat-sdk — Integration Guide
7
+
8
+ You are an expert on the `@aigentyc/chat-sdk` React SDK. Use this skill when the user is building, debugging, or extending an app that uses the SDK.
9
+
10
+ ## Decision tree: pick the right component
11
+
12
+ ```
13
+ Drop-in full-page chat? → <Chat projectId apiEndpoint apiKey />
14
+ Floating chat bubble? → <ChatWidget projectId apiEndpoint apiKey />
15
+ Custom layout, own container? → <ChatProvider> + <ChatInterface />
16
+ Completely custom UI? → useAigentycChat() hook
17
+ ```
18
+
19
+ Component props are identical between `<Chat>` and `<ChatWidget>` — swap freely.
20
+
21
+ ## Required setup (every integration)
22
+
23
+ 1. `npm install @aigentyc/chat-sdk` (peer: `react>=19`)
24
+ 2. Import CSS once: `import "@aigentyc/chat-sdk/theme/styles.css"`
25
+ 3. Pass **three** props: `projectId`, `apiEndpoint`, `apiKey`
26
+
27
+ **`apiKey` IS required for third-party domain embeds.** Without it, `/api/kb/chat` returns 401. The "no apiKey needed" path only works inside `app.aigentyc.com`. Get a project-scoped key from the dashboard (Settings → API Keys) with permission `Chat: Full` and add the embed domain to Allowed Origins.
28
+
29
+ Environment-variable pattern:
30
+ - Next.js: `NEXT_PUBLIC_AIGENTYC_API_KEY`
31
+ - Vite: `VITE_AIGENTYC_API_KEY`
32
+
33
+ ## Slots system (how to customize UI)
34
+
35
+ The `slots` prop replaces specific pieces. Every slot receives `DefaultComponent` so you can compose or fully replace.
36
+
37
+ **Two slot categories commonly confused:**
38
+ - `slots.tools` — **keyed by tool NAME** (e.g. `searchProducts`). Use for per-tool display.
39
+ - `slots.toolRenderers` — **keyed by render MODE** (`visualization`, `json_render`, `legacy`, `preset`, `text`). Use to swap an entire category of renderers.
40
+
41
+ **All available slots:**
42
+ - Layout: `header`, `footer`, `input`, `welcomePage`, `loader`, `emptyState`
43
+ - Messages: `assistantMessage`, `userMessage`, `systemMessage`, `feedback`
44
+ - Tools: `tools` (by name), `toolRenderers` (by mode)
45
+ - Live chat: `liveChatPanel`, `satisfactionRating`, `visitorIdentityForm`
46
+ - Widget: `floatingButton`
47
+
48
+ **Pattern for a slot override:**
49
+
50
+ ```tsx
51
+ import type { AssistantMessageSlotProps } from "@aigentyc/chat-sdk";
52
+
53
+ function MyAssistant({ text, message, DefaultComponent, ...rest }: AssistantMessageSlotProps & { DefaultComponent: any }) {
54
+ // Wrap the default:
55
+ return <div className="my-wrapper"><DefaultComponent text={text} message={message} {...rest} /></div>;
56
+ // OR replace it entirely:
57
+ // return <div className="my-bubble">{text}</div>;
58
+ }
59
+
60
+ <Chat slots={{ assistantMessage: MyAssistant }} projectId="..." apiEndpoint="..." apiKey="..." />
61
+ ```
62
+
63
+ ## Theming
64
+
65
+ CSS vars under `[data-aigentyc-chat]`. Pass `theme` prop:
66
+
67
+ ```tsx
68
+ <Chat theme={{ primaryColor: "#eb1d22", fontFamily: "Inter, sans-serif" }} ... />
69
+ ```
70
+
71
+ Or override CSS vars directly: `--ac-primary`, `--ac-background`, `--ac-card`, `--ac-text`, `--ac-user-bubble-bg`, `--ac-assistant-bubble-bg`.
72
+
73
+ **Dark mode works automatically** — the SDK uses `bg-background`/`bg-card` with theme vars, not hardcoded whites.
74
+
75
+ ## Tool rendering (backend-driven custom UI)
76
+
77
+ Custom tools configured in the dashboard return a result with `uiRenderMode`:
78
+ - `visualization` → recharts (10 chart types)
79
+ - `json_render` → `@json-render/shadcn` spec
80
+ - `legacy` → HTML/CSS template with `{{field}}` / `{{#each}}` substitution
81
+ - `preset` / `text` → JSON card
82
+ - `hidden` / `none` → render nothing
83
+
84
+ Override via `slots.tools[toolName]`:
85
+
86
+ ```tsx
87
+ import type { ToolRendererProps } from "@aigentyc/chat-sdk";
88
+ import { normalizeToolRows } from "@aigentyc/chat-sdk";
89
+
90
+ function ProductGrid({ result }: ToolRendererProps) {
91
+ const rows = normalizeToolRows(result?.data); // handles flat | wrapped | raw DB shapes
92
+ return <div className="grid grid-cols-2 gap-2">{rows.map((r, i) => <Card key={i} {...r} />)}</div>;
93
+ }
94
+
95
+ <Chat slots={{ tools: { searchProducts: ProductGrid } }} ... />
96
+ ```
97
+
98
+ ## Event callbacks
99
+
100
+ Attach analytics/side-effect hooks via top-level props (they flow into `ChatEventCallbacks`):
101
+
102
+ ```tsx
103
+ <Chat
104
+ onMessageSent={(m) => analytics.track("sent", m)}
105
+ onMessageReceived={(m) => analytics.track("received", m)}
106
+ onNewConversation={(sessionId) => console.log("new session", sessionId)}
107
+ onStopGeneration={() => console.log("user stopped stream")}
108
+ onToolCall={(name, args) => console.log("tool", name)}
109
+ onToolResult={(name, result) => console.log("result", name)}
110
+ onError={(err) => Sentry.captureException(err)}
111
+ />
112
+ ```
113
+
114
+ ## Headless hook
115
+
116
+ ```tsx
117
+ import { useAigentycChat } from "@aigentyc/chat-sdk/hooks";
118
+
119
+ const {
120
+ messages, status, sendMessage, stopGeneration,
121
+ newConversation, clearMessages,
122
+ activeTools, liveChat, sessionId,
123
+ } = useAigentycChat({ projectId, apiEndpoint, apiKey });
124
+ ```
125
+
126
+ Build any UI you want on top. All events (`onMessageSent`, `onStopGeneration`, `onNewConversation`, etc.) work the same.
127
+
128
+ ## Common props reference
129
+
130
+ | Prop | Type | Notes |
131
+ |------|------|-------|
132
+ | `projectId` | `string` | **required** |
133
+ | `apiEndpoint` | `string` | **required** — typically `https://app.aigentyc.ai` |
134
+ | `apiKey` | `string` | Required for embeds on non-aigentyc domains |
135
+ | `theme` | `ThemeConfig` | Brand colors, fonts |
136
+ | `slots` | `SlotMap` | UI customization |
137
+ | `language` | `"en" \| "he" \| string` | Sets RTL for `he` automatically |
138
+ | `messagePartOrder` | `"text-first" \| "tools-first" \| "stream-order"` | **new** — text/tool sort inside each message |
139
+ | `showSources` | `boolean` | Citation list under assistant messages |
140
+ | `persistMessages` | `boolean` | Default `true`, localStorage keyed by projectId |
141
+ | `enableLiveChat` | `boolean` | Human handoff (needs `socket.io-client`) |
142
+ | `chatServiceUrl` | `string` | WebSocket URL for live chat |
143
+
144
+ ## Rules — things to do / not to do
145
+
146
+ **Do:**
147
+ - Always include the CSS import
148
+ - Always pass `apiKey` for third-party embeds
149
+ - Use `slots` over forking the SDK
150
+ - Use `useAigentycChat` when you need full UI control
151
+ - Use `normalizeToolRows(result?.data)` when writing custom tool renderers
152
+ - Wrap untested custom renderers in `<ChatErrorBoundary>`
153
+
154
+ **Do not:**
155
+ - Add `"use client"` to files that wrap SDK components (the SDK already declares it)
156
+ - Import from `@aigentyc/chat-sdk/dist/*` — use public entry points only
157
+ - Hard-code API keys in committed source — always env vars
158
+ - Mix `slots.tools` (by name) and `slots.toolRenderers` (by mode) — dev console warns
159
+ - Downgrade React below 19
160
+
161
+ ## Troubleshooting — quick fixes
162
+
163
+ | Symptom | Fix |
164
+ |---------|-----|
165
+ | "Missing Authorization" / 401 | Add `apiKey` prop — see Auth section above |
166
+ | Origin rejected / 403 | Add your embed domain to the API key's Allowed Origins |
167
+ | Unstyled chat | Missing `import "@aigentyc/chat-sdk/theme/styles.css"` |
168
+ | Slot override doesn't show | `toolRenderers` is by mode, not tool name — use `slots.tools` |
169
+ | Welcome won't reset | Upgrade SDK (0.2+ fixes bidirectional welcome toggle) |
170
+ | Raw JSON from tool | Tool has no `uiRenderMode` or no renderer — set server-side or add `slots.tools[name]` |
171
+ | Hebrew shows LTR | Pass `language="he"` |
172
+ | Next.js hydration warning | Ensure you don't add `"use client"` yourself; SDK handles it |
173
+
174
+ ## Advanced: JSON-render tools (declarative UI)
175
+
176
+ JSON-render lets you describe UI as a spec (`root` + `elements` + `state`) with state binding, actions, and validation — no custom React code needed. Used for forms, dashboards, interactive tool output.
177
+
178
+ **Supported components** (from `@json-render/shadcn`): `Stack`, `Grid`, `Card`, `Tabs`, `Accordion`, `Heading`, `Text`, `Badge`, `Alert`, `Input`, `Textarea`, `Select`, `Checkbox`, `Radio`, `Switch`, `Slider`, `Button`, `Table`, `LineChart`, `BarChart`, `PieChart`, `AreaChart`, `Progress`, `Spinner`, `Image`, `Avatar`, `Pagination`, `Dialog`, `Drawer`.
179
+
180
+ **State binding** — paths are forward-slash (e.g. `/form/name`):
181
+ - `{ $bindState: "/form/name" }` — two-way binding (inputs)
182
+ - `{ $state: "/form/name" }` — one-way read (use in `body`, `endpoint`, etc.)
183
+
184
+ **Actions on `on.press`**:
185
+ - `navigate_url` → `{ url, target? }`
186
+ - `send_message` → `{ message }` — sends a follow-up chat message as the user
187
+ - `call_api` → `{ endpoint, method?, body? }` — validates inputs, resolves `$state` refs, handles form submit
188
+
189
+ **Form tool pattern** (email submission):
190
+
191
+ ```json
192
+ {
193
+ "toolType": "data_store",
194
+ "displayType": "json_render",
195
+ "jsonRenderSpec": {
196
+ "root": "form",
197
+ "elements": {
198
+ "form": { "type": "Stack", "props": { "gap": "md" }, "children": ["name", "phone", "submit"] },
199
+ "name": {
200
+ "type": "Input",
201
+ "props": {
202
+ "label": "שם", "name": "name", "placeholder": "הכנס שם",
203
+ "value": { "$bindState": "/form/name" },
204
+ "checks": [{ "type": "required", "message": "חובה" }]
205
+ }
206
+ },
207
+ "phone": {
208
+ "type": "Input",
209
+ "props": {
210
+ "label": "טלפון", "name": "phone",
211
+ "value": { "$bindState": "/form/phone" },
212
+ "checks": [
213
+ { "type": "required", "message": "חובה" },
214
+ { "type": "pattern", "args": { "pattern": "^[0-9]{10}$" }, "message": "10 ספרות" }
215
+ ]
216
+ }
217
+ },
218
+ "submit": {
219
+ "type": "Button",
220
+ "props": { "label": "שלח", "variant": "primary" },
221
+ "on": {
222
+ "press": {
223
+ "action": "call_api",
224
+ "params": {
225
+ "endpoint": "https://app.aigentyc.ai/api/kb/form-submit",
226
+ "method": "POST",
227
+ "body": {
228
+ "toolId": "<TOOL_ID>",
229
+ "projectId": "<PROJECT_ID>",
230
+ "formData": {
231
+ "name": { "$state": "/form/name" },
232
+ "phone": { "$state": "/form/phone" }
233
+ }
234
+ }
235
+ },
236
+ "onSuccess": { "set": { "/formSubmitted": true } },
237
+ "onError": { "set": { "/formError": "$error.message" } }
238
+ }
239
+ }
240
+ }
241
+ },
242
+ "state": { "form": { "name": "", "phone": "" }, "formSubmitted": false, "formError": "" },
243
+ "_formConfig": {
244
+ "mode": "email",
245
+ "to": "you@example.com",
246
+ "subject": "New form submission",
247
+ "successMessage": "Submitted, thank you!",
248
+ "errorMessage": "Something went wrong",
249
+ "hideFormAfter": true
250
+ }
251
+ }
252
+ }
253
+ ```
254
+
255
+ `_formConfig` lives **inside** `jsonRenderSpec`. The backend reads it when `/api/kb/form-submit` fires. Two modes:
256
+ - `mode: "email"` — routes via internal email service (`to`, `subject` required). Conversation summary auto-attached.
257
+ - `mode: "custom"` — proxies to `customEndpoint` (SSRF-protected: no localhost/private IPs).
258
+
259
+ ## Advanced: Flows (multi-step tool chains)
260
+
261
+ Flows orchestrate multiple tool steps — REST calls, custom-execute transforms, AI reranking, data store lookups. Configure via `flows_create` MCP tool with an opaque spec:
262
+
263
+ ```typescript
264
+ // CreateToolFlowInput
265
+ {
266
+ name: "findAndRank", // camelCase for AI
267
+ displayName: "Find + rank",
268
+ description: "Search products then rerank by relevance",
269
+ inputSchema: [{ name: "query", type: "string", required: true }],
270
+ steps: [
271
+ {
272
+ id: "search", order: 1, name: "Search", type: "tool_reference",
273
+ toolId: "tool_abc",
274
+ inputMapping: [{ target: "q", source: { type: "flow_input", flowInputParam: "query" } }],
275
+ },
276
+ {
277
+ id: "rerank", order: 2, name: "Rerank", type: "ai_rerank",
278
+ aiRerankConfig: { model: "gpt-4o-mini", systemPrompt: "...", maxResults: 5 },
279
+ inputMapping: [{ target: "items", source: { type: "step_output", stepId: "search" } }],
280
+ onError: "skip",
281
+ },
282
+ ],
283
+ uiRenderMode: "json",
284
+ jsonRenderSpec: { /* renders the final merged output */ }
285
+ }
286
+ ```
287
+
288
+ Step types:
289
+ - `api` — REST call (uses `apiConfig`)
290
+ - `tool_reference` — call an existing tool (by `toolId`)
291
+ - `transform` — sandboxed JS (`transformCode`)
292
+ - `ai_rerank` — OpenAI-based filter/sort
293
+ - `data_store` — query a data store (uses `dataStoreConfig`)
294
+
295
+ Error handling per step: `stop` | `skip` | `default` (with `defaultValue`).
296
+
297
+ ## MCP capability reference
298
+
299
+ Which advanced fields are settable via `@aigentyc/mcp` tools:
300
+
301
+ | Feature | Via `tools_create` | Notes |
302
+ |---|---|---|
303
+ | `displayType` | ✅ (new — recommended) | Normalized to `uiRenderMode` automatically |
304
+ | `jsonRenderSpec` | ✅ opaque record | Includes `_formConfig` nested |
305
+ | `customHtml` / `customCss` | ✅ | |
306
+ | `mobileGridCols` / `desktopGridCols` | ✅ | |
307
+ | `componentActions` | ✅ opaque | |
308
+ | `uiRenderMode` | ✅ full enum | `legacy \| json \| json_render \| visualization \| preset \| text \| hidden \| none` |
309
+ | `toolType` | ✅ | `rest_api \| custom_execute \| transform \| hybrid \| data_store \| web_search` (`transform` is an alias for `custom_execute`) |
310
+ | Flow steps (`flows_create`) | ✅ opaque spec | Full `FlowStep[]` supported |
311
+ | Form submit endpoint | ❌ no dedicated MCP tool | Form tools = `toolType: "data_store"` + `jsonRenderSpec._formConfig` |
312
+
313
+ ## Transform tools — hoisting render keys
314
+
315
+ If you write a `custom_execute` / `transform` tool and want the runtime output to control rendering, return an object with these keys at the top level:
316
+
317
+ ```js
318
+ // transformCode
319
+ return {
320
+ data: [...], // actual payload
321
+ uiRenderMode: "json", // overrides tool config
322
+ jsonRenderSpec: { root: ... }, // overrides tool config
323
+ componentActions: [...], // overrides tool config
324
+ loadingText: "...",
325
+ uiComponent: "MyComponent",
326
+ };
327
+ ```
328
+
329
+ The backend hoists these to the top-level of the tool result so the SDK sees them. This lets you compute the spec dynamically per-call.
330
+
331
+ ## Further reading
332
+
333
+ - Full recipe book: see `llms.txt` in the package root (or fetch `https://unpkg.com/@aigentyc/chat-sdk/llms.txt`)
334
+ - Package: https://www.npmjs.com/package/@aigentyc/chat-sdk
335
+ - Dashboard (get projectId + apiKey): https://app.aigentyc.ai
336
+
337
+ ## When you finish a change
338
+
339
+ Check: did you add an `apiKey`? Did you pass `projectId` + `apiEndpoint`? Did you import the CSS exactly once in the layout/root? For slot overrides — did you use the correct slot name (warnings land in dev console)?
package/context7.json CHANGED
@@ -1,4 +1,4 @@
1
1
  {
2
- "url": "https://context7.com/llmstxt/cdn_jsdelivr_net_npm_aigentyc_chat-sdk_0_2_5_llms_txt",
2
+ "url": "https://context7.com/llmstxt/cdn_jsdelivr_net_npm_aigentyc_chat-sdk_0_3_0_llms_txt",
3
3
  "public_key": "pk_dHiyF4hGXkgbb1jdrT7TU"
4
4
  }
@@ -0,0 +1,64 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { Q as QuestionConfig } from './types-DlNwk-bG.cjs';
3
+
4
+ interface ChatInterfaceProps {
5
+ /** Allow per-instance overrides of any context value */
6
+ isOpen?: boolean;
7
+ onClose?: () => void;
8
+ onNewConversation?: () => void;
9
+ logoUrl?: string;
10
+ questions?: QuestionConfig[];
11
+ pageQuestions?: QuestionConfig[];
12
+ footerText?: string;
13
+ welcomeTitle?: string;
14
+ welcomeSubtitle?: string;
15
+ hideWelcomeHeader?: boolean;
16
+ showFirstMessage?: boolean;
17
+ hideHeader?: boolean;
18
+ pendingMessage?: string | null;
19
+ onPendingMessageConsumed?: () => void;
20
+ pageUrl?: string;
21
+ pageTitle?: string;
22
+ pageContextLoading?: boolean;
23
+ pageWelcomeTitle?: string;
24
+ pageWelcomeSubtitle?: string;
25
+ questionsLayout?: "vertical" | "horizontal";
26
+ questionsLayoutMobile?: "vertical" | "horizontal";
27
+ /**
28
+ * Show citation sources under each assistant message that used the
29
+ * `searchKnowledgeBase` tool. Off by default.
30
+ */
31
+ showSources?: boolean;
32
+ /**
33
+ * Controls the rendering order of message parts (text vs tool results).
34
+ * - `"text-first"` (default) — text parts render before tool cards
35
+ * - `"tools-first"` — tool cards render before text
36
+ * - `"stream-order"` — parts render in the order received from the API
37
+ */
38
+ messagePartOrder?: "text-first" | "tools-first" | "stream-order";
39
+ }
40
+ interface AssistantMessageSlotProps {
41
+ message: {
42
+ id: string;
43
+ parts?: Array<{
44
+ type: string;
45
+ text?: string;
46
+ }>;
47
+ };
48
+ partIndex: number;
49
+ text: string;
50
+ }
51
+ interface UserMessageSlotProps {
52
+ message: {
53
+ id: string;
54
+ parts?: Array<{
55
+ type: string;
56
+ text?: string;
57
+ }>;
58
+ };
59
+ partIndex: number;
60
+ text: string;
61
+ }
62
+ declare function ChatInterface(props: ChatInterfaceProps): react_jsx_runtime.JSX.Element;
63
+
64
+ export { type AssistantMessageSlotProps as A, type ChatInterfaceProps as C, type UserMessageSlotProps as U, ChatInterface as a };
@@ -0,0 +1,64 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { Q as QuestionConfig } from './types-DlNwk-bG.js';
3
+
4
+ interface ChatInterfaceProps {
5
+ /** Allow per-instance overrides of any context value */
6
+ isOpen?: boolean;
7
+ onClose?: () => void;
8
+ onNewConversation?: () => void;
9
+ logoUrl?: string;
10
+ questions?: QuestionConfig[];
11
+ pageQuestions?: QuestionConfig[];
12
+ footerText?: string;
13
+ welcomeTitle?: string;
14
+ welcomeSubtitle?: string;
15
+ hideWelcomeHeader?: boolean;
16
+ showFirstMessage?: boolean;
17
+ hideHeader?: boolean;
18
+ pendingMessage?: string | null;
19
+ onPendingMessageConsumed?: () => void;
20
+ pageUrl?: string;
21
+ pageTitle?: string;
22
+ pageContextLoading?: boolean;
23
+ pageWelcomeTitle?: string;
24
+ pageWelcomeSubtitle?: string;
25
+ questionsLayout?: "vertical" | "horizontal";
26
+ questionsLayoutMobile?: "vertical" | "horizontal";
27
+ /**
28
+ * Show citation sources under each assistant message that used the
29
+ * `searchKnowledgeBase` tool. Off by default.
30
+ */
31
+ showSources?: boolean;
32
+ /**
33
+ * Controls the rendering order of message parts (text vs tool results).
34
+ * - `"text-first"` (default) — text parts render before tool cards
35
+ * - `"tools-first"` — tool cards render before text
36
+ * - `"stream-order"` — parts render in the order received from the API
37
+ */
38
+ messagePartOrder?: "text-first" | "tools-first" | "stream-order";
39
+ }
40
+ interface AssistantMessageSlotProps {
41
+ message: {
42
+ id: string;
43
+ parts?: Array<{
44
+ type: string;
45
+ text?: string;
46
+ }>;
47
+ };
48
+ partIndex: number;
49
+ text: string;
50
+ }
51
+ interface UserMessageSlotProps {
52
+ message: {
53
+ id: string;
54
+ parts?: Array<{
55
+ type: string;
56
+ text?: string;
57
+ }>;
58
+ };
59
+ partIndex: number;
60
+ text: string;
61
+ }
62
+ declare function ChatInterface(props: ChatInterfaceProps): react_jsx_runtime.JSX.Element;
63
+
64
+ export { type AssistantMessageSlotProps as A, type ChatInterfaceProps as C, type UserMessageSlotProps as U, ChatInterface as a };
@@ -1,5 +1,6 @@
1
+ import * as React from 'react';
1
2
  import { RefObject, ComponentType } from 'react';
2
- import { f as LiveChatState, e as LiveChatMessage, C as ChatProviderProps, c as ChatMessage, a as ChatConfig, b as ChatEventCallbacks } from './types-DKJ_-nbG.js';
3
+ import { f as LiveChatState, e as LiveChatMessage, C as ChatProviderProps, c as ChatMessage, a as ChatConfig, b as ChatEventCallbacks } from './types-DlNwk-bG.js';
3
4
 
4
5
  type ChatStatus$1 = "idle" | "streaming" | "error";
5
6
  interface ActiveTool$1 {
@@ -144,5 +145,19 @@ declare function useSlots(): SlotMap;
144
145
  * Returns the override component for the given slot name, or undefined if none is set.
145
146
  */
146
147
  declare function useSlot<P = Record<string, unknown>>(name: SlotName): SlotComponent<P> | undefined;
148
+ /**
149
+ * Renders a slot: if an override exists, renders it with `{...props, DefaultComponent}`.
150
+ * Otherwise renders the DefaultComponent with the given props.
151
+ *
152
+ * The generic `P` is NOT constrained to `Record<string, unknown>` so concrete
153
+ * component prop types (e.g. `ChatHeaderProps`) flow through at call sites
154
+ * without `as never` casts. Internal spreads are cast through
155
+ * `Record<string, unknown>` — safe because JSX spread accepts any record.
156
+ *
157
+ * @param name - The slot name
158
+ * @param props - Props to pass to the component
159
+ * @param DefaultComponent - The built-in fallback component
160
+ */
161
+ declare function renderSlot<P>(name: SlotName, props: P, DefaultComponent: ComponentType<P>, slots: SlotMap): React.ReactElement;
147
162
 
148
- export { type LiveChatReturn as L, type UseAigentycChatOptions as U, type UseAigentycChatReturn as a, useChatContext as b, useLiveChat as c, useSlot as d, useSlots as e, useAigentycChat as u };
163
+ export { type LiveChatReturn as L, type SlotComponent as S, type UseAigentycChatOptions as U, type SlotName as a, type UseAigentycChatReturn as b, useChatContext as c, useLiveChat as d, useSlot as e, useSlots as f, renderSlot as r, useAigentycChat as u };