@feeble/blay-openclaw-plugin 0.1.17

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.
Files changed (79) hide show
  1. package/README.md +24 -0
  2. package/dist/channel/abort.d.ts +11 -0
  3. package/dist/channel/abort.js +20 -0
  4. package/dist/channel/abort.js.map +1 -0
  5. package/dist/channel/inbound.d.ts +53 -0
  6. package/dist/channel/inbound.js +384 -0
  7. package/dist/channel/inbound.js.map +1 -0
  8. package/dist/channel/plugin.d.ts +25 -0
  9. package/dist/channel/plugin.js +291 -0
  10. package/dist/channel/plugin.js.map +1 -0
  11. package/dist/channel/run-tracker.d.ts +54 -0
  12. package/dist/channel/run-tracker.js +137 -0
  13. package/dist/channel/run-tracker.js.map +1 -0
  14. package/dist/channel/runtime.d.ts +8 -0
  15. package/dist/channel/runtime.js +16 -0
  16. package/dist/channel/runtime.js.map +1 -0
  17. package/dist/channel/sse-client.d.ts +54 -0
  18. package/dist/channel/sse-client.js +154 -0
  19. package/dist/channel/sse-client.js.map +1 -0
  20. package/dist/channel/state.d.ts +6 -0
  21. package/dist/channel/state.js +11 -0
  22. package/dist/channel/state.js.map +1 -0
  23. package/dist/client.d.ts +23 -0
  24. package/dist/client.js +98 -0
  25. package/dist/client.js.map +1 -0
  26. package/dist/index.d.ts +16 -0
  27. package/dist/index.js +228 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/telemetry/pusher.d.ts +71 -0
  30. package/dist/telemetry/pusher.js +461 -0
  31. package/dist/telemetry/pusher.js.map +1 -0
  32. package/dist/telemetry/usage-collector.d.ts +39 -0
  33. package/dist/telemetry/usage-collector.js +60 -0
  34. package/dist/telemetry/usage-collector.js.map +1 -0
  35. package/dist/tools/action-items.d.ts +60 -0
  36. package/dist/tools/action-items.js +101 -0
  37. package/dist/tools/action-items.js.map +1 -0
  38. package/dist/tools/briefing.d.ts +15 -0
  39. package/dist/tools/briefing.js +138 -0
  40. package/dist/tools/briefing.js.map +1 -0
  41. package/dist/tools/comments.d.ts +43 -0
  42. package/dist/tools/comments.js +79 -0
  43. package/dist/tools/comments.js.map +1 -0
  44. package/dist/tools/context.d.ts +20 -0
  45. package/dist/tools/context.js +31 -0
  46. package/dist/tools/context.js.map +1 -0
  47. package/dist/tools/instrumentation.d.ts +19 -0
  48. package/dist/tools/instrumentation.js +84 -0
  49. package/dist/tools/instrumentation.js.map +1 -0
  50. package/dist/tools/notifications.d.ts +29 -0
  51. package/dist/tools/notifications.js +57 -0
  52. package/dist/tools/notifications.js.map +1 -0
  53. package/dist/tools/org.d.ts +12 -0
  54. package/dist/tools/org.js +31 -0
  55. package/dist/tools/org.js.map +1 -0
  56. package/dist/tools/projects.d.ts +73 -0
  57. package/dist/tools/projects.js +121 -0
  58. package/dist/tools/projects.js.map +1 -0
  59. package/dist/tools/search.d.ts +20 -0
  60. package/dist/tools/search.js +50 -0
  61. package/dist/tools/search.js.map +1 -0
  62. package/dist/tools/tasks.d.ts +110 -0
  63. package/dist/tools/tasks.js +168 -0
  64. package/dist/tools/tasks.js.map +1 -0
  65. package/dist/tools/users.d.ts +12 -0
  66. package/dist/tools/users.js +31 -0
  67. package/dist/tools/users.js.map +1 -0
  68. package/dist/types.d.ts +20 -0
  69. package/dist/types.js +5 -0
  70. package/dist/types.js.map +1 -0
  71. package/dist/utils/formatting.d.ts +16 -0
  72. package/dist/utils/formatting.js +196 -0
  73. package/dist/utils/formatting.js.map +1 -0
  74. package/dist/webhook/handler.d.ts +10 -0
  75. package/dist/webhook/handler.js +70 -0
  76. package/dist/webhook/handler.js.map +1 -0
  77. package/openclaw.plugin.json +21 -0
  78. package/package.json +36 -0
  79. package/skills/blay/SKILL.md +25 -0
@@ -0,0 +1,291 @@
1
+ /**
2
+ * Blay Channel Plugin — registers Blay as a native OpenClaw channel.
3
+ *
4
+ * This allows the agent to participate in Blay conversations using
5
+ * OpenClaw's native auto-reply pipeline. Inbound events arrive via
6
+ * a persistent SSE connection to the Blay API, and are dispatched
7
+ * through the same pipeline as Telegram/Discord/Slack messages.
8
+ * Agent responses are automatically delivered as Blay comments.
9
+ */
10
+ import { DEFAULT_BASE_URL } from "../client.js";
11
+ import { SSEClient } from "./sse-client.js";
12
+ import { dispatchBlayEvent, isAbortTrigger, handleAbortTrigger } from "./inbound.js";
13
+ const DEFAULT_ACCOUNT_ID = "default";
14
+ // ── Module-level gateway config ──────────────────────────────────────
15
+ let _gatewayPort = 18789;
16
+ let _gatewayBind = "loopback";
17
+ let _gatewayToken = null;
18
+ export function getGatewayPort() { return _gatewayPort; }
19
+ export function getGatewayBind() { return _gatewayBind; }
20
+ export function getGatewayToken() { return _gatewayToken; }
21
+ // ── Module-level SSE singleton ────────────────────────────────────────
22
+ // Must be module-level (not closure-scoped) so that if OpenClaw's health
23
+ // monitor creates a new gateway adapter instance on restart, we can still
24
+ // stop the old SSE connection. Without this, old connections leak and
25
+ // each receives + dispatches the same events → duplicate runs.
26
+ let _sseClient = null;
27
+ // ── Module-level event dedup ─────────────────────────────────────────
28
+ // Shared across all SSE connections so events seen by a previous connection
29
+ // are not re-dispatched by a new one after restart.
30
+ const _seenEvents = new Map(); // dedupKey -> insertedAt
31
+ const DEDUP_WINDOW_MS = 10 * 60 * 1000;
32
+ // ── Channel Meta ──────────────────────────────────────────────────────
33
+ const blayMeta = {
34
+ id: "blay-openclaw-plugin",
35
+ label: "Blay",
36
+ selectionLabel: "Blay",
37
+ docsPath: "/channels/blay",
38
+ blurb: "Project management and collaboration platform",
39
+ };
40
+ // ── Config Adapter ────────────────────────────────────────────────────
41
+ function createConfigAdapter(pluginConfig) {
42
+ return {
43
+ listAccountIds: () => [DEFAULT_ACCOUNT_ID],
44
+ resolveAccount: () => ({
45
+ accountId: DEFAULT_ACCOUNT_ID,
46
+ enabled: true,
47
+ apiKey: pluginConfig.apiKey,
48
+ apiUrl: pluginConfig.apiUrl ?? DEFAULT_BASE_URL,
49
+ }),
50
+ defaultAccountId: () => DEFAULT_ACCOUNT_ID,
51
+ isEnabled: () => true,
52
+ isConfigured: () => Boolean(pluginConfig.apiKey),
53
+ describeAccount: (account) => ({
54
+ accountId: account.accountId,
55
+ enabled: account.enabled,
56
+ configured: Boolean(account.apiKey),
57
+ }),
58
+ };
59
+ }
60
+ // ── Outbound Adapter ──────────────────────────────────────────────────
61
+ //
62
+ // Delivers agent responses as Blay comments. OpenClaw's reply pipeline
63
+ // calls sendText() after the agent produces a response.
64
+ function createOutboundAdapter(client) {
65
+ const sendTextImpl = async (ctx) => {
66
+ // `ctx.to` contains the target as "entityType:entityId" or just a bare entity ID
67
+ const parts = ctx.to.split(":", 2);
68
+ const hasPrefixedType = parts.length === 2 && ["task", "project", "resource", "actionItem"].includes(parts[0]);
69
+ const entityType = hasPrefixedType ? parts[0] : "task";
70
+ const entityId = hasPrefixedType ? parts[1] : ctx.to.trim();
71
+ if (!entityId) {
72
+ throw new Error(`[blay] Invalid outbound target "${ctx.to}" — no entity ID found`);
73
+ }
74
+ // Build comment body
75
+ const body = { content: ctx.text };
76
+ // Set the entity target
77
+ if (entityType === "task")
78
+ body.taskId = entityId;
79
+ else if (entityType === "project")
80
+ body.projectId = entityId;
81
+ else if (entityType === "resource")
82
+ body.resourceId = entityId;
83
+ else if (entityType === "actionItem")
84
+ body.actionItemId = entityId;
85
+ else
86
+ body.taskId = entityId;
87
+ const res = await client.post("/api/v1/comments", body);
88
+ if (!res.ok) {
89
+ throw new Error(`[blay] Failed to post comment: HTTP ${res.status}`);
90
+ }
91
+ return {
92
+ channel: "blay-openclaw-plugin",
93
+ messageId: res.data?.id ?? `blay-${Date.now()}`,
94
+ chatId: entityId,
95
+ };
96
+ };
97
+ return {
98
+ deliveryMode: "direct",
99
+ textChunkLimit: 10000,
100
+ sendText: sendTextImpl,
101
+ sendMedia: async (ctx) => {
102
+ // Blay doesn't support media attachments — deliver as text if available
103
+ if (ctx.text) {
104
+ return sendTextImpl(ctx);
105
+ }
106
+ return {
107
+ channel: "blay-openclaw-plugin",
108
+ messageId: `blay-noop-${Date.now()}`,
109
+ chatId: ctx.to.split(":", 2)[1] ?? "",
110
+ };
111
+ },
112
+ };
113
+ }
114
+ function createGatewayAdapter(client, pluginConfig) {
115
+ return {
116
+ startAccount: async (ctx) => {
117
+ const log = ctx.log;
118
+ _gatewayPort = ctx.cfg.gateway?.port ?? 18789;
119
+ _gatewayBind = ctx.cfg.gateway?.bind ?? "loopback";
120
+ _gatewayToken = ctx.cfg.gateway?.auth?.token ?? null;
121
+ if (_gatewayBind !== "loopback") {
122
+ log?.warn(`Gateway bind is "${_gatewayBind}" (not loopback) — cron tool will use gatewayUrl override`);
123
+ }
124
+ // Stop any existing SSE client before creating a new one.
125
+ // Uses module-level _sseClient so this works even if OpenClaw creates
126
+ // a new gateway adapter instance on restart (fresh closure).
127
+ if (_sseClient) {
128
+ log?.info("Stopping existing SSE client before restart");
129
+ _sseClient.stop();
130
+ _sseClient = null;
131
+ }
132
+ // 1. Resolve agent identity and whitelist
133
+ try {
134
+ const meRes = await client.get("/api/v1/me");
135
+ if (meRes.ok && meRes.data.userId) {
136
+ _agentUserId = meRes.data.userId;
137
+ _agentAllowedUserIds = meRes.data.agentAllowedUserIds ?? null;
138
+ log?.info(`Agent identity: "${meRes.data.name}" (${meRes.data.userId})`);
139
+ if (_agentAllowedUserIds && _agentAllowedUserIds.length > 0) {
140
+ log?.info(`User whitelist active: ${_agentAllowedUserIds.length} user(s)`);
141
+ }
142
+ }
143
+ }
144
+ catch {
145
+ log?.warn("Could not resolve agent identity — mention detection disabled");
146
+ }
147
+ // 2. Open SSE connection to the Blay event stream
148
+ const apiUrl = (pluginConfig.apiUrl ?? DEFAULT_BASE_URL).replace(/\/$/, "");
149
+ const sseStartedAt = Date.now();
150
+ const sseUrl = `${apiUrl}/api/v1/events/stream?since=${sseStartedAt}`;
151
+ _sseClient = new SSEClient({
152
+ url: sseUrl,
153
+ headers: {
154
+ Authorization: `Bearer ${pluginConfig.apiKey}`,
155
+ },
156
+ onEvent: (sseEvent) => {
157
+ // Log all SSE events for diagnostics
158
+ if (sseEvent.event === "heartbeat") {
159
+ return; // Heartbeats are too noisy
160
+ }
161
+ if (sseEvent.event === "connected") {
162
+ console.log(`[blay] SSE received: connected`);
163
+ return;
164
+ }
165
+ console.log(`[blay] SSE received event: type=${sseEvent.event} dataLen=${sseEvent.data?.length ?? 0}`);
166
+ // Parse the event data and enqueue for sequential dispatch
167
+ try {
168
+ const payload = JSON.parse(sseEvent.data);
169
+ console.log(`[blay] SSE parsed: event=${payload.event} actor=${payload.actor?.name ?? "?"} target=${payload.target?.type}:${payload.target?.id ?? "?"} ts=${payload.timestamp}`);
170
+ // Reject events older than this SSE connection (defense-in-depth
171
+ // against replay after restarts — the server filters via `since`
172
+ // but dedup map is cleared on restart so stale events could slip through)
173
+ if (payload.timestamp && payload.timestamp < sseStartedAt) {
174
+ console.log(`[blay] SSE filtered: event too old (${payload.timestamp} < ${sseStartedAt})`);
175
+ return;
176
+ }
177
+ // Deduplicate using composite key (module-level map shared across
178
+ // all SSE connections, survives restarts)
179
+ const dedupKey = `${payload.event}:${payload.target?.id ?? ""}:${payload.timestamp}`;
180
+ if (_seenEvents.has(dedupKey)) {
181
+ console.log(`[blay] SSE filtered: duplicate key ${dedupKey}`);
182
+ return;
183
+ }
184
+ _seenEvents.set(dedupKey, Date.now());
185
+ // Evict old entries to bound memory
186
+ const cutoff = Date.now() - DEDUP_WINDOW_MS;
187
+ for (const [key, insertedAt] of _seenEvents) {
188
+ if (insertedAt < cutoff)
189
+ _seenEvents.delete(key);
190
+ }
191
+ // Intercept abort triggers BEFORE dispatching through OpenClaw.
192
+ // Handle abort entirely at the plugin level — never enters the command lane.
193
+ if (payload.event === "comment_created" && isAbortTrigger(payload.data?.content)) {
194
+ console.log(`[blay] SSE abort trigger: "${payload.data?.content}" — handling directly`);
195
+ handleAbortTrigger(payload).catch(err => console.error("[blay] abort handler error:", err));
196
+ return;
197
+ }
198
+ console.log(`[blay] SSE dispatching: ${payload.event} from ${payload.actor?.name ?? "unknown"}`);
199
+ dispatchBlayEvent(payload).catch(err => console.error("[blay] event dispatch error:", err));
200
+ }
201
+ catch (err) {
202
+ console.error("[blay] Failed to parse SSE event:", err);
203
+ }
204
+ },
205
+ onConnected: () => {
206
+ log?.info("SSE event stream connected");
207
+ },
208
+ onDisconnected: () => {
209
+ log?.warn("SSE event stream disconnected — reconnecting...");
210
+ },
211
+ onError: (err) => {
212
+ log?.warn(`SSE error: ${err.message}`);
213
+ },
214
+ reconnectDelay: 2000,
215
+ maxReconnectDelay: 30000,
216
+ });
217
+ _sseClient.start();
218
+ log?.info("Blay channel started (SSE mode)");
219
+ // Block until OpenClaw signals shutdown via abort.
220
+ // OpenClaw expects startAccount to return a long-lived Promise that
221
+ // resolves only when the channel stops. Returning early causes the
222
+ // health monitor to think the channel crashed → restart loop.
223
+ if (!ctx.abortSignal.aborted) {
224
+ await new Promise((resolve) => {
225
+ ctx.abortSignal.addEventListener("abort", () => resolve(), { once: true });
226
+ });
227
+ }
228
+ // Cleanup when abort fires
229
+ if (_sseClient) {
230
+ _sseClient.stop();
231
+ _sseClient = null;
232
+ }
233
+ log?.info("Blay channel stopped");
234
+ },
235
+ stopAccount: async () => {
236
+ if (_sseClient) {
237
+ _sseClient.stop();
238
+ _sseClient = null;
239
+ }
240
+ },
241
+ };
242
+ }
243
+ // ── Agent Identity & Whitelist (set during gateway start) ─────────────
244
+ let _agentUserId = null;
245
+ let _agentAllowedUserIds = null;
246
+ export function getAgentUserId() {
247
+ return _agentUserId;
248
+ }
249
+ export function getAgentAllowedUserIds() {
250
+ return _agentAllowedUserIds;
251
+ }
252
+ // ── Plugin Factory ────────────────────────────────────────────────────
253
+ export function createBlayChannelPlugin(client, pluginConfig) {
254
+ return {
255
+ id: "blay-openclaw-plugin",
256
+ meta: blayMeta,
257
+ capabilities: {
258
+ chatTypes: ["group"],
259
+ media: false,
260
+ polls: false,
261
+ reactions: false,
262
+ threads: false,
263
+ nativeCommands: false,
264
+ },
265
+ defaults: {
266
+ queue: {
267
+ debounceMs: 8000, // Wait for conversation to settle before agent responds
268
+ },
269
+ },
270
+ config: createConfigAdapter(pluginConfig),
271
+ outbound: createOutboundAdapter(client),
272
+ gateway: createGatewayAdapter(client, pluginConfig),
273
+ messaging: {
274
+ targetResolver: {
275
+ hint: "Use entityType:entityId format (e.g. task:abc123, project:xyz) or just the entity ID",
276
+ looksLikeId: (raw) => {
277
+ // Accept any non-empty value — Blay targets are always entity IDs
278
+ // (prefixed like "task:abc123" or bare IDs). No directory lookup needed.
279
+ return raw.trim().length > 0;
280
+ },
281
+ },
282
+ normalizeTarget: (raw) => raw.trim(),
283
+ formatTargetDisplay: (params) => {
284
+ if (params.display)
285
+ return params.display;
286
+ return params.target;
287
+ },
288
+ },
289
+ };
290
+ }
291
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/channel/plugin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * RunTracker — manages agent run lifecycle and telemetry collection.
3
+ *
4
+ * Creates a run record at the start of event dispatch, accumulates tool calls
5
+ * and comment IDs during execution, then sends a final PATCH on completion.
6
+ *
7
+ * All API calls are fire-and-forget (try/catch guarded) — a logging failure
8
+ * must never break agent execution.
9
+ *
10
+ * Module-level current-run singleton is safe because OpenClaw processes
11
+ * SSE events sequentially per agent.
12
+ */
13
+ import type { BlayClient } from "../client.js";
14
+ export interface ToolCallRecord {
15
+ name: string;
16
+ params?: unknown;
17
+ result?: string;
18
+ status: "success" | "error";
19
+ error?: string;
20
+ startedAt: number;
21
+ completedAt: number;
22
+ durationMs: number;
23
+ }
24
+ export declare class RunTracker {
25
+ private client;
26
+ private runId;
27
+ private toolCalls;
28
+ private commentIds;
29
+ private startTime;
30
+ private triggerEvent;
31
+ private triggerActorId?;
32
+ private triggerActorName?;
33
+ private entityType?;
34
+ private entityId?;
35
+ constructor(client: BlayClient, opts: {
36
+ triggerEvent: string;
37
+ triggerActorId?: string;
38
+ triggerActorName?: string;
39
+ entityType?: string;
40
+ entityId?: string;
41
+ });
42
+ /** POST to create the run record. */
43
+ start(): Promise<void>;
44
+ /** Push a tool call record (accumulated in memory). */
45
+ recordToolCall(record: ToolCallRecord): void;
46
+ /** Push a comment ID (accumulated in memory). */
47
+ recordComment(commentId: string): void;
48
+ /** PATCH with status "completed" and all accumulated data. */
49
+ complete(): Promise<void>;
50
+ /** PATCH with status "failed" and error message. */
51
+ fail(error: unknown): Promise<void>;
52
+ }
53
+ export declare function setCurrentRunTracker(tracker: RunTracker | null): void;
54
+ export declare function getCurrentRunTracker(): RunTracker | null;
@@ -0,0 +1,137 @@
1
+ /**
2
+ * RunTracker — manages agent run lifecycle and telemetry collection.
3
+ *
4
+ * Creates a run record at the start of event dispatch, accumulates tool calls
5
+ * and comment IDs during execution, then sends a final PATCH on completion.
6
+ *
7
+ * All API calls are fire-and-forget (try/catch guarded) — a logging failure
8
+ * must never break agent execution.
9
+ *
10
+ * Module-level current-run singleton is safe because OpenClaw processes
11
+ * SSE events sequentially per agent.
12
+ */
13
+ import { getUsageCollector } from "../telemetry/usage-collector.js";
14
+ import { getTelemetryPusher } from "../telemetry/pusher.js";
15
+ export class RunTracker {
16
+ client;
17
+ runId = null;
18
+ toolCalls = [];
19
+ commentIds = [];
20
+ startTime;
21
+ triggerEvent;
22
+ triggerActorId;
23
+ triggerActorName;
24
+ entityType;
25
+ entityId;
26
+ constructor(client, opts) {
27
+ this.client = client;
28
+ this.startTime = Date.now();
29
+ this.triggerEvent = opts.triggerEvent;
30
+ this.triggerActorId = opts.triggerActorId;
31
+ this.triggerActorName = opts.triggerActorName;
32
+ this.entityType = opts.entityType;
33
+ this.entityId = opts.entityId;
34
+ }
35
+ /** POST to create the run record. */
36
+ async start() {
37
+ try {
38
+ const res = await this.client.post("/api/v1/agent-runs", {
39
+ triggerEvent: this.triggerEvent,
40
+ triggerActorId: this.triggerActorId,
41
+ triggerActorName: this.triggerActorName,
42
+ entityType: this.entityType,
43
+ entityId: this.entityId,
44
+ });
45
+ if (res.ok && res.data?.id) {
46
+ this.runId = res.data.id;
47
+ }
48
+ else {
49
+ console.error("[blay] Failed to create agent run:", res.status);
50
+ }
51
+ }
52
+ catch (err) {
53
+ console.error("[blay] Failed to create agent run:", err);
54
+ }
55
+ }
56
+ /** Push a tool call record (accumulated in memory). */
57
+ recordToolCall(record) {
58
+ this.toolCalls.push(record);
59
+ }
60
+ /** Push a comment ID (accumulated in memory). */
61
+ recordComment(commentId) {
62
+ this.commentIds.push(commentId);
63
+ }
64
+ /** PATCH with status "completed" and all accumulated data. */
65
+ async complete() {
66
+ if (!this.runId)
67
+ return;
68
+ const now = Date.now();
69
+ try {
70
+ // Collect token usage from the UsageCollector
71
+ const usage = getUsageCollector()?.getAndResetUsage();
72
+ const tokenFields = usage && usage.totalTokens > 0
73
+ ? {
74
+ inputTokens: usage.inputTokens,
75
+ outputTokens: usage.outputTokens,
76
+ totalTokens: usage.totalTokens,
77
+ estimatedCostUsd: usage.estimatedCost,
78
+ }
79
+ : {};
80
+ await this.client.patch(`/api/v1/agent-runs/${this.runId}`, {
81
+ status: "completed",
82
+ toolCalls: this.toolCalls,
83
+ commentIds: this.commentIds.length > 0 ? this.commentIds : undefined,
84
+ completedAt: now,
85
+ durationMs: now - this.startTime,
86
+ ...tokenFields,
87
+ });
88
+ // Notify TelemetryPusher
89
+ getTelemetryPusher()?.recordRunCompleted();
90
+ }
91
+ catch (err) {
92
+ console.error("[blay] Failed to complete agent run:", err);
93
+ }
94
+ }
95
+ /** PATCH with status "failed" and error message. */
96
+ async fail(error) {
97
+ if (!this.runId)
98
+ return;
99
+ const now = Date.now();
100
+ const errorMessage = error instanceof Error ? error.message : String(error);
101
+ try {
102
+ // Collect token usage even on failure
103
+ const usage = getUsageCollector()?.getAndResetUsage();
104
+ const tokenFields = usage && usage.totalTokens > 0
105
+ ? {
106
+ inputTokens: usage.inputTokens,
107
+ outputTokens: usage.outputTokens,
108
+ totalTokens: usage.totalTokens,
109
+ estimatedCostUsd: usage.estimatedCost,
110
+ }
111
+ : {};
112
+ await this.client.patch(`/api/v1/agent-runs/${this.runId}`, {
113
+ status: "failed",
114
+ toolCalls: this.toolCalls,
115
+ commentIds: this.commentIds.length > 0 ? this.commentIds : undefined,
116
+ errorMessage,
117
+ completedAt: now,
118
+ durationMs: now - this.startTime,
119
+ ...tokenFields,
120
+ });
121
+ // Notify TelemetryPusher
122
+ getTelemetryPusher()?.recordRunFailed();
123
+ }
124
+ catch (err) {
125
+ console.error("[blay] Failed to record agent run failure:", err);
126
+ }
127
+ }
128
+ }
129
+ // ── Module-level current-run singleton ──────────────────────────────────
130
+ let _currentTracker = null;
131
+ export function setCurrentRunTracker(tracker) {
132
+ _currentTracker = tracker;
133
+ }
134
+ export function getCurrentRunTracker() {
135
+ return _currentTracker;
136
+ }
137
+ //# sourceMappingURL=run-tracker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-tracker.js","sourceRoot":"","sources":["../../src/channel/run-tracker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Channel Runtime — stores the PluginRuntime reference for use by channel adapters.
3
+ *
4
+ * Follows the same pattern as the Telegram channel extension.
5
+ */
6
+ import type { PluginRuntime } from "openclaw/plugin-sdk";
7
+ export declare function setBlayRuntime(runtime: PluginRuntime): void;
8
+ export declare function getBlayRuntime(): PluginRuntime;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Channel Runtime — stores the PluginRuntime reference for use by channel adapters.
3
+ *
4
+ * Follows the same pattern as the Telegram channel extension.
5
+ */
6
+ let _runtime = null;
7
+ export function setBlayRuntime(runtime) {
8
+ _runtime = runtime;
9
+ }
10
+ export function getBlayRuntime() {
11
+ if (!_runtime) {
12
+ throw new Error("[blay] PluginRuntime not initialized — setBlayRuntime() must be called first");
13
+ }
14
+ return _runtime;
15
+ }
16
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/channel/runtime.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,IAAI,QAAQ,GAAyB,IAAI,CAAC;AAE1C,MAAM,UAAU,cAAc,CAAC,OAAsB;IACnD,QAAQ,GAAG,OAAO,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,8EAA8E,CAAC,CAAC;IAClG,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Minimal SSE Client for Node.js
3
+ *
4
+ * Connects to a Server-Sent Events endpoint using fetch streams.
5
+ * Handles reconnection with exponential backoff.
6
+ * No external dependencies — uses Node.js built-in fetch.
7
+ */
8
+ export interface SSEEvent {
9
+ event: string;
10
+ data: string;
11
+ id?: string;
12
+ }
13
+ export interface SSEClientOptions {
14
+ url: string;
15
+ headers?: Record<string, string>;
16
+ onEvent: (event: SSEEvent) => void;
17
+ onError?: (error: Error) => void;
18
+ onConnected?: () => void;
19
+ onDisconnected?: () => void;
20
+ /** Initial reconnect delay in ms (default: 1000) */
21
+ reconnectDelay?: number;
22
+ /** Max reconnect delay in ms (default: 30000) */
23
+ maxReconnectDelay?: number;
24
+ }
25
+ export declare class SSEClient {
26
+ private abortController;
27
+ private reconnectDelay;
28
+ private maxReconnectDelay;
29
+ private currentDelay;
30
+ private running;
31
+ private options;
32
+ private lastEventId;
33
+ /**
34
+ * Generation counter — incremented on every stop(). Prevents stale
35
+ * reconnection chains from forking when stop() + start() is called
36
+ * while a reconnection sleep is in progress.
37
+ */
38
+ private generation;
39
+ constructor(options: SSEClientOptions);
40
+ /**
41
+ * Start the SSE connection. Reconnects automatically on failure.
42
+ */
43
+ start(): void;
44
+ /**
45
+ * Stop the SSE connection permanently.
46
+ */
47
+ stop(): void;
48
+ private connectWithGen;
49
+ /**
50
+ * Parse SSE events from a text buffer.
51
+ * Returns parsed events and the remaining unparsed text.
52
+ */
53
+ private parseEvents;
54
+ }