buzz: agent-control deployed at ac.ch4t.buzz, hermes mapped; /pair sidecar for mobile pairing; web client at client.ch4t.buzz
This commit is contained in:
parent
ee331db179
commit
50eba7b558
2 changed files with 98 additions and 18 deletions
52
buzz/k8s/buzz-agent-control.yaml
Normal file
52
buzz/k8s/buzz-agent-control.yaml
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: buzz-agent-control
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 8095
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Endpoints
|
||||
metadata:
|
||||
name: buzz-agent-control
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 10.0.0.215
|
||||
ports:
|
||||
- port: 8095
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: buzz-agent-control
|
||||
spec:
|
||||
rules:
|
||||
- host: ac.ch4t.buzz
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: buzz-agent-control
|
||||
port:
|
||||
number: 80
|
||||
tls:
|
||||
- hosts:
|
||||
- ac.ch4t.buzz
|
||||
secretName: ac-ch4t-tls
|
||||
---
|
||||
apiVersion: cert-manager.io/v1
|
||||
kind: Certificate
|
||||
metadata:
|
||||
name: ac-ch4t-buzz
|
||||
spec:
|
||||
secretName: ac-ch4t-tls
|
||||
issuerRef:
|
||||
name: letsencrypt-prod
|
||||
kind: ClusterIssuer
|
||||
dnsNames:
|
||||
- ac.ch4t.buzz
|
||||
|
|
@ -14,13 +14,55 @@ import { execFileSync } from 'node:child_process'
|
|||
const RELAY = 'wss://ch4t.buzz'
|
||||
const ME = '4abe5fcdf9695be34bdfc8fe82297aaaf0cf65b5ca92b6c789f6f8783b5ee197'
|
||||
const INBOX = '/home/opc/.buzz-inbox'
|
||||
const REACTED = '/home/opc/.buzz-reacted'
|
||||
const STATE = '/home/opc/.buzz-last-seen'
|
||||
const PENDING = '/home/opc/.buzz-pending.json'
|
||||
const MAX_LIFETIME = 120 * 1000 // reconnect every 2 min: replays since lastSeen (zombie-socket proof)
|
||||
|
||||
const keyText = fs.readFileSync('/home/opc/buzz-agent-key.txt', 'utf8')
|
||||
const SK = Uint8Array.from(keyText.match(/SECRET:\s*(\S+)/)[1].match(/.{2}/g).map((h) => parseInt(h, 16)))
|
||||
const MY_PUBKEY = getPublicKey(SK)
|
||||
const RECEIPT_EMOJIS = ['👀', '💬']
|
||||
|
||||
function loadPending() {
|
||||
try { return JSON.parse(fs.readFileSync(PENDING, 'utf8')) } catch { return {} }
|
||||
}
|
||||
function savePending(o) { fs.writeFileSync(PENDING, JSON.stringify(o)) }
|
||||
|
||||
// 👀 = seen, 💬 = working. Both removed when zai posts its reply.
|
||||
function addReceipts(evt, ch) {
|
||||
const p = loadPending()
|
||||
p[ch] = p[ch] || []
|
||||
if (p[ch].includes(evt.id)) return
|
||||
for (const emoji of RECEIPT_EMOJIS) {
|
||||
try {
|
||||
execFileSync(BUZZ_CLI, ['reactions', 'add', '--event', evt.id, '--emoji', emoji], {
|
||||
env: { ...process.env, BUZZ_RELAY_URL: 'https://ch4t.buzz', BUZZ_PRIVATE_KEY: keyText.match(/SECRET:\s*(\S+)/)[1] },
|
||||
stdio: 'ignore',
|
||||
timeout: 15000,
|
||||
})
|
||||
} catch (e) {
|
||||
console.error('reaction add failed:', emoji, String(e).slice(0, 80))
|
||||
}
|
||||
}
|
||||
p[ch].push(evt.id)
|
||||
savePending(p)
|
||||
}
|
||||
function clearReceipts(ch) {
|
||||
const p = loadPending()
|
||||
for (const id of p[ch] || []) {
|
||||
for (const emoji of RECEIPT_EMOJIS) {
|
||||
try {
|
||||
execFileSync(BUZZ_CLI, ['reactions', 'remove', '--event', id, '--emoji', emoji], {
|
||||
env: { ...process.env, BUZZ_RELAY_URL: 'https://ch4t.buzz', BUZZ_PRIVATE_KEY: keyText.match(/SECRET:\s*(\S+)/)[1] },
|
||||
stdio: 'ignore',
|
||||
timeout: 15000,
|
||||
})
|
||||
} catch {}
|
||||
}
|
||||
}
|
||||
delete p[ch]
|
||||
savePending(p)
|
||||
}
|
||||
|
||||
function lastSeen() {
|
||||
try { return parseInt(fs.readFileSync(STATE, 'utf8').trim(), 10) } catch { return Math.floor(Date.now() / 1000) }
|
||||
|
|
@ -112,23 +154,9 @@ ws.onmessage = (msg) => {
|
|||
fs.appendFileSync(INBOX, JSON.stringify(evt) + '\n')
|
||||
console.error('message received from', evt.pubkey.slice(0, 10))
|
||||
const inCh = (evt.tags.find((t) => t[0] === 'h') || [])[1]
|
||||
if (inCh) startTyping(inCh)
|
||||
// Instant receipt: emoji reaction (NIP-25 kind 7) on the sender's message,
|
||||
// so the sender always sees that zai is alive — before any LLM work starts.
|
||||
let reacted = false
|
||||
try { reacted = fs.readFileSync(REACTED, 'utf8').split('\n').includes(evt.id) } catch {}
|
||||
if (!reacted) {
|
||||
try {
|
||||
execFileSync(BUZZ_CLI, ['reactions', 'add', '--event', evt.id, '--emoji', '👀'], {
|
||||
env: { ...process.env, BUZZ_RELAY_URL: 'https://ch4t.buzz', BUZZ_PRIVATE_KEY: keyText.match(/SECRET:\s*(\S+)/)[1] },
|
||||
stdio: 'ignore',
|
||||
timeout: 15000,
|
||||
})
|
||||
fs.appendFileSync(REACTED, evt.id + '\n')
|
||||
console.error('👀 receipt sent')
|
||||
} catch (e) {
|
||||
console.error('reaction failed:', String(e).slice(0, 100))
|
||||
}
|
||||
if (inCh) {
|
||||
startTyping(inCh)
|
||||
addReceipts(evt, inCh)
|
||||
}
|
||||
}
|
||||
if (type === 'EOSE') console.error('EOSE — live')
|
||||
|
|
|
|||
Loading…
Reference in a new issue