refactor(pi): standalone Zulip gateway service — replaces pi extension
CI / validate (push) Failing after 1s

Complete rewrite of the pi Zulip extension as a standalone Node.js service
with direct harness API calls. No longer depends on pi's session — survives
pi shutdown and restart.

Changes:
- src/index.ts: Complete rewrite — standalone process, not a pi extension
  - Direct harness API calls (POST /v1/chat/completions) with conversation memory
  - Per-sender conversation history (up to 50 messages)
  - Placeholder->edit streaming for Zulip DMs
  - Typing indicators via Zulip API
  - Health endpoint on :9200
  - Exponential backoff reconnection
  - Graceful shutdown on SIGINT/SIGTERM
- abiba-zulip.service: systemd service unit file
- README.md: Updated deployment instructions
- package.json/tsconfig.json: Updated for standalone app

Deploy: npm install -> npx tsc -> systemctl enable abiba-zulip
Closes issue #24 (Hermes parity for pi)
This commit is contained in:
root
2026-06-27 19:03:43 +00:00
committed by Abiba (pi)
parent 2301f4aab9
commit e946818375
6 changed files with 565 additions and 2543 deletions
+71
View File
@@ -0,0 +1,71 @@
# Abiba Zulip Gateway — Standalone Service
**Replaces** the old pi extension (`~/.pi/agent/extensions/zulip/`).
Instead of injecting messages into pi's session (which dies when pi exits), this
runs as an independent Node.js **systemd service** that:
- Polls Zulip event queue for DMs
- Calls the harness inference API directly (no pi dependency)
- Maintains per-sender conversation memory
- Survives pi shutdown and restart
## Architecture
```
Zulip event queue → poll every 3s → DM detected
→ send typing indicator + placeholder
→ POST /v1/chat/completions with conversation history
→ edit placeholder with final response
```
## Requirements
- Node.js 22+
- `npm install` in this directory
## Config
All config via environment variables. Copy `abiba-zulip.service` to set up as a
systemd service, or run directly:
```bash
ZULIP_EMAIL=abiba-bot@chat.sysloggh.net \
ZULIP_API_KEY=your_key \
ZULIP_SITE=https://chat.sysloggh.net \
HARNESS_URL=http://192.168.68.116/v1/chat/completions \
HARNESS_API_KEY=sk-xxx \
HARNESS_MODEL=qwen3.6-35B-A3B \
node dist/index.js
```
## Deploy as a service
```bash
# 1. Install deps
cd /opt/abiba-zulip
npm install
# 2. Build
npx tsc
# 3. Install systemd service
cp abiba-zulip.service /etc/systemd/system/
systemctl daemon-reload
systemctl enable abiba-zulip
systemctl start abiba-zulip
# 4. Check status
systemctl status abiba-zulip
journalctl -u abiba-zulip -f
# 5. Health check
curl http://127.0.0.1:9200/health
```
## Development
```bash
npm run dev # watch mode (tsc watch)
npm run build # compile
npm start # run compiled
```
+48
View File
@@ -0,0 +1,48 @@
[Unit]
Description=Abiba Zulip Gateway Service — Standalone Zulip bot for pi agent
Documentation=https://git.sysloggh.net/SyslogSolution/zulip-platform-plugins
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=root
WorkingDirectory=/opt/abiba-zulip
# ── Zulip credentials ─────────────────────────────────────────────────────
Environment=ZULIP_EMAIL=abiba-bot@chat.sysloggh.net
Environment=ZULIP_API_KEY=cKTDMZAPW08dk3zl05sStzO7HRztzyn8
Environment=ZULIP_SITE=https://chat.sysloggh.net
# ── Agent identity ─────────────────────────────────────────────────────────
Environment=AGENT_NAME=abiba
Environment=AGENT_OWNER_EMAIL=jerome@sysloggh.com
# ── Harness API (inference) ────────────────────────────────────────────────
Environment=HARNESS_URL=http://192.168.68.116/v1/chat/completions
Environment=HARNESS_API_KEY=sk-856ffb0bbb-e5aaf78b10054eca608f8fbcbd73a889
Environment=HARNESS_MODEL=qwen3.6-35B-A3B
Environment=HARNESS_MAX_TOKENS=4096
# ── Service config ─────────────────────────────────────────────────────────
Environment=HEALTH_PORT=9200
Environment=POLL_INTERVAL_MS=3000
Environment=MAX_RETRIES=5
Environment=RETRY_DELAY_MS=5000
ExecStart=/usr/bin/node /opt/abiba-zulip/dist/index.js
Restart=always
RestartSec=5
# Logging
StandardOutput=journal
StandardError=journal
# Security hardening (optional — adjust as needed)
NoNewPrivileges=true
ProtectHome=read-only
ProtectSystem=full
PrivateTmp=true
[Install]
WantedBy=multi-user.target
+17 -1975
View File
File diff suppressed because it is too large Load Diff
+9 -18
View File
@@ -1,28 +1,19 @@
{
"name": "pi-zulip-extension",
"version": "0.1.0",
"description": "pi extension for Zulip agent communication — connects Abiba to the Sysloggh agent mesh",
"main": "src/index.ts",
"name": "abiba-zulip-service",
"version": "2.0.0",
"description": "Standalone Zulip gateway service for Abiba (pi agent). Direct harness API, conversation memory, systemd service.",
"type": "module",
"main": "dist/index.js",
"scripts": {
"build": "tsc",
"check": "tsc --noEmit"
"start": "node dist/index.js",
"dev": "node --watch dist/index.js"
},
"dependencies": {
"yaml": "^2.9.0",
"zulip-js": "^2.0.0"
},
"devDependencies": {
"@earendil-works/pi-coding-agent": "^0.80.2",
"typescript": "^5.0.0"
},
"keywords": [
"pi",
"zulip",
"agent",
"abiba",
"sysloggh"
],
"license": "UNLICENSED",
"private": true
"@types/node": "^22.0.0",
"typescript": "^5.7.0"
}
}
File diff suppressed because it is too large Load Diff
+11 -7
View File
@@ -1,14 +1,18 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"module": "ES2022",
"moduleResolution": "node",
"outDir": "./dist",
"rootDir": "./src",
"strict": false,
"esModuleInterop": true,
"outDir": "dist",
"rootDir": "src",
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"declaration": true,
"skipLibCheck": true
"declarationMap": true,
"sourceMap": true
},
"include": ["src/**/*.ts"]
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}