@syengup/friday-channel-next 0.1.17 → 0.1.18

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.
@@ -23,12 +23,15 @@ import { fridayAttachmentLookupKey, fridayFilesPublicUrl, readFile, resolveMedia
23
23
  import { runFridayDispatch } from "../../agent/dispatch-bridge.js";
24
24
  import { saveInboundMediaBuffer } from "../../agent/media-bridge.js";
25
25
  import { contextTokensFromUsageRecord, getRunMetadata, getRunRoute, hasRunFinalDelivered, markRunFinalDelivered, registerRunRoute, setRunMetadata, } from "../../run-metadata.js";
26
- import { createFridayNextLogger } from "../../logging.js";
26
+ import { createFridayNextLogger, setFridayNextLogLevel } from "../../logging.js";
27
27
  const logger = createFridayNextLogger("messages");
28
- const log = (action, deviceId, runId, detail) => {
28
+ // Routine per-message / per-stream lifecycle events log at "debug" so they stay out of
29
+ // the default ("info") OpenClaw log; only genuine problems (rejections, run errors) surface.
30
+ // Raise the friday-next channel logLevel to "debug" to see the full per-message trace.
31
+ const log = (action, deviceId, runId, detail, level = "debug") => {
29
32
  const runPart = runId ? ` runId=${runId}` : "";
30
33
  const detailPart = detail ? ` detail=${detail}` : "";
31
- logger.info(`[${action}] deviceId=${deviceId}${runPart}${detailPart}`);
34
+ logger[level](`[${action}] deviceId=${deviceId}${runPart}${detailPart}`);
32
35
  };
33
36
  function collectReplyPayloadMediaUrls(pl) {
34
37
  const fromArr = Array.isArray(pl.mediaUrls)
@@ -285,7 +288,7 @@ export async function handleMessages(req, res) {
285
288
  }
286
289
  const token = extractBearerToken(req);
287
290
  if (!token) {
288
- log("AUTH_FAILED", "(unknown)", undefined, "missing or invalid token");
291
+ log("AUTH_FAILED", "(unknown)", undefined, "missing or invalid token", "warn");
289
292
  res.statusCode = 401;
290
293
  res.setHeader("Content-Type", "application/json");
291
294
  res.end(JSON.stringify({ error: "Unauthorized: bearer token mismatch" }));
@@ -293,7 +296,7 @@ export async function handleMessages(req, res) {
293
296
  }
294
297
  const payload = (await readJsonBody(req));
295
298
  if (!payload) {
296
- log("BAD_REQUEST", "(unknown)", undefined, "invalid JSON body");
299
+ log("BAD_REQUEST", "(unknown)", undefined, "invalid JSON body", "warn");
297
300
  res.statusCode = 400;
298
301
  res.setHeader("Content-Type", "application/json");
299
302
  res.end(JSON.stringify({ error: "Invalid JSON body" }));
@@ -302,7 +305,7 @@ export async function handleMessages(req, res) {
302
305
  const { deviceId, text, attachments = [], sessionKey: rawSessionKey } = payload;
303
306
  const normalizedDeviceId = deviceId?.trim().toUpperCase();
304
307
  if (typeof rawSessionKey !== "string" || !rawSessionKey.length) {
305
- log("BAD_REQUEST", "(unknown)", undefined, "missing sessionKey");
308
+ log("BAD_REQUEST", "(unknown)", undefined, "missing sessionKey", "warn");
306
309
  res.statusCode = 400;
307
310
  res.setHeader("Content-Type", "application/json");
308
311
  res.end(JSON.stringify({ error: "Missing required field: sessionKey" }));
@@ -311,14 +314,14 @@ export async function handleMessages(req, res) {
311
314
  const appSessionKey = rawSessionKey.trim();
312
315
  const baseSessionKey = toSessionStoreKey(appSessionKey);
313
316
  if (!normalizedDeviceId) {
314
- log("BAD_REQUEST", "(unknown)", undefined, "missing deviceId");
317
+ log("BAD_REQUEST", "(unknown)", undefined, "missing deviceId", "warn");
315
318
  res.statusCode = 400;
316
319
  res.setHeader("Content-Type", "application/json");
317
320
  res.end(JSON.stringify({ error: "Missing required field: deviceId" }));
318
321
  return true;
319
322
  }
320
323
  if (!text || !text.trim()) {
321
- log("BAD_REQUEST", normalizedDeviceId, undefined, "missing text");
324
+ log("BAD_REQUEST", normalizedDeviceId, undefined, "missing text", "warn");
322
325
  res.statusCode = 400;
323
326
  res.setHeader("Content-Type", "application/json");
324
327
  res.end(JSON.stringify({ error: "Missing required field: text" }));
@@ -334,6 +337,7 @@ export async function handleMessages(req, res) {
334
337
  res.end(JSON.stringify({ accepted: true, deviceId: normalizedDeviceId, runId }));
335
338
  log("MESSAGE_RECEIVED", normalizedDeviceId, runId, `textLen=${trimmedText.length} attachments=${attachments.length} sessionKey=${baseSessionKey}`);
336
339
  const cfg = resolveFridayNextConfig(getHostOpenClawConfigSnapshot(runtime.config));
340
+ setFridayNextLogLevel(cfg.logLevel);
337
341
  // Resolve defaults from the OpenClaw agent config so settings are never left empty. Prefers the
338
342
  // target agent's own model/thinking over the global defaults (see resolveAgentDefaults).
339
343
  const { model: defaultModel, thinking: defaultThinking } = resolveAgentDefaults(baseSessionKey);
@@ -415,7 +419,7 @@ export async function handleMessages(req, res) {
415
419
  }
416
420
  },
417
421
  onError: (err) => {
418
- log("RUN_ERROR", normalizedDeviceId, runId, String(err));
422
+ log("RUN_ERROR", normalizedDeviceId, runId, String(err), "error");
419
423
  sseEmitter.broadcastToRun(runId, {
420
424
  type: "outbound",
421
425
  data: {
@@ -455,7 +459,7 @@ export async function handleMessages(req, res) {
455
459
  log("RUN_COMPLETE", normalizedDeviceId, runId);
456
460
  }
457
461
  catch (err) {
458
- log("RUN_ERROR", normalizedDeviceId, runId, String(err));
462
+ log("RUN_ERROR", normalizedDeviceId, runId, String(err), "error");
459
463
  sseEmitter.broadcastToRun(runId, {
460
464
  type: "outbound",
461
465
  data: {
@@ -473,7 +477,7 @@ export async function handleMessages(req, res) {
473
477
  }
474
478
  };
475
479
  runAgent().catch((err) => {
476
- log("RUN_ERROR", normalizedDeviceId, runId, String(err));
480
+ log("RUN_ERROR", normalizedDeviceId, runId, String(err), "error");
477
481
  sseEmitter.untrackRun(runId);
478
482
  });
479
483
  return true;
@@ -1,5 +1,6 @@
1
1
  import type { FridayNextLogLevel } from "./config.js";
2
- export declare function createFridayNextLogger(scope: string, level?: FridayNextLogLevel): {
2
+ export declare function setFridayNextLogLevel(level: FridayNextLogLevel): void;
3
+ export declare function createFridayNextLogger(scope: string, _level?: FridayNextLogLevel): {
3
4
  debug: (message: string) => void;
4
5
  info: (message: string) => void;
5
6
  warn: (message: string) => void;
@@ -4,9 +4,18 @@ const levelOrder = {
4
4
  warn: 30,
5
5
  error: 40,
6
6
  };
7
- export function createFridayNextLogger(scope, level = "info") {
7
+ // Process-wide active level, honored by every logger at call time. Handlers call
8
+ // setFridayNextLogLevel() once the friday-next channel config resolves, so
9
+ // `channels.friday-next.logLevel: "debug"` turns the full per-message trace back on.
10
+ let activeLevel = "info";
11
+ export function setFridayNextLogLevel(level) {
12
+ activeLevel = level;
13
+ }
14
+ // The optional `level` arg is accepted for call-site compatibility but the effective
15
+ // threshold is the process-wide active level (single knob driven by config.logLevel).
16
+ export function createFridayNextLogger(scope, _level) {
8
17
  const base = `[friday-next:${scope}]`;
9
- const enabled = (current) => levelOrder[current] >= levelOrder[level];
18
+ const enabled = (current) => levelOrder[current] >= levelOrder[activeLevel];
10
19
  return {
11
20
  debug: (message) => {
12
21
  if (enabled("debug"))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@syengup/friday-channel-next",
3
- "version": "0.1.17",
3
+ "version": "0.1.18",
4
4
  "description": "OpenClaw Friday Next Apple channel plugin",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -57,14 +57,23 @@ import {
57
57
  registerRunRoute,
58
58
  setRunMetadata,
59
59
  } from "../../run-metadata.js";
60
- import { createFridayNextLogger } from "../../logging.js";
60
+ import { createFridayNextLogger, setFridayNextLogLevel } from "../../logging.js";
61
61
 
62
62
  const logger = createFridayNextLogger("messages");
63
63
 
64
- const log = (action: string, deviceId: string, runId?: string, detail?: string) => {
64
+ // Routine per-message / per-stream lifecycle events log at "debug" so they stay out of
65
+ // the default ("info") OpenClaw log; only genuine problems (rejections, run errors) surface.
66
+ // Raise the friday-next channel logLevel to "debug" to see the full per-message trace.
67
+ const log = (
68
+ action: string,
69
+ deviceId: string,
70
+ runId?: string,
71
+ detail?: string,
72
+ level: "debug" | "info" | "warn" | "error" = "debug",
73
+ ) => {
65
74
  const runPart = runId ? ` runId=${runId}` : "";
66
75
  const detailPart = detail ? ` detail=${detail}` : "";
67
- logger.info(`[${action}] deviceId=${deviceId}${runPart}${detailPart}`);
76
+ logger[level](`[${action}] deviceId=${deviceId}${runPart}${detailPart}`);
68
77
  };
69
78
 
70
79
  function collectReplyPayloadMediaUrls(pl: { mediaUrls?: string[]; mediaUrl?: string | null }): string[] {
@@ -381,7 +390,7 @@ export async function handleMessages(req: IncomingMessage, res: ServerResponse):
381
390
 
382
391
  const token = extractBearerToken(req);
383
392
  if (!token) {
384
- log("AUTH_FAILED", "(unknown)", undefined, "missing or invalid token");
393
+ log("AUTH_FAILED", "(unknown)", undefined, "missing or invalid token", "warn");
385
394
  res.statusCode = 401;
386
395
  res.setHeader("Content-Type", "application/json");
387
396
  res.end(JSON.stringify({ error: "Unauthorized: bearer token mismatch" }));
@@ -390,7 +399,7 @@ export async function handleMessages(req: IncomingMessage, res: ServerResponse):
390
399
 
391
400
  const payload = (await readJsonBody(req)) as FridayMessagePayload | null;
392
401
  if (!payload) {
393
- log("BAD_REQUEST", "(unknown)", undefined, "invalid JSON body");
402
+ log("BAD_REQUEST", "(unknown)", undefined, "invalid JSON body", "warn");
394
403
  res.statusCode = 400;
395
404
  res.setHeader("Content-Type", "application/json");
396
405
  res.end(JSON.stringify({ error: "Invalid JSON body" }));
@@ -401,7 +410,7 @@ export async function handleMessages(req: IncomingMessage, res: ServerResponse):
401
410
  const normalizedDeviceId = deviceId?.trim().toUpperCase();
402
411
 
403
412
  if (typeof rawSessionKey !== "string" || !rawSessionKey.length) {
404
- log("BAD_REQUEST", "(unknown)", undefined, "missing sessionKey");
413
+ log("BAD_REQUEST", "(unknown)", undefined, "missing sessionKey", "warn");
405
414
  res.statusCode = 400;
406
415
  res.setHeader("Content-Type", "application/json");
407
416
  res.end(JSON.stringify({ error: "Missing required field: sessionKey" }));
@@ -412,7 +421,7 @@ export async function handleMessages(req: IncomingMessage, res: ServerResponse):
412
421
  const baseSessionKey = toSessionStoreKey(appSessionKey);
413
422
 
414
423
  if (!normalizedDeviceId) {
415
- log("BAD_REQUEST", "(unknown)", undefined, "missing deviceId");
424
+ log("BAD_REQUEST", "(unknown)", undefined, "missing deviceId", "warn");
416
425
  res.statusCode = 400;
417
426
  res.setHeader("Content-Type", "application/json");
418
427
  res.end(JSON.stringify({ error: "Missing required field: deviceId" }));
@@ -420,7 +429,7 @@ export async function handleMessages(req: IncomingMessage, res: ServerResponse):
420
429
  }
421
430
 
422
431
  if (!text || !text.trim()) {
423
- log("BAD_REQUEST", normalizedDeviceId, undefined, "missing text");
432
+ log("BAD_REQUEST", normalizedDeviceId, undefined, "missing text", "warn");
424
433
  res.statusCode = 400;
425
434
  res.setHeader("Content-Type", "application/json");
426
435
  res.end(JSON.stringify({ error: "Missing required field: text" }));
@@ -447,6 +456,7 @@ export async function handleMessages(req: IncomingMessage, res: ServerResponse):
447
456
  );
448
457
 
449
458
  const cfg = resolveFridayNextConfig(getHostOpenClawConfigSnapshot(runtime.config));
459
+ setFridayNextLogLevel(cfg.logLevel);
450
460
 
451
461
  // Resolve defaults from the OpenClaw agent config so settings are never left empty. Prefers the
452
462
  // target agent's own model/thinking over the global defaults (see resolveAgentDefaults).
@@ -544,7 +554,7 @@ export async function handleMessages(req: IncomingMessage, res: ServerResponse):
544
554
  }
545
555
  },
546
556
  onError: (err: unknown) => {
547
- log("RUN_ERROR", normalizedDeviceId, runId, String(err));
557
+ log("RUN_ERROR", normalizedDeviceId, runId, String(err), "error");
548
558
  sseEmitter.broadcastToRun(
549
559
  runId,
550
560
  {
@@ -588,7 +598,7 @@ export async function handleMessages(req: IncomingMessage, res: ServerResponse):
588
598
  });
589
599
  log("RUN_COMPLETE", normalizedDeviceId, runId);
590
600
  } catch (err) {
591
- log("RUN_ERROR", normalizedDeviceId, runId, String(err));
601
+ log("RUN_ERROR", normalizedDeviceId, runId, String(err), "error");
592
602
  sseEmitter.broadcastToRun(
593
603
  runId,
594
604
  {
@@ -610,7 +620,7 @@ export async function handleMessages(req: IncomingMessage, res: ServerResponse):
610
620
  };
611
621
 
612
622
  runAgent().catch((err) => {
613
- log("RUN_ERROR", normalizedDeviceId, runId, String(err));
623
+ log("RUN_ERROR", normalizedDeviceId, runId, String(err), "error");
614
624
  sseEmitter.untrackRun(runId);
615
625
  });
616
626
 
package/src/logging.ts CHANGED
@@ -7,9 +7,20 @@ const levelOrder: Record<FridayNextLogLevel, number> = {
7
7
  error: 40,
8
8
  };
9
9
 
10
- export function createFridayNextLogger(scope: string, level: FridayNextLogLevel = "info") {
10
+ // Process-wide active level, honored by every logger at call time. Handlers call
11
+ // setFridayNextLogLevel() once the friday-next channel config resolves, so
12
+ // `channels.friday-next.logLevel: "debug"` turns the full per-message trace back on.
13
+ let activeLevel: FridayNextLogLevel = "info";
14
+
15
+ export function setFridayNextLogLevel(level: FridayNextLogLevel): void {
16
+ activeLevel = level;
17
+ }
18
+
19
+ // The optional `level` arg is accepted for call-site compatibility but the effective
20
+ // threshold is the process-wide active level (single knob driven by config.logLevel).
21
+ export function createFridayNextLogger(scope: string, _level?: FridayNextLogLevel) {
11
22
  const base = `[friday-next:${scope}]`;
12
- const enabled = (current: FridayNextLogLevel) => levelOrder[current] >= levelOrder[level];
23
+ const enabled = (current: FridayNextLogLevel) => levelOrder[current] >= levelOrder[activeLevel];
13
24
  return {
14
25
  debug: (message: string) => {
15
26
  if (enabled("debug")) console.debug(`${base} ${message}`);