diff --git a/src/backend/src/modules/puterai/OpenRouterService.js b/src/backend/src/modules/puterai/OpenRouterService.js
new file mode 100644
index 00000000..23761615
--- /dev/null
+++ b/src/backend/src/modules/puterai/OpenRouterService.js
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2024-present Puter Technologies Inc.
+ *
+ * This file is part of Puter.
+ *
+ * Puter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+// METADATA // {"ai-commented":{"service":"claude"}}
+const BaseService = require("../../services/BaseService");
+const OpenAIUtil = require("./lib/OpenAIUtil");
+
+const PUTER_PROMPT = `
+ You are running on an open-source platform called Puter,
+ under the OpenRouter implementation for a driver interface
+ called puter-chat-completion.
+`.replace('\n', ' ').trim();
+
+
+/**
+* XAIService class - Provides integration with X.AI's API for chat completions
+* Extends BaseService to implement the puter-chat-completion interface.
+* Handles model management, message adaptation, streaming responses,
+* and usage tracking for X.AI's language models like Grok.
+* @extends BaseService
+*/
+class OpenRouterService extends BaseService {
+ static MODULES = {
+ openai: require('openai'),
+ kv: globalThis.kv,
+ uuidv4: require('uuid').v4,
+ axios: require('axios'),
+ }
+
+
+ /**
+ * Gets the system prompt used for AI interactions
+ * @returns {string} The base system prompt that identifies the AI as running on Puter
+ */
+ get_system_prompt () {
+ return PUTER_PROMPT;
+ }
+
+ adapt_model (model) {
+ return model;
+ }
+
+
+ /**
+ * Initializes the XAI service by setting up the OpenAI client and registering with the AI chat provider
+ * @private
+ * @returns {Promise} Resolves when initialization is complete
+ */
+ async _init () {
+ this.api_base_url = 'https://openrouter.ai/api/v1';
+ this.openai = new this.modules.openai.OpenAI({
+ apiKey: this.config.apiKey,
+ baseURL: this.api_base_url,
+ });
+ this.kvkey = this.modules.uuidv4();
+
+ const svc_aiChat = this.services.get('ai-chat');
+ svc_aiChat.register_provider({
+ service_name: this.service_name,
+ alias: true,
+ });
+ }
+
+
+ /**
+ * Returns the default model identifier for the XAI service
+ * @returns {string} The default model ID 'grok-beta'
+ */
+ get_default_model () {
+ return 'grok-beta';
+ }
+
+ static IMPLEMENTS = {
+ ['puter-chat-completion']: {
+ /**
+ * Returns a list of available models and their details.
+ * See AIChatService for more information.
+ *
+ * @returns Promise> Array of model details
+ */
+ async models () {
+ return await this.models_();
+ },
+ /**
+ * Returns a list of available model names including their aliases
+ * @returns {Promise} Array of model identifiers and their aliases
+ * @description Retrieves all available model IDs and their aliases,
+ * flattening them into a single array of strings that can be used for model selection
+ */
+ async list () {
+ const models = await this.models_();
+ const model_names = [];
+ for ( const model of models ) {
+ model_names.push(model.id);
+ }
+ return model_names;
+ },
+
+ /**
+ * AI Chat completion method.
+ * See AIChatService for more details.
+ */
+ async complete ({ messages, stream, model, tools }) {
+ model = this.adapt_model(model);
+
+ if ( model.startsWith('openrouter:') ) {
+ model = model.slice('openrouter:'.length);
+ }
+
+ messages = await OpenAIUtil.process_input_messages(messages);
+
+ messages.unshift({
+ role: 'system',
+ content: this.get_system_prompt()
+ })
+
+ const completion = await this.openai.chat.completions.create({
+ messages,
+ model: model ?? this.get_default_model(),
+ ...(tools ? { tools } : {}),
+ max_tokens: 1000,
+ stream,
+ ...(stream ? {
+ stream_options: { include_usage: true },
+ } : {}),
+ });
+
+ return OpenAIUtil.handle_completion_output({
+ usage_calculator: OpenAIUtil.create_usage_calculator({
+ model_details: (await this.models_()).find(m => m.id === 'openrouter:' + model),
+ }),
+ stream, completion,
+ });
+ }
+ }
+ }
+
+
+ /**
+ * Retrieves available AI models and their specifications
+ * @returns {Promise} Array of model objects containing:
+ * - id: Model identifier string
+ * - name: Human readable model name
+ * - context: Maximum context window size
+ * - cost: Pricing information object with currency and rates
+ * @private
+ */
+ async models_ () {
+ const axios = this.require('axios');
+
+ const cached_models = this.modules.kv.get(`${this.kvkey}:models`);
+ if ( cached_models ) {
+ return cached_models;
+ }
+ const resp = await axios.request({
+ method: 'GET',
+ url: this.api_base_url + '/models',
+ });
+ const resp_models = resp.data.data;
+ const coerced_models = [];
+ for ( const model of resp_models ) {
+ coerced_models.push({
+ id: 'openrouter:' + model.id,
+ name: model.name + ' (OpenRouter)',
+ cost: {
+ currency: 'usd-cents',
+ tokens: 1_000_000,
+ input: model.pricing.prompt * 1000000,
+ output: model.pricing.completion * 1000000,
+ }
+ });
+ }
+ this.modules.kv.set(`${this.kvkey}:models`, coerced_models);
+ return coerced_models;
+ }
+}
+
+module.exports = {
+ OpenRouterService,
+};
+
diff --git a/src/backend/src/modules/puterai/PuterAIModule.js b/src/backend/src/modules/puterai/PuterAIModule.js
index 0ede2391..b6fa45a1 100644
--- a/src/backend/src/modules/puterai/PuterAIModule.js
+++ b/src/backend/src/modules/puterai/PuterAIModule.js
@@ -103,6 +103,10 @@ class PuterAIModule extends AdvancedBase {
const { GeminiService } = require('./GeminiService');
services.registerService('gemini', GeminiService);
}
+ if ( !! config?.services?.['openrouter'] ) {
+ const { OpenRouterService } = require('./OpenRouterService');
+ services.registerService('openrouter', OpenRouterService);
+ }
const { AIChatService } = require('./AIChatService');
services.registerService('ai-chat', AIChatService);
diff --git a/src/puter-js/src/modules/AI.js b/src/puter-js/src/modules/AI.js
index ee63e252..c0aaf597 100644
--- a/src/puter-js/src/modules/AI.js
+++ b/src/puter-js/src/modules/AI.js
@@ -285,6 +285,9 @@ class AI{
){
driver = 'gemini';
}
+ else if ( options.model.startsWith('openrouter:') ) {
+ driver = 'openrouter';
+ }
// stream flag from settings
if(settings.stream !== undefined && typeof settings.stream === 'boolean'){