@modelnex/sdk 0.5.27 → 0.5.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.
- package/dist/index.js +430 -134
- package/dist/index.mjs +430 -134
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1827,8 +1827,153 @@ async function captureScreenshot(selector) {
|
|
|
1827
1827
|
return canvas.toDataURL("image/png");
|
|
1828
1828
|
}
|
|
1829
1829
|
|
|
1830
|
+
// src/utils/experience-tool-bridge.ts
|
|
1831
|
+
var activeBridge = null;
|
|
1832
|
+
function registerExperienceToolBridge(bridge) {
|
|
1833
|
+
activeBridge = bridge;
|
|
1834
|
+
return () => {
|
|
1835
|
+
if (activeBridge === bridge) {
|
|
1836
|
+
activeBridge = null;
|
|
1837
|
+
}
|
|
1838
|
+
};
|
|
1839
|
+
}
|
|
1840
|
+
function getExperienceToolBridge() {
|
|
1841
|
+
return activeBridge;
|
|
1842
|
+
}
|
|
1843
|
+
|
|
1844
|
+
// src/utils/tourDiscovery.ts
|
|
1845
|
+
async function fetchTours(serverUrl, toursApiBase, websiteId, userType, userId, experienceType = "tour") {
|
|
1846
|
+
try {
|
|
1847
|
+
const params = new URLSearchParams({
|
|
1848
|
+
websiteId,
|
|
1849
|
+
userType
|
|
1850
|
+
});
|
|
1851
|
+
if (userId) params.set("userId", userId);
|
|
1852
|
+
if (experienceType !== "tour") params.set("type", experienceType);
|
|
1853
|
+
const res = await fetch(getTourApiUrl(serverUrl, toursApiBase, `/tours?${params.toString()}`));
|
|
1854
|
+
if (!res.ok) return [];
|
|
1855
|
+
const data = await res.json();
|
|
1856
|
+
return data.tours ?? [];
|
|
1857
|
+
} catch {
|
|
1858
|
+
return [];
|
|
1859
|
+
}
|
|
1860
|
+
}
|
|
1861
|
+
async function fetchTourById(serverUrl, toursApiBase, tourId, experienceType = "tour", websiteId) {
|
|
1862
|
+
try {
|
|
1863
|
+
const url = new URL(withWebsiteId(getTourApiUrl(serverUrl, toursApiBase, `/tours/${tourId}`), websiteId));
|
|
1864
|
+
if (experienceType !== "tour") {
|
|
1865
|
+
url.searchParams.set("type", experienceType);
|
|
1866
|
+
}
|
|
1867
|
+
const res = await fetch(url.toString());
|
|
1868
|
+
if (!res.ok) {
|
|
1869
|
+
return null;
|
|
1870
|
+
}
|
|
1871
|
+
const data = await res.json();
|
|
1872
|
+
return data.tour ?? null;
|
|
1873
|
+
} catch {
|
|
1874
|
+
return null;
|
|
1875
|
+
}
|
|
1876
|
+
}
|
|
1877
|
+
async function markTourComplete(serverUrl, toursApiBase, tourId, userId, experienceType = "tour", websiteId) {
|
|
1878
|
+
try {
|
|
1879
|
+
const url = new URL(withWebsiteId(getTourApiUrl(serverUrl, toursApiBase, `/tours/${tourId}/complete`), websiteId));
|
|
1880
|
+
if (experienceType !== "tour") {
|
|
1881
|
+
url.searchParams.set("type", experienceType);
|
|
1882
|
+
}
|
|
1883
|
+
await fetch(url.toString(), {
|
|
1884
|
+
method: "POST",
|
|
1885
|
+
headers: { "Content-Type": "application/json" },
|
|
1886
|
+
body: JSON.stringify({ userId })
|
|
1887
|
+
});
|
|
1888
|
+
} catch {
|
|
1889
|
+
}
|
|
1890
|
+
}
|
|
1891
|
+
async function markTourDismissed(serverUrl, toursApiBase, tourId, userId, experienceType = "tour", websiteId) {
|
|
1892
|
+
try {
|
|
1893
|
+
const url = new URL(withWebsiteId(getTourApiUrl(serverUrl, toursApiBase, `/tours/${tourId}/dismiss`), websiteId));
|
|
1894
|
+
if (experienceType !== "tour") {
|
|
1895
|
+
url.searchParams.set("type", experienceType);
|
|
1896
|
+
}
|
|
1897
|
+
await fetch(url.toString(), {
|
|
1898
|
+
method: "POST",
|
|
1899
|
+
headers: { "Content-Type": "application/json" },
|
|
1900
|
+
body: JSON.stringify({ userId })
|
|
1901
|
+
});
|
|
1902
|
+
} catch {
|
|
1903
|
+
}
|
|
1904
|
+
}
|
|
1905
|
+
async function recordTourEvent(serverUrl, toursApiBase, tourId, userId, eventType, websiteId) {
|
|
1906
|
+
try {
|
|
1907
|
+
const url = withWebsiteId(getTourApiUrl(serverUrl, toursApiBase, `/tours/${tourId}/events`), websiteId);
|
|
1908
|
+
await fetch(url, {
|
|
1909
|
+
method: "POST",
|
|
1910
|
+
headers: { "Content-Type": "application/json" },
|
|
1911
|
+
body: JSON.stringify({ userId, eventType })
|
|
1912
|
+
});
|
|
1913
|
+
} catch {
|
|
1914
|
+
}
|
|
1915
|
+
}
|
|
1916
|
+
function getToursBaseUrl(serverUrl, toursApiBase) {
|
|
1917
|
+
if (toursApiBase?.startsWith("/")) {
|
|
1918
|
+
return `${typeof window !== "undefined" ? window.location.origin : ""}${toursApiBase.replace(/\/$/, "")}`;
|
|
1919
|
+
}
|
|
1920
|
+
return serverUrl.replace(/\/$/, "");
|
|
1921
|
+
}
|
|
1922
|
+
function getTourApiUrl(serverUrl, toursApiBase, path) {
|
|
1923
|
+
const base = getToursBaseUrl(serverUrl, toursApiBase);
|
|
1924
|
+
return toursApiBase ? `${base}${path}` : `${base}/api${path}`;
|
|
1925
|
+
}
|
|
1926
|
+
function withWebsiteId(url, websiteId) {
|
|
1927
|
+
if (!websiteId) {
|
|
1928
|
+
return url;
|
|
1929
|
+
}
|
|
1930
|
+
const baseOrigin = typeof window !== "undefined" ? window.location.origin : "http://localhost";
|
|
1931
|
+
const resolved = new URL(url, baseOrigin);
|
|
1932
|
+
resolved.searchParams.set("websiteId", websiteId);
|
|
1933
|
+
return resolved.toString();
|
|
1934
|
+
}
|
|
1935
|
+
function normalizeTrigger(trigger) {
|
|
1936
|
+
if (trigger === "feature_launch" || trigger === "feature_unlocked" || trigger === "feature_unlock" || trigger === "new_feature") {
|
|
1937
|
+
return "feature_launch";
|
|
1938
|
+
}
|
|
1939
|
+
if (trigger === "return_visit") {
|
|
1940
|
+
return "return_visit";
|
|
1941
|
+
}
|
|
1942
|
+
return trigger ?? "first_visit";
|
|
1943
|
+
}
|
|
1944
|
+
function getStartPolicy(tour) {
|
|
1945
|
+
return tour.startPolicy ?? (normalizeTrigger(tour.trigger) === "manual" ? "immediate_start" : "prompt_only");
|
|
1946
|
+
}
|
|
1947
|
+
function getNotificationType(tour) {
|
|
1948
|
+
return tour.notificationType ?? "bubble_card";
|
|
1949
|
+
}
|
|
1950
|
+
function getUserProfileFeatures(userProfile) {
|
|
1951
|
+
const directFeatures = Array.isArray(userProfile.features) ? userProfile.features : [];
|
|
1952
|
+
const nestedFeatures = Array.isArray(userProfile.tourFacts?.features) ? userProfile.tourFacts.features : [];
|
|
1953
|
+
return [...new Set([...directFeatures, ...nestedFeatures].filter((value) => Boolean(value)))];
|
|
1954
|
+
}
|
|
1955
|
+
function isTourEligible(tour, userProfile) {
|
|
1956
|
+
switch (normalizeTrigger(tour.trigger)) {
|
|
1957
|
+
case "first_visit":
|
|
1958
|
+
return !!userProfile.isNewUser;
|
|
1959
|
+
case "return_visit":
|
|
1960
|
+
return userProfile.isNewUser === false;
|
|
1961
|
+
case "feature_launch": {
|
|
1962
|
+
const featureKey = tour.featureKey?.trim();
|
|
1963
|
+
if (!featureKey) return false;
|
|
1964
|
+
return getUserProfileFeatures(userProfile).includes(featureKey);
|
|
1965
|
+
}
|
|
1966
|
+
case "manual":
|
|
1967
|
+
return false;
|
|
1968
|
+
default:
|
|
1969
|
+
return false;
|
|
1970
|
+
}
|
|
1971
|
+
}
|
|
1972
|
+
|
|
1830
1973
|
// src/hooks/useBuiltinActions.ts
|
|
1831
1974
|
var resolutionCache = /* @__PURE__ */ new Map();
|
|
1975
|
+
var DEFAULT_WORKFLOW_SEARCH_LIMIT = 5;
|
|
1976
|
+
var WORKFLOW_TYPES = ["onboarding", "tour"];
|
|
1832
1977
|
function safeQueryAll2(selector) {
|
|
1833
1978
|
try {
|
|
1834
1979
|
return Array.from(document.querySelectorAll(selector)).filter(
|
|
@@ -2003,6 +2148,137 @@ function lastResortScan(fingerprint, options, elements) {
|
|
|
2003
2148
|
function cacheResolution(originalFp, selector, resolvedFp) {
|
|
2004
2149
|
resolutionCache.set(originalFp, { selector, resolvedFingerprint: resolvedFp });
|
|
2005
2150
|
}
|
|
2151
|
+
function normalizeWorkflowQuery(value) {
|
|
2152
|
+
return value.trim().toLowerCase();
|
|
2153
|
+
}
|
|
2154
|
+
function getWorkflowSearchText(tour) {
|
|
2155
|
+
const firstSteps = (tour.steps || []).slice(0, 6).flatMap((step) => [step.goal, step.narration, step.ask]).filter(Boolean).join(" ");
|
|
2156
|
+
return [
|
|
2157
|
+
tour.name,
|
|
2158
|
+
tour.type,
|
|
2159
|
+
tour.trigger,
|
|
2160
|
+
tour.startPolicy,
|
|
2161
|
+
tour.featureKey,
|
|
2162
|
+
tour.goal?.primaryAction,
|
|
2163
|
+
tour.goal?.successMetric,
|
|
2164
|
+
...tour.targetUserTypes,
|
|
2165
|
+
firstSteps
|
|
2166
|
+
].filter(Boolean).join(" ").toLowerCase();
|
|
2167
|
+
}
|
|
2168
|
+
function scoreWorkflowMatch(tour, query) {
|
|
2169
|
+
const normalizedQuery = normalizeWorkflowQuery(query);
|
|
2170
|
+
if (!normalizedQuery) return 1;
|
|
2171
|
+
const name = tour.name.toLowerCase();
|
|
2172
|
+
const featureKey = (tour.featureKey || "").toLowerCase();
|
|
2173
|
+
const haystack = getWorkflowSearchText(tour);
|
|
2174
|
+
if (name === normalizedQuery) return 140;
|
|
2175
|
+
if (featureKey && featureKey === normalizedQuery) return 125;
|
|
2176
|
+
if (name.includes(normalizedQuery)) return 115;
|
|
2177
|
+
if (featureKey && featureKey.includes(normalizedQuery)) return 100;
|
|
2178
|
+
if (haystack.includes(normalizedQuery)) return 85;
|
|
2179
|
+
const words = normalizedQuery.split(/\s+/).filter((word) => word.length > 1);
|
|
2180
|
+
if (words.length === 0) return 0;
|
|
2181
|
+
const matched = words.filter((word) => haystack.includes(word));
|
|
2182
|
+
if (matched.length === 0) return 0;
|
|
2183
|
+
const ratio = matched.length / words.length;
|
|
2184
|
+
return Math.round(ratio * 70);
|
|
2185
|
+
}
|
|
2186
|
+
function summarizeWorkflowStep(step, index) {
|
|
2187
|
+
const detail = step.goal || step.ask || step.narration || step.rawNarration || "No description";
|
|
2188
|
+
return `${index + 1}. [${step.type}] ${detail}`;
|
|
2189
|
+
}
|
|
2190
|
+
function formatWorkflowSummary(tour, options) {
|
|
2191
|
+
const stepLimit = options?.stepLimit ?? 4;
|
|
2192
|
+
const parts = [
|
|
2193
|
+
`**${tour.name}**`,
|
|
2194
|
+
`ID: ${tour.id}`,
|
|
2195
|
+
`Type: ${tour.type || "tour"}`,
|
|
2196
|
+
`Trigger: ${tour.trigger}`,
|
|
2197
|
+
`Start policy: ${tour.startPolicy || "prompt_only"}`,
|
|
2198
|
+
tour.featureKey ? `Feature key: ${tour.featureKey}` : null,
|
|
2199
|
+
tour.targetUserTypes?.length ? `Target users: ${tour.targetUserTypes.join(", ")}` : null,
|
|
2200
|
+
`Steps: ${tour.steps?.length ?? 0}`,
|
|
2201
|
+
tour.goal?.primaryAction ? `Primary action: ${tour.goal.primaryAction}` : null
|
|
2202
|
+
].filter(Boolean);
|
|
2203
|
+
if (options?.includeSteps) {
|
|
2204
|
+
const stepPreview = (tour.steps || []).slice(0, stepLimit).map((step, index) => summarizeWorkflowStep(step, index)).join("\n");
|
|
2205
|
+
if (stepPreview) {
|
|
2206
|
+
parts.push(`Steps preview:
|
|
2207
|
+
${stepPreview}`);
|
|
2208
|
+
}
|
|
2209
|
+
}
|
|
2210
|
+
return parts.join("\n");
|
|
2211
|
+
}
|
|
2212
|
+
function getRequestedWorkflowTypes(experienceType) {
|
|
2213
|
+
if (!experienceType || experienceType === "all") {
|
|
2214
|
+
return WORKFLOW_TYPES;
|
|
2215
|
+
}
|
|
2216
|
+
return [experienceType];
|
|
2217
|
+
}
|
|
2218
|
+
async function fetchAvailableWorkflows(getters, experienceType) {
|
|
2219
|
+
const serverUrl = getters.serverUrl();
|
|
2220
|
+
const websiteId = getters.websiteId();
|
|
2221
|
+
if (!serverUrl) {
|
|
2222
|
+
throw new Error("Server URL is not configured.");
|
|
2223
|
+
}
|
|
2224
|
+
if (!websiteId) {
|
|
2225
|
+
throw new Error("websiteId is required to search workflows.");
|
|
2226
|
+
}
|
|
2227
|
+
const userProfile = getters.userProfile();
|
|
2228
|
+
const userType = userProfile?.type || "";
|
|
2229
|
+
const userId = userProfile?.userId;
|
|
2230
|
+
const toursApiBase = getters.toursApiBase();
|
|
2231
|
+
const requestedTypes = getRequestedWorkflowTypes(experienceType);
|
|
2232
|
+
const lists = await Promise.all(
|
|
2233
|
+
requestedTypes.map(
|
|
2234
|
+
(type) => fetchTours(serverUrl, toursApiBase, websiteId, userType, userId, type)
|
|
2235
|
+
)
|
|
2236
|
+
);
|
|
2237
|
+
return lists.flatMap(
|
|
2238
|
+
(list, index) => list.map((tour) => ({
|
|
2239
|
+
...tour,
|
|
2240
|
+
type: tour.type || requestedTypes[index]
|
|
2241
|
+
}))
|
|
2242
|
+
);
|
|
2243
|
+
}
|
|
2244
|
+
async function resolveWorkflowFromInput(getters, params) {
|
|
2245
|
+
const serverUrl = getters.serverUrl();
|
|
2246
|
+
const websiteId = getters.websiteId();
|
|
2247
|
+
const toursApiBase = getters.toursApiBase();
|
|
2248
|
+
if (!serverUrl) {
|
|
2249
|
+
throw new Error("Server URL is not configured.");
|
|
2250
|
+
}
|
|
2251
|
+
if (params.workflowId) {
|
|
2252
|
+
const requestedTypes = getRequestedWorkflowTypes(params.experienceType);
|
|
2253
|
+
for (const type of requestedTypes) {
|
|
2254
|
+
const workflow = await fetchTourById(serverUrl, toursApiBase, params.workflowId, type, websiteId);
|
|
2255
|
+
if (workflow) {
|
|
2256
|
+
return { workflow: { ...workflow, type: workflow.type || type } };
|
|
2257
|
+
}
|
|
2258
|
+
}
|
|
2259
|
+
}
|
|
2260
|
+
const query = params.name?.trim();
|
|
2261
|
+
if (!query) {
|
|
2262
|
+
return { workflow: null, reason: "Provide either workflowId or name." };
|
|
2263
|
+
}
|
|
2264
|
+
const workflows = await fetchAvailableWorkflows(getters, params.experienceType);
|
|
2265
|
+
const ranked = workflows.map((workflow) => ({ workflow, score: scoreWorkflowMatch(workflow, query) })).filter(({ score }) => score > 0).sort((a, b) => b.score - a.score);
|
|
2266
|
+
if (ranked.length === 0) {
|
|
2267
|
+
return {
|
|
2268
|
+
workflow: null,
|
|
2269
|
+
reason: `No workflow matched "${query}". Try search_workflows first for available options.`
|
|
2270
|
+
};
|
|
2271
|
+
}
|
|
2272
|
+
if (ranked.length > 1 && ranked[0].score === ranked[1].score) {
|
|
2273
|
+
return {
|
|
2274
|
+
workflow: null,
|
|
2275
|
+
reason: `Multiple workflows matched "${query}". Try view_workflow with an exact workflowId.
|
|
2276
|
+
|
|
2277
|
+
` + ranked.slice(0, 3).map(({ workflow }) => formatWorkflowSummary(workflow)).join("\n\n---\n\n")
|
|
2278
|
+
};
|
|
2279
|
+
}
|
|
2280
|
+
return { workflow: ranked[0].workflow };
|
|
2281
|
+
}
|
|
2006
2282
|
var screenshotSchema = import_zod2.z.object({
|
|
2007
2283
|
selector: import_zod2.z.string().optional().describe("Optional CSS selector to capture a specific element. Omit to capture the full viewport.")
|
|
2008
2284
|
});
|
|
@@ -2283,15 +2559,91 @@ function createSearchTaggedElementsAction(getTagStore) {
|
|
|
2283
2559
|
}
|
|
2284
2560
|
};
|
|
2285
2561
|
}
|
|
2562
|
+
var workflowExperienceTypeSchema = import_zod2.z.enum(["onboarding", "tour", "all"]);
|
|
2563
|
+
var searchWorkflowsSchema = import_zod2.z.object({
|
|
2564
|
+
query: import_zod2.z.string().optional().describe("Optional workflow name, feature, or task phrase to search for. Omit to list available workflows."),
|
|
2565
|
+
experienceType: workflowExperienceTypeSchema.optional().describe("Which workflow type to search: onboarding, tour, or all. Default: onboarding."),
|
|
2566
|
+
limit: import_zod2.z.number().optional().describe(`Maximum number of workflows to return (default: ${DEFAULT_WORKFLOW_SEARCH_LIMIT}).`)
|
|
2567
|
+
});
|
|
2568
|
+
function createSearchWorkflowsAction(getters) {
|
|
2569
|
+
return {
|
|
2570
|
+
id: "search_workflows",
|
|
2571
|
+
description: "Search available workflows and tours that can be launched for the current website/user. Use this when the user asks for onboarding, a walkthrough, a tutorial, a guided setup, or a named workflow/tour.",
|
|
2572
|
+
schema: searchWorkflowsSchema,
|
|
2573
|
+
execute: async (params) => {
|
|
2574
|
+
const workflows = await fetchAvailableWorkflows(getters, params.experienceType ?? "onboarding");
|
|
2575
|
+
if (workflows.length === 0) {
|
|
2576
|
+
return "No workflows are currently available for this website/user.";
|
|
2577
|
+
}
|
|
2578
|
+
const query = params.query?.trim();
|
|
2579
|
+
const limit = params.limit ?? DEFAULT_WORKFLOW_SEARCH_LIMIT;
|
|
2580
|
+
const ranked = workflows.map((workflow) => ({
|
|
2581
|
+
workflow,
|
|
2582
|
+
score: query ? scoreWorkflowMatch(workflow, query) : 1
|
|
2583
|
+
})).filter(({ score }) => score > 0).sort((a, b) => b.score - a.score).slice(0, limit);
|
|
2584
|
+
if (ranked.length === 0) {
|
|
2585
|
+
return `No workflows matched "${query}".`;
|
|
2586
|
+
}
|
|
2587
|
+
return ranked.map(({ workflow }) => formatWorkflowSummary(workflow)).join("\n\n---\n\n");
|
|
2588
|
+
}
|
|
2589
|
+
};
|
|
2590
|
+
}
|
|
2591
|
+
var resolveWorkflowSchema = import_zod2.z.object({
|
|
2592
|
+
workflowId: import_zod2.z.string().optional().describe("Exact workflow id when known."),
|
|
2593
|
+
name: import_zod2.z.string().optional().describe("Workflow name or a close name match when the id is unknown."),
|
|
2594
|
+
experienceType: workflowExperienceTypeSchema.optional().describe("Which workflow type to search: onboarding, tour, or all. Default: onboarding.")
|
|
2595
|
+
});
|
|
2596
|
+
function createViewWorkflowAction(getters) {
|
|
2597
|
+
return {
|
|
2598
|
+
id: "view_workflow",
|
|
2599
|
+
description: "View a specific workflow or tour in more detail, including its id, trigger, start policy, and the first few steps. Use after search_workflows when you need to inspect a candidate before starting it.",
|
|
2600
|
+
schema: resolveWorkflowSchema,
|
|
2601
|
+
execute: async (params) => {
|
|
2602
|
+
const { workflow, reason } = await resolveWorkflowFromInput(getters, params);
|
|
2603
|
+
if (!workflow) {
|
|
2604
|
+
return reason || "Workflow not found.";
|
|
2605
|
+
}
|
|
2606
|
+
return formatWorkflowSummary(workflow, { includeSteps: true, stepLimit: 5 });
|
|
2607
|
+
}
|
|
2608
|
+
};
|
|
2609
|
+
}
|
|
2610
|
+
var startWorkflowSchema = resolveWorkflowSchema.extend({
|
|
2611
|
+
reviewMode: import_zod2.z.boolean().optional().describe("Optional. Start in review mode instead of normal playback. Default: false.")
|
|
2612
|
+
});
|
|
2613
|
+
function createStartWorkflowAction(getters) {
|
|
2614
|
+
return {
|
|
2615
|
+
id: "start_workflow",
|
|
2616
|
+
description: "Start a specific workflow or tour in the chat experience. Use this after search_workflows or view_workflow when the user wants to begin a named guided workflow.",
|
|
2617
|
+
schema: startWorkflowSchema,
|
|
2618
|
+
execute: async (params) => {
|
|
2619
|
+
const { workflow, reason } = await resolveWorkflowFromInput(getters, params);
|
|
2620
|
+
if (!workflow) {
|
|
2621
|
+
return reason || "Workflow not found.";
|
|
2622
|
+
}
|
|
2623
|
+
const bridge = getExperienceToolBridge();
|
|
2624
|
+
if (!bridge) {
|
|
2625
|
+
return "Workflow launch is unavailable because no chat playback controller is mounted.";
|
|
2626
|
+
}
|
|
2627
|
+
bridge.startExperience(workflow, workflow.type, params.reviewMode ? {
|
|
2628
|
+
reviewMode: true,
|
|
2629
|
+
reviewMetadata: { trigger: "agent_tool" }
|
|
2630
|
+
} : void 0);
|
|
2631
|
+
return `Started workflow "${workflow.name}" (${workflow.id}).`;
|
|
2632
|
+
}
|
|
2633
|
+
};
|
|
2634
|
+
}
|
|
2286
2635
|
var BUILTIN_ACTION_IDS = {
|
|
2287
2636
|
screenshot: "take_screenshot",
|
|
2288
2637
|
click: "click_element",
|
|
2289
2638
|
fill: "fill_input",
|
|
2290
2639
|
wait: "request_user_action",
|
|
2291
2640
|
searchDocs: "search_docs",
|
|
2292
|
-
searchTaggedElements: "search_tagged_elements"
|
|
2641
|
+
searchTaggedElements: "search_tagged_elements",
|
|
2642
|
+
searchWorkflows: "search_workflows",
|
|
2643
|
+
viewWorkflow: "view_workflow",
|
|
2644
|
+
startWorkflow: "start_workflow"
|
|
2293
2645
|
};
|
|
2294
|
-
function useBuiltinActions(registerAction, unregisterAction, tagStore, serverUrl, websiteId) {
|
|
2646
|
+
function useBuiltinActions(registerAction, unregisterAction, tagStore, serverUrl, websiteId, toursApiBase, userProfile) {
|
|
2295
2647
|
const registeredRef = (0, import_react8.useRef)(false);
|
|
2296
2648
|
const tagStoreRef = (0, import_react8.useRef)(tagStore);
|
|
2297
2649
|
tagStoreRef.current = tagStore;
|
|
@@ -2299,18 +2651,33 @@ function useBuiltinActions(registerAction, unregisterAction, tagStore, serverUrl
|
|
|
2299
2651
|
serverUrlRef.current = serverUrl;
|
|
2300
2652
|
const websiteIdRef = (0, import_react8.useRef)(websiteId);
|
|
2301
2653
|
websiteIdRef.current = websiteId;
|
|
2654
|
+
const toursApiBaseRef = (0, import_react8.useRef)(toursApiBase);
|
|
2655
|
+
toursApiBaseRef.current = toursApiBase;
|
|
2656
|
+
const userProfileRef = (0, import_react8.useRef)(userProfile);
|
|
2657
|
+
userProfileRef.current = userProfile;
|
|
2302
2658
|
(0, import_react8.useEffect)(() => {
|
|
2303
2659
|
if (registeredRef.current) return;
|
|
2304
2660
|
registeredRef.current = true;
|
|
2305
2661
|
const getTagStore = () => tagStoreRef.current;
|
|
2306
2662
|
const getServerUrl = () => serverUrlRef.current;
|
|
2307
2663
|
const getWebsiteId = () => websiteIdRef.current;
|
|
2664
|
+
const getToursApiBase = () => toursApiBaseRef.current;
|
|
2665
|
+
const getUserProfile = () => userProfileRef.current;
|
|
2666
|
+
const workflowToolGetters = {
|
|
2667
|
+
serverUrl: getServerUrl,
|
|
2668
|
+
websiteId: getWebsiteId,
|
|
2669
|
+
toursApiBase: getToursApiBase,
|
|
2670
|
+
userProfile: getUserProfile
|
|
2671
|
+
};
|
|
2308
2672
|
registerAction(BUILTIN_SCREENSHOT_ACTION);
|
|
2309
2673
|
registerAction(createClickAction(getTagStore));
|
|
2310
2674
|
registerAction(createFillAction(getTagStore));
|
|
2311
2675
|
registerAction(createWaitAction(getTagStore));
|
|
2312
2676
|
registerAction(createSearchDocsAction(getServerUrl, getWebsiteId));
|
|
2313
2677
|
registerAction(createSearchTaggedElementsAction(getTagStore));
|
|
2678
|
+
registerAction(createSearchWorkflowsAction(workflowToolGetters));
|
|
2679
|
+
registerAction(createViewWorkflowAction(workflowToolGetters));
|
|
2680
|
+
registerAction(createStartWorkflowAction(workflowToolGetters));
|
|
2314
2681
|
return () => {
|
|
2315
2682
|
unregisterAction(BUILTIN_SCREENSHOT_ACTION.id);
|
|
2316
2683
|
unregisterAction(BUILTIN_ACTION_IDS.click);
|
|
@@ -2318,6 +2685,9 @@ function useBuiltinActions(registerAction, unregisterAction, tagStore, serverUrl
|
|
|
2318
2685
|
unregisterAction(BUILTIN_ACTION_IDS.wait);
|
|
2319
2686
|
unregisterAction(BUILTIN_ACTION_IDS.searchDocs);
|
|
2320
2687
|
unregisterAction(BUILTIN_ACTION_IDS.searchTaggedElements);
|
|
2688
|
+
unregisterAction(BUILTIN_ACTION_IDS.searchWorkflows);
|
|
2689
|
+
unregisterAction(BUILTIN_ACTION_IDS.viewWorkflow);
|
|
2690
|
+
unregisterAction(BUILTIN_ACTION_IDS.startWorkflow);
|
|
2321
2691
|
registeredRef.current = false;
|
|
2322
2692
|
};
|
|
2323
2693
|
}, [registerAction, unregisterAction]);
|
|
@@ -2572,135 +2942,6 @@ function readPreviewSessionSuppression() {
|
|
|
2572
2942
|
}
|
|
2573
2943
|
}
|
|
2574
2944
|
|
|
2575
|
-
// src/utils/tourDiscovery.ts
|
|
2576
|
-
async function fetchTours(serverUrl, toursApiBase, websiteId, userType, userId, experienceType = "tour") {
|
|
2577
|
-
try {
|
|
2578
|
-
const params = new URLSearchParams({
|
|
2579
|
-
websiteId,
|
|
2580
|
-
userType
|
|
2581
|
-
});
|
|
2582
|
-
if (userId) params.set("userId", userId);
|
|
2583
|
-
if (experienceType !== "tour") params.set("type", experienceType);
|
|
2584
|
-
const res = await fetch(getTourApiUrl(serverUrl, toursApiBase, `/tours?${params.toString()}`));
|
|
2585
|
-
if (!res.ok) return [];
|
|
2586
|
-
const data = await res.json();
|
|
2587
|
-
return data.tours ?? [];
|
|
2588
|
-
} catch {
|
|
2589
|
-
return [];
|
|
2590
|
-
}
|
|
2591
|
-
}
|
|
2592
|
-
async function fetchTourById(serverUrl, toursApiBase, tourId, experienceType = "tour", websiteId) {
|
|
2593
|
-
try {
|
|
2594
|
-
const url = new URL(withWebsiteId(getTourApiUrl(serverUrl, toursApiBase, `/tours/${tourId}`), websiteId));
|
|
2595
|
-
if (experienceType !== "tour") {
|
|
2596
|
-
url.searchParams.set("type", experienceType);
|
|
2597
|
-
}
|
|
2598
|
-
const res = await fetch(url.toString());
|
|
2599
|
-
if (!res.ok) {
|
|
2600
|
-
return null;
|
|
2601
|
-
}
|
|
2602
|
-
const data = await res.json();
|
|
2603
|
-
return data.tour ?? null;
|
|
2604
|
-
} catch {
|
|
2605
|
-
return null;
|
|
2606
|
-
}
|
|
2607
|
-
}
|
|
2608
|
-
async function markTourComplete(serverUrl, toursApiBase, tourId, userId, experienceType = "tour", websiteId) {
|
|
2609
|
-
try {
|
|
2610
|
-
const url = new URL(withWebsiteId(getTourApiUrl(serverUrl, toursApiBase, `/tours/${tourId}/complete`), websiteId));
|
|
2611
|
-
if (experienceType !== "tour") {
|
|
2612
|
-
url.searchParams.set("type", experienceType);
|
|
2613
|
-
}
|
|
2614
|
-
await fetch(url.toString(), {
|
|
2615
|
-
method: "POST",
|
|
2616
|
-
headers: { "Content-Type": "application/json" },
|
|
2617
|
-
body: JSON.stringify({ userId })
|
|
2618
|
-
});
|
|
2619
|
-
} catch {
|
|
2620
|
-
}
|
|
2621
|
-
}
|
|
2622
|
-
async function markTourDismissed(serverUrl, toursApiBase, tourId, userId, experienceType = "tour", websiteId) {
|
|
2623
|
-
try {
|
|
2624
|
-
const url = new URL(withWebsiteId(getTourApiUrl(serverUrl, toursApiBase, `/tours/${tourId}/dismiss`), websiteId));
|
|
2625
|
-
if (experienceType !== "tour") {
|
|
2626
|
-
url.searchParams.set("type", experienceType);
|
|
2627
|
-
}
|
|
2628
|
-
await fetch(url.toString(), {
|
|
2629
|
-
method: "POST",
|
|
2630
|
-
headers: { "Content-Type": "application/json" },
|
|
2631
|
-
body: JSON.stringify({ userId })
|
|
2632
|
-
});
|
|
2633
|
-
} catch {
|
|
2634
|
-
}
|
|
2635
|
-
}
|
|
2636
|
-
async function recordTourEvent(serverUrl, toursApiBase, tourId, userId, eventType, websiteId) {
|
|
2637
|
-
try {
|
|
2638
|
-
const url = withWebsiteId(getTourApiUrl(serverUrl, toursApiBase, `/tours/${tourId}/events`), websiteId);
|
|
2639
|
-
await fetch(url, {
|
|
2640
|
-
method: "POST",
|
|
2641
|
-
headers: { "Content-Type": "application/json" },
|
|
2642
|
-
body: JSON.stringify({ userId, eventType })
|
|
2643
|
-
});
|
|
2644
|
-
} catch {
|
|
2645
|
-
}
|
|
2646
|
-
}
|
|
2647
|
-
function getToursBaseUrl(serverUrl, toursApiBase) {
|
|
2648
|
-
if (toursApiBase?.startsWith("/")) {
|
|
2649
|
-
return `${typeof window !== "undefined" ? window.location.origin : ""}${toursApiBase.replace(/\/$/, "")}`;
|
|
2650
|
-
}
|
|
2651
|
-
return serverUrl.replace(/\/$/, "");
|
|
2652
|
-
}
|
|
2653
|
-
function getTourApiUrl(serverUrl, toursApiBase, path) {
|
|
2654
|
-
const base = getToursBaseUrl(serverUrl, toursApiBase);
|
|
2655
|
-
return toursApiBase ? `${base}${path}` : `${base}/api${path}`;
|
|
2656
|
-
}
|
|
2657
|
-
function withWebsiteId(url, websiteId) {
|
|
2658
|
-
if (!websiteId) {
|
|
2659
|
-
return url;
|
|
2660
|
-
}
|
|
2661
|
-
const baseOrigin = typeof window !== "undefined" ? window.location.origin : "http://localhost";
|
|
2662
|
-
const resolved = new URL(url, baseOrigin);
|
|
2663
|
-
resolved.searchParams.set("websiteId", websiteId);
|
|
2664
|
-
return resolved.toString();
|
|
2665
|
-
}
|
|
2666
|
-
function normalizeTrigger(trigger) {
|
|
2667
|
-
if (trigger === "feature_launch" || trigger === "feature_unlocked" || trigger === "feature_unlock" || trigger === "new_feature") {
|
|
2668
|
-
return "feature_launch";
|
|
2669
|
-
}
|
|
2670
|
-
if (trigger === "return_visit") {
|
|
2671
|
-
return "return_visit";
|
|
2672
|
-
}
|
|
2673
|
-
return trigger ?? "first_visit";
|
|
2674
|
-
}
|
|
2675
|
-
function getStartPolicy(tour) {
|
|
2676
|
-
return tour.startPolicy ?? (normalizeTrigger(tour.trigger) === "manual" ? "immediate_start" : "prompt_only");
|
|
2677
|
-
}
|
|
2678
|
-
function getNotificationType(tour) {
|
|
2679
|
-
return tour.notificationType ?? "bubble_card";
|
|
2680
|
-
}
|
|
2681
|
-
function getUserProfileFeatures(userProfile) {
|
|
2682
|
-
const directFeatures = Array.isArray(userProfile.features) ? userProfile.features : [];
|
|
2683
|
-
const nestedFeatures = Array.isArray(userProfile.tourFacts?.features) ? userProfile.tourFacts.features : [];
|
|
2684
|
-
return [...new Set([...directFeatures, ...nestedFeatures].filter((value) => Boolean(value)))];
|
|
2685
|
-
}
|
|
2686
|
-
function isTourEligible(tour, userProfile) {
|
|
2687
|
-
switch (normalizeTrigger(tour.trigger)) {
|
|
2688
|
-
case "first_visit":
|
|
2689
|
-
return !!userProfile.isNewUser;
|
|
2690
|
-
case "return_visit":
|
|
2691
|
-
return userProfile.isNewUser === false;
|
|
2692
|
-
case "feature_launch": {
|
|
2693
|
-
const featureKey = tour.featureKey?.trim();
|
|
2694
|
-
if (!featureKey) return false;
|
|
2695
|
-
return getUserProfileFeatures(userProfile).includes(featureKey);
|
|
2696
|
-
}
|
|
2697
|
-
case "manual":
|
|
2698
|
-
return false;
|
|
2699
|
-
default:
|
|
2700
|
-
return false;
|
|
2701
|
-
}
|
|
2702
|
-
}
|
|
2703
|
-
|
|
2704
2945
|
// src/hooks/useTourPlayback.ts
|
|
2705
2946
|
var import_react12 = require("react");
|
|
2706
2947
|
|
|
@@ -8616,6 +8857,7 @@ function Tooltip({ children, title }) {
|
|
|
8616
8857
|
);
|
|
8617
8858
|
}
|
|
8618
8859
|
var BUBBLE_EXPANDED_STORAGE_KEY = "modelnex-chat-bubble-expanded";
|
|
8860
|
+
var BUBBLE_DOCKED_STORAGE_KEY = "modelnex-chat-bubble-docked";
|
|
8619
8861
|
var TOUR_MINIMIZED_STORAGE_KEY = "modelnex-tour-bubble-minimized";
|
|
8620
8862
|
var BotIcon = () => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "var(--modelnex-bubble-icon-size, 20px)", height: "var(--modelnex-bubble-icon-size, 20px)", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
8621
8863
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "m12 3-1.912 5.813a2 2 0 0 1-1.275 1.275L3 12l5.813 1.912a2 2 0 0 1 1.275 1.275L12 21l1.912-5.813a2 2 0 0 1 1.275-1.275L21 12l-5.813-1.912a2 2 0 0 1-1.275-1.275L12 3Z" }),
|
|
@@ -8629,6 +8871,18 @@ var CloseIcon = () => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { wid
|
|
|
8629
8871
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
|
|
8630
8872
|
] });
|
|
8631
8873
|
var MinimizeIcon = () => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M8 18h8" }) });
|
|
8874
|
+
var DockIcon = () => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
8875
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M12 3v10" }),
|
|
8876
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "m8 9 4 4 4-4" }),
|
|
8877
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M4 17h16" }),
|
|
8878
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M6 21h12" })
|
|
8879
|
+
] });
|
|
8880
|
+
var UndockIcon = () => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
8881
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M12 21V11" }),
|
|
8882
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "m8 15 4-4 4 4" }),
|
|
8883
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M4 7h16" }),
|
|
8884
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M6 3h12" })
|
|
8885
|
+
] });
|
|
8632
8886
|
var TrashIcon = () => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
8633
8887
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M3 6h18" }),
|
|
8634
8888
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" }),
|
|
@@ -8849,6 +9103,7 @@ function ModelNexChatBubble({
|
|
|
8849
9103
|
const ctx = (0, import_react18.useContext)(ModelNexContext);
|
|
8850
9104
|
const [hydrated, setHydrated] = (0, import_react18.useState)(false);
|
|
8851
9105
|
const [expanded, setExpanded] = (0, import_react18.useState)(false);
|
|
9106
|
+
const [docked, setDocked] = (0, import_react18.useState)(false);
|
|
8852
9107
|
const [input, setInput] = (0, import_react18.useState)("");
|
|
8853
9108
|
const messages = ctx?.chatMessages ?? [];
|
|
8854
9109
|
const setMessages = ctx?.setChatMessages ?? (() => {
|
|
@@ -8903,6 +9158,11 @@ function ModelNexChatBubble({
|
|
|
8903
9158
|
const activePlayback = playbackController.playback;
|
|
8904
9159
|
const activeExperienceType = playbackController.activeExperienceType;
|
|
8905
9160
|
const startingExperienceType = playbackController.startingExperienceType;
|
|
9161
|
+
(0, import_react18.useEffect)(() => {
|
|
9162
|
+
return registerExperienceToolBridge({
|
|
9163
|
+
startExperience: playbackController.startExperience
|
|
9164
|
+
});
|
|
9165
|
+
}, [playbackController.startExperience]);
|
|
8906
9166
|
const createPlaybackView = (0, import_react18.useCallback)((experienceType) => {
|
|
8907
9167
|
const isActiveExperience = activePlayback.isActive && activeExperienceType === experienceType;
|
|
8908
9168
|
const pendingTour = playbackController.pendingPrompt?.experienceType === experienceType ? playbackController.pendingPrompt.tour : null;
|
|
@@ -9000,8 +9260,10 @@ function ModelNexChatBubble({
|
|
|
9000
9260
|
setHydrated(true);
|
|
9001
9261
|
try {
|
|
9002
9262
|
setExpanded(sessionStorage.getItem(BUBBLE_EXPANDED_STORAGE_KEY) === "true");
|
|
9263
|
+
setDocked(sessionStorage.getItem(BUBBLE_DOCKED_STORAGE_KEY) === "true");
|
|
9003
9264
|
} catch {
|
|
9004
9265
|
setExpanded(false);
|
|
9266
|
+
setDocked(false);
|
|
9005
9267
|
}
|
|
9006
9268
|
}, []);
|
|
9007
9269
|
const sttActiveRef = (0, import_react18.useRef)(false);
|
|
@@ -9061,6 +9323,13 @@ function ModelNexChatBubble({
|
|
|
9061
9323
|
} catch {
|
|
9062
9324
|
}
|
|
9063
9325
|
}, [tourPlayback.isActive, onboardingPlayback.isActive]);
|
|
9326
|
+
const setDockedState = (0, import_react18.useCallback)((next) => {
|
|
9327
|
+
setDocked(next);
|
|
9328
|
+
try {
|
|
9329
|
+
sessionStorage.setItem(BUBBLE_DOCKED_STORAGE_KEY, String(next));
|
|
9330
|
+
} catch {
|
|
9331
|
+
}
|
|
9332
|
+
}, []);
|
|
9064
9333
|
(0, import_react18.useEffect)(() => {
|
|
9065
9334
|
if (shouldAutoExpandForPendingPrompt({
|
|
9066
9335
|
pendingPrompt,
|
|
@@ -9422,11 +9691,13 @@ function ModelNexChatBubble({
|
|
|
9422
9691
|
fontFamily: "var(--modelnex-font)",
|
|
9423
9692
|
...themeStyles
|
|
9424
9693
|
};
|
|
9694
|
+
const desktopPanelHeight = docked ? "min(calc(100vh - 48px), calc(var(--modelnex-panel-max-height, 600px) + 180px))" : "var(--modelnex-panel-max-height, 600px)";
|
|
9695
|
+
const desktopPanelMaxHeight = docked ? "calc(100vh - 48px)" : "calc(100vh - 120px)";
|
|
9425
9696
|
const panelStyle = {
|
|
9426
9697
|
width: isMobile ? "100%" : "var(--modelnex-panel-width, 380px)",
|
|
9427
9698
|
maxWidth: "calc(100vw - 32px)",
|
|
9428
|
-
height: isMobile ? "100%" :
|
|
9429
|
-
maxHeight: "
|
|
9699
|
+
height: isMobile ? "100%" : desktopPanelHeight,
|
|
9700
|
+
maxHeight: isMobile ? "100%" : desktopPanelMaxHeight,
|
|
9430
9701
|
borderRadius: isMobile ? "0" : "var(--modelnex-radius-panel, 20px)",
|
|
9431
9702
|
border: isMobile ? "none" : "1px solid var(--modelnex-border, #e4e4e7)",
|
|
9432
9703
|
background: "var(--modelnex-bg, #ffffff)",
|
|
@@ -9578,6 +9849,31 @@ function ModelNexChatBubble({
|
|
|
9578
9849
|
] })
|
|
9579
9850
|
] }) }),
|
|
9580
9851
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "4px" }, children: [
|
|
9852
|
+
!isMobile && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Tooltip, { title: docked ? "Undock" : "Dock", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
9853
|
+
"button",
|
|
9854
|
+
{
|
|
9855
|
+
onClick: () => setDockedState(!docked),
|
|
9856
|
+
style: {
|
|
9857
|
+
padding: "8px 10px",
|
|
9858
|
+
borderRadius: "10px",
|
|
9859
|
+
border: "none",
|
|
9860
|
+
background: docked ? "rgba(79,70,229,0.08)" : "transparent",
|
|
9861
|
+
cursor: "pointer",
|
|
9862
|
+
color: docked ? "var(--modelnex-accent, #4f46e5)" : "#71717a",
|
|
9863
|
+
transition: "all 0.2s",
|
|
9864
|
+
display: "flex",
|
|
9865
|
+
alignItems: "center",
|
|
9866
|
+
gap: "6px",
|
|
9867
|
+
fontSize: "12px",
|
|
9868
|
+
fontWeight: 700
|
|
9869
|
+
},
|
|
9870
|
+
"aria-label": docked ? "Undock chat bubble" : "Dock chat bubble",
|
|
9871
|
+
children: [
|
|
9872
|
+
docked ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(UndockIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(DockIcon, {}),
|
|
9873
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: docked ? "Undock" : "Dock" })
|
|
9874
|
+
]
|
|
9875
|
+
}
|
|
9876
|
+
) }),
|
|
9581
9877
|
(tourPlayback.isActive || onboardingPlayback.isActive || voice.isSpeaking) && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Tooltip, { title: voice.isMuted ? "Unmute" : "Mute", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
9582
9878
|
"button",
|
|
9583
9879
|
{
|
|
@@ -11368,7 +11664,7 @@ var ModelNexProvider = ({
|
|
|
11368
11664
|
}, []);
|
|
11369
11665
|
const extractedElements = useAutoExtract();
|
|
11370
11666
|
const tagStore = useTagStore({ serverUrl, websiteId });
|
|
11371
|
-
useBuiltinActions(registerAction, unregisterAction, tagStore, serverUrl, websiteId);
|
|
11667
|
+
useBuiltinActions(registerAction, unregisterAction, tagStore, serverUrl, websiteId, toursApiBase, userProfile);
|
|
11372
11668
|
const CHAT_STORAGE_KEY = "modelnex-chat-messages";
|
|
11373
11669
|
const [chatMessages, setChatMessagesRaw] = (0, import_react21.useState)([]);
|
|
11374
11670
|
(0, import_react21.useEffect)(() => {
|