Custom AI adapter in P4 Code Review
Use a custom AI adapter in P4 Code Review to integrate AI services that are not directly compatible with the built-in AI integration format.
A custom AI adapter allows you to define how requests are sent to your AI service and how responses are processed before being returned to P4 Code Review.
When to use a custom AI adapter
Use a custom AI adapter if:
-
Your AI service does not support the required request and response format.
-
You need to transform requests before sending them to the AI service.
-
You need to process or modify responses returned from the AI service.
-
You want to integrate a proprietary or internal AI system.
How a custom AI adapter works
A custom adapter acts as a translation layer between P4 Code Review and your AI service:
-
P4 Code Review sends a request to the adapter.
-
The adapter transforms the request into the format expected by your AI service.
-
The adapter sends the request to the AI service.
-
The adapter processes the response.
-
The adapter returns a formatted response to P4 Code Review.
You can write and integrate a Custom AI Adapter for your in-house or on-premise AI vendor with P4 Code Review.
On this page:
Compatibility
The Custom AI Adapter feature has been tested with the following AI vendors and models:
-
Anthropic Claude:
claude-opus-4-6claude-sonnet-4-6
-
Google Gemini:
gemini-1.0-progemini-2.5-flashgemini-3.1-flash-lite-preview
-
OpenAI:
-
gpt-4
-
-
LM Studio:
lmstudio-community/gemma-3-1B-it-qat-GGUFlmstudio-community/Qwen3-1.7B-GGUFlmstudio-community/DeepSeek-R1-Distill-Llama-8B-GGUFlmstudio-community/Meta-Llama-3.1-8B-Instruct-GGU
If you are developing a Custom AI Adapter for a different vendor or model, additional configuration might be required. For specific configuration details, see the vendor's documentation.
Create a Custom AI Adapter
There are two ways to configure AI in P4 Code Review:
-
Use AI configuration in System Information (Recommended)
-
To learn more, see Configuration.
-
-
Use ai_review block
config.php(Not recommended)
The following steps outline how to configure a Custom AI Adapter using the ai_review block in config.php.
To write a Custom AI Adapter in P4 Code Review, start by copying the GenericAIAdapter.php file from your installation and then complete these three stages:
To review the terms for using your own API keys, download the API Key Usage Agreement for Perforce P4 Code Review.
Copy and modify GenericAIAdapter
-
Go to the folder
module/AiAnalysis/src/Service/ -
Create the copy of file
GenericAIAdapter.phpwithin the same folder. -
Rename the copied file. For example:
CustomAIAdapter.php. -
Use the copied file as the starting point for your custom adapter implementation.
Always copy theGenericAIAdapter.phpfile from your P4 Code Review installation rather than recreating it from a documentation example.The installed file contains all methods required by the version of P4 Code Review that you are running. Future releases can add new methods that are required by AI features. Copying the file directly from your installation helps ensure that your custom adapter remains compatible with your P4 Code Review version.
-
Update the class name from:
class GenericAIAdapter
To
class CustomAIAdapter
-
Modify the implementation to communicate with your AI provider.
AI Checklist compatibility
Custom AI adapters must implement all methods provided by the version of GenericAIAdapter.php included with your P4 Code Review installation.
For example, P4 Code Review 2026.2 introduced the AI Checklist feature, which requires the executeCheckListAIRequest() method. If your custom adapter does not implement this method, AI Checklist requests cannot be processed correctly.
To avoid compatibility issues, always create custom adapters by copying the current GenericAIAdapter.php file from your installation and then modifying it for your AI provider.
Validate the response
-
Go to the folder
module/AiAnalysis/src/Service/, open theAbstractAiAdapter.phpfile, and copy thevalidateResultfunction. -
Open
CustomAIAdapter.phpand overwritevalidateResultwith the copied function. -
Modify the copied function in
CustomAIAdapter.phpwith your AI model’s response format.
An example of an unmodifiedvalidateResultfunction is as follows:Copyprotected function validateResult(object $result): bool
{
if (!property_exists($result, 'error') &&
property_exists($result, 'choices') &&
isset($result->choices[0]) && is_object($result->choices[0]) &&
property_exists($result->choices[0], 'message') &&
is_object($result->choices[0]->message) &&
property_exists($result->choices[0]->message, 'content')) {
return true;
}
return false;
}If your AI model response is not a object, modify the
validateResultfunction inCustomAIAdapter.phpso that it can handle the response.For example, if the AI vendor returns the response as an array, update the
validateResultfunction to parse the response.An example of an updated
validateResultfunction that can handle the response as an array:Copyprotected function validateAIResponse(array $result): bool
{
if (is_array($result) && isset($result[0]) && is_object($result[0]) &&
property_exists($result[0], 'embedding'))
{
return true;
}
return false;
} -
If your AI model’s response format is different from the example above, modify the format accordingly.
Also updateIAiAnalysisHelperwithin theCustomAIAdapter.phpfile.
An example of different AI response format is shown below:Copy{
"id": "chatcmpl-B9MBs8CjcvOU2jLn4n570S5qMJKcT",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "Hello! How can I assist you today?",
"refusal": null,
"annotations": []
},
}
],
} -
Update the
Services.phpfile located inmodule/Application/src/Config/to include an entry forCustomAIAdapteralongside the other AI adapters.
An example for the AI adapter entries in this file:Copyconst LM_STUDIO_AI = 'lmStudioAI';
const CUSTOM_AI = 'customAI'; -
Update the
AiServiceFactory.phpfile located inmodule/AiAnalysis/src/Factory/to include an entry forCustomAIAdapteralongside the other AI adapters.
An example for the AI adapter entries in this file:Copyconst OPENAIADAPTER = 'openAI';
const GENERICAIADAPTER = 'genericAI';
const LMSTUDIOAIADAPTER = 'lmStudioAI';
const CUSTOMAIADAPTER = 'customAI';
Add custom AI adapter to config files
Two config files require updating with entries for the custom AI adapter:
-
module/AiAnalysis/config/module.config.php
-
SWARM_ROOT/data.config.php
To update the files:
-
Open the
module.config.phpfile found in module/AiAnalysis/config/. -
At the top of the
module.config.phpfile, add ausestatement for theCustomAIAdapterabove the currentusestatement for theGenericAIAdapter. Below is an example of theseusestatements:Copyuse AiAnalysis\Service\CustomAIAdapter;
use AiAnalysis\Service\GenericAIAdapter; -
Inside the same
module.config.phpfile, find theservice_managerarray, and add the following entries.In the
aliasesarray, add:AiServiceFactory::CUSTOMAIADAPTER => CustomAIAdapter::class
In the
factoriesarray, add:CustomAIAdapter::class => AiServiceFactory::classServices::CUSTOM_AI => CustomAIAdapter::class
An example of the updated
service_managerarray in themodule.config.phpfile.Copy'service_manager' => [
'aliases' => [
IDao::AI_ANALYSIS_DAO => AiAnalysisDAO::class,
AiServiceFactory::OPENAIADAPTER => OpenAIAdapter::class,
AiServiceFactory::GENERICAIADAPTER => GenericAIAdapter::class,
AiServiceFactory::LMSTUDIOAIADAPTER => LMStudioAIAdapter::class,
IAiAnalysis::NAME => AiAnalysis::class,
IAiAnalysis::DISCARD_ANALYSIS_FILTER => DiscardAnalysis::class,
AiServiceFactory::CUSTOMAIADAPTER => CustomAIAdapter::class
],
'factories' => [
AiAnalysisDAO::class => InvokableServiceFactory::class,
OpenAIAdapter::class => AiServiceFactory::class,
Services::OPEN_AI => OpenAIAdapter::class,
GenericAIAdapter::class => AiServiceFactory::class,
Services::GENERIC_AI => GenericAIAdapter::class,
LMStudioAIAdapter::class => AiServiceFactory::class,
Services::LM_STUDIO_AI => LMStudioAIAdapter::class,
AiAnalysis::class => InvokableServiceFactory::class,
AiAnalysisChecker::class => InvokableServiceFactory::class,
AiAnalysisCharLimitChecker::class => InvokableServiceFactory::class,
AiAnalysisDataRetentionLifetimeChecker::class => InvokableServiceFactory::class,
DiscardAnalysis::class => InvokableServiceFactory::class,
CustomAIAdapter::class => AiServiceFactory::class,
Services::CUSTOM_AI => CustomAIAdapter::class,
],
], -
Open
config.phpfile found inSWARM_ROOT/data/. -
Update the
ai_reviewmodule with the values for the custom AI Adapter.Make sure you updateapi_end_pointwith your AI vendor end point .Below is an example of a modified
ai_reviewmodule:Copy'ai_review' => array(
// Please read through the https://www.perforce.com/generative-ai-policy before you enable this feature
'enabled' => true,
'data_retention_lifetime' => '150 days',
'timeout' => 500,
'ai_vendors' => array(
'ai_model1' => array(
'ai_vendor' => 'customAI',
'ai_package_id' => '1', // id should be one & should not modify it
'ai_package_key' => 'CustomAIPackage', // This is for future purposes when we will be supporting multiple models & will have an AI configuration page on UI
'ai_package_value' => 'Custom AI', // This is used for displaying the model type on the AI vendor response summary
'ai_package_type' => "Explain the following code ", // This is prompt type
'api_key' => '$SECRET_KEY', // Add in the API-key for you AI vendor
'api_end_point' => 'http://myAIVendorAPI/chat/completion', //Add an optional API endpoint
'ai_min_char_limit' => 10,
'ai_max_char_limit' => 70000
),
),
),
After completing these steps, a custom AI adapter has been added to P4 Code Review that supports your in-house AI model.