diff --git a/index.html b/index.html
index 556b381..9d4ebc0 100644
--- a/index.html
+++ b/index.html
@@ -4098,6 +4098,14 @@
Whisper Messaging
Private encrypted communications
whisper.zhtp
+
+
+
+
🤖
+
Ren AI
+
Your AI assistant for the Sovereign Network
+
ren.zhtp
+
@@ -4995,6 +5003,22 @@ Whisper Messaging
+
+
+
+
+
+
diff --git a/src/app.js b/src/app.js
index 1b7bfb9..aa162f2 100644
--- a/src/app.js
+++ b/src/app.js
@@ -1495,9 +1495,37 @@ Examples:
const modal = document.getElementById(modalId);
if (modal) {
modal.style.display = 'flex';
- console.log('📂 Modal opened:', modalId);
+ console.log('Modal opened:', modalId);
} else {
- console.warn('⚠️ Modal not found:', modalId);
+ console.warn('Modal not found:', modalId);
+ }
+ }
+
+ // Open Ren AI Chat
+ openRenChat() {
+ console.log('Opening Ren AI chat...');
+
+ // Initialize Ren client if not already done
+ if (!window.renClient) {
+ window.renClient = new window.RenClient({
+ zkDidManager: this.zkdidManager
+ });
+ }
+
+ // Initialize Ren panel if not already done
+ if (!window.renPanel) {
+ window.renPanel = new window.RenChatPanel({
+ client: window.renClient
+ });
+ }
+
+ // Open the modal
+ this.openModal('renModal');
+
+ // Render the chat panel into the modal content
+ const renContent = document.getElementById('renContent');
+ if (renContent && window.renPanel) {
+ window.renPanel.render(renContent);
}
}
@@ -1699,6 +1727,9 @@ Examples:
case 'whisper':
this.navigateToUrl('zhtp://whisper.zhtp');
break;
+ case 'ren':
+ this.openRenChat();
+ break;
default:
console.log('Unknown action:', action);
}
diff --git a/src/ren/ren-client.js b/src/ren/ren-client.js
new file mode 100644
index 0000000..334189d
--- /dev/null
+++ b/src/ren/ren-client.js
@@ -0,0 +1,608 @@
+/**
+ * Ren Cloud Client - Hardwired AI Integration
+ *
+ * Like Gemini in Chrome:
+ * - No local model downloads
+ * - No fallback chains (Ren only)
+ * - Browser sends signed requests to Ren cloud service
+ * - Inference happens server-side
+ */
+
+// Configuration - Production endpoint
+const REN_CLOUD_URL = 'https://ren.sovereign.network/api';
+// Development endpoint (local)
+const REN_LOCAL_URL = 'http://localhost:8765';
+
+/**
+ * Ren Cloud Client
+ * Handles all communication with Ren AI service
+ */
+class RenClient {
+ constructor(options = {}) {
+ this.zkDidManager = options.zkDidManager || null;
+ this.endpoint = options.endpoint || this._detectEndpoint();
+ this.sessionId = null;
+ this._available = null;
+ this._eventListeners = new Map();
+
+ console.log('[Ren] Client initialized with endpoint:', this.endpoint);
+ }
+
+ /**
+ * Detect which endpoint to use - local dev or cloud
+ */
+ _detectEndpoint() {
+ // In development, try local first
+ if (window.location.hostname === 'localhost' ||
+ window.location.protocol === 'file:') {
+ return REN_LOCAL_URL;
+ }
+ return REN_CLOUD_URL;
+ }
+
+ /**
+ * Set the ZK-DID manager for request signing
+ */
+ setZkDidManager(manager) {
+ this.zkDidManager = manager;
+ console.log('[Ren] ZK-DID manager connected');
+ }
+
+ /**
+ * Check if Ren service is available
+ */
+ async isAvailable() {
+ if (this._available !== null) {
+ return this._available;
+ }
+
+ try {
+ const controller = new AbortController();
+ const timeout = setTimeout(() => controller.abort(), 5000);
+
+ const response = await fetch(`${this.endpoint}/health`, {
+ signal: controller.signal
+ });
+
+ clearTimeout(timeout);
+ this._available = response.ok;
+ return this._available;
+ } catch (error) {
+ console.warn('[Ren] Service unavailable:', error.message);
+ this._available = false;
+ return false;
+ }
+ }
+
+ /**
+ * Sign a request payload with user's DID
+ */
+ async _signRequest(payload) {
+ if (!this.zkDidManager || !this.zkDidManager.currentIdentity) {
+ // Return unsigned request if no identity
+ return {
+ ...payload,
+ timestamp: Date.now()
+ };
+ }
+
+ const identity = this.zkDidManager.currentIdentity;
+ const signedPayload = {
+ ...payload,
+ did: identity.did,
+ timestamp: Date.now()
+ };
+
+ // Sign the payload
+ try {
+ const signature = await this.zkDidManager.signData(
+ JSON.stringify(signedPayload)
+ );
+ signedPayload.signature = signature;
+ } catch (error) {
+ console.warn('[Ren] Could not sign request:', error.message);
+ }
+
+ return signedPayload;
+ }
+
+ /**
+ * Send a chat message to Ren
+ * @param {string} message - User message
+ * @param {Object} options - Optional settings
+ * @returns {Promise