From 951afc0c7f11a558912eb9b14b941fa77eb7a0be Mon Sep 17 00:00:00 2001 From: ninooooonin Date: Fri, 14 Aug 2026 20:34:02 +0800 Subject: [PATCH 1/3] Add AI agent callback tools for navigation and dashboard context retrieval --- .../Drawer/DrawerContent/NavCard.jsx | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/layout/Dashboard/Drawer/DrawerContent/NavCard.jsx b/src/layout/Dashboard/Drawer/DrawerContent/NavCard.jsx index 23b6cce..b2ec542 100644 --- a/src/layout/Dashboard/Drawer/DrawerContent/NavCard.jsx +++ b/src/layout/Dashboard/Drawer/DrawerContent/NavCard.jsx @@ -116,6 +116,26 @@ export default function NavCard() { // Engagement SDK Router if (window.engagement) { window.engagement.setRouter((newUrl) => navigate(newUrl)); + + // Callback tools the AI agent can invoke client-side. + // The handler receives the parsed tool args and its return value is sent + // back to the agent as the tool result. + window.engagement.registerCallbackTool('navigate_to_page', ({ page }) => { + const routes = ['home', 'projects', 'reports', 'teams']; + if (!routes.includes(page)) { + return { status: 'error', message: `Unknown page "${page}". Available pages: ${routes.join(', ')}` }; + } + navigate(`/${page}`); + return { status: 'ok', page }; + }); + + window.engagement.registerCallbackTool('get_dashboard_context', () => ({ + status: 'ok', + activeAPI, + localSDK, + user_id: userSlug, + path: window.location.pathname + })); } else { console.warn('window.engagement is not available for router and boot setup.'); } From c4f87558b13885268941e2d3692a6977a068222e Mon Sep 17 00:00:00 2001 From: ninooooonin Date: Fri, 14 Aug 2026 20:49:46 +0800 Subject: [PATCH 2/3] Refactor AI agent callback tools in NavCard component --- .../Drawer/DrawerContent/NavCard.jsx | 21 +++---------------- 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/src/layout/Dashboard/Drawer/DrawerContent/NavCard.jsx b/src/layout/Dashboard/Drawer/DrawerContent/NavCard.jsx index b2ec542..ba48b9f 100644 --- a/src/layout/Dashboard/Drawer/DrawerContent/NavCard.jsx +++ b/src/layout/Dashboard/Drawer/DrawerContent/NavCard.jsx @@ -117,25 +117,10 @@ export default function NavCard() { if (window.engagement) { window.engagement.setRouter((newUrl) => navigate(newUrl)); - // Callback tools the AI agent can invoke client-side. - // The handler receives the parsed tool args and its return value is sent - // back to the agent as the tool result. - window.engagement.registerCallbackTool('navigate_to_page', ({ page }) => { - const routes = ['home', 'projects', 'reports', 'teams']; - if (!routes.includes(page)) { - return { status: 'error', message: `Unknown page "${page}". Available pages: ${routes.join(', ')}` }; - } - navigate(`/${page}`); - return { status: 'ok', page }; + // Callback tool the AI agent can invoke client-side. + window.engagement.registerCallbackTool('test_callback_tool', (args) => { + console.log('registerCallbackTool', args); }); - - window.engagement.registerCallbackTool('get_dashboard_context', () => ({ - status: 'ok', - activeAPI, - localSDK, - user_id: userSlug, - path: window.location.pathname - })); } else { console.warn('window.engagement is not available for router and boot setup.'); } From 13dc45703be8c8c8ce57154d5a7355f60ef5bd2e Mon Sep 17 00:00:00 2001 From: ninooooonin Date: Tue, 3 Nov 2026 20:42:09 +0800 Subject: [PATCH 3/3] Add group management functionality to NavCard component --- .../Drawer/DrawerContent/NavCard.jsx | 44 ++++++++++++++++--- src/utils/localStorage.js | 36 +++++++++++++++ 2 files changed, 74 insertions(+), 6 deletions(-) diff --git a/src/layout/Dashboard/Drawer/DrawerContent/NavCard.jsx b/src/layout/Dashboard/Drawer/DrawerContent/NavCard.jsx index ba48b9f..4274fba 100644 --- a/src/layout/Dashboard/Drawer/DrawerContent/NavCard.jsx +++ b/src/layout/Dashboard/Drawer/DrawerContent/NavCard.jsx @@ -40,7 +40,15 @@ import { getLocalActiveAPI, setLocalActiveAPI, getLocalLaunchCode, - setLocalLaunchCode + setLocalLaunchCode, + getLocalGroupType, + setLocalGroupType, + getLocalGroupName, + setLocalGroupName, + getLocalGroupProperty, + setLocalGroupProperty, + getLocalGroupPropertyValue, + setLocalGroupPropertyValue } from 'utils/localStorage'; export default function NavCard() { @@ -53,12 +61,16 @@ export default function NavCard() { const [userSlug, setUserSlug] = useState(getLocalUserSlug()); const [localSDK, setLocalSDK] = useState(getLocalSDKKey()); const [launchCode, setLaunchCode] = useState(getLocalLaunchCode()); + const [groupType, setGroupType] = useState(getLocalGroupType()); + const [groupName, setGroupName] = useState(getLocalGroupName()); + const [groupProperty, setGroupProperty] = useState(getLocalGroupProperty()); + const [groupPropertyValue, setGroupPropertyValue] = useState(getLocalGroupPropertyValue()); useEffect(() => { // Set the current launch code in localStorage on page load/refresh setLocalLaunchCode(launchCode); - const analyticsHost = localSDK === 'staging' ? 'https://api.stag2.amplitude.com/2/httpapi' : undefined; + const analyticsHost = activeAPI === 'staging' ? 'https://api.stag2.amplitude.com/2/httpapi' : undefined; const decideHostMap = { local: 'http://localhost:10001', @@ -110,6 +122,14 @@ export default function NavCard() { amplitude.identify(identifyEvent); + // Put the user in a group, and set a property on the group (not the user) for group property targeting + if (groupType && groupName) { + amplitude.setGroup(groupType, groupName); + if (groupProperty) { + amplitude.groupIdentify(groupType, groupName, new amplitude.Identify().set(groupProperty, groupPropertyValue)); + } + } + console.log('Local SDK is integrated with Amplitude', activeAPIKey, decideHost); } @@ -138,7 +158,7 @@ export default function NavCard() { return () => { console.log('NavCard unmounted'); }; - }, [activeAPI, localKey, stagingKey, prodKey, userSlug, localSDK, launchCode, navigate]); + }, [activeAPI, localKey, stagingKey, prodKey, userSlug, localSDK, launchCode, groupType, groupName, groupProperty, groupPropertyValue, navigate]); const handleInputChange = (e) => { const { name, value } = e.target; @@ -149,7 +169,11 @@ export default function NavCard() { userSlug: setLocalUserSlug, activeAPI: setLocalActiveAPI, localSDK: setLocalSDKKey, - launchCode: setLocalLaunchCode + launchCode: setLocalLaunchCode, + groupType: setLocalGroupType, + groupName: setLocalGroupName, + groupProperty: setLocalGroupProperty, + groupPropertyValue: setLocalGroupPropertyValue }; setters[name](value); const stateSetters = { @@ -159,7 +183,11 @@ export default function NavCard() { userSlug: setUserSlug, activeAPI: setActiveAPI, localSDK: setLocalSDK, - launchCode: setLaunchCode + launchCode: setLaunchCode, + groupType: setGroupType, + groupName: setGroupName, + groupProperty: setGroupProperty, + groupPropertyValue: setGroupPropertyValue }; stateSetters[name](value); }; @@ -220,7 +248,11 @@ export default function NavCard() { { id: 'localKey', label: 'Local API Key', value: localKey }, { id: 'stagingKey', label: 'Staging API Key', value: stagingKey }, { id: 'prodKey', label: 'Production API Key', value: prodKey }, - { id: 'userSlug', label: 'User Slug', value: userSlug } + { id: 'userSlug', label: 'User Slug', value: userSlug }, + { id: 'groupType', label: 'Group Type', value: groupType }, + { id: 'groupName', label: 'Group Name', value: groupName }, + { id: 'groupProperty', label: 'Group Property', value: groupProperty }, + { id: 'groupPropertyValue', label: 'Group Property Value', value: groupPropertyValue } ].map(({ id, label, value }) => renderInputField(id, label, value))} Active API diff --git a/src/utils/localStorage.js b/src/utils/localStorage.js index 7cdcd57..79bb96e 100644 --- a/src/utils/localStorage.js +++ b/src/utils/localStorage.js @@ -11,6 +11,10 @@ const LOCALSTORAGE_USER_SLUG = 'test-base-user'; const END_USER_API = 'engagement.dev_base_app.end_user_api'; const LOCALSTORAGE_INTEGRATION = 'engagement.dev_base_app.integration'; const LOCALSTORAGE_EUS_LOCATION = 'amplitude.engagement.eus_location'; +const LOCALSTORAGE_GROUP_TYPE = 'engagement.dev_base_app.group_type'; +const LOCALSTORAGE_GROUP_NAME = 'engagement.dev_base_app.group_name'; +const LOCALSTORAGE_GROUP_PROPERTY = 'engagement.dev_base_app.group_property'; +const LOCALSTORAGE_GROUP_PROPERTY_VALUE = 'engagement.dev_base_app.group_property_value'; export const setLocalStorage = (key, value) => { if (window !== 'undefined') { @@ -128,3 +132,35 @@ export const setLocalLaunchCode = (value) => { setLocalStorage(LOCALSTORAGE_LAUNCH_CODE, launchCodeValue); } +// Group (setGroup / groupIdentify) +export const getLocalGroupType = () => { + return getLocalStorage(LOCALSTORAGE_GROUP_TYPE) || ''; +} + +export const setLocalGroupType = (value) => { + setLocalStorage(LOCALSTORAGE_GROUP_TYPE, value); +} + +export const getLocalGroupName = () => { + return getLocalStorage(LOCALSTORAGE_GROUP_NAME) || ''; +} + +export const setLocalGroupName = (value) => { + setLocalStorage(LOCALSTORAGE_GROUP_NAME, value); +} + +export const getLocalGroupProperty = () => { + return getLocalStorage(LOCALSTORAGE_GROUP_PROPERTY) || ''; +} + +export const setLocalGroupProperty = (value) => { + setLocalStorage(LOCALSTORAGE_GROUP_PROPERTY, value); +} + +export const getLocalGroupPropertyValue = () => { + return getLocalStorage(LOCALSTORAGE_GROUP_PROPERTY_VALUE) || ''; +} + +export const setLocalGroupPropertyValue = (value) => { + setLocalStorage(LOCALSTORAGE_GROUP_PROPERTY_VALUE, value); +}