diff --git a/agents/k8s/reminder-service-deployment.yaml b/agents/k8s/reminder-service-deployment.yaml
index 2157429..c814340 100644
--- a/agents/k8s/reminder-service-deployment.yaml
+++ b/agents/k8s/reminder-service-deployment.yaml
@@ -60,7 +60,10 @@ spec:
- name: PERSONAL_NUM
value: "+14085505485"
- name: GROUP_URL
- value: "https://chat.whatsapp.com/FXO0SCLA8DpJwClNNWdhhx"
+ valueFrom:
+ configMapKeyRef:
+ name: whatsapp-config
+ key: default-group-url
volumeMounts:
- name: app-volume
mountPath: /app
diff --git a/agents/k8s/trip-service-deployment.yaml b/agents/k8s/trip-service-deployment.yaml
index 674a8f4..970aa4a 100644
--- a/agents/k8s/trip-service-deployment.yaml
+++ b/agents/k8s/trip-service-deployment.yaml
@@ -61,7 +61,10 @@ spec:
- name: PERSONAL_NUM
value: "+14085505485"
- name: GROUP_URL
- value: "https://chat.whatsapp.com/FXO0SCLA8DpJwClNNWdhhx"
+ valueFrom:
+ configMapKeyRef:
+ name: whatsapp-config
+ key: trip-group-url
- name: ANTHROPIC_API_KEY
valueFrom:
secretKeyRef:
diff --git a/agents/k8s/weather-cronjob.yaml b/agents/k8s/weather-cronjob.yaml
index 8f4b46b..576029e 100644
--- a/agents/k8s/weather-cronjob.yaml
+++ b/agents/k8s/weather-cronjob.yaml
@@ -19,6 +19,12 @@ spec:
containers:
- name: weather-reporter
image: node:18-alpine
+ env:
+ - name: GROUP_URL
+ valueFrom:
+ configMapKeyRef:
+ name: whatsapp-config
+ key: default-group-url
command:
- "node"
- "-e"
@@ -28,7 +34,7 @@ spec:
const ZIP = '16046';
const GATEWAY = 'http://whatsapp-gateway.ai-agents.svc.cluster.local:5001/send-message';
- const GROUP = 'https://chat.whatsapp.com/FXO0SCLA8DpJwClNNWdhhx';
+ const GROUP = process.env.GROUP_URL || 'https://chat.whatsapp.com/0Txfg7iZBbvIuvTbTqqgAX';
const PERSONAL = '+14085505485';
function weatherEmoji(desc) {
diff --git a/agents/k8s/whatsapp-config.yaml b/agents/k8s/whatsapp-config.yaml
new file mode 100644
index 0000000..a05569a
--- /dev/null
+++ b/agents/k8s/whatsapp-config.yaml
@@ -0,0 +1,8 @@
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: whatsapp-config
+ namespace: ai-agents
+data:
+ trip-group-url: "https://chat.whatsapp.com/HN2z93yhXPyEJPuoib3dws"
+ default-group-url: "https://chat.whatsapp.com/0Txfg7iZBbvIuvTbTqqgAX"
diff --git a/interface/hq-dashboard/app/api/config/whatsapp/route.js b/interface/hq-dashboard/app/api/config/whatsapp/route.js
new file mode 100644
index 0000000..d0605f7
--- /dev/null
+++ b/interface/hq-dashboard/app/api/config/whatsapp/route.js
@@ -0,0 +1,36 @@
+import { NextResponse } from 'next/server';
+import fs from 'fs';
+import yaml from 'js-yaml';
+
+const CONFIG_PATH = 'c:/Users/sunde/proxmox/agentic-os/agents/k8s/whatsapp-config.yaml';
+
+export async function GET() {
+ try {
+ const fileContents = fs.readFileSync(CONFIG_PATH, 'utf8');
+ const doc = yaml.load(fileContents);
+ return NextResponse.json({ success: true, data: doc.data });
+ } catch (e) {
+ return NextResponse.json({ success: false, error: e.message }, { status: 500 });
+ }
+}
+
+export async function PUT(req) {
+ try {
+ const body = await req.json();
+ const { defaultGroupUrl, tripGroupUrl } = body;
+
+ const fileContents = fs.readFileSync(CONFIG_PATH, 'utf8');
+ const doc = yaml.load(fileContents);
+
+ if (!doc.data) doc.data = {};
+ if (defaultGroupUrl) doc.data['default-group-url'] = defaultGroupUrl;
+ if (tripGroupUrl) doc.data['trip-group-url'] = tripGroupUrl;
+
+ const newYaml = yaml.dump(doc, { lineWidth: -1 });
+ fs.writeFileSync(CONFIG_PATH, newYaml, 'utf8');
+
+ return NextResponse.json({ success: true, data: doc.data });
+ } catch (e) {
+ return NextResponse.json({ success: false, error: e.message }, { status: 500 });
+ }
+}
diff --git a/interface/hq-dashboard/app/page.jsx b/interface/hq-dashboard/app/page.jsx
index 2f48c8d..0e65126 100644
--- a/interface/hq-dashboard/app/page.jsx
+++ b/interface/hq-dashboard/app/page.jsx
@@ -98,9 +98,52 @@ export default function Page() {
const [isSavingTrip, setIsSavingTrip] = useState(false);
const [isTestingTrip, setIsTestingTrip] = useState(false);
+ // Config State
+ const [configData, setConfigData] = useState({ defaultGroupUrl: "", tripGroupUrl: "" });
+ const [isSavingConfig, setIsSavingConfig] = useState(false);
+ const [configLoaded, setConfigLoaded] = useState(false);
+
const messagesEndRef = useRef(null);
const terminalEndRef = useRef(null);
+ useEffect(() => {
+ if (activeTab === "config" && !configLoaded) {
+ fetch('/api/config/whatsapp')
+ .then(res => res.json())
+ .then(data => {
+ if (data.success) {
+ setConfigData({
+ defaultGroupUrl: data.data['default-group-url'] || "",
+ tripGroupUrl: data.data['trip-group-url'] || ""
+ });
+ setConfigLoaded(true);
+ }
+ })
+ .catch(console.error);
+ }
+ }, [activeTab, configLoaded]);
+
+ const handleSaveConfig = async () => {
+ setIsSavingConfig(true);
+ try {
+ const res = await fetch('/api/config/whatsapp', {
+ method: 'PUT',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(configData)
+ });
+ const data = await res.json();
+ if (data.success) {
+ alert("Configuration saved successfully to Kubernetes manifest!");
+ } else {
+ alert("Failed to save: " + data.error);
+ }
+ } catch (e) {
+ alert("Error saving config: " + e.message);
+ } finally {
+ setIsSavingConfig(false);
+ }
+ };
+
useEffect(() => {
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
}, [messages, isClawTyping]);
@@ -690,6 +733,20 @@ export default function Page() {
+ Manage the WhatsApp group invite links used by the various Agentic OS microservices.
+ Changes here are written directly to the Kubernetes whatsapp-config.yaml ConfigMap.
+