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
14 changes: 14 additions & 0 deletions inc/config.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,20 @@ function frontend_agent_chat_list_accessible_agents(): array {
return $normalized;
}

/**
* Read the current user's active Data Machine agent preference when available.
*
* @return string Active agent slug or empty string.
*/
function frontend_agent_chat_get_active_agent_slug(): string {
$result = frontend_agent_chat_execute_ability( 'datamachine/get-active-agent', array() );
if ( is_wp_error( $result ) || ! is_array( $result ) || empty( $result['success'] ) ) {
return '';
}

return sanitize_title( (string) ( $result['agent_slug'] ?? '' ) );
}

/**
* Normalize an Agents API descriptor for frontend chat use.
*
Expand Down
72 changes: 70 additions & 2 deletions inc/rest.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,23 @@ function frontend_agent_chat_register_rest_routes(): void {
)
);

register_rest_route(
'frontend-agent-chat/v1',
'/agents/active',
array(
array(
'methods' => WP_REST_Server::READABLE,
'callback' => 'frontend_agent_chat_rest_get_active_agent',
'permission_callback' => 'frontend_agent_chat_rest_can_chat',
),
array(
'methods' => WP_REST_Server::CREATABLE,
'callback' => 'frontend_agent_chat_rest_set_active_agent',
'permission_callback' => 'frontend_agent_chat_rest_can_chat',
),
)
);

register_rest_route(
'frontend-agent-chat/v1',
'/chat',
Expand Down Expand Up @@ -127,12 +144,63 @@ function frontend_agent_chat_rest_can_chat( ?WP_REST_Request $request = null ):
* @return WP_REST_Response
*/
function frontend_agent_chat_rest_list_agents(): WP_REST_Response {
$agents = frontend_agent_chat_list_accessible_agents();
$agents = frontend_agent_chat_list_accessible_agents();
$active_slug = frontend_agent_chat_get_active_agent_slug();
return rest_ensure_response(
array(
'success' => true,
'data' => array(
'active_agent_slug' => $active_slug,
'agents' => array_map( 'frontend_agent_chat_rest_agent_summary', $agents ),
),
)
);
}

/**
* Get the current user's active Data Machine agent preference.
*
* @return WP_REST_Response
*/
function frontend_agent_chat_rest_get_active_agent(): WP_REST_Response {
return rest_ensure_response(
array(
'success' => true,
'data' => array(
'agent_slug' => frontend_agent_chat_get_active_agent_slug(),
),
)
);
}

/**
* Persist the current user's active Data Machine agent preference.
*
* @param WP_REST_Request $request REST request.
* @return WP_REST_Response|WP_Error
*/
function frontend_agent_chat_rest_set_active_agent( WP_REST_Request $request ) {
$agent_slug = sanitize_title( (string) $request->get_param( 'agent' ) );
if ( '' === $agent_slug ) {
$agent_slug = sanitize_title( (string) $request->get_param( 'agent_slug' ) );
}
if ( '' === $agent_slug ) {
return new WP_Error( 'frontend_agent_chat_missing_agent', __( 'Agent is required.', 'frontend-agent-chat' ), array( 'status' => 400 ) );
}

$result = frontend_agent_chat_execute_ability( 'datamachine/set-active-agent', array( 'agent' => $agent_slug ) );
if ( is_wp_error( $result ) ) {
return $result;
}
if ( empty( $result['success'] ) ) {
return new WP_Error( 'frontend_agent_chat_active_agent_failed', (string) ( $result['error'] ?? __( 'Failed to set active agent.', 'frontend-agent-chat' ) ), array( 'status' => 400 ) );
}

return rest_ensure_response(
array(
'success' => true,
'data' => array(
'agents' => array_map( 'frontend_agent_chat_rest_agent_summary', $agents ),
'agent_slug' => sanitize_title( (string) ( $result['agent_slug'] ?? $agent_slug ) ),
),
)
);
Expand Down
29 changes: 25 additions & 4 deletions src/AgentChat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ interface AgentSummary {
interface AgentsResponse {
success?: boolean;
data?: {
active_agent_slug?: string;
agents?: AgentSummary[];
};
}
Expand Down Expand Up @@ -111,6 +112,17 @@ function createAgentFetch( agentSlug: string ): FetchFn {
};
}

function persistActiveAgent( agentSlug: string ): void {
apiFetch( {
path: '/frontend-agent-chat/v1/agents/active',
method: 'POST',
data: { agent: agentSlug },
} ).catch( ( err: unknown ) => {
// eslint-disable-next-line no-console
console.error( 'AgentChat: failed to persist active agent', agentSlug, err );
} );
}

/**
* Upload a file to the WordPress Media Library.
*
Expand Down Expand Up @@ -167,23 +179,27 @@ export default function AgentChat( {
const [ selectedAgentSlug, setSelectedAgentSlug ] = useState( agentSlug ?? '' );
const metadata = useClientContextMetadata();
const selectedAgent = useMemo(
() => agents.find( ( agent ) => agent.slug === selectedAgentSlug ) ?? agents[0],
() => agents.find( ( agent ) => agent.slug === selectedAgentSlug ),
[ agents, selectedAgentSlug ]
);
const activeAgentSlug = selectedAgent?.slug ?? '';
const activeAgentName = selectedAgent?.name ?? agentName;
const activeAgentDescription = selectedAgent?.description ?? agentDescription;
const fabLabel = __( 'Consult Intelligence', 'frontend-agent-chat' );
const agentFetch = useMemo( () => createAgentFetch( activeAgentSlug ), [ activeAgentSlug ] );
const open = useCallback( () => setIsOpen( true ), [] );
const close = useCallback( () => setIsOpen( false ), [] );
const switchAgent = useCallback( ( event: ChangeEvent< HTMLSelectElement > ) => {
setSelectedAgentSlug( event.target.value );
const nextAgentSlug = event.target.value;
setSelectedAgentSlug( nextAgentSlug );
persistActiveAgent( nextAgentSlug );
}, [] );

useEffect( () => {
apiFetch( { path: agentsPath } )
.then( ( response ) => {
const nextAgents = ( response as AgentsResponse ).data?.agents ?? [];
const data = ( response as AgentsResponse ).data ?? {};
const nextAgents = data.agents ?? [];
if ( nextAgents.length === 0 ) {
return;
}
Expand All @@ -194,6 +210,11 @@ export default function AgentChat( {
return current;
}

const activeAgentSlug = data.active_agent_slug ?? '';
if ( activeAgentSlug && nextAgents.some( ( agent ) => agent.slug === activeAgentSlug ) ) {
return activeAgentSlug;
}

return nextAgents[0].slug;
} );
} )
Expand Down Expand Up @@ -242,7 +263,7 @@ export default function AgentChat( {
activeAgentName
),
},
activeAgentName,
fabLabel,
unreadCount > 0 &&
createElement(
'span',
Expand Down