diff --git a/app.js b/app.js
index 0a757f9..7b4f12d 100644
--- a/app.js
+++ b/app.js
@@ -500,6 +500,66 @@ class AdaptiveCalibrator {
}
}
+
+// ═══ NOSTR AGENT REGISTRATION ═══
+class NostrAgent {
+ constructor(pubkey) {
+ this.pubkey = pubkey;
+ this.relays = ['wss://relay.damus.io', 'wss://nos.lol'];
+ }
+
+ async announce(metadata) {
+ console.log(`[NOSTR] Announcing agent ${this.pubkey}...`);
+ const event = {
+ kind: 0,
+ pubkey: this.pubkey,
+ created_at: Math.floor(Date.now() / 1000),
+ tags: [],
+ content: JSON.stringify(metadata),
+ id: 'mock_id',
+ sig: 'mock_sig'
+ };
+
+ this.relays.forEach(url => {
+ console.log(`[NOSTR] Publishing to ${url}: `, event);
+ });
+
+ const container = document.getElementById('nostr-log-content');
+ if (container) {
+ const div = document.createElement('div');
+ div.className = 'nostr-entry';
+ div.innerHTML = `[${this.pubkey.substring(0,8)}...] ANNOUNCED`;
+ container.prepend(div);
+ }
+ }
+}
+
+// ═══ L402 CLIENT LOGIC ═══
+class L402Client {
+ async fetchWithL402(url) {
+ console.log(`[L402] Fetching ${url}...`);
+ const response = await fetch(url);
+
+ if (response.status === 402) {
+ const authHeader = response.headers.get('WWW-Authenticate');
+ console.log(`[L402] Challenge received: ${authHeader}`);
+
+ const container = document.getElementById('l402-log-content');
+ if (container) {
+ const div = document.createElement('div');
+ div.className = 'l402-entry';
+ div.innerHTML = `CHALLENGE Payment Required`;
+ container.prepend(div);
+ }
+ return { status: 402, challenge: authHeader };
+ }
+
+ return response.json();
+ }
+}
+
+let nostrAgent, l402Client;
+
let metaLayer, neuroBridge, cbr, symbolicPlanner, knowledgeGraph, blackboard, symbolicEngine, calibrator;
let agentFSMs = {};
@@ -511,6 +571,9 @@ function setupGOFAI() {
cbr = new CaseBasedReasoner();
neuroBridge = new NeuroSymbolicBridge(symbolicEngine, blackboard);
metaLayer = new MetaReasoningLayer(symbolicPlanner, blackboard);
+ nostrAgent = new NostrAgent("npub1...");
+ l402Client = new L402Client();
+ nostrAgent.announce({ name: "Timmy Nexus Agent", capabilities: ["GOFAI", "L402"] });
calibrator = new AdaptiveCalibrator('nexus-v1', { base_rate: 0.05 });
// Setup initial facts
@@ -538,6 +601,7 @@ function updateGOFAI(delta, elapsed) {
// Simulate calibration update
calibrator.update({ input_tokens: 100, complexity_score: 0.5 }, 0.06);
+ if (Math.random() > 0.95) l402Client.fetchWithL402("http://localhost:8080/api/cost-estimate");
}
metaLayer.track(startTime);
diff --git a/l402_server.py b/l402_server.py
new file mode 100644
index 0000000..e83d929
--- /dev/null
+++ b/l402_server.py
@@ -0,0 +1,35 @@
+
+#!/usr/bin/env python3
+from http.server import HTTPServer, BaseHTTPRequestHandler
+import json
+import secrets
+
+class L402Handler(BaseHTTPRequestHandler):
+ def do_GET(self):
+ if self.path == '/api/cost-estimate':
+ # Simulate L402 Challenge
+ macaroon = secrets.token_hex(16)
+ invoice = "lnbc1..." # Mock invoice
+
+ self.send_response(402)
+ self.send_header('WWW-Authenticate', f'L402 macaroon="{macaroon}", invoice="{invoice}"')
+ self.send_header('Content-type', 'application/json')
+ self.end_headers()
+
+ response = {
+ "error": "Payment Required",
+ "message": "Please pay the invoice to access cost estimation."
+ }
+ self.wfile.write(json.dumps(response).encode())
+ else:
+ self.send_response(404)
+ self.end_headers()
+
+def run(server_class=HTTPServer, handler_class=L402Handler, port=8080):
+ server_address = ('', port)
+ httpd = server_class(server_address, handler_class)
+ print(f"Starting L402 Skeleton Server on port {port}...")
+ httpd.serve_forever()
+
+if __name__ == "__main__":
+ run()
diff --git a/style.css b/style.css
index 5594850..0cc38b5 100644
--- a/style.css
+++ b/style.css
@@ -1042,3 +1042,8 @@ canvas#nexus-canvas {
.cal-label { color: #ffd700; }
.cal-val { color: #4af0c0; }
.cal-err { color: #ff4466; opacity: 0.8; }
+
+.nostr-pubkey { color: #ffd700; }
+.nostr-status { color: #4af0c0; font-weight: 600; }
+.l402-status { color: #ff4466; font-weight: 600; }
+.l402-msg { color: #fff; }