@courseecho/ai-core-sdk 1.0.27 → 1.0.28

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.
@@ -14,6 +14,33 @@ async function safeJson(res) {
14
14
  return null;
15
15
  }
16
16
  }
17
+ // ─── Page-text capture helper ─────────────────────────────────────────────────
18
+ /**
19
+ * Extracts visible rendered text from the current page, deduplicated and capped
20
+ * at `maxChars` characters. Covers SPA content (course cards, mentor profiles,
21
+ * employee tables, etc.) that server-side crawlers cannot see.
22
+ *
23
+ * Priority: <main> → [role="main"] → <article> → document.body
24
+ * Safe to call in SSR/Node environments — returns '' when `document` is absent.
25
+ */
26
+ function capturePageText(maxChars = 8000) {
27
+ try {
28
+ if (typeof document === 'undefined')
29
+ return '';
30
+ const candidates = [
31
+ document.querySelector('main'),
32
+ document.querySelector('[role="main"]'),
33
+ document.querySelector('article'),
34
+ document.body,
35
+ ];
36
+ const el = candidates.find((c) => c && (c.innerText?.trim().length ?? 0) > 50) ?? document.body;
37
+ const raw = (el?.innerText ?? '').replace(/\s{3,}/g, '\n\n').trim();
38
+ return raw.length > maxChars ? raw.slice(0, maxChars) : raw;
39
+ }
40
+ catch {
41
+ return '';
42
+ }
43
+ }
17
44
  export class AiCommunicationService {
18
45
  constructor(apiEndpoint, apiKey, minRequestIntervalMs = 1500) {
19
46
  this.lastQuotaInfo = null;
@@ -123,11 +150,20 @@ export class AiCommunicationService {
123
150
  else if (this.apiKey) {
124
151
  headers['X-API-Key'] = this.apiKey;
125
152
  }
153
+ // Capture live rendered page text so the AI can answer from SPA content
154
+ // (mentor cards, course listings, employee tables, etc.) that server-side
155
+ // crawlers cannot see. We prefer targeted semantic regions for cleaner data.
156
+ const enrichedRequest = {
157
+ ...request,
158
+ pageText: request.pageText ?? capturePageText(8000),
159
+ pageUrl: request.pageUrl ?? (typeof window !== 'undefined' ? window.location.href : undefined),
160
+ pageTitle: request.pageTitle ?? (typeof window !== 'undefined' ? document.title : undefined),
161
+ };
126
162
  try {
127
163
  const response = await fetch(`${this.apiEndpoint}/api/aiorchestrator/query`, {
128
164
  method: 'POST',
129
165
  headers,
130
- body: JSON.stringify(request),
166
+ body: JSON.stringify(enrichedRequest),
131
167
  });
132
168
  if (!response.ok) {
133
169
  const errorData = await safeJson(response);
package/dist/models.d.ts CHANGED
@@ -159,12 +159,57 @@ export interface AiContextConfig {
159
159
  */
160
160
  minRequestIntervalMs?: number;
161
161
  };
162
+ /**
163
+ * Mobile responsiveness configuration.
164
+ * Controls how the widget behaves on mobile devices (< 768px).
165
+ */
166
+ mobileConfig?: {
167
+ /**
168
+ * Enable collapsible mobile view.
169
+ * On small screens, shows a small icon that expands when clicked.
170
+ * Default: true
171
+ */
172
+ enableCollapsible?: boolean;
173
+ /**
174
+ * Width breakpoint (in px) below which mobile view activates.
175
+ * Default: 768
176
+ */
177
+ breakpoint?: number;
178
+ /**
179
+ * Height of the collapsed preview badge (in px).
180
+ * Default: 60
181
+ */
182
+ collapsedHeight?: number;
183
+ /**
184
+ * Width of the collapsed preview badge (in px).
185
+ * Default: 60
186
+ */
187
+ collapsedWidth?: number;
188
+ /**
189
+ * Animation duration for expand/collapse (in ms).
190
+ * Default: 300
191
+ */
192
+ animationDuration?: number;
193
+ /**
194
+ * Show a pulsing indicator on the collapsed badge to attract attention.
195
+ * Default: true
196
+ */
197
+ showPulsingIndicator?: boolean;
198
+ };
162
199
  }
163
200
  export interface AiQueryRequest {
164
201
  userQuery: string;
165
202
  pageType: string;
166
203
  entityId?: string;
167
204
  contextData?: Record<string, any>;
205
+ pageUrl?: string;
206
+ pageTitle?: string;
207
+ /**
208
+ * Rendered page text captured from the user's browser (document.body.innerText).
209
+ * Provides live page content for SPAs where content is injected via API calls
210
+ * and is not available in the server-side crawl.
211
+ */
212
+ pageText?: string;
168
213
  [key: string]: any;
169
214
  }
170
215
  export interface AiQueryResponse {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@courseecho/ai-core-sdk",
3
- "version": "1.0.27",
3
+ "version": "1.0.28",
4
4
  "description": "Framework-agnostic core AI chat SDK. Shared logic for all framework wrappers.",
5
5
  "license": "MIT",
6
6
  "author": "CourseEcho",