Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion apps/help-center/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ window.configData = {
env_id: isProxied ? 'staging' : 'production',
features: {
'help/gpt-response': true,
'unified-agent': false, // Enable to use unified AI agent instead of HelpCenterGPT
},
wapuu: false,
i18n_default_locale_slug: 'en',
Expand Down
14 changes: 14 additions & 0 deletions packages/agents-manager/src/global.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* Global type declarations for the Agents Manager package.
*/

/**
* agentsManagerData is set as a global const via wp_add_inline_script
* in Jetpack's Agents Manager feature.
*/
declare const agentsManagerData:
| {
agentProviders?: string[];
useUnifiedExperience?: boolean;
}
| undefined;
3 changes: 3 additions & 0 deletions packages/agents-manager/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ export type { UnifiedAIAgentProps } from './components/unified-ai-agent';

export { AGENTS_MANAGER_STORE } from './stores';

// Utility for checking unified experience from inline script data
export { getUseUnifiedExperienceFromInlineData } from './utils/load-external-providers';

// Extension API types for other plugins to hook into
export type {
Ability,
Expand Down
16 changes: 14 additions & 2 deletions packages/agents-manager/src/utils/load-external-providers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,20 @@ import type { ToolProvider, ContextProvider, Suggestion } from '../types';
import type { SubmitOptions } from '@automattic/agenttic-client';
import type { MarkdownComponents, MarkdownExtensions } from '@automattic/agenttic-ui';

// agentsManagerData is set as a global const via wp_add_inline_script
declare const agentsManagerData: { agentProviders?: string[] } | undefined;
/**
* Check if the unified experience flag is set via agentsManagerData.
*
* This is used on wp-admin environments (Atomic, Garden, Simple sites) where
* the flag is injected server-side by Jetpack's Agents Manager.
*
* @returns The useUnifiedExperience value, or undefined if not available.
*/
export function getUseUnifiedExperienceFromInlineData(): boolean | undefined {
if ( typeof agentsManagerData !== 'undefined' ) {
return agentsManagerData?.useUnifiedExperience;
}
return undefined;
}

/**
* Navigation continuation hook type - provided by environments that support
Expand Down
53 changes: 53 additions & 0 deletions packages/help-center/src/data/use-unified-ai-chat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { getUseUnifiedExperienceFromInlineData } from '@automattic/agents-manager';
import { useQuery } from '@tanstack/react-query';
import wpcomRequest, { canAccessWpcomApis } from 'wpcom-proxy-request';

interface CalypsoPreferencesResponse {
calypso_preferences?: {
unified_ai_chat?: boolean;
};
}

/**
* Determines if the user should see the unified AI chat experience.
*
* This hook uses a hybrid approach to work across all environments:
*
* 1. **wp-admin environments** (Atomic, Garden, Simple sites):
* The flag is available via `agentsManagerData.useUnifiedExperience`,
* injected server-side by Jetpack's Agents Manager.
*
* 2. **Calypso app** (wordpress.com):
* The flag is fetched from the `/me/preferences` endpoint.
*
* The rollout logic lives in Agents Manager (Jetpack) via the
* `agents_manager_use_unified_experience` filter.
*/
export function useUnifiedAiChat( enabled = true ) {
return useQuery< boolean, Error >( {
queryKey: [ 'unified-ai-chat' ],
queryFn: async () => {
// 1. Check inline script first (available on wp-admin via Jetpack's Agents Manager)
const inlineValue = getUseUnifiedExperienceFromInlineData();
if ( inlineValue !== undefined ) {
return inlineValue;
}

// 2. Fall back to /me/preferences endpoint for Calypso app (wordpress.com)
if ( canAccessWpcomApis() ) {
const response: CalypsoPreferencesResponse = await wpcomRequest( {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you happen to look to see if this has already been loaded elsewhere or is otherwise in Calypso state? I think it might be preloaded.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked now. React Query already caches this with 5-minute staleTime, so subsequent renders don't make additional requests.

I gave it a go anyway and the required changes seemed too big for the benefit IMO.

Copy link
Member

@jom jom Dec 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're currently making 3-4 GET requests to various versions of /me/preferences on Calypso load. This is adding another. The client/ does have getPreference in client/state/preferences/selectors.js, but we'd need to pass it down in client/layout/help-center-loader.tsx, I think. It could be a followup task, but it seems to be a systemic problem in Calypso.

Maybe it can wait until we add an async loader for agents-manager.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're currently making 3-4 GET requests to various versions of /me/preferences on Calypso load.

That's right.

This is adding another.

This is not what I saw. When I checked I didn't see this adding any extra request. On further reviewed it seemed to be because of staleTime. Do you see something different? If this is adding an extra request I am happy changing the implementation not to do it. Otherwise maybe we can create a ticket and tackle down this multiple requests as a followup task.

path: '/me/preferences',
apiVersion: '1.1',
} );

return response.calypso_preferences?.unified_ai_chat ?? false;
}

// 3. No data available - default to false
return false;
},
enabled,
refetchOnWindowFocus: false,
staleTime: 300000, // 5 minutes
} );
}
24 changes: 3 additions & 21 deletions packages/help-center/src/hooks/use-should-use-unified-agent.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,8 @@
/* eslint-disable no-restricted-imports */
import config from '@automattic/calypso-config';
import { useSupportStatus } from '../data/use-support-status';

function isUnifiedAgentFlagSetInURL(): boolean {
const currentUrl = window.location.href;
const urlParams = new URLSearchParams( new URL( currentUrl ).search );
const flags = urlParams.get( 'flags' );
return flags?.split( ',' ).includes( 'unified-agent' ) ?? false;
}
import { useUnifiedAiChat } from '../data/use-unified-ai-chat';

export const useShouldUseUnifiedAgent = () => {
const { data: supportStatus } = useSupportStatus();

// Check if user is eligible via support status API
// Note: This will need to be added to the backend support-status endpoint
const isEligibleViaAPI = Boolean( supportStatus?.eligibility?.unified_agent_enabled );

// Force unified agent via URL flag (for testing)
const isFlagSetInURL = isUnifiedAgentFlagSetInURL();

// Unified agent can be enabled via config
const isConfigEnabled = config.isEnabled( 'unified-agent' );
const { data: isEligibleViaAPI } = useUnifiedAiChat();

return isEligibleViaAPI || isFlagSetInURL || isConfigEnabled;
return isEligibleViaAPI;
};
Loading