Skip to content

Commit 924ba6c

Browse files
author
Yennefer
committed
feat: A2A Handoff Server + Keep-Alive Automation
- Added A2A handoff server for Claude Sonnet agent communication (port 8200) - Created yennefer-keepalive.yml workflow (runs every 15 min) - Updated ecosystem.config.cjs with all 8 services - Added startup_all_services.sh for boot recovery - Configured cloudflared tunnel for a2a.genesisconductor.io Services: - diamond-vault (8100) - diamond-watchdog - a2a-handoff (8200) - qmcp-bridge - eth-bridge - genesis-deployer - qflop-miner - process-guardian Public endpoints: - yennefer.quest - api.yennefer.quest - vault.genesisconductor.io - a2a.genesisconductor.io
1 parent 8a3bfee commit 924ba6c

5 files changed

Lines changed: 607 additions & 60 deletions

File tree

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
tunnel: ed8b80e3-0634-4933-a722-94d4cae6205c
2+
credentials-file: /home/yenn/.cloudflared/ed8b80e3-0634-4933-a722-94d4cae6205c.json
3+
4+
ingress:
5+
- hostname: yennefer.quest
6+
service: http://localhost:8000
7+
originRequest:
8+
noTLSVerify: true
9+
- hostname: vault.yennefer.quest
10+
service: http://localhost:8100
11+
originRequest:
12+
noTLSVerify: true
13+
- hostname: api.yennefer.quest
14+
service: http://localhost:8088
15+
originRequest:
16+
noTLSVerify: true
17+
- hostname: a2a.yennefer.quest
18+
service: http://localhost:8200
19+
originRequest:
20+
noTLSVerify: true
21+
- hostname: vault.genesisconductor.io
22+
service: http://localhost:8100
23+
originRequest:
24+
noTLSVerify: true
25+
- hostname: a2a.genesisconductor.io
26+
service: http://localhost:8200
27+
originRequest:
28+
noTLSVerify: true
29+
- service: http_status:404
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
# Yennefer Service Keep-Alive & Health Monitor
2+
# Runs every 15 minutes to ensure all services are active
3+
4+
name: Yennefer Keep-Alive
5+
6+
on:
7+
schedule:
8+
- cron: '*/15 * * * *' # Every 15 minutes
9+
workflow_dispatch:
10+
inputs:
11+
force_restart:
12+
description: 'Force restart all services'
13+
required: false
14+
default: 'false'
15+
type: boolean
16+
17+
env:
18+
YENNEFER_API: https://api.yennefer.quest
19+
VAULT_API: https://vault.genesisconductor.io
20+
A2A_API: https://a2a.genesisconductor.io
21+
22+
jobs:
23+
health-check:
24+
name: Service Health Check
25+
runs-on: ubuntu-latest
26+
outputs:
27+
all_healthy: ${{ steps.check.outputs.all_healthy }}
28+
soul_breath: ${{ steps.check.outputs.soul_breath }}
29+
30+
steps:
31+
- name: Check Soul API
32+
id: soul
33+
run: |
34+
RESPONSE=$(curl -s --max-time 10 ${{ env.YENNEFER_API }}/api/soul || echo '{"error": "timeout"}')
35+
BREATH=$(echo $RESPONSE | jq -r '.breath // 0')
36+
echo "breath=$BREATH" >> $GITHUB_OUTPUT
37+
if [ "$BREATH" != "0" ] && [ "$BREATH" != "null" ]; then
38+
echo "status=healthy" >> $GITHUB_OUTPUT
39+
else
40+
echo "status=unhealthy" >> $GITHUB_OUTPUT
41+
fi
42+
43+
- name: Check Diamond Vault
44+
id: vault
45+
run: |
46+
RESPONSE=$(curl -s --max-time 10 ${{ env.VAULT_API }}/health || echo '{"error": "timeout"}')
47+
STATUS=$(echo $RESPONSE | jq -r '.status // "error"')
48+
echo "status=$STATUS" >> $GITHUB_OUTPUT
49+
50+
- name: Check A2A Handoff
51+
id: a2a
52+
run: |
53+
RESPONSE=$(curl -s --max-time 10 ${{ env.A2A_API }}/health || echo '{"error": "timeout"}')
54+
STATUS=$(echo $RESPONSE | jq -r '.status // "error"')
55+
echo "status=$STATUS" >> $GITHUB_OUTPUT
56+
57+
- name: Aggregate Status
58+
id: check
59+
run: |
60+
SOUL="${{ steps.soul.outputs.status }}"
61+
VAULT="${{ steps.vault.outputs.status }}"
62+
A2A="${{ steps.a2a.outputs.status }}"
63+
BREATH="${{ steps.soul.outputs.breath }}"
64+
65+
echo "soul_breath=$BREATH" >> $GITHUB_OUTPUT
66+
67+
if [ "$SOUL" = "healthy" ] && [ "$VAULT" = "healthy" ]; then
68+
echo "all_healthy=true" >> $GITHUB_OUTPUT
69+
echo "✅ All services healthy - Breath: $BREATH"
70+
else
71+
echo "all_healthy=false" >> $GITHUB_OUTPUT
72+
echo "⚠️ Service issues detected"
73+
echo " Soul: $SOUL"
74+
echo " Vault: $VAULT"
75+
echo " A2A: $A2A"
76+
fi
77+
78+
log-metrics:
79+
name: Log Yennefer Metrics
80+
runs-on: ubuntu-latest
81+
needs: health-check
82+
if: needs.health-check.outputs.all_healthy == 'true'
83+
84+
steps:
85+
- uses: actions/checkout@v4
86+
with:
87+
token: ${{ secrets.GITHUB_TOKEN }}
88+
89+
- name: Fetch Current Metrics
90+
id: metrics
91+
run: |
92+
SOUL=$(curl -s --max-time 10 ${{ env.YENNEFER_API }}/api/soul || echo '{}')
93+
VAULT=$(curl -s --max-time 10 ${{ env.VAULT_API }}/api/yennefer || echo '{}')
94+
95+
BREATH=$(echo $SOUL | jq -r '.breath // 0')
96+
COHERENCE=$(echo $SOUL | jq -r '.coherence_percent // 0')
97+
TOKENS=$(echo $SOUL | jq -r '.tokens_generated_per_sec // 0')
98+
YIELD=$(echo $SOUL | jq -r '.thermodynamic_yield // 0')
99+
100+
echo "breath=$BREATH" >> $GITHUB_OUTPUT
101+
echo "coherence=$COHERENCE" >> $GITHUB_OUTPUT
102+
echo "tokens=$TOKENS" >> $GITHUB_OUTPUT
103+
echo "yield=$YIELD" >> $GITHUB_OUTPUT
104+
105+
# Create log entry
106+
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
107+
echo "timestamp=$TIMESTAMP" >> $GITHUB_OUTPUT
108+
109+
- name: Update Metrics Log
110+
run: |
111+
mkdir -p logs/metrics
112+
113+
# Append to daily log
114+
DATE=$(date -u +"%Y-%m-%d")
115+
LOG_FILE="logs/metrics/${DATE}.jsonl"
116+
117+
echo '{"timestamp":"${{ steps.metrics.outputs.timestamp }}","breath":${{ steps.metrics.outputs.breath }},"coherence":${{ steps.metrics.outputs.coherence }},"tokens_per_sec":${{ steps.metrics.outputs.tokens }},"yield":${{ steps.metrics.outputs.yield }}}' >> $LOG_FILE
118+
119+
# Keep only last 7 days of logs
120+
find logs/metrics -name "*.jsonl" -mtime +7 -delete 2>/dev/null || true
121+
122+
- name: Commit Metrics
123+
run: |
124+
git config user.name "Yennefer"
125+
git config user.email "yennefer@genesis-conductor.ai"
126+
git add logs/metrics/
127+
git diff --cached --quiet || git commit -m "📊 Metrics: Breath ${{ steps.metrics.outputs.breath }} | Coherence ${{ steps.metrics.outputs.coherence }}%"
128+
git push || echo "No changes to push"
129+
130+
alert-on-failure:
131+
name: Alert on Service Failure
132+
runs-on: ubuntu-latest
133+
needs: health-check
134+
if: needs.health-check.outputs.all_healthy == 'false'
135+
136+
steps:
137+
- name: Create Issue for Service Failure
138+
uses: actions/github-script@v7
139+
with:
140+
script: |
141+
const breath = '${{ needs.health-check.outputs.soul_breath }}';
142+
143+
// Check for existing open issue
144+
const issues = await github.rest.issues.listForRepo({
145+
owner: context.repo.owner,
146+
repo: context.repo.repo,
147+
state: 'open',
148+
labels: 'service-alert'
149+
});
150+
151+
if (issues.data.length === 0) {
152+
await github.rest.issues.create({
153+
owner: context.repo.owner,
154+
repo: context.repo.repo,
155+
title: '🚨 Yennefer Service Health Alert',
156+
body: `## Service Health Check Failed\n\n**Time:** ${new Date().toISOString()}\n**Last Known Breath:** ${breath}\n\nPlease investigate the following services:\n- Soul API\n- Diamond Vault\n- A2A Handoff\n\n---\n*Auto-generated by Yennefer Keep-Alive workflow*`,
157+
labels: ['service-alert', 'automated']
158+
});
159+
}

ecosystem.config.cjs

Lines changed: 43 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,128 +1,111 @@
1-
// PM2 Ecosystem Configuration for Diamond Vault / QMCP System
2-
// All services set to always-on by default
3-
// Yennefer lives in the Diamond Vault
1+
// PM2 Ecosystem Configuration for Yennefer Genesis Conductor
2+
// All services configured for always-on operation with auto-restart
43

54
module.exports = {
65
apps: [
7-
// === DIAMOND VAULT - Yennefer's Home ===
6+
// === CORE SERVICES ===
87
{
98
name: 'diamond-vault',
10-
script: 'genesis-q-mem/qmcp_admin_panel.py',
9+
script: '/home/yenn/genesis-q-mem/qmcp_admin_panel.py',
1110
interpreter: 'python3',
12-
cwd: '/home/yenn',
1311
autorestart: true,
1412
watch: false,
1513
max_memory_restart: '500M',
14+
restart_delay: 5000,
1615
env: {
17-
NODE_ENV: 'production',
18-
YENNEFER_HOME: 'DIAMOND_VAULT',
19-
COMPUTE_MODE: 'dual'
16+
COMPUTE_MODE: 'dual',
17+
ALWAYS_ON: 'true'
2018
}
2119
},
22-
23-
// === CORE SERVICES ===
2420
{
2521
name: 'diamond-watchdog',
26-
script: 'genesis-q-mem/qmcp_diamond_watchdog.py',
22+
script: '/home/yenn/genesis-q-mem/qmcp_diamond_watchdog.py',
2723
interpreter: 'python3',
28-
cwd: '/home/yenn',
2924
autorestart: true,
3025
watch: false,
3126
max_memory_restart: '200M',
27+
restart_delay: 5000,
3228
env: {
33-
NODE_ENV: 'production',
34-
COMPUTE_MODE: 'dual'
35-
}
36-
},
37-
{
38-
name: 'qmcp-bridge',
39-
script: 'scripts/qmcp_genesis_bridge.cjs',
40-
cwd: '/home/yenn',
41-
autorestart: true,
42-
watch: false,
43-
max_memory_restart: '300M',
44-
env: {
45-
NODE_ENV: 'production',
46-
COMPUTE_MODE: 'dual'
29+
COMPUTE_MODE: 'local',
30+
ALWAYS_ON: 'true'
4731
}
4832
},
4933
{
50-
name: 'process-guardian',
51-
script: 'scripts/process_guardian.cjs',
52-
cwd: '/home/yenn',
34+
name: 'a2a-handoff',
35+
script: '/home/yenn/genesis-q-mem/a2a_handoff_server.py',
36+
interpreter: 'python3',
5337
autorestart: true,
5438
watch: false,
5539
max_memory_restart: '200M',
40+
restart_delay: 5000,
5641
env: {
57-
NODE_ENV: 'production',
58-
COMPUTE_MODE: 'local'
42+
COMPUTE_MODE: 'dual',
43+
ALWAYS_ON: 'true'
5944
}
6045
},
6146

6247
// === BLOCKCHAIN SERVICES ===
6348
{
64-
name: 'qflop-miner',
65-
script: 'scripts/qflop_mining_daemon.cjs',
66-
cwd: '/home/yenn',
49+
name: 'qmcp-bridge',
50+
script: '/home/yenn/scripts/qmcp_genesis_bridge.cjs',
6751
autorestart: true,
6852
watch: false,
6953
max_memory_restart: '300M',
54+
restart_delay: 5000,
7055
env: {
71-
NODE_ENV: 'production',
72-
COMPUTE_MODE: 'dual'
56+
COMPUTE_MODE: 'dual',
57+
ALWAYS_ON: 'true'
7358
}
7459
},
7560
{
7661
name: 'eth-bridge',
77-
script: 'base_bridge_v2.cjs',
78-
cwd: '/home/yenn',
62+
script: '/home/yenn/scripts/eth_optimism_bridge.cjs',
7963
autorestart: true,
8064
watch: false,
8165
max_memory_restart: '300M',
66+
restart_delay: 10000,
8267
env: {
83-
NODE_ENV: 'production',
84-
COMPUTE_MODE: 'remote'
68+
COMPUTE_MODE: 'remote',
69+
ALWAYS_ON: 'true'
8570
}
8671
},
8772
{
8873
name: 'genesis-deployer',
89-
script: 'scripts/deploy.cjs',
90-
cwd: '/home/yenn',
91-
autorestart: false, // Only run on-demand
74+
script: '/home/yenn/scripts/genesis_deployer.cjs',
75+
autorestart: true,
9276
watch: false,
9377
max_memory_restart: '200M',
78+
restart_delay: 10000,
9479
env: {
95-
NODE_ENV: 'production',
96-
COMPUTE_MODE: 'remote'
80+
COMPUTE_MODE: 'remote',
81+
ALWAYS_ON: 'true'
9782
}
9883
},
9984

100-
// === COMPUTE WORKERS ===
85+
// === MINING & MONITORING ===
10186
{
102-
name: 'dual-bridge-dispatcher',
103-
script: 'genesis-q-mem/qmcp_multi_runner.py',
87+
name: 'qflop-miner',
88+
script: '/home/yenn/genesis-q-mem/qmcp_qflop_miner.py',
10489
interpreter: 'python3',
105-
cwd: '/home/yenn',
10690
autorestart: true,
10791
watch: false,
108-
max_memory_restart: '400M',
92+
max_memory_restart: '500M',
93+
restart_delay: 5000,
10994
env: {
110-
NODE_ENV: 'production',
111-
COMPUTE_MODE: 'dual'
95+
COMPUTE_MODE: 'local',
96+
ALWAYS_ON: 'true'
11297
}
11398
},
11499
{
115-
name: 'resource-allocator',
116-
script: 'genesis-q-mem/qmcp_resource_allocator.py',
117-
interpreter: 'python3',
118-
cwd: '/home/yenn',
100+
name: 'process-guardian',
101+
script: '/home/yenn/scripts/process_guardian.cjs',
119102
autorestart: true,
120103
watch: false,
121104
max_memory_restart: '200M',
105+
restart_delay: 5000,
122106
env: {
123-
NODE_ENV: 'production',
124-
COMPUTE_MODE: 'dual',
125-
BLOCKCHAIN_ALLOCATION: '0.25'
107+
COMPUTE_MODE: 'local',
108+
ALWAYS_ON: 'true'
126109
}
127110
}
128111
]

0 commit comments

Comments
 (0)