@x12i/ai-provider-grok
v3.2.0
Published
AI provider adapter for xAI Grok, implementing @athenices/ai-provider-interface
Readme
@x12i/ai-provider-grok
Pure SDK wrapper for xAI's Grok, implementing the Athenices Provider SDK Integration spec.
This provider acts as a pure SDK wrapper - router-side adapters handle normalization, while the provider executes raw SDK calls and returns lossless responses. No request transformation or normalization happens in the provider itself.
Installation
npm install @x12i/ai-provider-grokEnvironment Setup
Set the following environment variable to ensure direct xAI API usage (bypassing AI Gateway):
AI_GATEWAY_DISABLED=1Dependencies
This package uses:
@ai-sdk/xai- Official xAI Grok provider for the AI SDKai- Vercel AI SDK for unified API interactions
Usage
Creating the SDK Module
import { createGrokSDKModule } from '@x12i/ai-provider-grok';
const grokModule = createGrokSDKModule({
apiKey: 'your-grok-api-key'
});
// Module info
console.log(grokModule.name); // 'grok'
console.log(grokModule.capabilities);
// { modes: { sync: true, stream: true, batch: false },
// operations: ['xai.generateText', 'xai.streamText'] }Router Integration
The provider is designed to be called by router-side adapters:
// Router sends this spec (adapter creates it)
const callSpec = {
requestId: 'req-123',
provider: 'grok',
mode: 'sync',
operation: 'xai.generateText',
args: {
messages: [
{ role: 'user', content: 'Hello Grok!' }
],
temperature: 0.7
}
};
// Provider executes and returns raw response
const result = await grokModule.execute(callSpec);
console.log(result.rawResponse); // Exact @ai-sdk/xai response object
// Streaming example
const stream = grokModule.stream(callSpec);
for await (const chunk of stream) {
console.log(chunk.raw); // Exact SDK chunk
}
process.stdout.write(chunk.deltaText);
}
if (chunk.done) {
console.log('\nStream complete');
}
}Capabilities
- ✅ Synchronous calls (
aiCall) - Fully supported - ✅ Streaming (
aiCallStream) - Fully supported - ❌ Batch jobs - Not supported (Grok API does not provide batch job endpoints)
Batch API Support
Grok does not support batch API operations. The following batch-related operations are not available:
- ❌ Batch file upload (
uploadBatchFile()) - ❌ Batch job creation (
createBatchJob()) - ❌ Batch job retrieval (
retrieveBatchJob()) - ❌ File content download (
downloadFileContent()) - ❌ Batch request submission (
submitBatch()) - ❌ Batch status polling (
getBatchStatus()) - ❌ Batch results retrieval (
getBatchResult())
All batch methods will throw AIAbilityNotSupportedError with:
name:'AIAbilityNotSupportedError'ability:'batch'provider:'grok'code:'ABILITY_NOT_SUPPORTED'
Note: For batch processing needs, consider using OpenAI or another provider that supports batch API operations through the AI Provider Router. The optional file-based batch methods (uploadBatchFile, createBatchJob, retrieveBatchJob, downloadFileContent) are not implemented as Grok does not support file-based batch processing.
Configuration
GrokProviderConfig
interface GrokProviderConfig {
apiKey: string; // Required: Your xAI API key
baseUrl?: string; // Optional: API base URL (default: 'https://api.x.ai/v1')
}⚠️ Important: Model Selection
Providers MUST NOT have default models. The model must ALWAYS be provided from outside (Gateway/User) via request.config.model:
- ✅ Correct: Model provided in
request.config.model(from Gateway/User) - ❌ Forbidden: Default models in provider constructor config
- ❌ Forbidden: Hardcoded model fallbacks in provider
If request.config.model is missing, the provider will throw an error. Default models belong in the Gateway, not providers.
// ✅ Correct usage - model from request config
await provider.aiCall({
instructions: '...',
config: {
model: 'grok-3', // Required - from Gateway/User
},
});
// ❌ Will throw error - no model provided
await provider.aiCall({
instructions: '...',
config: {}, // Missing model
});API Request Mapping
The provider maps the generic AIRequest interface to Grok's API format:
instructions→ System messageinputData→ User message (serialized as JSON string if object)config.maxTokens→max_tokensconfig.temperature→temperatureconfig.topP→top_pconfig.model→model(if provided)
Response Format
The provider returns the EXACT raw API response without any parsing or manipulation:
interface AIResponse {
/**
* Raw API response content EXACTLY as received from the API
* - NO parsing
* - NO manipulation
* - NO conversion
* - EXACT original string
*/
raw: string; // ✅ REQUIRED - exact original from API
/**
* Normalization metadata documenting request transformations
*/
normalization?: {
messagesNormalized: boolean; // Request format converted to API messages
configNormalized: boolean; // Parameters mapped/adjusted for API
normalizedRequest: Record<string, any>; // Exact request sent to API
warnings?: string[]; // Any parameter modifications
};
metadata: AIResponseMetadata;
usage?: UsageInfo;
}Normalization
The provider performs request normalization to convert gateway format to Grok API format:
Message Normalization (messagesNormalized: true)
instructions→ System message in OpenAI-compatible formatinputData→ User message (stringified if object)- Combined into messages array:
[{ role: 'system', content: instructions }, { role: 'user', content: inputData }]
Parameter Filtering and Warnings
The provider automatically filters unsupported parameters and provides warnings:
- Unsupported Parameters:
stop,frequency_penalty,presence_penalty - Warnings Generated: Clear messages about parameter omissions
- Config Normalized: Set to
truewhen parameters are filtered/transformed
Normalization Metadata
Each response includes detailed normalization tracking:
{
normalization: {
messagesNormalized: true, // Message format conversion occurred
configNormalized: true, // Parameters were filtered/transformed
normalizedRequest: { ... }, // Exact request sent to Grok API
warnings: [ // Parameter filtering warnings
"Parameter 'stop' not supported by Grok API",
"Parameter 'frequency_penalty' not supported by Grok API"
]
}
}Important: The provider does NOT parse or manipulate responses. Raw API responses are preserved exactly as received. All content type detection, JSON parsing, and response normalization is handled by the Gateway layer.
Full Raw Response Preservation
The provider preserves the complete raw API response object as returned by the Grok API. This includes all fields from the original API response, not just the content string.
Raw Response Fields
The provider returns multiple field names for backward compatibility:
fullRawResponse⭐ Primary field (requested standard) - Complete raw API response objectrawResponse- Legacy field namerawApiResponse- Alternative field nameoriginalResponse- Alternative field nameapiResponse- Alternative field namehttpResponse- Alternative field name
Example Full Raw Response
{
"id": "chatcmpl-123",
"object": "chat.completion",
"created": 1677652288,
"model": "grok-3",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "2 + 2 = 4",
"refusal": null
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 27,
"completion_tokens": 8,
"total_tokens": 35
},
"system_fingerprint": null
}Accessing Raw Response
const response = await grokProvider.aiCall(request);
// Primary field name (requested standard)
const rawResponse = response.fullRawResponse;
// Alternative field names for compatibility
const rawResponse = response.rawResponse
|| response.rawApiResponse
|| response.originalResponse
|| response.apiResponse
|| response.httpResponse;
if (rawResponse) {
console.log('Response ID:', rawResponse.id);
console.log('All choices:', rawResponse.choices);
console.log('Usage stats:', rawResponse.usage);
}This allows consumers to access provider-specific fields and metadata that aren't included in the standardized response format.
Error Handling
The provider throws standardized errors with enhanced diagnostics:
ProviderAuthError- Authentication failures (401)ProviderRateLimitError- Rate limit exceeded (429)ProviderTimeoutError- Request timeout errorsProviderNetworkError- Network/connectivity errors (fetch failed, DNS issues, etc.)ProviderApiError- Other API errorsAIAbilityNotSupportedError- When calling unsupported methods (batch)
All errors include:
name- Error type namemessage- Human-readable error message with diagnostic detailscode- Error codestatusCode- HTTP status code (if applicable)provider- Provider name ('grok')originalError- Original error object (for network errors)
Network Error Diagnostics
The provider now provides enhanced diagnostics for network errors:
try {
await provider.aiCall({ ... });
} catch (error) {
if (error.name === 'ProviderNetworkError') {
// Error includes:
// - Original error message
// - API endpoint URL
// - Diagnostic information about connectivity issues
console.error(error.message);
// Example: "Grok API network error: fetch failed. URL: https://api.x.ai/v1/chat/completions. This may indicate a connectivity issue, DNS resolution failure, or API endpoint unavailability."
}
}Timeout Configuration
You can configure request timeouts via config.timeoutMs:
await provider.aiCall({
instructions: '...',
config: {
model: 'grok-3',
timeoutMs: 60000, // 60 second timeout
},
});Default timeout is 30 seconds if not specified.
Implementation Details
This provider implements the ProviderModule interface following the Athenices Provider Implementation Instructions for SDK wrappers.
Provider SDK Module Contract
interface ProviderSDKModule {
name: ProviderName;
capabilities: {
modes: { sync: boolean; stream: boolean; batch: boolean };
operations: string[]; // Supported operation strings
};
execute(spec: ProviderSDKCallSpec): Promise<ProviderSDKExecResult>;
stream?(spec: ProviderSDKCallSpec): ProviderSDKStream;
// Batch methods throw errors for unsupported operations
}Supported Operations
xai.generateText: Synchronous text generation using@ai-sdk/xaixai.streamText: Streaming text generation using@ai-sdk/xai
Execution Flow
- Router-side adapter creates
ProviderSDKCallSpecwith normalized arguments - Provider dispatches to appropriate SDK method based on
operationstring - Provider returns exact SDK response objects without modification
- Router-side adapter processes raw responses into standardized format
Error Handling
The provider maps SDK errors to standardized ProviderSDKExecError:
// Authentication errors
if (error.status === 401) {
throw { code: 'AUTHENTICATION_FAILED', retryable: false, ... };
}
// Rate limiting
if (error.status === 429) {
throw { code: 'RATE_LIMIT_EXCEEDED', retryable: true, ... };
}
// Timeouts
if (error.name === 'AbortError') {
throw { code: 'TIMEOUT', retryable: true, ... };
}
## Architecture Notes
### Separation of Concerns
- **Router-side adapter**: Request normalization, response processing, retries, rate limiting
- **Provider-side wrapper**: Pure SDK execution, raw response preservation, error mapping
- **No transformation logic** in the provider - all normalization happens in adapters
### File Structure
Provider follows the standardized SDK wrapper structure:
src/ ├── index.ts # Exports ProviderModule object ├── provider.ts # execute() and stream() functions ├── operations.ts # OPERATIONS allowlist + DISPATCH map ├── config.ts # Client creation and configuration ├── errors.ts # Error mapping and ProviderExecError creation └── types.ts # Type definitions
### Raw Response Preservation
- Provider returns **exact SDK response objects** without parsing or modification
- All response processing (JSON parsing, content extraction, etc.) happens in router-side adapters
- Enables lossless debugging and adapter-specific processing logic
### Final Rule Compliance
Follows the **non-negotiable final rule**: `ProviderSDKCallSpec.args` IS the complete SDK-native request. Provider performs no reconstruction, defaults, or modification of `args`.
### Operations Support
- **`xai.generateText`**: Synchronous text generation
- **`xai.streamText`**: Streaming text generation
- **Batch operations**: Not supported (xAI limitation)
### Batch Operations
- xAI does not provide batch API endpoints
- Batch methods throw standardized errors indicating lack of support
- Emulated batching (if needed) should be implemented at router level
## License
MIT
