@agentforge-io/chat-sdk 2.4.0-dev.10 → 2.4.0-dev.12
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.
- package/dist/react.d.ts +13 -0
- package/dist/react.js +28 -2
- package/package.json +1 -1
package/dist/react.d.ts
CHANGED
|
@@ -205,6 +205,19 @@ export interface ChatWidgetHandle {
|
|
|
205
205
|
* the textarea hasn't mounted yet or is disabled.
|
|
206
206
|
*/
|
|
207
207
|
focus(): void;
|
|
208
|
+
/**
|
|
209
|
+
* Warm up the underlying session — fires the initial
|
|
210
|
+
* `GET /agent` (and optionally a `resumeConversation` lookup) so
|
|
211
|
+
* the first `send()` doesn't pay the round-trip. Idempotent:
|
|
212
|
+
* subsequent calls join the same in-flight promise.
|
|
213
|
+
*
|
|
214
|
+
* Hosts call this when the visitor signals INTENT to chat (e.g.
|
|
215
|
+
* tapping a fake-composer pill that opens a drawer) so the
|
|
216
|
+
* session boot overlaps with the visitor finding the keyboard
|
|
217
|
+
* and tapping out their first message. Safe no-op if the session
|
|
218
|
+
* is already past `loading`.
|
|
219
|
+
*/
|
|
220
|
+
warmup(): void;
|
|
208
221
|
}
|
|
209
222
|
/**
|
|
210
223
|
* Drop-in chat widget. Owns its own `ChatSession` and re-renders on every
|
package/dist/react.js
CHANGED
|
@@ -448,6 +448,14 @@ function ChatWidget(props) {
|
|
|
448
448
|
return;
|
|
449
449
|
el.focus({ preventScroll: true });
|
|
450
450
|
},
|
|
451
|
+
warmup: () => {
|
|
452
|
+
// session.start() is idempotent — joins the in-flight
|
|
453
|
+
// promise if one exists, resolves immediately if start
|
|
454
|
+
// already completed.
|
|
455
|
+
if (!session)
|
|
456
|
+
return;
|
|
457
|
+
void session.start();
|
|
458
|
+
},
|
|
451
459
|
};
|
|
452
460
|
return () => {
|
|
453
461
|
// Drop the handle on unmount so a stale ref can't fire send
|
|
@@ -538,7 +546,9 @@ function ChatWidget(props) {
|
|
|
538
546
|
onShortcutClick(text, i);
|
|
539
547
|
else
|
|
540
548
|
setDraft(text);
|
|
541
|
-
}, children: text }, `${i}-${text}`))) })), (0, jsx_runtime_1.jsxs)("div", { className: "af-input-row", children: [composerLeftSlot && ((0, jsx_runtime_1.jsx)("div", { className: "af-input-left", children: composerLeftSlot })), (0, jsx_runtime_1.jsx)("textarea", { ref: inputRef, className: "af-input", value: draft, onChange: (e) => setDraft(e.target.value), onKeyDown: onKeyDown, placeholder:
|
|
549
|
+
}, children: text }, `${i}-${text}`))) })), (0, jsx_runtime_1.jsxs)("div", { className: "af-input-row", "data-loading": status === 'loading' || status === 'idle' ? '' : undefined, children: [composerLeftSlot && ((0, jsx_runtime_1.jsx)("div", { className: "af-input-left", children: composerLeftSlot })), (0, jsx_runtime_1.jsx)("textarea", { ref: inputRef, className: "af-input", value: draft, onChange: (e) => setDraft(e.target.value), onKeyDown: onKeyDown, placeholder: status === 'idle' || status === 'loading'
|
|
550
|
+
? 'Preparing chat…'
|
|
551
|
+
: inputPlaceholder ?? 'Type a message…', rows: 1,
|
|
542
552
|
// The textarea stays editable while the agent is
|
|
543
553
|
// streaming so the visitor can compose their next
|
|
544
554
|
// message without waiting. Only block when the
|
|
@@ -553,7 +563,14 @@ function ChatWidget(props) {
|
|
|
553
563
|
// before `handleSend` runs, the button then disables
|
|
554
564
|
// (sendDisabled flips true on status change), focus
|
|
555
565
|
// jumps to <body>, and the on-screen keyboard collapses.
|
|
556
|
-
onPointerDown: (e) => e.preventDefault(), onClick: handleSend, disabled: sendDisabled, "aria-label":
|
|
566
|
+
onPointerDown: (e) => e.preventDefault(), onClick: handleSend, disabled: sendDisabled, "aria-label": status === 'sending' || status === 'streaming'
|
|
567
|
+
? 'Sending message'
|
|
568
|
+
: status === 'idle' || status === 'loading'
|
|
569
|
+
? 'Preparing chat'
|
|
570
|
+
: 'Send message', children: status === 'sending' ||
|
|
571
|
+
status === 'streaming' ||
|
|
572
|
+
status === 'idle' ||
|
|
573
|
+
status === 'loading' ? ((0, jsx_runtime_1.jsx)(SpinnerIcon, {})) : ((0, jsx_runtime_1.jsx)(SendIcon, {})) })] }), !bare && (0, jsx_runtime_1.jsx)("div", { className: "af-footer", children: "Powered by AgentForge" })] })] }));
|
|
557
574
|
}
|
|
558
575
|
function MessageBubble({ message, session, readOnly, onDecision, onContinue, bare = false, showAvatar = false, avatarTheme, avatarName, avatarAgentId, speakerLabel, }) {
|
|
559
576
|
const kind = message.metadata?.kind;
|
|
@@ -726,6 +743,11 @@ function CloseIcon() {
|
|
|
726
743
|
function SendIcon() {
|
|
727
744
|
return ((0, jsx_runtime_1.jsxs)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [(0, jsx_runtime_1.jsx)("line", { x1: "22", y1: "2", x2: "11", y2: "13" }), (0, jsx_runtime_1.jsx)("polygon", { points: "22 2 15 22 11 13 2 9 22 2" })] }));
|
|
728
745
|
}
|
|
746
|
+
function SpinnerIcon() {
|
|
747
|
+
// Inline SVG spinner — no external dep. Stroke-dasharray
|
|
748
|
+
// arc rotates via the CSS keyframes injected by WIDGET_CSS.
|
|
749
|
+
return ((0, jsx_runtime_1.jsxs)("svg", { viewBox: "0 0 24 24", fill: "none", className: "af-spinner", "aria-hidden": true, children: [(0, jsx_runtime_1.jsx)("circle", { cx: "12", cy: "12", r: "9", stroke: "currentColor", strokeOpacity: "0.25", strokeWidth: "2.5" }), (0, jsx_runtime_1.jsx)("path", { d: "M21 12a9 9 0 0 0-9-9", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round" })] }));
|
|
750
|
+
}
|
|
729
751
|
// Stylesheet kept verbatim from the standalone widget.js so the React
|
|
730
752
|
// component is visually indistinguishable from the script-injected one.
|
|
731
753
|
const WIDGET_CSS = `
|
|
@@ -810,6 +832,8 @@ const WIDGET_CSS = `
|
|
|
810
832
|
to { opacity: 1; transform: translateY(0); }
|
|
811
833
|
}
|
|
812
834
|
.af-input-row { padding: 12px; border-top: 1px solid var(--af-border); background: var(--af-bg); display: flex; gap: 8px; align-items: flex-end; }
|
|
835
|
+
.af-input-row[data-loading] .af-input { cursor: progress; opacity: 0.7; }
|
|
836
|
+
.af-input-row[data-loading] .af-input::placeholder { font-style: italic; }
|
|
813
837
|
/* Composer left slot — hosts use this for affordance buttons that
|
|
814
838
|
scope the next turn (member picker, tools menu, attachments).
|
|
815
839
|
align-items: center keeps a single-line chip vertically centered
|
|
@@ -869,6 +893,8 @@ const WIDGET_CSS = `
|
|
|
869
893
|
.af-send:active:not(:disabled) { transform: translateY(0); }
|
|
870
894
|
.af-send:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
871
895
|
.af-send svg { width: 16px; height: 16px; }
|
|
896
|
+
.af-send .af-spinner { animation: af-spin 720ms linear infinite; }
|
|
897
|
+
@keyframes af-spin { to { transform: rotate(360deg); } }
|
|
872
898
|
.af-error { padding: 10px 16px; font-size: 12px; color: #b91c1c; background: #fef2f2; border-top: 1px solid #fee2e2; }
|
|
873
899
|
.af-footer { padding: 6px 12px; font-size: 10px; color: var(--af-muted); text-align: center; background: var(--af-bubble-bg); border-top: 1px solid var(--af-border); }
|
|
874
900
|
/* Approval and blocked bubbles. Amber for needs-decision, red for
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentforge-io/chat-sdk",
|
|
3
|
-
"version": "2.4.0-dev.
|
|
3
|
+
"version": "2.4.0-dev.12",
|
|
4
4
|
"description": "Framework-free chat session SDK for AgentForge public chat tokens. Headless — no DOM. Drop into any frontend (React, Vue, Svelte, vanilla) and listen for events.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|