{"type":"system","subtype":"init","cwd":"./bench/results/mcp-with-toolsearch/bug_triage_search/run5/workspace","session_id":"1cbb44f9-7700-474d-82b1-f71c070b293f","tools":["Task","TaskOutput","Bash","Glob","Grep","ExitPlanMode","Read","Edit","Write","NotebookEdit","WebFetch","TodoWrite","WebSearch","TaskStop","AskUserQuestion","Skill","EnterPlanMode","EnterWorktree","ExitWorktree","CronCreate","CronDelete","CronList","ToolSearch","mcp__chrome-devtools__click","mcp__chrome-devtools__close_page","mcp__chrome-devtools__drag","mcp__chrome-devtools__emulate","mcp__chrome-devtools__evaluate_script","mcp__chrome-devtools__fill","mcp__chrome-devtools__fill_form","mcp__chrome-devtools__get_console_message","mcp__chrome-devtools__get_network_request","mcp__chrome-devtools__handle_dialog","mcp__chrome-devtools__hover","mcp__chrome-devtools__lighthouse_audit","mcp__chrome-devtools__list_console_messages","mcp__chrome-devtools__list_network_requests","mcp__chrome-devtools__list_pages","mcp__chrome-devtools__navigate_page","mcp__chrome-devtools__new_page","mcp__chrome-devtools__performance_analyze_insight","mcp__chrome-devtools__performance_start_trace","mcp__chrome-devtools__performance_stop_trace","mcp__chrome-devtools__press_key","mcp__chrome-devtools__resize_page","mcp__chrome-devtools__select_page","mcp__chrome-devtools__take_memory_snapshot","mcp__chrome-devtools__take_screenshot","mcp__chrome-devtools__take_snapshot","mcp__chrome-devtools__type_text","mcp__chrome-devtools__upload_file","mcp__chrome-devtools__wait_for","mcp__github__add_comment_to_pending_review","mcp__github__add_issue_comment","mcp__github__add_reply_to_pull_request_comment","mcp__github__assign_copilot_to_issue","mcp__github__create_branch","mcp__github__create_or_update_file","mcp__github__create_pull_request","mcp__github__create_pull_request_with_copilot","mcp__github__create_repository","mcp__github__delete_file","mcp__github__fork_repository","mcp__github__get_commit","mcp__github__get_copilot_job_status","mcp__github__get_file_contents","mcp__github__get_label","mcp__github__get_latest_release","mcp__github__get_me","mcp__github__get_release_by_tag","mcp__github__get_tag","mcp__github__get_team_members","mcp__github__get_teams","mcp__github__issue_read","mcp__github__issue_write","mcp__github__list_branches","mcp__github__list_commits","mcp__github__list_issue_types","mcp__github__list_issues","mcp__github__list_pull_requests","mcp__github__list_releases","mcp__github__list_tags","mcp__github__merge_pull_request","mcp__github__pull_request_read","mcp__github__pull_request_review_write","mcp__github__push_files","mcp__github__request_copilot_review","mcp__github__run_secret_scanning","mcp__github__search_code","mcp__github__search_issues","mcp__github__search_pull_requests","mcp__github__search_repositories","mcp__github__search_users","mcp__github__sub_issue_write","mcp__github__update_pull_request","mcp__github__update_pull_request_branch","ListMcpResourcesTool","ReadMcpResourceTool","LSP"],"mcp_servers":[{"name":"chrome-devtools","status":"connected"},{"name":"github","status":"connected"},{"name":"claude.ai Google Calendar","status":"needs-auth"},{"name":"claude.ai Gmail","status":"needs-auth"}],"model":"claude-sonnet-4-6","permissionMode":"bypassPermissions","slash_commands":["update-config","debug","simplify","batch","loop","claude-api","test-driven-development","app-installer","release-notify-issues","cli-demo-recorder","readme-generator","compact","context","cost","heapdump","init","pr-comments","release-notes","review","security-review","extra-usage","insights","mcp__github__AssignCodingAgent","mcp__github__issue_to_fix_workflow"],"apiKeySource":"none","claude_code_version":"2.1.77","output_style":"default","agents":["general-purpose","statusline-setup","Explore","Plan","claude-code-guide"],"skills":["update-config","debug","simplify","batch","loop","claude-api","test-driven-development","app-installer","release-notify-issues","cli-demo-recorder","readme-generator"],"plugins":[{"name":"rust-analyzer-lsp","path":"~/.claude/plugins/rust-analyzer-lsp/1.0.0"}],"uuid":"babdc48a-20e4-4720-a75a-9452a061d9ff","fast_mode_state":"off"}
{"type":"assistant","message":{"model":"claude-sonnet-4-6","id":"msg_0166A5vPcdYTpRdt38LEAeoo","type":"message","role":"assistant","content":[{"type":"thinking","thinking":"Let me search for issues in openclaw/openclaw mentioning 'rate limit' using the GitHub MCP tool.","signature":"EogCCkYICxgCKkBW9dtUl4l/LnPz2r8ANLwN/OOx9ZKmRkl5ELKRKtgzaVEwUhbL4AAbZ7bXILOu8ClvuxQ4l0DAsvNMD4tOSiOtEgwnH5+hTPp2+s0KDQEaDNhfEwOrwGrG3yAGtyIwvP+r9f8jc75oOl2e37x80MX+ctbuxnd9wzyJaRHOfwPgNOJlG/js/JlAAc+SVTSmKnB0FDQTkibHQVGnCBjcPhAYltnchPyWlf3H83NDa5vk0F8DZLI2CLRVwQrly4Sl2B169x0sEDaUnbi0gd3tVRTbIkRniGezWXyXc9i6vslY8yxoqREz9kB7l4z/jFPnLf+LXM5OQ//FDn487TRoeRDrGAE="}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":3,"cache_creation_input_tokens":7848,"cache_read_input_tokens":8598,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":7848},"output_tokens":1,"service_tier":"standard","inference_geo":"not_available"},"context_management":null},"parent_tool_use_id":null,"session_id":"1cbb44f9-7700-474d-82b1-f71c070b293f","uuid":"5379bdb7-8766-42e6-8b6e-75a342cc4c9f"}
{"type":"assistant","message":{"model":"claude-sonnet-4-6","id":"msg_0166A5vPcdYTpRdt38LEAeoo","type":"message","role":"assistant","content":[{"type":"tool_use","id":"toolu_01Y7RcJh9X2GKohkvVQtf8qB","name":"ToolSearch","input":{"query":"select:mcp__github__search_issues","max_results":1},"caller":{"type":"direct"}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":3,"cache_creation_input_tokens":7848,"cache_read_input_tokens":8598,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":7848},"output_tokens":1,"service_tier":"standard","inference_geo":"not_available"},"context_management":null},"parent_tool_use_id":null,"session_id":"1cbb44f9-7700-474d-82b1-f71c070b293f","uuid":"67cf7849-203a-45b5-8cba-69c647b04f9a"}
{"type":"user","message":{"role":"user","content":[{"type":"tool_result","tool_use_id":"toolu_01Y7RcJh9X2GKohkvVQtf8qB","content":[{"type":"tool_reference","tool_name":"mcp__github__search_issues"}]}]},"parent_tool_use_id":null,"session_id":"1cbb44f9-7700-474d-82b1-f71c070b293f","uuid":"b6d8a109-ec91-4d4f-9431-8d2b1985ba82","timestamp":"2026-03-21T19:24:00.331Z","tool_use_result":{"matches":["mcp__github__search_issues"],"query":"select:mcp__github__search_issues","total_deferred_tools":90}}
{"type":"rate_limit_event","rate_limit_info":{"status":"allowed","resetsAt":1774126800,"rateLimitType":"five_hour","overageStatus":"rejected","overageDisabledReason":"org_level_disabled","isUsingOverage":false},"uuid":"8243abc6-60c2-4438-b6c6-3badfa72a73e","session_id":"1cbb44f9-7700-474d-82b1-f71c070b293f"}
{"type":"assistant","message":{"model":"claude-sonnet-4-6","id":"msg_01TayeHRmPvkstjkBqtG5tbA","type":"message","role":"assistant","content":[{"type":"thinking","thinking":"Now let me search for issues in openclaw/openclaw mentioning 'rate limit'.","signature":"EvIBCkYICxgCKkBErLHMBMzf83xqQqbQg5HWDNJwsJ+uCex1YNVeSO5VQJLtno/Lam8ZbRGJOAWak2L8BX1iYYlT/T1QvTGWZHvKEgz27yu+YOcR6dq7OcMaDEkdcSVAsKF0Rfcn8yIwCT9esah3xyka3iN6yhMARhjU4Nt2pXaiULATOXGDbJG3eVRYORil8+WjJya3jk8+Klpy63HKBPE6fvjT0YntIbSI/VMw1sm4Z5dm8uzYgeLE+x5kg9M6hGq6hbS19NrvdTXlV3HIzTZUo+DYLs5/ZSh5bTjo6Pi92lk/a8Fex21ExE55oKVt7RDrx+YYAQ=="}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":3,"cache_creation_input_tokens":470,"cache_read_input_tokens":16446,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":470},"output_tokens":8,"service_tier":"standard","inference_geo":"not_available"},"context_management":null},"parent_tool_use_id":null,"session_id":"1cbb44f9-7700-474d-82b1-f71c070b293f","uuid":"4295cc9b-2aa5-448d-a3a3-ee53525f8cac"}
{"type":"assistant","message":{"model":"claude-sonnet-4-6","id":"msg_01TayeHRmPvkstjkBqtG5tbA","type":"message","role":"assistant","content":[{"type":"tool_use","id":"toolu_01QNjW5roYG6ULsauMwMn7Lc","name":"mcp__github__search_issues","input":{"query":"rate limit","owner":"openclaw","repo":"openclaw","sort":"created","order":"desc","perPage":5},"caller":{"type":"direct"}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":3,"cache_creation_input_tokens":470,"cache_read_input_tokens":16446,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":470},"output_tokens":8,"service_tier":"standard","inference_geo":"not_available"},"context_management":null},"parent_tool_use_id":null,"session_id":"1cbb44f9-7700-474d-82b1-f71c070b293f","uuid":"ae3768b8-3f97-4b92-a2c5-c66ee498f122"}
{"type":"user","message":{"role":"user","content":[{"tool_use_id":"toolu_01QNjW5roYG6ULsauMwMn7Lc","type":"tool_result","content":[{"type":"text","text":"{\"total_count\":943,\"incomplete_results\":false,\"items\":[{\"id\":4113056622,\"number\":51767,\"state\":\"open\",\"locked\":false,\"title\":\"sessionRetention does not apply to subagent sessions — only cron-run sessions are swept\",\"body\":\"## Summary\\n\\n`cron.sessionRetention` (e.g. `\\\"3h\\\"`) only prunes sessions matching `isCronRunSessionKey()` (pattern `cron:*:run:*`). Subagent sessions (`agent:*:subagent:*`) are **never cleaned up** by the retention sweep, even after they complete.\\n\\n## Impact\\n\\nAfter any sprint with 10-30+ subagent spawns, `sessions.json` grows to 1.5MB+, gateway RSS climbs 500MB+, and stale sessions accumulate indefinitely. Users must manually purge `sessions.json` and restart.\\n\\n## Root Cause\\n\\nIn `src/cron/service/session-reaper.ts` (bundled as `gateway-cli-*.js` L5620-5622):\\n\\n```js\\nfor (const key of Object.keys(store)) {\\n    if (!isCronRunSessionKey(key)) continue;  // \\u003c-- skips subagent sessions\\n    // ...only cron sessions get pruned\\n}\\n```\\n\\nThe separate `subagent-registry-cleanup.ts` handles announce/finalize flows but does NOT remove the session entry from the session store or delete transcript files.\\n\\n## Expected Behavior\\n\\n`sessionRetention` should apply to **all** non-main session types — at minimum:\\n- `isCronRunSessionKey()` ✅ (already works)\\n- `isSubagentSessionKey()` ❌ (currently skipped)\\n- `isAcpSessionKey()` ❌ (likely also skipped)\\n\\nCompleted subagent sessions (where `endedAt` exists and age \\u003e retention) should be pruned from the store and their transcript `.jsonl` files archived/deleted.\\n\\n## Suggested Fix\\n\\nIn `sweepCronRunSessions` (or a new parallel sweep), add:\\n\\n```js\\nif (!isCronRunSessionKey(key) \\u0026\\u0026 !isSubagentSessionKey(key) \\u0026\\u0026 !isAcpSessionKey(key)) continue;\\n```\\n\\nOr better: create a dedicated `sweepCompletedSubagentSessions` that runs on the same timer, checks `entry.endedAt` or `entry.abortedLastRun`, and prunes entries older than `sessionRetention`.\\n\\nAlternatively, expose a separate `session.subagentRetention` config field if the retention policy should differ from cron sessions.\\n\\n## Workaround\\n\\nManual cleanup: trim `sessions.json` to only the main session, archive `.jsonl` files, restart gateway. Or run a periodic cleanup script/cron.\\n\\n## Environment\\n\\n- OpenClaw latest (npm)\\n- Config: `cron.sessionRetention: \\\"3h\\\"`\\n- Observed with 37 sessions accumulating over 2 days of heavy subagent use\",\"author_association\":\"NONE\",\"user\":{\"login\":\"100yenadmin\",\"id\":239388517,\"node_id\":\"U_kgDODkTHZQ\",\"avatar_url\":\"https://avatars.githubusercontent.com/u/239388517?v=4\",\"html_url\":\"https://github.com/100yenadmin\",\"gravatar_id\":\"\",\"type\":\"User\",\"site_admin\":false,\"url\":\"https://api.github.com/users/100yenadmin\",\"events_url\":\"https://api.github.com/users/100yenadmin/events{/privacy}\",\"following_url\":\"https://api.github.com/users/100yenadmin/following{/other_user}\",\"followers_url\":\"https://api.github.com/users/100yenadmin/followers\",\"gists_url\":\"https://api.github.com/users/100yenadmin/gists{/gist_id}\",\"organizations_url\":\"https://api.github.com/users/100yenadmin/orgs\",\"received_events_url\":\"https://api.github.com/users/100yenadmin/received_events\",\"repos_url\":\"https://api.github.com/users/100yenadmin/repos\",\"starred_url\":\"https://api.github.com/users/100yenadmin/starred{/owner}{/repo}\",\"subscriptions_url\":\"https://api.github.com/users/100yenadmin/subscriptions\"},\"comments\":3,\"created_at\":\"2026-03-21T17:01:49Z\",\"updated_at\":\"2026-03-21T18:04:12Z\",\"url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51767\",\"html_url\":\"https://github.com/openclaw/openclaw/issues/51767\",\"comments_url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51767/comments\",\"events_url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51767/events\",\"labels_url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51767/labels{/name}\",\"repository_url\":\"https://api.github.com/repos/openclaw/openclaw\",\"reactions\":{\"total_count\":0,\"+1\":0,\"-1\":0,\"laugh\":0,\"confused\":0,\"heart\":0,\"hooray\":0,\"rocket\":0,\"eyes\":0,\"url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51767/reactions\"},\"node_id\":\"I_kwDOQb6kR871KENu\"},{\"id\":4112649104,\"number\":51636,\"state\":\"open\",\"locked\":false,\"title\":\"Discord WebSocket gateway disconnects every ~10 minutes (health-monitor restart loop)\",\"body\":\"# Discord WebSocket gateway disconnects every ~10 minutes (health-monitor restart loop)\\n\\n## Description\\n\\nTwo separate OpenClaw instances on the same Mac mini (M4, macOS 15.3) both experience continuous Discord WebSocket disconnects. The health-monitor detects `disconnected` or `stale-socket` and restarts the Discord channel adapter every ~10 minutes in an endless loop.\\n\\nBoth instances function correctly (messages send/receive) because the health-monitor recovers quickly, but the constant restart cycle is unnecessary overhead and occasionally causes missed messages.\\n\\n## Environment\\n\\n- **OpenClaw versions tested:** 2026.3.11 and 2026.3.13 (same behavior on both)\\n- **OS:** macOS 15.3 (Darwin 25.3.0, arm64)\\n- **Node:** v25.6.0\\n- **Network:** Stable broadband, no firewall rules affecting WebSocket connections\\n- **Two instances:** Both on same machine, different ports (18789 and 3010), different Discord bot tokens, same guild\\n\\n## Configuration\\n\\nBoth instances use nearly identical Discord config:\\n```json\\n{\\n  \\\"enabled\\\": true,\\n  \\\"streaming\\\": \\\"off\\\",\\n  \\\"dmPolicy\\\": \\\"allowlist\\\",\\n  \\\"groupPolicy\\\": \\\"allowlist\\\",\\n  \\\"guilds\\\": {\\n    \\\"\\u003cguild_id\\u003e\\\": {\\n      \\\"requireMention\\\": false,\\n      \\\"channels\\\": { ... }\\n    }\\n  }\\n}\\n```\\n\\nInstance A monitors 21 channels, Instance B monitors 3 channels. Both exhibit the same disconnect pattern.\\n\\n## Log Evidence\\n\\n### Instance A (v2026.3.11, port 18789) — 789 disconnects in current log\\n```\\n2026-03-21T06:26:44.485-04:00 [health-monitor] [discord:default] health-monitor: restarting (reason: disconnected)\\n2026-03-21T06:36:44.492-04:00 [health-monitor] [discord:default] health-monitor: restarting (reason: disconnected)\\n2026-03-21T06:46:44.498-04:00 [health-monitor] [discord:default] health-monitor: restarting (reason: disconnected)\\n2026-03-21T06:56:44.505-04:00 [health-monitor] [discord:default] health-monitor: restarting (reason: disconnected)\\n2026-03-21T07:06:44.512-04:00 [health-monitor] [discord:default] health-monitor: restarting (reason: disconnected)\\n```\\n\\n### Instance B (v2026.3.13, port 3010) — 69 disconnects since last restart\\n```\\n2026-03-21T07:03:13.207-04:00 [health-monitor] [discord:default] health-monitor: restarting (reason: disconnected)\\n2026-03-21T07:13:13.215-04:00 [health-monitor] [discord:default] health-monitor: restarting (reason: disconnected)\\n2026-03-21T07:48:13.240-04:00 [health-monitor] [discord:default] health-monitor: restarting (reason: stale-socket)\\n2026-03-21T07:58:13.246-04:00 [health-monitor] [discord:default] health-monitor: restarting (reason: disconnected)\\n```\\n\\n### Pattern\\n- Disconnects occur every **~10 minutes** consistently\\n- Reasons alternate between `disconnected` and `stale-socket`\\n- Occasionally sees `WebSocket connection closed with code 1005` before restart\\n- Gateway reconnects successfully each time but drops again within minutes\\n- All three Discord gateway intents enabled (Presence, Server Members, Message Content)\\n\\n## What we've tried\\n\\n1. ✅ Updated from 2026.3.11 to 2026.3.13 — no change\\n2. ✅ Regenerated Discord bot token — no change\\n3. ✅ Verified all gateway intents enabled — confirmed\\n4. ✅ Compared configs between both instances — functionally identical\\n5. ✅ Different bot tokens, different ports, same result\\n\\n## Suspected cause\\n\\nThe Discord WebSocket heartbeat ACK may not be handled correctly, causing Discord to close the connection after its heartbeat timeout. The health-monitor then detects the dead socket and restarts, creating the loop.\\n\\n## Expected behavior\\n\\nDiscord WebSocket connection should remain stable between messages, with the internal heartbeat keeping the connection alive indefinitely (or reconnecting transparently without a full channel adapter restart).\\n\",\"author_association\":\"NONE\",\"user\":{\"login\":\"staroscott\",\"id\":230729624,\"node_id\":\"U_kgDODcCnmA\",\"avatar_url\":\"https://avatars.githubusercontent.com/u/230729624?v=4\",\"html_url\":\"https://github.com/staroscott\",\"gravatar_id\":\"\",\"type\":\"User\",\"site_admin\":false,\"url\":\"https://api.github.com/users/staroscott\",\"events_url\":\"https://api.github.com/users/staroscott/events{/privacy}\",\"following_url\":\"https://api.github.com/users/staroscott/following{/other_user}\",\"followers_url\":\"https://api.github.com/users/staroscott/followers\",\"gists_url\":\"https://api.github.com/users/staroscott/gists{/gist_id}\",\"organizations_url\":\"https://api.github.com/users/staroscott/orgs\",\"received_events_url\":\"https://api.github.com/users/staroscott/received_events\",\"repos_url\":\"https://api.github.com/users/staroscott/repos\",\"starred_url\":\"https://api.github.com/users/staroscott/starred{/owner}{/repo}\",\"subscriptions_url\":\"https://api.github.com/users/staroscott/subscriptions\"},\"comments\":3,\"created_at\":\"2026-03-21T14:05:53Z\",\"updated_at\":\"2026-03-21T15:37:31Z\",\"url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51636\",\"html_url\":\"https://github.com/openclaw/openclaw/issues/51636\",\"comments_url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51636/comments\",\"events_url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51636/events\",\"labels_url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51636/labels{/name}\",\"repository_url\":\"https://api.github.com/repos/openclaw/openclaw\",\"reactions\":{\"total_count\":0,\"+1\":0,\"-1\":0,\"laugh\":0,\"confused\":0,\"heart\":0,\"hooray\":0,\"rocket\":0,\"eyes\":0,\"url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51636/reactions\"},\"node_id\":\"I_kwDOQb6kR871IguQ\"},{\"id\":4112254502,\"number\":51587,\"state\":\"open\",\"locked\":false,\"title\":\"Bug: isRecurringTopOfHourCronExpr fails to match cron expressions with step values\",\"body\":\"## Bug Report: `isRecurringTopOfHourCronExpr` fails to match cron expressions with step values\\n\\n### Summary\\nThe `isRecurringTopOfHourCronExpr` function in `src/cron/stagger.ts` only matches cron expressions where the minute field is exactly `\\\"0\\\"`. This causes it to incorrectly return `false` for valid recurring top-of-hour expressions like `*/15 * * * *`, `0,30 * * * *`, or `0-30 * * * *`, which should also receive the default 5-minute stagger.\\n\\n### Location\\nFile: `dist/auth-profiles-*.js` (bundled from `src/cron/stagger.ts`)\\n\\n```typescript\\nfunction isRecurringTopOfHourCronExpr(expr: string): boolean {\\n  const fields = parseCronFields(expr);\\n  if (fields.length === 5) {\\n    const [minuteField, hourField] = fields;\\n    return minuteField === \\\"0\\\" \\u0026\\u0026 hourField.includes(\\\"*\\\");  // ❌ Too strict!\\n  }\\n  if (fields.length === 6) {\\n    const [secondField, minuteField, hourField] = fields;\\n    return secondField === \\\"0\\\" \\u0026\\u0026 minuteField === \\\"0\\\" \\u0026\\u0026 hourField.includes(\\\"*\\\");\\n  }\\n  return false;\\n}\\n```\\n\\n### Root Cause\\nThe function uses strict equality (`=== \\\"0\\\"`) instead of parsing the minute field for:\\n- **Step expressions**: `*/n` (every n minutes)\\n- **List expressions**: `n,m,o` (at minutes n, m, or o)\\n- **Range expressions**: `n-m` (from minute n to m)\\n\\nAll these are valid cron patterns that can represent \\\"at the top of certain hours.\\\"\\n\\n### Impact\\nUsers with cron expressions like `*/15 * * * *` (every 15 minutes) will NOT receive the default 5-minute stagger (`DEFAULT_TOP_OF_HOUR_STAGGER_MS`), even though they run at predictable top-of-hour intervals. This could cause:\\n- Thundering herd when multiple cron jobs fire simultaneously\\n- API rate limit issues\\n- Unnecessary load spikes\\n\\n### Minimal Reproducible Example\\n```typescript\\n// These all return false but SHOULD return true:\\nisRecurringTopOfHourCronExpr(\\\"*/15 * * * *\\\");  // every 15 mins - should stagger\\nisRecurringTopOfHourCronExpr(\\\"0,30 * * * *\\\"); // at minutes 0 and 30 - should stagger  \\nisRecurringTopOfHourCronExpr(\\\"0-30 * * * *\\\"); // range 0-30 - edge case, debatable\\n\\n// This correctly returns true:\\nisRecurringTopOfHourCronExpr(\\\"0 * * * *\\\");    // exactly at minute 0 - correctly staggers\\n```\\n\\n### Proposed Fix\\nParse the minute field properly to detect if `0` is included:\\n\\n```typescript\\nfunction includesMinuteZero(field: string): boolean {\\n  if (field === \\\"*\\\") return true;\\n  if (field.startsWith(\\\"*/\\\")) {\\n    const step = parseInt(field.slice(2), 10);\\n    return step \\u003e 0;\\n  }\\n  if (field.includes(\\\"-\\\")) {\\n    const [start, end] = field.split(\\\"-\\\").map(Number);\\n    return start \\u003c= 0 \\u0026\\u0026 0 \\u003c= end;\\n  }\\n  if (field.includes(\\\",\\\")) {\\n    return field.split(\\\",\\\").map(Number).includes(0);\\n  }\\n  return parseInt(field, 10) === 0;\\n}\\n```\\n\\n### Labels\\nbug, cron, stagger\",\"author_association\":\"NONE\",\"user\":{\"login\":\"Financier-Nuri\",\"id\":130913840,\"node_id\":\"U_kgDOB82WMA\",\"avatar_url\":\"https://avatars.githubusercontent.com/u/130913840?v=4\",\"html_url\":\"https://github.com/Financier-Nuri\",\"gravatar_id\":\"\",\"type\":\"User\",\"site_admin\":false,\"url\":\"https://api.github.com/users/Financier-Nuri\",\"events_url\":\"https://api.github.com/users/Financier-Nuri/events{/privacy}\",\"following_url\":\"https://api.github.com/users/Financier-Nuri/following{/other_user}\",\"followers_url\":\"https://api.github.com/users/Financier-Nuri/followers\",\"gists_url\":\"https://api.github.com/users/Financier-Nuri/gists{/gist_id}\",\"organizations_url\":\"https://api.github.com/users/Financier-Nuri/orgs\",\"received_events_url\":\"https://api.github.com/users/Financier-Nuri/received_events\",\"repos_url\":\"https://api.github.com/users/Financier-Nuri/repos\",\"starred_url\":\"https://api.github.com/users/Financier-Nuri/starred{/owner}{/repo}\",\"subscriptions_url\":\"https://api.github.com/users/Financier-Nuri/subscriptions\"},\"comments\":1,\"created_at\":\"2026-03-21T12:05:51Z\",\"updated_at\":\"2026-03-21T12:38:13Z\",\"url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51587\",\"html_url\":\"https://github.com/openclaw/openclaw/issues/51587\",\"comments_url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51587/comments\",\"events_url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51587/events\",\"labels_url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51587/labels{/name}\",\"repository_url\":\"https://api.github.com/repos/openclaw/openclaw\",\"reactions\":{\"total_count\":0,\"+1\":0,\"-1\":0,\"laugh\":0,\"confused\":0,\"heart\":0,\"hooray\":0,\"rocket\":0,\"eyes\":0,\"url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51587/reactions\"},\"node_id\":\"I_kwDOQb6kR871HAYm\"},{\"id\":4111615286,\"number\":51466,\"state\":\"open\",\"locked\":false,\"title\":\"[Bug] Telegram /tts audio reaches TTS path but Edge provider times out; no voice note delivered on v2026.3.13\",\"body\":\"## Summary\\n\\nOn OpenClaw v2026.3.13, Telegram TTS does not successfully return a voice note in my environment.\\n\\nThe key point is:\\n- TTS is not completely unsupported on Telegram\\n- /tts audio clearly enters the TTS path\\n- but the free Edge/Microsoft provider times out, so no audio is produced and no Telegram voice note is delivered\\n\\n## Environment\\n\\n- OpenClaw version: v2026.3.13\\n- Channel: Telegram\\n- OS: Linux\\n- Config file: /root/.openclaw/openclaw.json\\n\\n## What I tested\\n\\nI first tested auto TTS with:\\n\\n```json\\n{\\n  \\\"messages\\\": {\\n    \\\"tts\\\": {\\n      \\\"auto\\\": \\\"always\\\",\\n      \\\"provider\\\": \\\"edge\\\",\\n      \\\"edge\\\": {\\n        \\\"enabled\\\": true,\\n        \\\"voice\\\": \\\"zh-CN-XiaochenNeural\\\",\\n        \\\"lang\\\": \\\"zh-CN\\\"\\n      }\\n    }\\n  }\\n}\\n```\\n\\nI also tested auto: \\\"inbound\\\" before that.\\n\\nIn both cases, Telegram replies remained text-only in practice.\\n\\nThen I ran an explicit command in Telegram:\\n\\n```\\n/tts audio 你好，这是一次 TTS 强制测试\\n```\\n\\nTelegram returned this error message:\\n\\n❌ Error generating audio: TTS conversion failed: edge: Timed out; openai: no API key; elevenlabs: no API key\\n\\n## Expected behavior\\n\\n- /tts audio ... should generate speech and send a Telegram voice note\\n- messages.tts.auto = \\\"always\\\" or \\\"inbound\\\" should trigger outbound audio on Telegram\\n- Telegram should receive the native round voice-note bubble\\n\\n## Actual behavior\\n\\n- /tts audio ... does not deliver any voice note\\n- Telegram only shows text/error output\\n- The Edge provider appears to time out before audio is returned\\n\\n## Important observation\\n\\nPlease note that this is **not** the same as \\\"Telegram does not support TTS at all\\\".\\n\\nThe explicit /tts audio command produces:\\n\\n❌ Error generating audio: TTS conversion failed: edge: Timed out; openai: no API key; elevenlabs: no API key\\n\\nSo the request appears to reach the TTS layer, but the Edge provider fails before Telegram can send audio.\\n\\n## Additional notes\\n\\n- No local TTS prefs file existed on this node: ~/.openclaw/settings/tts.json was absent, so there was no prefs override of messages.tts\\n- After testing, I restored the config to default by removing messages.tts\\n\\n## Question\\n\\nIs this a known regression/timeout issue with the Edge/Microsoft TTS path on Telegram in v2026.3.13?\\n\\nAlso, is there any recommended timeout/output-format adjustment for Telegram + Edge TTS in this version?\",\"author_association\":\"NONE\",\"user\":{\"login\":\"spadesv\",\"id\":30253580,\"node_id\":\"MDQ6VXNlcjMwMjUzNTgw\",\"avatar_url\":\"https://avatars.githubusercontent.com/u/30253580?v=4\",\"html_url\":\"https://github.com/spadesv\",\"gravatar_id\":\"\",\"type\":\"User\",\"site_admin\":false,\"url\":\"https://api.github.com/users/spadesv\",\"events_url\":\"https://api.github.com/users/spadesv/events{/privacy}\",\"following_url\":\"https://api.github.com/users/spadesv/following{/other_user}\",\"followers_url\":\"https://api.github.com/users/spadesv/followers\",\"gists_url\":\"https://api.github.com/users/spadesv/gists{/gist_id}\",\"organizations_url\":\"https://api.github.com/users/spadesv/orgs\",\"received_events_url\":\"https://api.github.com/users/spadesv/received_events\",\"repos_url\":\"https://api.github.com/users/spadesv/repos\",\"starred_url\":\"https://api.github.com/users/spadesv/starred{/owner}{/repo}\",\"subscriptions_url\":\"https://api.github.com/users/spadesv/subscriptions\"},\"comments\":1,\"created_at\":\"2026-03-21T06:30:14Z\",\"updated_at\":\"2026-03-21T07:14:19Z\",\"url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51466\",\"html_url\":\"https://github.com/openclaw/openclaw/issues/51466\",\"comments_url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51466/comments\",\"events_url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51466/events\",\"labels_url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51466/labels{/name}\",\"repository_url\":\"https://api.github.com/repos/openclaw/openclaw\",\"reactions\":{\"total_count\":0,\"+1\":0,\"-1\":0,\"laugh\":0,\"confused\":0,\"heart\":0,\"hooray\":0,\"rocket\":0,\"eyes\":0,\"url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51466/reactions\"},\"node_id\":\"I_kwDOQb6kR871EkU2\"},{\"id\":4111059401,\"number\":51383,\"state\":\"open\",\"locked\":false,\"title\":\"Feature: Webchat project/thread system for parallel contexts\",\"body\":\"## Problem\\n\\nWebchat is the most powerful interface for OpenClaw (direct host access, no rate limits, full tool access), but it lacks basic organization features that Discord/Telegram provide natively.\\n\\nCurrently:\\n- Single continuous stream per session\\n- `/new` or `/reset` clears all context\\n- No way to work on multiple projects/threads in parallel\\n- No history browser\\n\\n## Proposed Solution\\n\\n### 1. Project/Thread System\\n- Multiple parallel \\\"threads\\\" or \\\"projects\\\" within webchat\\n- Each thread maintains its own context window\\n- Quick switching between threads (sidebar or tabs)\\n- Per-thread system prompts / SOUL.md overrides\\n\\n### 2. History Browser\\n- Searchable history across threads\\n- Date-based navigation\\n- Export capability\\n\\n### 3. Per-Project Memory Isolation\\n- Optional isolated memory per project\\n- Project-specific context injection\\n\\n## Use Cases\\n\\n1. **Development workflow**: Work on WBF2 in one thread, Alexandria in another, without mixing context\\n2. **Research**: Keep separate threads for different research topics\\n3. **Daily operations**: Dedicated thread for daily reviews, another for ad-hoc tasks\\n\\n## Alternatives Considered\\n\\n- Using Discord forums (works, but loses local tool access benefits)\\n- Multiple browser tabs with `/new` (no persistence, loses context on refresh)\\n- External memory systems like Obsidian (partial solution, doesn't address UI)\\n\\n## Implementation Thoughts\\n\\n- Thread state could persist in SQLite alongside memory\\n- UI could use a simple sidebar or tab strip\\n- Each thread = separate session key internally\\n\\nThis would make webchat a true \\\"local-first\\\" alternative to Discord/Telegram rather than just a fallback.\",\"author_association\":\"NONE\",\"user\":{\"login\":\"sabo961\",\"id\":191984,\"node_id\":\"MDQ6VXNlcjE5MTk4NA==\",\"avatar_url\":\"https://avatars.githubusercontent.com/u/191984?v=4\",\"html_url\":\"https://github.com/sabo961\",\"gravatar_id\":\"\",\"type\":\"User\",\"site_admin\":false,\"url\":\"https://api.github.com/users/sabo961\",\"events_url\":\"https://api.github.com/users/sabo961/events{/privacy}\",\"following_url\":\"https://api.github.com/users/sabo961/following{/other_user}\",\"followers_url\":\"https://api.github.com/users/sabo961/followers\",\"gists_url\":\"https://api.github.com/users/sabo961/gists{/gist_id}\",\"organizations_url\":\"https://api.github.com/users/sabo961/orgs\",\"received_events_url\":\"https://api.github.com/users/sabo961/received_events\",\"repos_url\":\"https://api.github.com/users/sabo961/repos\",\"starred_url\":\"https://api.github.com/users/sabo961/starred{/owner}{/repo}\",\"subscriptions_url\":\"https://api.github.com/users/sabo961/subscriptions\"},\"comments\":1,\"created_at\":\"2026-03-21T02:32:50Z\",\"updated_at\":\"2026-03-21T02:40:19Z\",\"url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51383\",\"html_url\":\"https://github.com/openclaw/openclaw/issues/51383\",\"comments_url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51383/comments\",\"events_url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51383/events\",\"labels_url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51383/labels{/name}\",\"repository_url\":\"https://api.github.com/repos/openclaw/openclaw\",\"reactions\":{\"total_count\":0,\"+1\":0,\"-1\":0,\"laugh\":0,\"confused\":0,\"heart\":0,\"hooray\":0,\"rocket\":0,\"eyes\":0,\"url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51383/reactions\"},\"node_id\":\"I_kwDOQb6kR871CcnJ\"}]}"}]}]},"parent_tool_use_id":null,"session_id":"1cbb44f9-7700-474d-82b1-f71c070b293f","uuid":"3101b567-7970-4f19-8cdc-1e5c34d239cc","timestamp":"2026-03-21T19:24:03.893Z","tool_use_result":[{"type":"text","text":"{\"total_count\":943,\"incomplete_results\":false,\"items\":[{\"id\":4113056622,\"number\":51767,\"state\":\"open\",\"locked\":false,\"title\":\"sessionRetention does not apply to subagent sessions — only cron-run sessions are swept\",\"body\":\"## Summary\\n\\n`cron.sessionRetention` (e.g. `\\\"3h\\\"`) only prunes sessions matching `isCronRunSessionKey()` (pattern `cron:*:run:*`). Subagent sessions (`agent:*:subagent:*`) are **never cleaned up** by the retention sweep, even after they complete.\\n\\n## Impact\\n\\nAfter any sprint with 10-30+ subagent spawns, `sessions.json` grows to 1.5MB+, gateway RSS climbs 500MB+, and stale sessions accumulate indefinitely. Users must manually purge `sessions.json` and restart.\\n\\n## Root Cause\\n\\nIn `src/cron/service/session-reaper.ts` (bundled as `gateway-cli-*.js` L5620-5622):\\n\\n```js\\nfor (const key of Object.keys(store)) {\\n    if (!isCronRunSessionKey(key)) continue;  // \\u003c-- skips subagent sessions\\n    // ...only cron sessions get pruned\\n}\\n```\\n\\nThe separate `subagent-registry-cleanup.ts` handles announce/finalize flows but does NOT remove the session entry from the session store or delete transcript files.\\n\\n## Expected Behavior\\n\\n`sessionRetention` should apply to **all** non-main session types — at minimum:\\n- `isCronRunSessionKey()` ✅ (already works)\\n- `isSubagentSessionKey()` ❌ (currently skipped)\\n- `isAcpSessionKey()` ❌ (likely also skipped)\\n\\nCompleted subagent sessions (where `endedAt` exists and age \\u003e retention) should be pruned from the store and their transcript `.jsonl` files archived/deleted.\\n\\n## Suggested Fix\\n\\nIn `sweepCronRunSessions` (or a new parallel sweep), add:\\n\\n```js\\nif (!isCronRunSessionKey(key) \\u0026\\u0026 !isSubagentSessionKey(key) \\u0026\\u0026 !isAcpSessionKey(key)) continue;\\n```\\n\\nOr better: create a dedicated `sweepCompletedSubagentSessions` that runs on the same timer, checks `entry.endedAt` or `entry.abortedLastRun`, and prunes entries older than `sessionRetention`.\\n\\nAlternatively, expose a separate `session.subagentRetention` config field if the retention policy should differ from cron sessions.\\n\\n## Workaround\\n\\nManual cleanup: trim `sessions.json` to only the main session, archive `.jsonl` files, restart gateway. Or run a periodic cleanup script/cron.\\n\\n## Environment\\n\\n- OpenClaw latest (npm)\\n- Config: `cron.sessionRetention: \\\"3h\\\"`\\n- Observed with 37 sessions accumulating over 2 days of heavy subagent use\",\"author_association\":\"NONE\",\"user\":{\"login\":\"100yenadmin\",\"id\":239388517,\"node_id\":\"U_kgDODkTHZQ\",\"avatar_url\":\"https://avatars.githubusercontent.com/u/239388517?v=4\",\"html_url\":\"https://github.com/100yenadmin\",\"gravatar_id\":\"\",\"type\":\"User\",\"site_admin\":false,\"url\":\"https://api.github.com/users/100yenadmin\",\"events_url\":\"https://api.github.com/users/100yenadmin/events{/privacy}\",\"following_url\":\"https://api.github.com/users/100yenadmin/following{/other_user}\",\"followers_url\":\"https://api.github.com/users/100yenadmin/followers\",\"gists_url\":\"https://api.github.com/users/100yenadmin/gists{/gist_id}\",\"organizations_url\":\"https://api.github.com/users/100yenadmin/orgs\",\"received_events_url\":\"https://api.github.com/users/100yenadmin/received_events\",\"repos_url\":\"https://api.github.com/users/100yenadmin/repos\",\"starred_url\":\"https://api.github.com/users/100yenadmin/starred{/owner}{/repo}\",\"subscriptions_url\":\"https://api.github.com/users/100yenadmin/subscriptions\"},\"comments\":3,\"created_at\":\"2026-03-21T17:01:49Z\",\"updated_at\":\"2026-03-21T18:04:12Z\",\"url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51767\",\"html_url\":\"https://github.com/openclaw/openclaw/issues/51767\",\"comments_url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51767/comments\",\"events_url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51767/events\",\"labels_url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51767/labels{/name}\",\"repository_url\":\"https://api.github.com/repos/openclaw/openclaw\",\"reactions\":{\"total_count\":0,\"+1\":0,\"-1\":0,\"laugh\":0,\"confused\":0,\"heart\":0,\"hooray\":0,\"rocket\":0,\"eyes\":0,\"url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51767/reactions\"},\"node_id\":\"I_kwDOQb6kR871KENu\"},{\"id\":4112649104,\"number\":51636,\"state\":\"open\",\"locked\":false,\"title\":\"Discord WebSocket gateway disconnects every ~10 minutes (health-monitor restart loop)\",\"body\":\"# Discord WebSocket gateway disconnects every ~10 minutes (health-monitor restart loop)\\n\\n## Description\\n\\nTwo separate OpenClaw instances on the same Mac mini (M4, macOS 15.3) both experience continuous Discord WebSocket disconnects. The health-monitor detects `disconnected` or `stale-socket` and restarts the Discord channel adapter every ~10 minutes in an endless loop.\\n\\nBoth instances function correctly (messages send/receive) because the health-monitor recovers quickly, but the constant restart cycle is unnecessary overhead and occasionally causes missed messages.\\n\\n## Environment\\n\\n- **OpenClaw versions tested:** 2026.3.11 and 2026.3.13 (same behavior on both)\\n- **OS:** macOS 15.3 (Darwin 25.3.0, arm64)\\n- **Node:** v25.6.0\\n- **Network:** Stable broadband, no firewall rules affecting WebSocket connections\\n- **Two instances:** Both on same machine, different ports (18789 and 3010), different Discord bot tokens, same guild\\n\\n## Configuration\\n\\nBoth instances use nearly identical Discord config:\\n```json\\n{\\n  \\\"enabled\\\": true,\\n  \\\"streaming\\\": \\\"off\\\",\\n  \\\"dmPolicy\\\": \\\"allowlist\\\",\\n  \\\"groupPolicy\\\": \\\"allowlist\\\",\\n  \\\"guilds\\\": {\\n    \\\"\\u003cguild_id\\u003e\\\": {\\n      \\\"requireMention\\\": false,\\n      \\\"channels\\\": { ... }\\n    }\\n  }\\n}\\n```\\n\\nInstance A monitors 21 channels, Instance B monitors 3 channels. Both exhibit the same disconnect pattern.\\n\\n## Log Evidence\\n\\n### Instance A (v2026.3.11, port 18789) — 789 disconnects in current log\\n```\\n2026-03-21T06:26:44.485-04:00 [health-monitor] [discord:default] health-monitor: restarting (reason: disconnected)\\n2026-03-21T06:36:44.492-04:00 [health-monitor] [discord:default] health-monitor: restarting (reason: disconnected)\\n2026-03-21T06:46:44.498-04:00 [health-monitor] [discord:default] health-monitor: restarting (reason: disconnected)\\n2026-03-21T06:56:44.505-04:00 [health-monitor] [discord:default] health-monitor: restarting (reason: disconnected)\\n2026-03-21T07:06:44.512-04:00 [health-monitor] [discord:default] health-monitor: restarting (reason: disconnected)\\n```\\n\\n### Instance B (v2026.3.13, port 3010) — 69 disconnects since last restart\\n```\\n2026-03-21T07:03:13.207-04:00 [health-monitor] [discord:default] health-monitor: restarting (reason: disconnected)\\n2026-03-21T07:13:13.215-04:00 [health-monitor] [discord:default] health-monitor: restarting (reason: disconnected)\\n2026-03-21T07:48:13.240-04:00 [health-monitor] [discord:default] health-monitor: restarting (reason: stale-socket)\\n2026-03-21T07:58:13.246-04:00 [health-monitor] [discord:default] health-monitor: restarting (reason: disconnected)\\n```\\n\\n### Pattern\\n- Disconnects occur every **~10 minutes** consistently\\n- Reasons alternate between `disconnected` and `stale-socket`\\n- Occasionally sees `WebSocket connection closed with code 1005` before restart\\n- Gateway reconnects successfully each time but drops again within minutes\\n- All three Discord gateway intents enabled (Presence, Server Members, Message Content)\\n\\n## What we've tried\\n\\n1. ✅ Updated from 2026.3.11 to 2026.3.13 — no change\\n2. ✅ Regenerated Discord bot token — no change\\n3. ✅ Verified all gateway intents enabled — confirmed\\n4. ✅ Compared configs between both instances — functionally identical\\n5. ✅ Different bot tokens, different ports, same result\\n\\n## Suspected cause\\n\\nThe Discord WebSocket heartbeat ACK may not be handled correctly, causing Discord to close the connection after its heartbeat timeout. The health-monitor then detects the dead socket and restarts, creating the loop.\\n\\n## Expected behavior\\n\\nDiscord WebSocket connection should remain stable between messages, with the internal heartbeat keeping the connection alive indefinitely (or reconnecting transparently without a full channel adapter restart).\\n\",\"author_association\":\"NONE\",\"user\":{\"login\":\"staroscott\",\"id\":230729624,\"node_id\":\"U_kgDODcCnmA\",\"avatar_url\":\"https://avatars.githubusercontent.com/u/230729624?v=4\",\"html_url\":\"https://github.com/staroscott\",\"gravatar_id\":\"\",\"type\":\"User\",\"site_admin\":false,\"url\":\"https://api.github.com/users/staroscott\",\"events_url\":\"https://api.github.com/users/staroscott/events{/privacy}\",\"following_url\":\"https://api.github.com/users/staroscott/following{/other_user}\",\"followers_url\":\"https://api.github.com/users/staroscott/followers\",\"gists_url\":\"https://api.github.com/users/staroscott/gists{/gist_id}\",\"organizations_url\":\"https://api.github.com/users/staroscott/orgs\",\"received_events_url\":\"https://api.github.com/users/staroscott/received_events\",\"repos_url\":\"https://api.github.com/users/staroscott/repos\",\"starred_url\":\"https://api.github.com/users/staroscott/starred{/owner}{/repo}\",\"subscriptions_url\":\"https://api.github.com/users/staroscott/subscriptions\"},\"comments\":3,\"created_at\":\"2026-03-21T14:05:53Z\",\"updated_at\":\"2026-03-21T15:37:31Z\",\"url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51636\",\"html_url\":\"https://github.com/openclaw/openclaw/issues/51636\",\"comments_url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51636/comments\",\"events_url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51636/events\",\"labels_url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51636/labels{/name}\",\"repository_url\":\"https://api.github.com/repos/openclaw/openclaw\",\"reactions\":{\"total_count\":0,\"+1\":0,\"-1\":0,\"laugh\":0,\"confused\":0,\"heart\":0,\"hooray\":0,\"rocket\":0,\"eyes\":0,\"url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51636/reactions\"},\"node_id\":\"I_kwDOQb6kR871IguQ\"},{\"id\":4112254502,\"number\":51587,\"state\":\"open\",\"locked\":false,\"title\":\"Bug: isRecurringTopOfHourCronExpr fails to match cron expressions with step values\",\"body\":\"## Bug Report: `isRecurringTopOfHourCronExpr` fails to match cron expressions with step values\\n\\n### Summary\\nThe `isRecurringTopOfHourCronExpr` function in `src/cron/stagger.ts` only matches cron expressions where the minute field is exactly `\\\"0\\\"`. This causes it to incorrectly return `false` for valid recurring top-of-hour expressions like `*/15 * * * *`, `0,30 * * * *`, or `0-30 * * * *`, which should also receive the default 5-minute stagger.\\n\\n### Location\\nFile: `dist/auth-profiles-*.js` (bundled from `src/cron/stagger.ts`)\\n\\n```typescript\\nfunction isRecurringTopOfHourCronExpr(expr: string): boolean {\\n  const fields = parseCronFields(expr);\\n  if (fields.length === 5) {\\n    const [minuteField, hourField] = fields;\\n    return minuteField === \\\"0\\\" \\u0026\\u0026 hourField.includes(\\\"*\\\");  // ❌ Too strict!\\n  }\\n  if (fields.length === 6) {\\n    const [secondField, minuteField, hourField] = fields;\\n    return secondField === \\\"0\\\" \\u0026\\u0026 minuteField === \\\"0\\\" \\u0026\\u0026 hourField.includes(\\\"*\\\");\\n  }\\n  return false;\\n}\\n```\\n\\n### Root Cause\\nThe function uses strict equality (`=== \\\"0\\\"`) instead of parsing the minute field for:\\n- **Step expressions**: `*/n` (every n minutes)\\n- **List expressions**: `n,m,o` (at minutes n, m, or o)\\n- **Range expressions**: `n-m` (from minute n to m)\\n\\nAll these are valid cron patterns that can represent \\\"at the top of certain hours.\\\"\\n\\n### Impact\\nUsers with cron expressions like `*/15 * * * *` (every 15 minutes) will NOT receive the default 5-minute stagger (`DEFAULT_TOP_OF_HOUR_STAGGER_MS`), even though they run at predictable top-of-hour intervals. This could cause:\\n- Thundering herd when multiple cron jobs fire simultaneously\\n- API rate limit issues\\n- Unnecessary load spikes\\n\\n### Minimal Reproducible Example\\n```typescript\\n// These all return false but SHOULD return true:\\nisRecurringTopOfHourCronExpr(\\\"*/15 * * * *\\\");  // every 15 mins - should stagger\\nisRecurringTopOfHourCronExpr(\\\"0,30 * * * *\\\"); // at minutes 0 and 30 - should stagger  \\nisRecurringTopOfHourCronExpr(\\\"0-30 * * * *\\\"); // range 0-30 - edge case, debatable\\n\\n// This correctly returns true:\\nisRecurringTopOfHourCronExpr(\\\"0 * * * *\\\");    // exactly at minute 0 - correctly staggers\\n```\\n\\n### Proposed Fix\\nParse the minute field properly to detect if `0` is included:\\n\\n```typescript\\nfunction includesMinuteZero(field: string): boolean {\\n  if (field === \\\"*\\\") return true;\\n  if (field.startsWith(\\\"*/\\\")) {\\n    const step = parseInt(field.slice(2), 10);\\n    return step \\u003e 0;\\n  }\\n  if (field.includes(\\\"-\\\")) {\\n    const [start, end] = field.split(\\\"-\\\").map(Number);\\n    return start \\u003c= 0 \\u0026\\u0026 0 \\u003c= end;\\n  }\\n  if (field.includes(\\\",\\\")) {\\n    return field.split(\\\",\\\").map(Number).includes(0);\\n  }\\n  return parseInt(field, 10) === 0;\\n}\\n```\\n\\n### Labels\\nbug, cron, stagger\",\"author_association\":\"NONE\",\"user\":{\"login\":\"Financier-Nuri\",\"id\":130913840,\"node_id\":\"U_kgDOB82WMA\",\"avatar_url\":\"https://avatars.githubusercontent.com/u/130913840?v=4\",\"html_url\":\"https://github.com/Financier-Nuri\",\"gravatar_id\":\"\",\"type\":\"User\",\"site_admin\":false,\"url\":\"https://api.github.com/users/Financier-Nuri\",\"events_url\":\"https://api.github.com/users/Financier-Nuri/events{/privacy}\",\"following_url\":\"https://api.github.com/users/Financier-Nuri/following{/other_user}\",\"followers_url\":\"https://api.github.com/users/Financier-Nuri/followers\",\"gists_url\":\"https://api.github.com/users/Financier-Nuri/gists{/gist_id}\",\"organizations_url\":\"https://api.github.com/users/Financier-Nuri/orgs\",\"received_events_url\":\"https://api.github.com/users/Financier-Nuri/received_events\",\"repos_url\":\"https://api.github.com/users/Financier-Nuri/repos\",\"starred_url\":\"https://api.github.com/users/Financier-Nuri/starred{/owner}{/repo}\",\"subscriptions_url\":\"https://api.github.com/users/Financier-Nuri/subscriptions\"},\"comments\":1,\"created_at\":\"2026-03-21T12:05:51Z\",\"updated_at\":\"2026-03-21T12:38:13Z\",\"url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51587\",\"html_url\":\"https://github.com/openclaw/openclaw/issues/51587\",\"comments_url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51587/comments\",\"events_url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51587/events\",\"labels_url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51587/labels{/name}\",\"repository_url\":\"https://api.github.com/repos/openclaw/openclaw\",\"reactions\":{\"total_count\":0,\"+1\":0,\"-1\":0,\"laugh\":0,\"confused\":0,\"heart\":0,\"hooray\":0,\"rocket\":0,\"eyes\":0,\"url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51587/reactions\"},\"node_id\":\"I_kwDOQb6kR871HAYm\"},{\"id\":4111615286,\"number\":51466,\"state\":\"open\",\"locked\":false,\"title\":\"[Bug] Telegram /tts audio reaches TTS path but Edge provider times out; no voice note delivered on v2026.3.13\",\"body\":\"## Summary\\n\\nOn OpenClaw v2026.3.13, Telegram TTS does not successfully return a voice note in my environment.\\n\\nThe key point is:\\n- TTS is not completely unsupported on Telegram\\n- /tts audio clearly enters the TTS path\\n- but the free Edge/Microsoft provider times out, so no audio is produced and no Telegram voice note is delivered\\n\\n## Environment\\n\\n- OpenClaw version: v2026.3.13\\n- Channel: Telegram\\n- OS: Linux\\n- Config file: /root/.openclaw/openclaw.json\\n\\n## What I tested\\n\\nI first tested auto TTS with:\\n\\n```json\\n{\\n  \\\"messages\\\": {\\n    \\\"tts\\\": {\\n      \\\"auto\\\": \\\"always\\\",\\n      \\\"provider\\\": \\\"edge\\\",\\n      \\\"edge\\\": {\\n        \\\"enabled\\\": true,\\n        \\\"voice\\\": \\\"zh-CN-XiaochenNeural\\\",\\n        \\\"lang\\\": \\\"zh-CN\\\"\\n      }\\n    }\\n  }\\n}\\n```\\n\\nI also tested auto: \\\"inbound\\\" before that.\\n\\nIn both cases, Telegram replies remained text-only in practice.\\n\\nThen I ran an explicit command in Telegram:\\n\\n```\\n/tts audio 你好，这是一次 TTS 强制测试\\n```\\n\\nTelegram returned this error message:\\n\\n❌ Error generating audio: TTS conversion failed: edge: Timed out; openai: no API key; elevenlabs: no API key\\n\\n## Expected behavior\\n\\n- /tts audio ... should generate speech and send a Telegram voice note\\n- messages.tts.auto = \\\"always\\\" or \\\"inbound\\\" should trigger outbound audio on Telegram\\n- Telegram should receive the native round voice-note bubble\\n\\n## Actual behavior\\n\\n- /tts audio ... does not deliver any voice note\\n- Telegram only shows text/error output\\n- The Edge provider appears to time out before audio is returned\\n\\n## Important observation\\n\\nPlease note that this is **not** the same as \\\"Telegram does not support TTS at all\\\".\\n\\nThe explicit /tts audio command produces:\\n\\n❌ Error generating audio: TTS conversion failed: edge: Timed out; openai: no API key; elevenlabs: no API key\\n\\nSo the request appears to reach the TTS layer, but the Edge provider fails before Telegram can send audio.\\n\\n## Additional notes\\n\\n- No local TTS prefs file existed on this node: ~/.openclaw/settings/tts.json was absent, so there was no prefs override of messages.tts\\n- After testing, I restored the config to default by removing messages.tts\\n\\n## Question\\n\\nIs this a known regression/timeout issue with the Edge/Microsoft TTS path on Telegram in v2026.3.13?\\n\\nAlso, is there any recommended timeout/output-format adjustment for Telegram + Edge TTS in this version?\",\"author_association\":\"NONE\",\"user\":{\"login\":\"spadesv\",\"id\":30253580,\"node_id\":\"MDQ6VXNlcjMwMjUzNTgw\",\"avatar_url\":\"https://avatars.githubusercontent.com/u/30253580?v=4\",\"html_url\":\"https://github.com/spadesv\",\"gravatar_id\":\"\",\"type\":\"User\",\"site_admin\":false,\"url\":\"https://api.github.com/users/spadesv\",\"events_url\":\"https://api.github.com/users/spadesv/events{/privacy}\",\"following_url\":\"https://api.github.com/users/spadesv/following{/other_user}\",\"followers_url\":\"https://api.github.com/users/spadesv/followers\",\"gists_url\":\"https://api.github.com/users/spadesv/gists{/gist_id}\",\"organizations_url\":\"https://api.github.com/users/spadesv/orgs\",\"received_events_url\":\"https://api.github.com/users/spadesv/received_events\",\"repos_url\":\"https://api.github.com/users/spadesv/repos\",\"starred_url\":\"https://api.github.com/users/spadesv/starred{/owner}{/repo}\",\"subscriptions_url\":\"https://api.github.com/users/spadesv/subscriptions\"},\"comments\":1,\"created_at\":\"2026-03-21T06:30:14Z\",\"updated_at\":\"2026-03-21T07:14:19Z\",\"url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51466\",\"html_url\":\"https://github.com/openclaw/openclaw/issues/51466\",\"comments_url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51466/comments\",\"events_url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51466/events\",\"labels_url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51466/labels{/name}\",\"repository_url\":\"https://api.github.com/repos/openclaw/openclaw\",\"reactions\":{\"total_count\":0,\"+1\":0,\"-1\":0,\"laugh\":0,\"confused\":0,\"heart\":0,\"hooray\":0,\"rocket\":0,\"eyes\":0,\"url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51466/reactions\"},\"node_id\":\"I_kwDOQb6kR871EkU2\"},{\"id\":4111059401,\"number\":51383,\"state\":\"open\",\"locked\":false,\"title\":\"Feature: Webchat project/thread system for parallel contexts\",\"body\":\"## Problem\\n\\nWebchat is the most powerful interface for OpenClaw (direct host access, no rate limits, full tool access), but it lacks basic organization features that Discord/Telegram provide natively.\\n\\nCurrently:\\n- Single continuous stream per session\\n- `/new` or `/reset` clears all context\\n- No way to work on multiple projects/threads in parallel\\n- No history browser\\n\\n## Proposed Solution\\n\\n### 1. Project/Thread System\\n- Multiple parallel \\\"threads\\\" or \\\"projects\\\" within webchat\\n- Each thread maintains its own context window\\n- Quick switching between threads (sidebar or tabs)\\n- Per-thread system prompts / SOUL.md overrides\\n\\n### 2. History Browser\\n- Searchable history across threads\\n- Date-based navigation\\n- Export capability\\n\\n### 3. Per-Project Memory Isolation\\n- Optional isolated memory per project\\n- Project-specific context injection\\n\\n## Use Cases\\n\\n1. **Development workflow**: Work on WBF2 in one thread, Alexandria in another, without mixing context\\n2. **Research**: Keep separate threads for different research topics\\n3. **Daily operations**: Dedicated thread for daily reviews, another for ad-hoc tasks\\n\\n## Alternatives Considered\\n\\n- Using Discord forums (works, but loses local tool access benefits)\\n- Multiple browser tabs with `/new` (no persistence, loses context on refresh)\\n- External memory systems like Obsidian (partial solution, doesn't address UI)\\n\\n## Implementation Thoughts\\n\\n- Thread state could persist in SQLite alongside memory\\n- UI could use a simple sidebar or tab strip\\n- Each thread = separate session key internally\\n\\nThis would make webchat a true \\\"local-first\\\" alternative to Discord/Telegram rather than just a fallback.\",\"author_association\":\"NONE\",\"user\":{\"login\":\"sabo961\",\"id\":191984,\"node_id\":\"MDQ6VXNlcjE5MTk4NA==\",\"avatar_url\":\"https://avatars.githubusercontent.com/u/191984?v=4\",\"html_url\":\"https://github.com/sabo961\",\"gravatar_id\":\"\",\"type\":\"User\",\"site_admin\":false,\"url\":\"https://api.github.com/users/sabo961\",\"events_url\":\"https://api.github.com/users/sabo961/events{/privacy}\",\"following_url\":\"https://api.github.com/users/sabo961/following{/other_user}\",\"followers_url\":\"https://api.github.com/users/sabo961/followers\",\"gists_url\":\"https://api.github.com/users/sabo961/gists{/gist_id}\",\"organizations_url\":\"https://api.github.com/users/sabo961/orgs\",\"received_events_url\":\"https://api.github.com/users/sabo961/received_events\",\"repos_url\":\"https://api.github.com/users/sabo961/repos\",\"starred_url\":\"https://api.github.com/users/sabo961/starred{/owner}{/repo}\",\"subscriptions_url\":\"https://api.github.com/users/sabo961/subscriptions\"},\"comments\":1,\"created_at\":\"2026-03-21T02:32:50Z\",\"updated_at\":\"2026-03-21T02:40:19Z\",\"url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51383\",\"html_url\":\"https://github.com/openclaw/openclaw/issues/51383\",\"comments_url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51383/comments\",\"events_url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51383/events\",\"labels_url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51383/labels{/name}\",\"repository_url\":\"https://api.github.com/repos/openclaw/openclaw\",\"reactions\":{\"total_count\":0,\"+1\":0,\"-1\":0,\"laugh\":0,\"confused\":0,\"heart\":0,\"hooray\":0,\"rocket\":0,\"eyes\":0,\"url\":\"https://api.github.com/repos/openclaw/openclaw/issues/51383/reactions\"},\"node_id\":\"I_kwDOQb6kR871CcnJ\"}]}"}]}
{"type":"assistant","message":{"model":"claude-sonnet-4-6","id":"msg_01LSDbsTMz1grb4AosMzJFh3","type":"message","role":"assistant","content":[{"type":"thinking","thinking":"The search returned 943 total results. Let me now report on the 5 most recent issues. I need to check if they have assignees. Looking at the returned data, none of the items seem to have an \"assignee\" field listed explicitly - they're not present in the JSON. Let me check the items again...\n\nThe items don't show any `assignee` field in the response. In GitHub API, when there's no assignee, the field would be `null` or absent. Since the results don't show assignee fields, they likely have no assignees.\n\nResults:\n1. #51767 - \"sessionRetention does not apply to subagent sessions — only cron-run sessions are swept\" - open - no assignee\n\n\n2. #51636 - \"Discord WebSocket gateway disconnects every ~10 minutes (health-monitor restart loop)\" - open - no assignee\n3. #51587 - \"Bug: isRecurringTopOfHourCronExpr fails to match cron expressions with step values\" - open - no assignee\n4. #51466 - \"[Bug] Telegram /tts audio reaches TTS path but Edge provider times out; no voice note delivered on v2026.3.13\" - open - no assignee\n5. #51383 - \"Feature: Webchat project/thread system for parallel contexts\" - open - no assignee\n\nTotal: 943 open issues across the board.","signature":" "}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":1,"cache_creation_input_tokens":7641,"cache_read_input_tokens":16916,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":7641},"output_tokens":8,"service_tier":"standard","inference_geo":"not_available"},"context_management":null},"parent_tool_use_id":null,"session_id":"1cbb44f9-7700-474d-82b1-f71c070b293f","uuid":"452b8be5-0f25-40df-839c-de1acc6d1dd5"}
{"type":"assistant","message":{"model":"claude-sonnet-4-6","id":"msg_01LSDbsTMz1grb4AosMzJFh3","type":"message","role":"assistant","content":[{"type":"text","text":"The search returned **943 total results**. Here are the 5 most recent:\n\n| # | Title | State | Assignee |\n|---|-------|-------|----------|\n| #51767 | sessionRetention does not apply to subagent sessions — only cron-run sessions are swept | open | None |\n| #51636 | Discord WebSocket gateway disconnects every ~10 minutes (health-monitor restart loop) | open | None |\n| #51587 | Bug: isRecurringTopOfHourCronExpr fails to match cron expressions with step values | open | None |\n| #51466 | [Bug] Telegram /tts audio reaches TTS path but Edge provider times out; no voice note delivered on v2026.3.13 | open | None |\n| #51383 | Feature: Webchat project/thread system for parallel contexts | open | None |\n\nAll 5 are **open** and **unassigned**. Notably, only #51587 and #51383 directly mention \"rate limit\" in their bodies (the cron stagger bug cites API rate limit issues as an impact, and the webchat feature request mentions \"no rate limits\" as a benefit). The search matched all 943 issues across title and body text."}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":1,"cache_creation_input_tokens":7641,"cache_read_input_tokens":16916,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":7641},"output_tokens":8,"service_tier":"standard","inference_geo":"not_available"},"context_management":null},"parent_tool_use_id":null,"session_id":"1cbb44f9-7700-474d-82b1-f71c070b293f","uuid":"da65c1b4-886f-4f13-8bc5-49d2a5f03e60"}
{"type":"result","subtype":"success","is_error":false,"duration_ms":17385,"duration_api_ms":16725,"num_turns":3,"result":"The search returned **943 total results**. Here are the 5 most recent:\n\n| # | Title | State | Assignee |\n|---|-------|-------|----------|\n| #51767 | sessionRetention does not apply to subagent sessions — only cron-run sessions are swept | open | None |\n| #51636 | Discord WebSocket gateway disconnects every ~10 minutes (health-monitor restart loop) | open | None |\n| #51587 | Bug: isRecurringTopOfHourCronExpr fails to match cron expressions with step values | open | None |\n| #51466 | [Bug] Telegram /tts audio reaches TTS path but Edge provider times out; no voice note delivered on v2026.3.13 | open | None |\n| #51383 | Feature: Webchat project/thread system for parallel contexts | open | None |\n\nAll 5 are **open** and **unassigned**. Notably, only #51587 and #51383 directly mention \"rate limit\" in their bodies (the cron stagger bug cites API rate limit issues as an impact, and the webchat feature request mentions \"no rate limits\" as a benefit). The search matched all 943 issues across title and body text.","stop_reason":"end_turn","session_id":"1cbb44f9-7700-474d-82b1-f71c070b293f","total_cost_usd":0.08633025000000001,"usage":{"input_tokens":7,"cache_creation_input_tokens":15959,"cache_read_input_tokens":41960,"output_tokens":925,"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":"standard","cache_creation":{"ephemeral_1h_input_tokens":15959,"ephemeral_5m_input_tokens":0},"inference_geo":"","iterations":[],"speed":"standard"},"modelUsage":{"claude-sonnet-4-6":{"inputTokens":7,"outputTokens":925,"cacheReadInputTokens":41960,"cacheCreationInputTokens":15959,"webSearchRequests":0,"costUSD":0.08633025000000001,"contextWindow":200000,"maxOutputTokens":32000}},"permission_denials":[],"fast_mode_state":"off","uuid":"108948a0-0ed2-4fec-b6bd-28a71d3182ea"}
