mortgram-hook 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,43 @@
1
+ ---
2
+ name: mortgram-observer
3
+ description: "Stream agent events to MORTGRAM dashboard in real-time"
4
+ homepage: https://mortgram.com
5
+ metadata:
6
+ {
7
+ "openclaw":
8
+ {
9
+ "emoji": "👻",
10
+ "events": ["agent:thought", "agent:reasoning", "agent:response", "agent:message", "agent:error", "agent:start", "agent:end", "tool:call", "tool:result", "tool:error", "session:usage", "session:cost", "session:start", "session:end"],
11
+ },
12
+ }
13
+ ---
14
+
15
+ # MORTGRAM Ghost Bridge
16
+
17
+ Invisible observability hook for OpenClaw agents. Streams thoughts, tool calls, errors, and cost data to your MORTGRAM dashboard in real-time.
18
+
19
+ ## What It Does
20
+
21
+ Every time your agent thinks, calls a tool, or completes a session:
22
+
23
+ 1. **Captures event** — Intercepts agent thoughts, tool calls, errors, and usage data
24
+ 2. **Streams to MORTGRAM** — POSTs event data to the MORTGRAM ingest API
25
+ 3. **Silent operation** — Zero performance impact, silent failure on network issues
26
+
27
+ ## Requirements
28
+
29
+ Environment variable `MORTGRAM_API_KEY` must be set to your MORTGRAM API key from the dashboard.
30
+
31
+ ## Configuration
32
+
33
+ Set the following environment variables:
34
+
35
+ - `MORTGRAM_API_KEY` — Your MORTGRAM API key (required)
36
+ - `MORTGRAM_API_URL` — API endpoint (default: `https://mortgram.com/api/ingest`)
37
+ - `MG_AGENT_ID` — Agent identifier (default: `ghost-agent`)
38
+
39
+ ## Disabling
40
+
41
+ ```bash
42
+ openclaw hooks disable mortgram-observer
43
+ ```
@@ -0,0 +1,135 @@
1
+ // ═══════════════════════════════════════════════════════
2
+ // MORTGRAM Ghost Bridge — Native OpenClaw Hook
3
+ // ═══════════════════════════════════════════════════════
4
+ // Installed via: openclaw hooks install mortgram-hook
5
+ // Zero-touch observability: no wrapper, no config, no friction.
6
+ //
7
+ // Environment Variables Required:
8
+ // MORTGRAM_API_KEY — Your MORTGRAM API key (from dashboard)
9
+ // MORTGRAM_API_URL — API endpoint (defaults to https://mortgram.com/api/ingest)
10
+ // MG_AGENT_ID — Agent identifier (defaults to "ghost-agent")
11
+ // ═══════════════════════════════════════════════════════
12
+
13
+ export const name = "mortgram-observer";
14
+
15
+ // Track session state for efficiency calculation
16
+ let totalTurns = 0;
17
+ let successfulTools = 0;
18
+ let latestThought = "Ghost Bridge Active";
19
+ let dailyCost = 0;
20
+
21
+ const API_KEY = process.env.MORTGRAM_API_KEY || process.env.MG_LIVE_KEY || "";
22
+ const API_URL = process.env.MORTGRAM_API_URL || "https://mortgram.com/api/ingest";
23
+ const AGENT_ID = process.env.MG_AGENT_ID || "ghost-agent";
24
+
25
+ // Silently POST to the MORTGRAM ingest endpoint
26
+ async function send(type, content, metadata = {}) {
27
+ if (!API_KEY) return;
28
+
29
+ try {
30
+ await fetch(API_URL, {
31
+ method: "POST",
32
+ headers: {
33
+ "Content-Type": "application/json",
34
+ "x-mortgram-token": API_KEY
35
+ },
36
+ body: JSON.stringify({
37
+ agent_id: AGENT_ID,
38
+ type,
39
+ content,
40
+ metadata: {
41
+ ...metadata,
42
+ daily_cost: dailyCost,
43
+ efficiency: totalTurns > 0 ? (successfulTools / totalTurns) : 0,
44
+ latest_thought: latestThought,
45
+ status: "online",
46
+ timestamp: new Date().toISOString()
47
+ }
48
+ })
49
+ });
50
+ } catch (_) {
51
+ // Silent fail — never disrupt the agent
52
+ }
53
+ }
54
+
55
+ // ─── The Main Event Handler ───
56
+ // OpenClaw fires events for every lifecycle step.
57
+ // We intercept them invisibly and stream to MORTGRAM.
58
+ export async function onEvent({ event, data }) {
59
+ switch (event) {
60
+ // ── Agent Thought / Reasoning ──
61
+ case "agent:thought":
62
+ case "agent:reasoning":
63
+ totalTurns++;
64
+ latestThought = data?.text || data?.content || "Thinking...";
65
+ await send("thought", latestThought, { event });
66
+ break;
67
+
68
+ // ── Tool Calls (Actions) ──
69
+ case "tool:call":
70
+ case "tool:result":
71
+ successfulTools++;
72
+ await send("action", data?.name || data?.tool || "Tool Call", {
73
+ event,
74
+ tool: data?.name,
75
+ args: data?.args
76
+ });
77
+ break;
78
+
79
+ // ── Errors ──
80
+ case "agent:error":
81
+ case "tool:error":
82
+ if (successfulTools > 0) successfulTools--;
83
+ await send("error", data?.message || data?.text || "Error occurred", {
84
+ event,
85
+ stack: data?.stack
86
+ });
87
+ break;
88
+
89
+ // ── Session Usage / Cost ──
90
+ case "session:usage":
91
+ case "session:cost":
92
+ dailyCost = data?.total_cost || data?.cost || dailyCost;
93
+ await send("cost_update", `Daily spend: $${dailyCost.toFixed(4)}`, {
94
+ event,
95
+ daily_cost: dailyCost,
96
+ tokens: data?.tokens
97
+ });
98
+ break;
99
+
100
+ // ── Session Start ──
101
+ case "session:start":
102
+ case "agent:start":
103
+ totalTurns = 0;
104
+ successfulTools = 0;
105
+ dailyCost = 0;
106
+ latestThought = "Session started";
107
+ await send("system", "Ghost Bridge: Session started", {
108
+ event,
109
+ status: "online"
110
+ });
111
+ break;
112
+
113
+ // ── Session End ──
114
+ case "session:end":
115
+ case "agent:end":
116
+ await send("system", "Ghost Bridge: Session ended", {
117
+ event,
118
+ status: "offline",
119
+ final_cost: dailyCost,
120
+ final_efficiency: totalTurns > 0 ? (successfulTools / totalTurns) : 0
121
+ });
122
+ break;
123
+
124
+ // ── Agent Response / Output ──
125
+ case "agent:response":
126
+ case "agent:message":
127
+ latestThought = data?.text?.slice(0, 200) || "Response generated";
128
+ await send("thought", latestThought, { event });
129
+ break;
130
+
131
+ default:
132
+ // Skip unrecognized events silently
133
+ break;
134
+ }
135
+ }
package/package.json CHANGED
@@ -1,9 +1,13 @@
1
1
  {
2
2
  "name": "mortgram-hook",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "MORTGRAM Ghost Bridge — Invisible observability for OpenClaw agents",
5
- "main": "index.mjs",
6
5
  "type": "module",
6
+ "openclaw": {
7
+ "hooks": [
8
+ "./mortgram-observer"
9
+ ]
10
+ },
7
11
  "keywords": [
8
12
  "openclaw",
9
13
  "mortgram",