@lumin-io/openclaw-diagnostics 0.1.0
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.
- package/dist/index.d.ts +48 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +384 -0
- package/dist/index.js.map +1 -0
- package/openclaw.plugin.json +32 -0
- package/package.json +45 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @lumin-io/openclaw-diagnostics — Lumin's deepest hook into OpenClaw.
|
|
3
|
+
*
|
|
4
|
+
* Two related but separate APIs in OpenClaw observe a model call:
|
|
5
|
+
*
|
|
6
|
+
* 1. `internalDiagnostics.onEvent` — the bus the bundled
|
|
7
|
+
* `@openclaw/diagnostics-otel` plugin reads. Carries timing,
|
|
8
|
+
* sizes, and provider IDs but the runtime never populates the
|
|
9
|
+
* `inputMessages` / `outputMessages` fields the OTel exporter
|
|
10
|
+
* tries to read, so the diagnostics-otel content-capture flag
|
|
11
|
+
* is effectively non-functional in 2026.5.x. Fixing that needs
|
|
12
|
+
* an upstream PR; meanwhile we route around it.
|
|
13
|
+
*
|
|
14
|
+
* 2. **Typed hooks** (`llm_input`, `llm_output`) — the registration
|
|
15
|
+
* surface used by trusted plugins. These DO carry full content
|
|
16
|
+
* (`prompt`, `historyMessages`, `systemPrompt`, `assistantTexts`,
|
|
17
|
+
* `usage`) at runtime, which is exactly what an observability
|
|
18
|
+
* tool needs.
|
|
19
|
+
*
|
|
20
|
+
* This plugin uses (2). On every llm_input / llm_output we build a
|
|
21
|
+
* Lumin SpanInput and POST to `/v1/spans`. The agent never blocks on
|
|
22
|
+
* us — failures are swallowed and budgeted with a short timeout.
|
|
23
|
+
*
|
|
24
|
+
* Activation prerequisite: non-bundled plugins must opt into
|
|
25
|
+
* conversation access, so the operator's openclaw.json must contain
|
|
26
|
+
*
|
|
27
|
+
* "plugins": {
|
|
28
|
+
* "entries": {
|
|
29
|
+
* "lumin-diagnostics": {
|
|
30
|
+
* "hooks": { "allowConversationAccess": true }
|
|
31
|
+
* }
|
|
32
|
+
* }
|
|
33
|
+
* }
|
|
34
|
+
*
|
|
35
|
+
* The plugin's install step writes that for the operator; if it's
|
|
36
|
+
* missing, OpenClaw silently drops the hook registration and we
|
|
37
|
+
* never see content. The plugin warns once at startup if the flag
|
|
38
|
+
* isn't set so the misconfiguration surfaces immediately.
|
|
39
|
+
*/
|
|
40
|
+
declare const _default: {
|
|
41
|
+
id: string;
|
|
42
|
+
name: string;
|
|
43
|
+
description: string;
|
|
44
|
+
configSchema: import("openclaw/plugin-sdk/plugin-entry").OpenClawPluginConfigSchema;
|
|
45
|
+
register: NonNullable<import("openclaw/plugin-sdk/plugin-entry").OpenClawPluginDefinition["register"]>;
|
|
46
|
+
} & Pick<import("openclaw/plugin-sdk/plugin-entry").OpenClawPluginDefinition, "kind" | "reload" | "nodeHostCommands" | "securityAuditCollectors">;
|
|
47
|
+
export default _default;
|
|
48
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;;;;;;;;AAwWH,wBA2GG"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @lumin-io/openclaw-diagnostics — Lumin's deepest hook into OpenClaw.
|
|
3
|
+
*
|
|
4
|
+
* Two related but separate APIs in OpenClaw observe a model call:
|
|
5
|
+
*
|
|
6
|
+
* 1. `internalDiagnostics.onEvent` — the bus the bundled
|
|
7
|
+
* `@openclaw/diagnostics-otel` plugin reads. Carries timing,
|
|
8
|
+
* sizes, and provider IDs but the runtime never populates the
|
|
9
|
+
* `inputMessages` / `outputMessages` fields the OTel exporter
|
|
10
|
+
* tries to read, so the diagnostics-otel content-capture flag
|
|
11
|
+
* is effectively non-functional in 2026.5.x. Fixing that needs
|
|
12
|
+
* an upstream PR; meanwhile we route around it.
|
|
13
|
+
*
|
|
14
|
+
* 2. **Typed hooks** (`llm_input`, `llm_output`) — the registration
|
|
15
|
+
* surface used by trusted plugins. These DO carry full content
|
|
16
|
+
* (`prompt`, `historyMessages`, `systemPrompt`, `assistantTexts`,
|
|
17
|
+
* `usage`) at runtime, which is exactly what an observability
|
|
18
|
+
* tool needs.
|
|
19
|
+
*
|
|
20
|
+
* This plugin uses (2). On every llm_input / llm_output we build a
|
|
21
|
+
* Lumin SpanInput and POST to `/v1/spans`. The agent never blocks on
|
|
22
|
+
* us — failures are swallowed and budgeted with a short timeout.
|
|
23
|
+
*
|
|
24
|
+
* Activation prerequisite: non-bundled plugins must opt into
|
|
25
|
+
* conversation access, so the operator's openclaw.json must contain
|
|
26
|
+
*
|
|
27
|
+
* "plugins": {
|
|
28
|
+
* "entries": {
|
|
29
|
+
* "lumin-diagnostics": {
|
|
30
|
+
* "hooks": { "allowConversationAccess": true }
|
|
31
|
+
* }
|
|
32
|
+
* }
|
|
33
|
+
* }
|
|
34
|
+
*
|
|
35
|
+
* The plugin's install step writes that for the operator; if it's
|
|
36
|
+
* missing, OpenClaw silently drops the hook registration and we
|
|
37
|
+
* never see content. The plugin warns once at startup if the flag
|
|
38
|
+
* isn't set so the misconfiguration surfaces immediately.
|
|
39
|
+
*/
|
|
40
|
+
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
|
|
41
|
+
const DEFAULT_HOST = "http://localhost:8000";
|
|
42
|
+
const DEFAULT_PROJECT = "openclaw";
|
|
43
|
+
const DEFAULT_MAX_CONTENT_CHARS = 32_768;
|
|
44
|
+
const DEFAULT_TIMEOUT_MS = 5_000;
|
|
45
|
+
// ----- helpers ------------------------------------------------------------
|
|
46
|
+
function stringify(value, maxLen) {
|
|
47
|
+
if (value === null || value === undefined)
|
|
48
|
+
return undefined;
|
|
49
|
+
let s;
|
|
50
|
+
if (typeof value === "string") {
|
|
51
|
+
s = value;
|
|
52
|
+
}
|
|
53
|
+
else if (Array.isArray(value)) {
|
|
54
|
+
s = value
|
|
55
|
+
.map((v) => (typeof v === "string" ? v : safeJsonStringify(v)))
|
|
56
|
+
.join("\n");
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
s = safeJsonStringify(value);
|
|
60
|
+
}
|
|
61
|
+
if (s.length <= maxLen)
|
|
62
|
+
return s;
|
|
63
|
+
return s.slice(0, maxLen - 16) + "…(truncated)";
|
|
64
|
+
}
|
|
65
|
+
function safeJsonStringify(v) {
|
|
66
|
+
try {
|
|
67
|
+
const out = JSON.stringify(v);
|
|
68
|
+
return out === undefined ? String(v) : out;
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return String(v);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Format an OpenClaw 32-hex traceId / 16-hex spanId as a UUID so it
|
|
76
|
+
* collides with the trace_id schema Lumin already uses for OTLP-
|
|
77
|
+
* ingested spans. Also pads / hashes a fallback so we always get a
|
|
78
|
+
* deterministic 32-hex ID even when the hook runs without a trace
|
|
79
|
+
* scope.
|
|
80
|
+
*/
|
|
81
|
+
function asUuid(hex, fallback) {
|
|
82
|
+
const h = (hex || "").toLowerCase().replace(/[^0-9a-f]/g, "");
|
|
83
|
+
const padded = h.length >= 32 ? h.slice(0, 32) : h.padStart(32, "0");
|
|
84
|
+
if (!padded || /^0+$/.test(padded)) {
|
|
85
|
+
const fp = fnv1a64(fallback).padStart(32, "0").slice(-32);
|
|
86
|
+
return uuidify(fp);
|
|
87
|
+
}
|
|
88
|
+
return uuidify(padded);
|
|
89
|
+
}
|
|
90
|
+
function uuidify(hex32) {
|
|
91
|
+
return `${hex32.slice(0, 8)}-${hex32.slice(8, 12)}-${hex32.slice(12, 16)}-${hex32.slice(16, 20)}-${hex32.slice(20, 32)}`;
|
|
92
|
+
}
|
|
93
|
+
function fnv1a64(s) {
|
|
94
|
+
let h = 0x811c9dc5;
|
|
95
|
+
for (let i = 0; i < s.length; i++) {
|
|
96
|
+
h ^= s.charCodeAt(i);
|
|
97
|
+
h = Math.imul(h, 0x01000193) >>> 0;
|
|
98
|
+
}
|
|
99
|
+
let h2 = 0xcbf29ce4;
|
|
100
|
+
for (let i = s.length - 1; i >= 0; i--) {
|
|
101
|
+
h2 ^= s.charCodeAt(i);
|
|
102
|
+
h2 = Math.imul(h2, 0x01000193) >>> 0;
|
|
103
|
+
}
|
|
104
|
+
return h.toString(16).padStart(8, "0") + h2.toString(16).padStart(8, "0");
|
|
105
|
+
}
|
|
106
|
+
function nowIso() {
|
|
107
|
+
return new Date().toISOString().replace("Z", "000Z");
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Walk an OpenClaw assistant message's content blocks and concatenate
|
|
111
|
+
* any ``{type: "thinking", thinking: "..."}`` payloads. Reasoning
|
|
112
|
+
* models attach these BEFORE the visible text, but
|
|
113
|
+
* ``assistantTexts`` strips them. Returning undefined means "no
|
|
114
|
+
* thinking blocks present" — the caller should leave the metadata
|
|
115
|
+
* field absent rather than write an empty string.
|
|
116
|
+
*
|
|
117
|
+
* Defensive: lastAssistant is typed as ``unknown`` and provider
|
|
118
|
+
* shapes drift, so every step type-checks before recursing.
|
|
119
|
+
*/
|
|
120
|
+
function extractThinkingFromAssistant(lastAssistant) {
|
|
121
|
+
if (!lastAssistant || typeof lastAssistant !== "object")
|
|
122
|
+
return undefined;
|
|
123
|
+
const content = lastAssistant.content;
|
|
124
|
+
if (!Array.isArray(content))
|
|
125
|
+
return undefined;
|
|
126
|
+
const parts = [];
|
|
127
|
+
for (const block of content) {
|
|
128
|
+
if (!block || typeof block !== "object")
|
|
129
|
+
continue;
|
|
130
|
+
const b = block;
|
|
131
|
+
if (b.type === "thinking" && typeof b.thinking === "string" && b.thinking.length > 0) {
|
|
132
|
+
parts.push(b.thinking);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return parts.length > 0 ? parts.join("\n\n") : undefined;
|
|
136
|
+
}
|
|
137
|
+
// ----- transport ----------------------------------------------------------
|
|
138
|
+
class LuminClient {
|
|
139
|
+
host;
|
|
140
|
+
project;
|
|
141
|
+
timeoutMs;
|
|
142
|
+
failureLogged = false;
|
|
143
|
+
constructor(cfg) {
|
|
144
|
+
this.host = (cfg.host || process.env.LUMIN_HOST || DEFAULT_HOST).replace(/\/+$/, "");
|
|
145
|
+
this.project = cfg.project || DEFAULT_PROJECT;
|
|
146
|
+
this.timeoutMs = cfg.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Fire-and-forget POST. Rule 7 generalized: a Lumin outage must
|
|
150
|
+
* never affect the agent. The first failure logs once; subsequent
|
|
151
|
+
* failures are silenced.
|
|
152
|
+
*/
|
|
153
|
+
async send(span) {
|
|
154
|
+
const body = JSON.stringify({ spans: [span] });
|
|
155
|
+
const ctrl = new AbortController();
|
|
156
|
+
const timer = setTimeout(() => ctrl.abort(), this.timeoutMs);
|
|
157
|
+
try {
|
|
158
|
+
const resp = await fetch(`${this.host}/v1/spans`, {
|
|
159
|
+
method: "POST",
|
|
160
|
+
headers: {
|
|
161
|
+
"Content-Type": "application/json",
|
|
162
|
+
"X-Lumin-Project": this.project,
|
|
163
|
+
},
|
|
164
|
+
body,
|
|
165
|
+
signal: ctrl.signal,
|
|
166
|
+
});
|
|
167
|
+
if (!resp.ok && !this.failureLogged) {
|
|
168
|
+
// eslint-disable-next-line no-console
|
|
169
|
+
console.warn(`[lumin-diagnostics] Lumin returned ${resp.status} ${resp.statusText} — further failures suppressed`);
|
|
170
|
+
this.failureLogged = true;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
catch (err) {
|
|
174
|
+
if (!this.failureLogged) {
|
|
175
|
+
// eslint-disable-next-line no-console
|
|
176
|
+
console.warn(`[lumin-diagnostics] Could not reach Lumin at ${this.host}/v1/spans (${err.message}). Further failures suppressed.`);
|
|
177
|
+
this.failureLogged = true;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
finally {
|
|
181
|
+
clearTimeout(timer);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
const PENDING_TTL_MS = 5 * 60 * 1000;
|
|
186
|
+
class PendingLlmRegistry {
|
|
187
|
+
byRunId = new Map();
|
|
188
|
+
cleanupHandle;
|
|
189
|
+
set(runId, entry) {
|
|
190
|
+
this.byRunId.set(runId, entry);
|
|
191
|
+
this.scheduleSweep();
|
|
192
|
+
}
|
|
193
|
+
take(runId) {
|
|
194
|
+
const v = this.byRunId.get(runId);
|
|
195
|
+
if (v)
|
|
196
|
+
this.byRunId.delete(runId);
|
|
197
|
+
return v;
|
|
198
|
+
}
|
|
199
|
+
size() {
|
|
200
|
+
return this.byRunId.size;
|
|
201
|
+
}
|
|
202
|
+
scheduleSweep() {
|
|
203
|
+
if (this.cleanupHandle)
|
|
204
|
+
return;
|
|
205
|
+
this.cleanupHandle = setTimeout(() => {
|
|
206
|
+
this.cleanupHandle = undefined;
|
|
207
|
+
const now = Date.now();
|
|
208
|
+
for (const [k, v] of this.byRunId) {
|
|
209
|
+
if (now - v.startedAtMs > PENDING_TTL_MS)
|
|
210
|
+
this.byRunId.delete(k);
|
|
211
|
+
}
|
|
212
|
+
if (this.byRunId.size > 0)
|
|
213
|
+
this.scheduleSweep();
|
|
214
|
+
}, PENDING_TTL_MS);
|
|
215
|
+
// unref so a sweeper doesn't keep the gateway process alive
|
|
216
|
+
if (typeof this.cleanupHandle === "object" && this.cleanupHandle && "unref" in this.cleanupHandle) {
|
|
217
|
+
this.cleanupHandle.unref?.();
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
// ----- per-event translators ---------------------------------------------
|
|
222
|
+
function buildSpanFromPair(runId, pending, output, cfg, hookCtx) {
|
|
223
|
+
const maxLen = cfg.maxContentChars ?? DEFAULT_MAX_CONTENT_CHARS;
|
|
224
|
+
const trace = hookCtx?.trace || pending.trace;
|
|
225
|
+
const traceId = asUuid(trace?.traceId, runId);
|
|
226
|
+
const spanId = asUuid(trace?.spanId, `${runId}:llm`);
|
|
227
|
+
const parentId = trace?.parentSpanId
|
|
228
|
+
? asUuid(trace.parentSpanId, runId)
|
|
229
|
+
: undefined;
|
|
230
|
+
const usage = output.usage || {};
|
|
231
|
+
const outputText = output.assistantTexts && output.assistantTexts.length
|
|
232
|
+
? output.assistantTexts.join("\n")
|
|
233
|
+
: (output.lastAssistant !== undefined ? safeJsonStringify(output.lastAssistant) : undefined);
|
|
234
|
+
// Reasoning models (gpt-oss, claude-extended-thinking, o-series) emit
|
|
235
|
+
// ``{type: "thinking", thinking: "..."}`` blocks under
|
|
236
|
+
// ``lastAssistant.content`` BEFORE the visible text. ``assistantTexts``
|
|
237
|
+
// strips those out — fine for the operator-facing output, but we
|
|
238
|
+
// lose the reasoning trace entirely. Pull thinking out separately
|
|
239
|
+
// and surface it as a metadata field so operators can see WHY the
|
|
240
|
+
// model answered the way it did. Defensive parse: lastAssistant is
|
|
241
|
+
// typed as unknown by the public hook contract, so we check before
|
|
242
|
+
// walking it.
|
|
243
|
+
const thinkingText = extractThinkingFromAssistant(output.lastAssistant);
|
|
244
|
+
return {
|
|
245
|
+
id: spanId,
|
|
246
|
+
trace_id: traceId,
|
|
247
|
+
parent_span_id: parentId,
|
|
248
|
+
name: "openclaw.llm",
|
|
249
|
+
type: "llm",
|
|
250
|
+
started_at: pending.startedAt,
|
|
251
|
+
ended_at: nowIso(),
|
|
252
|
+
status: "ok",
|
|
253
|
+
model: output.model,
|
|
254
|
+
provider: output.provider,
|
|
255
|
+
tokens_input: usage.input,
|
|
256
|
+
tokens_output: usage.output,
|
|
257
|
+
input: pending.input,
|
|
258
|
+
output: outputText ? stringify(outputText, maxLen) : undefined,
|
|
259
|
+
session_id: output.sessionId || hookCtx?.sessionId,
|
|
260
|
+
metadata: {
|
|
261
|
+
"openclaw.runId": runId,
|
|
262
|
+
"openclaw.harnessId": output.harnessId,
|
|
263
|
+
"openclaw.resolvedRef": output.resolvedRef,
|
|
264
|
+
"openclaw.images_count": pending.imagesCount,
|
|
265
|
+
// Lightweight summary of what was replayed to the model, so an
|
|
266
|
+
// operator can see "this turn carried N prior messages and an
|
|
267
|
+
// M-character system prompt" without dragging the actual
|
|
268
|
+
// payload into the trace's input field.
|
|
269
|
+
"openclaw.history_message_count": pending.historyMessageCount,
|
|
270
|
+
"openclaw.system_prompt_chars": pending.systemPromptChars,
|
|
271
|
+
// Reasoning trace for models that emit thinking blocks. Always
|
|
272
|
+
// captured (no opt-in) because the whole point of an
|
|
273
|
+
// observability tool is to show WHY the agent answered the way
|
|
274
|
+
// it did — silently dropping the reasoning would defeat the
|
|
275
|
+
// purpose. Field is absent (not empty) when the model didn't
|
|
276
|
+
// emit thinking, so dashboard rendering can branch on
|
|
277
|
+
// presence rather than length.
|
|
278
|
+
...(thinkingText !== undefined
|
|
279
|
+
? {
|
|
280
|
+
"openclaw.content.thinking": stringify(thinkingText, maxLen),
|
|
281
|
+
"openclaw.thinking_chars": thinkingText.length,
|
|
282
|
+
}
|
|
283
|
+
: {}),
|
|
284
|
+
...(cfg.captureSystemPrompt && pending.systemPrompt
|
|
285
|
+
? { "openclaw.content.system_prompt": stringify(pending.systemPrompt, maxLen) }
|
|
286
|
+
: {}),
|
|
287
|
+
},
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
// ----- plugin entry -------------------------------------------------------
|
|
291
|
+
export default definePluginEntry({
|
|
292
|
+
id: "lumin-diagnostics",
|
|
293
|
+
name: "@lumin-io/openclaw-diagnostics",
|
|
294
|
+
description: "Streams full-fidelity OpenClaw runs (prompts, responses, tool I/O, tokens) to a local Lumin instance via /v1/spans.",
|
|
295
|
+
configSchema: {
|
|
296
|
+
type: "object",
|
|
297
|
+
properties: {
|
|
298
|
+
host: { type: "string" },
|
|
299
|
+
project: { type: "string" },
|
|
300
|
+
captureSystemPrompt: { type: "boolean" },
|
|
301
|
+
maxContentChars: { type: "number" },
|
|
302
|
+
timeoutMs: { type: "number" },
|
|
303
|
+
},
|
|
304
|
+
},
|
|
305
|
+
register: (api) => {
|
|
306
|
+
const apiAny = api;
|
|
307
|
+
const cfg = apiAny.pluginConfig || {};
|
|
308
|
+
const client = new LuminClient(cfg);
|
|
309
|
+
const pending = new PendingLlmRegistry();
|
|
310
|
+
const log = apiAny.logger;
|
|
311
|
+
if (typeof apiAny.on !== "function") {
|
|
312
|
+
// Older OpenClaw runtimes without typed-hook support won't
|
|
313
|
+
// expose `api.on`. Silently degrade: register nothing.
|
|
314
|
+
log?.warn?.("lumin-diagnostics: this OpenClaw build doesn't expose api.on for typed hooks; content capture disabled. Upgrade OpenClaw to >= 2026.5.x.");
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
apiAny.on("llm_input", (rawEvent, rawCtx) => {
|
|
318
|
+
try {
|
|
319
|
+
const event = rawEvent;
|
|
320
|
+
const ctx = rawCtx;
|
|
321
|
+
const maxLen = cfg.maxContentChars ?? DEFAULT_MAX_CONTENT_CHARS;
|
|
322
|
+
// The input is JUST the user prompt for this turn. We
|
|
323
|
+
// deliberately do NOT pack history / systemPrompt into the
|
|
324
|
+
// input field: a Lumin trace represents one LLM call, not
|
|
325
|
+
// a conversation. Embedding the full chat history every
|
|
326
|
+
// turn (a) bloats every trace by 10x+ as conversations
|
|
327
|
+
// grow, (b) makes the dashboard view feel like a chat log
|
|
328
|
+
// instead of an agent run, and (c) is redundant with
|
|
329
|
+
// sessions, which group turns under the same conversation
|
|
330
|
+
// already.
|
|
331
|
+
//
|
|
332
|
+
// Counts and lightweight summaries go into metadata so
|
|
333
|
+
// operators can still see "this turn replayed 9 prior
|
|
334
|
+
// history messages" without the full payload.
|
|
335
|
+
const historyCount = Array.isArray(event.historyMessages)
|
|
336
|
+
? event.historyMessages.length
|
|
337
|
+
: 0;
|
|
338
|
+
pending.set(event.runId, {
|
|
339
|
+
startedAt: nowIso(),
|
|
340
|
+
startedAtMs: Date.now(),
|
|
341
|
+
systemPrompt: event.systemPrompt,
|
|
342
|
+
systemPromptChars: typeof event.systemPrompt === "string"
|
|
343
|
+
? event.systemPrompt.length
|
|
344
|
+
: 0,
|
|
345
|
+
historyMessageCount: historyCount,
|
|
346
|
+
input: stringify(event.prompt, maxLen),
|
|
347
|
+
imagesCount: event.imagesCount,
|
|
348
|
+
trace: ctx?.trace,
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
catch (err) {
|
|
352
|
+
log?.warn?.(`lumin-diagnostics: llm_input handler failed: ${err.message}`);
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
apiAny.on("llm_output", (rawEvent, rawCtx) => {
|
|
356
|
+
try {
|
|
357
|
+
const event = rawEvent;
|
|
358
|
+
const ctx = rawCtx;
|
|
359
|
+
const entry = pending.take(event.runId);
|
|
360
|
+
if (!entry) {
|
|
361
|
+
// No matching llm_input. Either the input hook dropped
|
|
362
|
+
// (e.g. raw model run path) or this is a fresh restart
|
|
363
|
+
// catching the tail of an in-flight run. Emit anyway —
|
|
364
|
+
// the operator still gets the assistant output.
|
|
365
|
+
const fallback = {
|
|
366
|
+
startedAt: nowIso(),
|
|
367
|
+
startedAtMs: Date.now(),
|
|
368
|
+
trace: ctx?.trace,
|
|
369
|
+
};
|
|
370
|
+
const span = buildSpanFromPair(event.runId, fallback, event, cfg, ctx);
|
|
371
|
+
void client.send(span).catch(() => { });
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
const span = buildSpanFromPair(event.runId, entry, event, cfg, ctx);
|
|
375
|
+
void client.send(span).catch(() => { });
|
|
376
|
+
}
|
|
377
|
+
catch (err) {
|
|
378
|
+
log?.warn?.(`lumin-diagnostics: llm_output handler failed: ${err.message}`);
|
|
379
|
+
}
|
|
380
|
+
});
|
|
381
|
+
log?.info?.(`lumin-diagnostics: subscribed to llm_input + llm_output → ${cfg.host || process.env.LUMIN_HOST || DEFAULT_HOST}/v1/spans (project=${cfg.project || DEFAULT_PROJECT})`);
|
|
382
|
+
},
|
|
383
|
+
});
|
|
384
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "lumin-diagnostics",
|
|
3
|
+
"activation": {
|
|
4
|
+
"onStartup": true
|
|
5
|
+
},
|
|
6
|
+
"configSchema": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"properties": {
|
|
10
|
+
"host": {
|
|
11
|
+
"type": "string",
|
|
12
|
+
"description": "Lumin API base URL. Defaults to LUMIN_HOST env or http://localhost:8000."
|
|
13
|
+
},
|
|
14
|
+
"project": {
|
|
15
|
+
"type": "string",
|
|
16
|
+
"description": "Lumin project label sent as X-Lumin-Project. Defaults to 'openclaw'."
|
|
17
|
+
},
|
|
18
|
+
"captureSystemPrompt": {
|
|
19
|
+
"type": "boolean",
|
|
20
|
+
"description": "Whether to capture the system prompt text on each model.call. Default false (system prompts are usually large and rarely actionable)."
|
|
21
|
+
},
|
|
22
|
+
"maxContentChars": {
|
|
23
|
+
"type": "number",
|
|
24
|
+
"description": "Cap on per-attribute content size in characters. Defaults to 32768. Truncated values are tagged '...(truncated)'."
|
|
25
|
+
},
|
|
26
|
+
"timeoutMs": {
|
|
27
|
+
"type": "number",
|
|
28
|
+
"description": "HTTP timeout for POST /v1/spans, milliseconds. Default 5000."
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lumin-io/openclaw-diagnostics",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Full-fidelity Lumin observability for OpenClaw — captures prompts, responses, tool I/O via OpenClaw's DiagnosticEvent bus (no privacy filter).",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"openclaw.plugin.json",
|
|
18
|
+
"README.md"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsc",
|
|
22
|
+
"test": "vitest run"
|
|
23
|
+
},
|
|
24
|
+
"peerDependencies": {
|
|
25
|
+
"openclaw": ">=2026.4.25"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@types/node": "^20.0.0",
|
|
29
|
+
"typescript": "^5.3.0",
|
|
30
|
+
"vitest": "^2.1.9"
|
|
31
|
+
},
|
|
32
|
+
"openclaw": {
|
|
33
|
+
"extensions": [
|
|
34
|
+
"./dist/index.js"
|
|
35
|
+
],
|
|
36
|
+
"install": {
|
|
37
|
+
"npmSpec": "@lumin-io/openclaw-diagnostics",
|
|
38
|
+
"defaultChoice": "npm",
|
|
39
|
+
"minHostVersion": ">=2026.4.25"
|
|
40
|
+
},
|
|
41
|
+
"compat": {
|
|
42
|
+
"pluginApi": ">=2026.5.4"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|