@poolzin/pool-bot 2026.1.39 → 2026.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (511) hide show
  1. package/assets/chrome-extension/README.md +3 -3
  2. package/assets/chrome-extension/background.js +5 -5
  3. package/assets/chrome-extension/manifest.json +3 -3
  4. package/assets/chrome-extension/options.html +4 -4
  5. package/assets/chrome-extension/options.js +1 -1
  6. package/dist/acp/client.js +3 -3
  7. package/dist/acp/types.js +1 -1
  8. package/dist/agents/agent-paths.js +3 -3
  9. package/dist/agents/auth-profiles/paths.js +3 -3
  10. package/dist/agents/bash-tools.exec.js +76 -25
  11. package/dist/agents/cli-runner/helpers.js +10 -12
  12. package/dist/agents/cli-runner.js +2 -2
  13. package/dist/agents/cloudflare-ai-gateway.js +31 -0
  14. package/dist/agents/compaction.js +16 -2
  15. package/dist/agents/context-window-guard.js +13 -10
  16. package/dist/agents/context.js +4 -4
  17. package/dist/agents/docs-path.js +1 -1
  18. package/dist/agents/identity.js +47 -7
  19. package/dist/agents/memory-search.js +25 -8
  20. package/dist/agents/minimax-vlm.js +1 -1
  21. package/dist/agents/model-auth.js +12 -1
  22. package/dist/agents/model-catalog.js +4 -4
  23. package/dist/agents/model-selection.js +31 -4
  24. package/dist/agents/models-config.js +3 -3
  25. package/dist/agents/models-config.providers.js +147 -39
  26. package/dist/agents/pi-embedded-block-chunker.js +117 -42
  27. package/dist/agents/pi-embedded-helpers/errors.js +183 -78
  28. package/dist/agents/pi-embedded-helpers/openai.js +1 -1
  29. package/dist/agents/pi-embedded-helpers.js +1 -1
  30. package/dist/agents/pi-embedded-runner/compact.js +9 -8
  31. package/dist/agents/pi-embedded-runner/model.js +63 -4
  32. package/dist/agents/pi-embedded-runner/run/attempt.js +27 -17
  33. package/dist/agents/pi-embedded-runner/run.js +203 -50
  34. package/dist/agents/pi-embedded-runner/system-prompt.js +10 -2
  35. package/dist/agents/pi-embedded-runner/tool-result-truncation.js +275 -0
  36. package/dist/agents/pi-embedded-runner/utils.js +1 -1
  37. package/dist/agents/pi-embedded-subscribe.js +118 -29
  38. package/dist/agents/pi-model-discovery.js +10 -0
  39. package/dist/agents/pi-tool-definition-adapter.js +50 -9
  40. package/dist/agents/pi-tools.before-tool-call.js +67 -0
  41. package/dist/agents/pi-tools.js +20 -10
  42. package/dist/agents/pi-tools.read.js +2 -2
  43. package/dist/agents/poolbot-tools.js +15 -10
  44. package/dist/agents/sandbox-paths.js +31 -0
  45. package/dist/agents/session-file-repair.js +83 -0
  46. package/dist/agents/session-tool-result-guard.js +94 -15
  47. package/dist/agents/session-transcript-repair.js +68 -0
  48. package/dist/agents/shell-utils.js +51 -0
  49. package/dist/agents/skills/bundled-context.js +23 -0
  50. package/dist/agents/skills/bundled-dir.js +41 -7
  51. package/dist/agents/skills/frontmatter.js +1 -1
  52. package/dist/agents/skills/workspace.js +2 -2
  53. package/dist/agents/skills-install.js +60 -23
  54. package/dist/agents/subagent-announce.js +79 -34
  55. package/dist/agents/system-prompt.js +28 -4
  56. package/dist/agents/together-models.js +127 -0
  57. package/dist/agents/tool-images.js +1 -1
  58. package/dist/agents/tool-policy.conformance.js +14 -0
  59. package/dist/agents/tool-policy.js +25 -1
  60. package/dist/agents/tools/browser-tool.js +3 -3
  61. package/dist/agents/tools/cron-tool.js +166 -19
  62. package/dist/agents/tools/discord-actions-presence.js +78 -0
  63. package/dist/agents/tools/image-tool.js +2 -2
  64. package/dist/agents/tools/memory-tool.js +93 -5
  65. package/dist/agents/tools/message-tool.js +56 -2
  66. package/dist/agents/tools/sessions-history-tool.js +69 -1
  67. package/dist/agents/tools/web-search.js +211 -42
  68. package/dist/agents/usage.js +23 -1
  69. package/dist/agents/workspace-run.js +67 -0
  70. package/dist/agents/workspace-templates.js +44 -0
  71. package/dist/auto-reply/command-auth.js +121 -6
  72. package/dist/auto-reply/commands-registry.data.js +1 -1
  73. package/dist/auto-reply/envelope.js +50 -72
  74. package/dist/auto-reply/reply/commands-compact.js +1 -0
  75. package/dist/auto-reply/reply/commands-context-report.js +3 -2
  76. package/dist/auto-reply/reply/commands-context.js +1 -0
  77. package/dist/auto-reply/reply/commands-models.js +107 -60
  78. package/dist/auto-reply/reply/commands-ptt.js +171 -0
  79. package/dist/auto-reply/reply/commands-session.js +2 -2
  80. package/dist/auto-reply/reply/get-reply-run.js +16 -5
  81. package/dist/auto-reply/reply/groups.js +1 -1
  82. package/dist/auto-reply/reply/inbound-context.js +9 -1
  83. package/dist/auto-reply/reply/inbound-meta.js +130 -0
  84. package/dist/auto-reply/reply/model-selection.js +3 -3
  85. package/dist/auto-reply/reply/untrusted-context.js +15 -0
  86. package/dist/auto-reply/status.js +1 -1
  87. package/dist/auto-reply/thinking.js +88 -43
  88. package/dist/browser/bridge-server.js +13 -0
  89. package/dist/browser/cdp.helpers.js +38 -24
  90. package/dist/browser/client-fetch.js +51 -8
  91. package/dist/browser/config.js +2 -11
  92. package/dist/browser/extension-relay.js +104 -43
  93. package/dist/browser/pw-ai.js +1 -1
  94. package/dist/browser/pw-session.js +143 -8
  95. package/dist/browser/pw-tools-core.interactions.js +125 -27
  96. package/dist/browser/pw-tools-core.responses.js +1 -1
  97. package/dist/browser/pw-tools-core.state.js +1 -1
  98. package/dist/browser/routes/agent.act.js +86 -41
  99. package/dist/browser/routes/dispatcher.js +4 -4
  100. package/dist/browser/screenshot.js +1 -1
  101. package/dist/browser/server-context.js +2 -2
  102. package/dist/browser/server.js +13 -0
  103. package/dist/build-info.json +3 -3
  104. package/dist/canvas-host/a2ui.js +3 -3
  105. package/dist/channels/plugins/catalog.js +2 -2
  106. package/dist/channels/plugins/onboarding/imessage.js +1 -1
  107. package/dist/channels/plugins/onboarding/signal.js +1 -1
  108. package/dist/channels/plugins/onboarding/slack.js +4 -4
  109. package/dist/channels/plugins/onboarding/whatsapp.js +3 -3
  110. package/dist/channels/plugins/pairing-message.js +1 -1
  111. package/dist/channels/reply-prefix.js +8 -1
  112. package/dist/cli/browser-cli-extension.js +2 -2
  113. package/dist/cli/cron-cli/register.cron-add.js +61 -40
  114. package/dist/cli/cron-cli/register.cron-edit.js +60 -34
  115. package/dist/cli/cron-cli/shared.js +56 -41
  116. package/dist/cli/dns-cli.js +26 -14
  117. package/dist/cli/docs-cli.js +1 -1
  118. package/dist/cli/gateway-cli/dev.js +1 -1
  119. package/dist/cli/gateway-cli/register.js +37 -19
  120. package/dist/cli/memory-cli.js +30 -20
  121. package/dist/cli/nodes-cli/register.canvas.js +1 -1
  122. package/dist/cli/parse-bytes.js +37 -0
  123. package/dist/cli/plugins-cli.js +1 -1
  124. package/dist/cli/run-main.js +2 -2
  125. package/dist/cli/security-cli.js +1 -1
  126. package/dist/cli/tagline.js +1 -1
  127. package/dist/cli/update-cli.js +173 -52
  128. package/dist/cli/webhooks-cli.js +5 -5
  129. package/dist/commands/agent.js +1 -0
  130. package/dist/commands/agents.commands.add.js +1 -1
  131. package/dist/commands/auth-choice.apply.api-providers.js +305 -17
  132. package/dist/commands/auth-choice.apply.js +4 -1
  133. package/dist/commands/auth-choice.apply.plugin-provider.js +2 -2
  134. package/dist/commands/auth-choice.apply.xai.js +63 -0
  135. package/dist/commands/auth-choice.preferred-provider.js +7 -1
  136. package/dist/commands/configure.wizard.js +1 -1
  137. package/dist/commands/dashboard.js +1 -1
  138. package/dist/commands/docs.js +1 -1
  139. package/dist/commands/doctor-config-flow.js +61 -5
  140. package/dist/commands/doctor-gateway-services.js +3 -3
  141. package/dist/commands/doctor-state-migrations.js +1 -1
  142. package/dist/commands/doctor-update.js +3 -3
  143. package/dist/commands/doctor.js +1 -1
  144. package/dist/commands/health.js +1 -1
  145. package/dist/commands/model-allowlist.js +29 -0
  146. package/dist/commands/model-picker.js +2 -1
  147. package/dist/commands/models/list.probe.js +2 -2
  148. package/dist/commands/models/list.registry.js +4 -4
  149. package/dist/commands/models/list.status-command.js +44 -24
  150. package/dist/commands/models/shared.js +15 -0
  151. package/dist/commands/onboard-auth.config-core.js +366 -28
  152. package/dist/commands/onboard-auth.credentials.js +71 -9
  153. package/dist/commands/onboard-auth.js +3 -3
  154. package/dist/commands/onboard-auth.models.js +26 -24
  155. package/dist/commands/onboard-custom.js +384 -0
  156. package/dist/commands/onboard-non-interactive/local/auth-choice-inference.js +35 -0
  157. package/dist/commands/onboard-non-interactive/local/auth-choice.js +146 -9
  158. package/dist/commands/onboard-skills.js +63 -38
  159. package/dist/commands/openai-model-default.js +41 -0
  160. package/dist/commands/status-all/report-lines.js +1 -1
  161. package/dist/commands/status.command.js +1 -1
  162. package/dist/commands/uninstall.js +3 -3
  163. package/dist/compat/legacy-names.js +1 -1
  164. package/dist/config/defaults.js +3 -2
  165. package/dist/config/io.js +3 -3
  166. package/dist/config/paths.js +136 -35
  167. package/dist/config/plugin-auto-enable.js +21 -5
  168. package/dist/config/redact-snapshot.js +153 -0
  169. package/dist/config/schema.field-metadata.js +590 -0
  170. package/dist/config/schema.js +3 -3
  171. package/dist/config/sessions/store.js +291 -23
  172. package/dist/config/types.memory.js +1 -0
  173. package/dist/config/version.js +4 -4
  174. package/dist/config/zod-schema.agent-defaults.js +3 -0
  175. package/dist/config/zod-schema.agent-runtime.js +13 -2
  176. package/dist/config/zod-schema.providers-core.js +142 -0
  177. package/dist/config/zod-schema.session.js +3 -0
  178. package/dist/cron/delivery.js +57 -0
  179. package/dist/cron/isolated-agent/delivery-target.js +18 -3
  180. package/dist/cron/isolated-agent/helpers.js +22 -5
  181. package/dist/cron/isolated-agent/run.js +171 -63
  182. package/dist/cron/isolated-agent/session.js +2 -0
  183. package/dist/cron/normalize.js +356 -28
  184. package/dist/cron/parse.js +10 -5
  185. package/dist/cron/run-log.js +35 -10
  186. package/dist/cron/schedule.js +41 -6
  187. package/dist/cron/service/jobs.js +208 -35
  188. package/dist/cron/service/ops.js +72 -16
  189. package/dist/cron/service/state.js +2 -0
  190. package/dist/cron/service/store.js +386 -14
  191. package/dist/cron/service/timer.js +390 -147
  192. package/dist/cron/session-reaper.js +86 -0
  193. package/dist/cron/store.js +23 -8
  194. package/dist/cron/validate-timestamp.js +43 -0
  195. package/dist/daemon/constants.js +7 -7
  196. package/dist/daemon/inspect.js +6 -6
  197. package/dist/daemon/systemd-unit.js +1 -1
  198. package/dist/discord/monitor/agent-components.js +438 -0
  199. package/dist/discord/monitor/allow-list.js +28 -5
  200. package/dist/discord/monitor/gateway-registry.js +29 -0
  201. package/dist/discord/monitor/native-command.js +44 -23
  202. package/dist/discord/monitor/sender-identity.js +45 -0
  203. package/dist/discord/pluralkit.js +27 -0
  204. package/dist/discord/send.outbound.js +92 -5
  205. package/dist/discord/send.shared.js +60 -23
  206. package/dist/discord/targets.js +84 -1
  207. package/dist/entry.js +15 -9
  208. package/dist/extensionAPI.js +8 -0
  209. package/dist/gateway/control-ui.js +8 -1
  210. package/dist/gateway/hooks-mapping.js +3 -0
  211. package/dist/gateway/hooks.js +65 -0
  212. package/dist/gateway/live-image-probe.js +1 -66
  213. package/dist/gateway/net.js +96 -31
  214. package/dist/gateway/node-command-policy.js +50 -15
  215. package/dist/gateway/openai-http.js +2 -2
  216. package/dist/gateway/openresponses-http.js +4 -4
  217. package/dist/gateway/origin-check.js +56 -0
  218. package/dist/gateway/protocol/client-info.js +9 -0
  219. package/dist/gateway/protocol/index.js +9 -2
  220. package/dist/gateway/protocol/schema/agents-models-skills.js +71 -1
  221. package/dist/gateway/protocol/schema/cron.js +22 -10
  222. package/dist/gateway/protocol/schema/protocol-schemas.js +16 -2
  223. package/dist/gateway/protocol/schema/sessions.js +12 -0
  224. package/dist/gateway/server/hooks.js +1 -1
  225. package/dist/gateway/server-broadcast.js +26 -9
  226. package/dist/gateway/server-chat.js +112 -23
  227. package/dist/gateway/server-discovery-runtime.js +10 -2
  228. package/dist/gateway/server-discovery.js +2 -2
  229. package/dist/gateway/server-http.js +110 -12
  230. package/dist/gateway/server-methods/agent-timestamp.js +60 -0
  231. package/dist/gateway/server-methods/agents.js +321 -2
  232. package/dist/gateway/server-methods/usage.js +559 -16
  233. package/dist/gateway/server-runtime-state.js +22 -8
  234. package/dist/gateway/server-startup-memory.js +16 -0
  235. package/dist/gateway/server.impl.js +7 -3
  236. package/dist/gateway/session-utils.fs.js +23 -25
  237. package/dist/gateway/session-utils.js +20 -10
  238. package/dist/gateway/sessions-patch.js +7 -22
  239. package/dist/gateway/test-helpers.server.js +35 -2
  240. package/dist/hooks/frontmatter.js +1 -1
  241. package/dist/hooks/hooks-status.js +1 -1
  242. package/dist/hooks/install.js +2 -2
  243. package/dist/hooks/loader.js +1 -1
  244. package/dist/hooks/workspace.js +3 -3
  245. package/dist/imessage/constants.js +2 -0
  246. package/dist/imessage/monitor/deliver.js +4 -1
  247. package/dist/imessage/monitor/monitor-provider.js +51 -1
  248. package/dist/index.js +2 -2
  249. package/dist/infra/bonjour-discovery.js +131 -70
  250. package/dist/infra/bonjour.js +3 -3
  251. package/dist/infra/control-ui-assets.js +134 -12
  252. package/dist/infra/errors.js +12 -0
  253. package/dist/infra/exec-approvals.js +266 -57
  254. package/dist/infra/format-time/format-datetime.js +79 -0
  255. package/dist/infra/format-time/format-duration.js +81 -0
  256. package/dist/infra/format-time/format-relative.js +80 -0
  257. package/dist/infra/heartbeat-runner.js +140 -49
  258. package/dist/infra/home-dir.js +54 -0
  259. package/dist/infra/net/fetch-guard.js +122 -0
  260. package/dist/infra/net/ssrf.js +65 -29
  261. package/dist/infra/outbound/abort.js +14 -0
  262. package/dist/infra/outbound/message-action-runner.js +77 -13
  263. package/dist/infra/outbound/outbound-session.js +143 -37
  264. package/dist/infra/path-env.js +3 -3
  265. package/dist/infra/poolbot-root.js +43 -1
  266. package/dist/infra/provider-usage.fetch.minimax.js +1 -1
  267. package/dist/infra/restart.js +1 -1
  268. package/dist/infra/session-cost-usage.js +631 -41
  269. package/dist/infra/state-migrations.js +317 -47
  270. package/dist/infra/tailscale.js +1 -1
  271. package/dist/infra/update-global.js +35 -0
  272. package/dist/infra/update-runner.js +149 -43
  273. package/dist/infra/warning-filter.js +65 -0
  274. package/dist/infra/widearea-dns.js +30 -9
  275. package/dist/logging/redact-identifier.js +12 -0
  276. package/dist/macos/relay.js +2 -2
  277. package/dist/media/fetch.js +81 -58
  278. package/dist/media/input-files.js +1 -1
  279. package/dist/media/mime.js +4 -0
  280. package/dist/media/png-encode.js +74 -0
  281. package/dist/media-understanding/apply.js +403 -3
  282. package/dist/media-understanding/attachments.js +38 -27
  283. package/dist/media-understanding/defaults.js +16 -0
  284. package/dist/media-understanding/providers/deepgram/audio.js +22 -14
  285. package/dist/media-understanding/providers/google/audio.js +24 -17
  286. package/dist/media-understanding/providers/google/video.js +24 -17
  287. package/dist/media-understanding/providers/image.js +4 -4
  288. package/dist/media-understanding/providers/index.js +4 -1
  289. package/dist/media-understanding/providers/openai/audio.js +22 -14
  290. package/dist/media-understanding/providers/shared.js +16 -11
  291. package/dist/media-understanding/providers/zai/index.js +6 -0
  292. package/dist/media-understanding/runner.js +158 -90
  293. package/dist/memory/backend-config.js +207 -0
  294. package/dist/memory/batch-voyage.js +277 -0
  295. package/dist/memory/embeddings-voyage.js +75 -0
  296. package/dist/memory/embeddings.js +29 -17
  297. package/dist/memory/internal.js +101 -18
  298. package/dist/memory/manager.js +155 -48
  299. package/dist/memory/search-manager.js +173 -0
  300. package/dist/memory/session-files.js +9 -3
  301. package/dist/memory/types.js +1 -0
  302. package/dist/node-host/runner.js +36 -26
  303. package/dist/node-host/with-timeout.js +27 -0
  304. package/dist/pairing/pairing-messages.js +1 -1
  305. package/dist/plugins/commands.js +5 -1
  306. package/dist/plugins/config-state.js +86 -7
  307. package/dist/plugins/discovery.js +1 -1
  308. package/dist/plugins/install.js +2 -2
  309. package/dist/plugins/source-display.js +51 -0
  310. package/dist/plugins/update.js +1 -1
  311. package/dist/process/exec.js +20 -2
  312. package/dist/routing/resolve-route.js +12 -0
  313. package/dist/routing/session-key.js +15 -0
  314. package/dist/runtime.js +2 -0
  315. package/dist/security/audit-extra.async.js +601 -0
  316. package/dist/security/audit-extra.js +2 -830
  317. package/dist/security/audit-extra.sync.js +505 -0
  318. package/dist/security/audit.js +2 -2
  319. package/dist/security/channel-metadata.js +34 -0
  320. package/dist/security/external-content.js +88 -6
  321. package/dist/security/skill-scanner.js +330 -0
  322. package/dist/sessions/session-key-utils.js +7 -0
  323. package/dist/shared/text/reasoning-tags.js +52 -7
  324. package/dist/signal/monitor/event-handler.js +80 -1
  325. package/dist/slack/monitor/media.js +85 -15
  326. package/dist/tailscale/detect.js +145 -0
  327. package/dist/telegram/bot/helpers.js +109 -28
  328. package/dist/telegram/bot-handlers.js +144 -3
  329. package/dist/telegram/bot-message-context.js +38 -11
  330. package/dist/telegram/bot-message-dispatch.js +48 -15
  331. package/dist/telegram/bot-native-commands.js +86 -29
  332. package/dist/telegram/bot.js +30 -29
  333. package/dist/telegram/model-buttons.js +163 -0
  334. package/dist/telegram/monitor.js +110 -85
  335. package/dist/telegram/send.js +129 -47
  336. package/dist/terminal/restore.js +45 -0
  337. package/dist/test-helpers/state-dir-env.js +16 -0
  338. package/dist/test-helpers/workspace.js +11 -0
  339. package/dist/test-utils/channel-plugins.js +82 -0
  340. package/dist/test-utils/ports.js +73 -0
  341. package/dist/tts/tts.js +12 -6
  342. package/dist/tui/tui-session-actions.js +166 -54
  343. package/dist/utils/fetch-timeout.js +20 -0
  344. package/dist/utils/normalize-secret-input.js +19 -0
  345. package/dist/utils/shell-argv.js +61 -0
  346. package/dist/utils/transcript-tools.js +58 -0
  347. package/dist/utils.js +55 -14
  348. package/dist/version.js +42 -5
  349. package/dist/web/qr-image.js +1 -61
  350. package/dist/wizard/onboarding.finalize.js +7 -7
  351. package/dist/wizard/onboarding.js +3 -3
  352. package/docs/RELEASE_WORKFOTS_COMPARISON.md +3 -3
  353. package/docs/_config.yml +2 -2
  354. package/docs/_layouts/default.html +9 -9
  355. package/docs/concepts/typebox.md +1 -1
  356. package/docs/docs.json +1 -1
  357. package/docs/northflank.mdx +7 -7
  358. package/docs/railway.mdx +3 -3
  359. package/docs/render.mdx +5 -5
  360. package/docs/start/lore.md +2 -2
  361. package/extensions/bluebubbles/index.ts +2 -2
  362. package/extensions/bluebubbles/package.json +1 -1
  363. package/extensions/bluebubbles/src/accounts.ts +8 -8
  364. package/extensions/bluebubbles/src/actions.test.ts +22 -22
  365. package/extensions/bluebubbles/src/actions.ts +5 -5
  366. package/extensions/bluebubbles/src/attachments.ts +2 -2
  367. package/extensions/bluebubbles/src/channel.ts +16 -16
  368. package/extensions/bluebubbles/src/chat.ts +2 -2
  369. package/extensions/bluebubbles/src/media-send.ts +2 -2
  370. package/extensions/bluebubbles/src/monitor.test.ts +46 -46
  371. package/extensions/bluebubbles/src/monitor.ts +5 -5
  372. package/extensions/bluebubbles/src/onboarding.ts +7 -7
  373. package/extensions/bluebubbles/src/reactions.ts +2 -2
  374. package/extensions/bluebubbles/src/send.ts +2 -2
  375. package/extensions/copilot-proxy/README.md +1 -1
  376. package/extensions/copilot-proxy/package.json +1 -1
  377. package/extensions/diagnostics-otel/index.ts +2 -2
  378. package/extensions/diagnostics-otel/package.json +1 -1
  379. package/extensions/diagnostics-otel/src/service.ts +3 -3
  380. package/extensions/discord/index.ts +2 -2
  381. package/extensions/discord/package.json +1 -1
  382. package/extensions/google-antigravity-auth/README.md +1 -1
  383. package/extensions/google-antigravity-auth/index.ts +1 -1
  384. package/extensions/google-antigravity-auth/package.json +1 -1
  385. package/extensions/google-gemini-cli-auth/README.md +1 -1
  386. package/extensions/google-gemini-cli-auth/oauth.ts +1 -1
  387. package/extensions/google-gemini-cli-auth/package.json +1 -1
  388. package/extensions/googlechat/index.ts +3 -3
  389. package/extensions/googlechat/package.json +1 -1
  390. package/extensions/googlechat/src/accounts.ts +8 -8
  391. package/extensions/googlechat/src/actions.ts +6 -6
  392. package/extensions/googlechat/src/channel.ts +21 -21
  393. package/extensions/googlechat/src/monitor.ts +8 -8
  394. package/extensions/googlechat/src/onboarding.ts +10 -10
  395. package/extensions/imessage/index.ts +2 -2
  396. package/extensions/imessage/package.json +1 -1
  397. package/extensions/line/index.ts +2 -2
  398. package/extensions/line/package.json +1 -1
  399. package/extensions/line/src/card-command.ts +2 -2
  400. package/extensions/line/src/channel.logout.test.ts +4 -4
  401. package/extensions/line/src/channel.sendPayload.test.ts +8 -8
  402. package/extensions/line/src/channel.ts +3 -3
  403. package/extensions/llm-task/README.md +3 -3
  404. package/extensions/llm-task/index.ts +2 -2
  405. package/extensions/llm-task/package.json +1 -1
  406. package/extensions/llm-task/src/llm-task-tool.ts +4 -4
  407. package/extensions/lobster/README.md +6 -6
  408. package/extensions/lobster/index.ts +2 -2
  409. package/extensions/lobster/src/lobster-tool.test.ts +4 -4
  410. package/extensions/lobster/src/lobster-tool.ts +2 -2
  411. package/extensions/matrix/index.ts +2 -2
  412. package/extensions/matrix/package.json +1 -1
  413. package/extensions/matrix/src/matrix/client/config.ts +1 -1
  414. package/extensions/matrix/src/matrix/monitor/handler.ts +1 -1
  415. package/extensions/matrix/src/onboarding.ts +1 -1
  416. package/extensions/mattermost/index.ts +2 -2
  417. package/extensions/mattermost/package.json +1 -1
  418. package/extensions/mattermost/src/mattermost/accounts.ts +8 -8
  419. package/extensions/mattermost/src/mattermost/monitor-helpers.ts +5 -5
  420. package/extensions/mattermost/src/mattermost/monitor.ts +2 -2
  421. package/extensions/mattermost/src/onboarding-helpers.ts +3 -3
  422. package/extensions/mattermost/src/onboarding.ts +2 -2
  423. package/extensions/memory-core/index.ts +2 -2
  424. package/extensions/memory-core/package.json +1 -1
  425. package/extensions/memory-lancedb/index.ts +3 -3
  426. package/extensions/memory-lancedb/package.json +1 -1
  427. package/extensions/msteams/index.ts +2 -2
  428. package/extensions/msteams/package.json +1 -1
  429. package/extensions/msteams/src/channel.directory.test.ts +2 -2
  430. package/extensions/msteams/src/channel.ts +2 -2
  431. package/extensions/msteams/src/graph-upload.ts +4 -4
  432. package/extensions/msteams/src/monitor-handler.ts +2 -2
  433. package/extensions/msteams/src/monitor.ts +2 -2
  434. package/extensions/msteams/src/onboarding.ts +9 -9
  435. package/extensions/msteams/src/reply-dispatcher.ts +2 -2
  436. package/extensions/msteams/src/send-context.ts +2 -2
  437. package/extensions/msteams/src/send.ts +4 -4
  438. package/extensions/nextcloud-talk/index.ts +2 -2
  439. package/extensions/nextcloud-talk/package.json +1 -1
  440. package/extensions/nextcloud-talk/src/channel.ts +7 -7
  441. package/extensions/nextcloud-talk/src/inbound.ts +7 -7
  442. package/extensions/nextcloud-talk/src/onboarding.ts +1 -1
  443. package/extensions/nostr/README.md +2 -2
  444. package/extensions/nostr/index.ts +5 -5
  445. package/extensions/nostr/package.json +1 -1
  446. package/extensions/nostr/src/types.ts +4 -4
  447. package/extensions/open-prose/index.ts +2 -2
  448. package/extensions/qwen-portal-auth/README.md +1 -1
  449. package/extensions/signal/index.ts +2 -2
  450. package/extensions/signal/package.json +1 -1
  451. package/extensions/slack/index.ts +2 -2
  452. package/extensions/slack/package.json +1 -1
  453. package/extensions/telegram/index.ts +2 -2
  454. package/extensions/telegram/package.json +1 -1
  455. package/extensions/telegram/src/channel.ts +2 -2
  456. package/extensions/tlon/README.md +2 -2
  457. package/extensions/tlon/index.ts +2 -2
  458. package/extensions/tlon/package.json +1 -1
  459. package/extensions/tlon/src/channel.ts +13 -13
  460. package/extensions/tlon/src/monitor/index.ts +3 -3
  461. package/extensions/tlon/src/onboarding.ts +3 -3
  462. package/extensions/tlon/src/types.ts +3 -3
  463. package/extensions/twitch/README.md +1 -1
  464. package/extensions/twitch/index.ts +2 -2
  465. package/extensions/twitch/package.json +1 -1
  466. package/extensions/twitch/src/config.ts +3 -3
  467. package/extensions/twitch/src/monitor.ts +3 -3
  468. package/extensions/twitch/src/onboarding.ts +9 -9
  469. package/extensions/twitch/src/outbound.test.ts +2 -2
  470. package/extensions/twitch/src/plugin.test.ts +2 -2
  471. package/extensions/twitch/src/plugin.ts +8 -8
  472. package/extensions/twitch/src/send.test.ts +2 -2
  473. package/extensions/twitch/src/send.ts +4 -4
  474. package/extensions/twitch/src/token.test.ts +8 -8
  475. package/extensions/twitch/src/token.ts +3 -3
  476. package/extensions/twitch/src/twitch-client.ts +3 -3
  477. package/extensions/twitch/src/types.ts +3 -3
  478. package/extensions/twitch/src/utils/markdown.ts +1 -1
  479. package/extensions/voice-call/README.md +3 -3
  480. package/extensions/voice-call/package.json +1 -1
  481. package/extensions/voice-call/src/core-bridge.ts +2 -2
  482. package/extensions/voice-call/src/response-generator.ts +1 -1
  483. package/extensions/whatsapp/index.ts +2 -2
  484. package/extensions/whatsapp/package.json +1 -1
  485. package/extensions/zalo/README.md +1 -1
  486. package/extensions/zalo/index.ts +2 -2
  487. package/extensions/zalo/package.json +1 -1
  488. package/extensions/zalo/src/accounts.ts +8 -8
  489. package/extensions/zalo/src/actions.ts +4 -4
  490. package/extensions/zalo/src/channel.directory.test.ts +2 -2
  491. package/extensions/zalo/src/channel.ts +18 -18
  492. package/extensions/zalo/src/monitor.ts +9 -9
  493. package/extensions/zalo/src/monitor.webhook.test.ts +2 -2
  494. package/extensions/zalo/src/onboarding.ts +24 -24
  495. package/extensions/zalo/src/send.ts +2 -2
  496. package/extensions/zalouser/README.md +2 -2
  497. package/extensions/zalouser/index.ts +2 -2
  498. package/extensions/zalouser/package.json +1 -1
  499. package/extensions/zalouser/src/accounts.ts +9 -9
  500. package/extensions/zalouser/src/channel.ts +24 -24
  501. package/extensions/zalouser/src/monitor.ts +4 -4
  502. package/extensions/zalouser/src/onboarding.ts +28 -28
  503. package/package.json +13 -251
  504. package/skills/nano-banana-pro/scripts/generate_image.py +1 -1
  505. package/skills/tmux/scripts/find-sessions.sh +1 -1
  506. package/CHANGELOG.md +0 -102
  507. package/README-header.png +0 -0
  508. package/git-hooks/pre-commit +0 -4
  509. package/scripts/format-staged.js +0 -148
  510. package/scripts/postinstall.js +0 -300
  511. package/scripts/setup-git-hooks.js +0 -96
@@ -1,54 +1,134 @@
1
+ import fs from "node:fs";
1
2
  import { loadConfig } from "../../config/config.js";
2
- import { loadCostUsageSummary } from "../../infra/session-cost-usage.js";
3
+ import { resolveSessionFilePath } from "../../config/sessions/paths.js";
3
4
  import { loadProviderUsageSummary } from "../../infra/provider-usage.js";
5
+ import { loadCostUsageSummary, loadSessionCostSummary, loadSessionUsageTimeSeries, discoverAllSessions, } from "../../infra/session-cost-usage.js";
6
+ import { parseAgentSessionKey } from "../../routing/session-key.js";
7
+ import { ErrorCodes, errorShape, formatValidationErrors, validateSessionsUsageParams, } from "../protocol/index.js";
8
+ import { listAgentsForGateway, loadCombinedSessionStoreForGateway, loadSessionEntry, } from "../session-utils.js";
4
9
  const COST_USAGE_CACHE_TTL_MS = 30_000;
5
10
  const costUsageCache = new Map();
11
+ /**
12
+ * Parse a date string (YYYY-MM-DD) to start of day timestamp in UTC.
13
+ * Returns undefined if invalid.
14
+ */
15
+ const parseDateToMs = (raw) => {
16
+ if (typeof raw !== "string" || !raw.trim()) {
17
+ return undefined;
18
+ }
19
+ const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(raw.trim());
20
+ if (!match) {
21
+ return undefined;
22
+ }
23
+ const [, year, month, day] = match;
24
+ // Use UTC to ensure consistent behavior across timezones
25
+ const ms = Date.UTC(parseInt(year), parseInt(month) - 1, parseInt(day));
26
+ if (Number.isNaN(ms)) {
27
+ return undefined;
28
+ }
29
+ return ms;
30
+ };
6
31
  const parseDays = (raw) => {
7
- if (typeof raw === "number" && Number.isFinite(raw))
32
+ if (typeof raw === "number" && Number.isFinite(raw)) {
8
33
  return Math.floor(raw);
34
+ }
9
35
  if (typeof raw === "string" && raw.trim() !== "") {
10
36
  const parsed = Number(raw);
11
- if (Number.isFinite(parsed))
37
+ if (Number.isFinite(parsed)) {
12
38
  return Math.floor(parsed);
39
+ }
40
+ }
41
+ return undefined;
42
+ };
43
+ /**
44
+ * Get date range from params (startDate/endDate or days).
45
+ * Falls back to last 30 days if not provided.
46
+ */
47
+ const parseDateRange = (params) => {
48
+ const now = new Date();
49
+ // Use UTC for consistent date handling
50
+ const todayStartMs = Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate());
51
+ const todayEndMs = todayStartMs + 24 * 60 * 60 * 1000 - 1;
52
+ const startMs = parseDateToMs(params.startDate);
53
+ const endMs = parseDateToMs(params.endDate);
54
+ if (startMs !== undefined && endMs !== undefined) {
55
+ // endMs should be end of day
56
+ return { startMs, endMs: endMs + 24 * 60 * 60 * 1000 - 1 };
57
+ }
58
+ const days = parseDays(params.days);
59
+ if (days !== undefined) {
60
+ const clampedDays = Math.max(1, days);
61
+ const start = todayStartMs - (clampedDays - 1) * 24 * 60 * 60 * 1000;
62
+ return { startMs: start, endMs: todayEndMs };
13
63
  }
14
- return 30;
64
+ // Default to last 30 days
65
+ const defaultStartMs = todayStartMs - 29 * 24 * 60 * 60 * 1000;
66
+ return { startMs: defaultStartMs, endMs: todayEndMs };
15
67
  };
68
+ async function discoverAllSessionsForUsage(params) {
69
+ const agents = listAgentsForGateway(params.config).agents;
70
+ const results = await Promise.all(agents.map(async (agent) => {
71
+ const sessions = await discoverAllSessions({
72
+ agentId: agent.id,
73
+ startMs: params.startMs,
74
+ endMs: params.endMs,
75
+ });
76
+ return sessions.map((session) => ({ ...session, agentId: agent.id }));
77
+ }));
78
+ return results.flat().toSorted((a, b) => b.mtime - a.mtime);
79
+ }
16
80
  async function loadCostUsageSummaryCached(params) {
17
- const days = Math.max(1, params.days);
81
+ const cacheKey = `${params.startMs}-${params.endMs}`;
18
82
  const now = Date.now();
19
- const cached = costUsageCache.get(days);
83
+ const cached = costUsageCache.get(cacheKey);
20
84
  if (cached?.summary && cached.updatedAt && now - cached.updatedAt < COST_USAGE_CACHE_TTL_MS) {
21
85
  return cached.summary;
22
86
  }
23
87
  if (cached?.inFlight) {
24
- if (cached.summary)
88
+ if (cached.summary) {
25
89
  return cached.summary;
90
+ }
26
91
  return await cached.inFlight;
27
92
  }
28
93
  const entry = cached ?? {};
29
- const inFlight = loadCostUsageSummary({ days, config: params.config })
94
+ const inFlight = loadCostUsageSummary({
95
+ startMs: params.startMs,
96
+ endMs: params.endMs,
97
+ config: params.config,
98
+ })
30
99
  .then((summary) => {
31
- costUsageCache.set(days, { summary, updatedAt: Date.now() });
100
+ costUsageCache.set(cacheKey, { summary, updatedAt: Date.now() });
32
101
  return summary;
33
102
  })
34
103
  .catch((err) => {
35
- if (entry.summary)
104
+ if (entry.summary) {
36
105
  return entry.summary;
106
+ }
37
107
  throw err;
38
108
  })
39
109
  .finally(() => {
40
- const current = costUsageCache.get(days);
110
+ const current = costUsageCache.get(cacheKey);
41
111
  if (current?.inFlight === inFlight) {
42
112
  current.inFlight = undefined;
43
- costUsageCache.set(days, current);
113
+ costUsageCache.set(cacheKey, current);
44
114
  }
45
115
  });
46
116
  entry.inFlight = inFlight;
47
- costUsageCache.set(days, entry);
48
- if (entry.summary)
117
+ costUsageCache.set(cacheKey, entry);
118
+ if (entry.summary) {
49
119
  return entry.summary;
120
+ }
50
121
  return await inFlight;
51
122
  }
123
+ // Exposed for unit tests (kept as a single export to avoid widening the public API surface).
124
+ export const __test = {
125
+ parseDateToMs,
126
+ parseDays,
127
+ parseDateRange,
128
+ discoverAllSessionsForUsage,
129
+ loadCostUsageSummaryCached,
130
+ costUsageCache,
131
+ };
52
132
  export const usageHandlers = {
53
133
  "usage.status": async ({ respond }) => {
54
134
  const summary = await loadProviderUsageSummary();
@@ -56,8 +136,471 @@ export const usageHandlers = {
56
136
  },
57
137
  "usage.cost": async ({ respond, params }) => {
58
138
  const config = loadConfig();
59
- const days = parseDays(params?.days);
60
- const summary = await loadCostUsageSummaryCached({ days, config });
139
+ const { startMs, endMs } = parseDateRange({
140
+ startDate: params?.startDate,
141
+ endDate: params?.endDate,
142
+ days: params?.days,
143
+ });
144
+ const summary = await loadCostUsageSummaryCached({ startMs, endMs, config });
61
145
  respond(true, summary, undefined);
62
146
  },
147
+ "sessions.usage": async ({ respond, params }) => {
148
+ if (!validateSessionsUsageParams(params)) {
149
+ respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, `invalid sessions.usage params: ${formatValidationErrors(validateSessionsUsageParams.errors)}`));
150
+ return;
151
+ }
152
+ const p = params;
153
+ const config = loadConfig();
154
+ const { startMs, endMs } = parseDateRange({
155
+ startDate: p.startDate,
156
+ endDate: p.endDate,
157
+ });
158
+ const limit = typeof p.limit === "number" && Number.isFinite(p.limit) ? p.limit : 50;
159
+ const includeContextWeight = p.includeContextWeight ?? false;
160
+ const specificKey = typeof p.key === "string" ? p.key.trim() : null;
161
+ // Load session store for named sessions
162
+ const { store } = loadCombinedSessionStoreForGateway(config);
163
+ const now = Date.now();
164
+ const mergedEntries = [];
165
+ // Optimization: If a specific key is requested, skip full directory scan
166
+ if (specificKey) {
167
+ const parsed = parseAgentSessionKey(specificKey);
168
+ const agentIdFromKey = parsed?.agentId;
169
+ const keyRest = parsed?.rest ?? specificKey;
170
+ // Prefer the store entry when available, even if the caller provides a discovered key
171
+ // (`agent:<id>:<sessionId>`) for a session that now has a canonical store key.
172
+ const storeBySessionId = new Map();
173
+ for (const [key, entry] of Object.entries(store)) {
174
+ if (entry?.sessionId) {
175
+ storeBySessionId.set(entry.sessionId, { key, entry });
176
+ }
177
+ }
178
+ const storeMatch = store[specificKey]
179
+ ? { key: specificKey, entry: store[specificKey] }
180
+ : null;
181
+ const storeByIdMatch = storeBySessionId.get(keyRest) ?? null;
182
+ const resolvedStoreKey = storeMatch?.key ?? storeByIdMatch?.key ?? specificKey;
183
+ const storeEntry = storeMatch?.entry ?? storeByIdMatch?.entry;
184
+ const sessionId = storeEntry?.sessionId ?? keyRest;
185
+ // Resolve the session file path
186
+ const sessionFile = resolveSessionFilePath(sessionId, storeEntry, {
187
+ agentId: agentIdFromKey,
188
+ });
189
+ try {
190
+ const stats = fs.statSync(sessionFile);
191
+ if (stats.isFile()) {
192
+ mergedEntries.push({
193
+ key: resolvedStoreKey,
194
+ sessionId,
195
+ sessionFile,
196
+ label: storeEntry?.label,
197
+ updatedAt: storeEntry?.updatedAt ?? stats.mtimeMs,
198
+ storeEntry,
199
+ });
200
+ }
201
+ }
202
+ catch {
203
+ // File doesn't exist - no results for this key
204
+ }
205
+ }
206
+ else {
207
+ // Full discovery for list view
208
+ const discoveredSessions = await discoverAllSessionsForUsage({
209
+ config,
210
+ startMs,
211
+ endMs,
212
+ });
213
+ // Build a map of sessionId -> store entry for quick lookup
214
+ const storeBySessionId = new Map();
215
+ for (const [key, entry] of Object.entries(store)) {
216
+ if (entry?.sessionId) {
217
+ storeBySessionId.set(entry.sessionId, { key, entry });
218
+ }
219
+ }
220
+ for (const discovered of discoveredSessions) {
221
+ const storeMatch = storeBySessionId.get(discovered.sessionId);
222
+ if (storeMatch) {
223
+ // Named session from store
224
+ mergedEntries.push({
225
+ key: storeMatch.key,
226
+ sessionId: discovered.sessionId,
227
+ sessionFile: discovered.sessionFile,
228
+ label: storeMatch.entry.label,
229
+ updatedAt: storeMatch.entry.updatedAt ?? discovered.mtime,
230
+ storeEntry: storeMatch.entry,
231
+ });
232
+ }
233
+ else {
234
+ // Unnamed session - use session ID as key, no label
235
+ mergedEntries.push({
236
+ // Keep agentId in the key so the dashboard can attribute sessions and later fetch logs.
237
+ key: `agent:${discovered.agentId}:${discovered.sessionId}`,
238
+ sessionId: discovered.sessionId,
239
+ sessionFile: discovered.sessionFile,
240
+ label: undefined, // No label for unnamed sessions
241
+ updatedAt: discovered.mtime,
242
+ });
243
+ }
244
+ }
245
+ }
246
+ // Sort by most recent first
247
+ mergedEntries.sort((a, b) => b.updatedAt - a.updatedAt);
248
+ // Apply limit
249
+ const limitedEntries = mergedEntries.slice(0, limit);
250
+ // Load usage for each session
251
+ const sessions = [];
252
+ const aggregateTotals = {
253
+ input: 0,
254
+ output: 0,
255
+ cacheRead: 0,
256
+ cacheWrite: 0,
257
+ totalTokens: 0,
258
+ totalCost: 0,
259
+ inputCost: 0,
260
+ outputCost: 0,
261
+ cacheReadCost: 0,
262
+ cacheWriteCost: 0,
263
+ missingCostEntries: 0,
264
+ };
265
+ const aggregateMessages = {
266
+ total: 0,
267
+ user: 0,
268
+ assistant: 0,
269
+ toolCalls: 0,
270
+ toolResults: 0,
271
+ errors: 0,
272
+ };
273
+ const toolAggregateMap = new Map();
274
+ const byModelMap = new Map();
275
+ const byProviderMap = new Map();
276
+ const byAgentMap = new Map();
277
+ const byChannelMap = new Map();
278
+ const dailyAggregateMap = new Map();
279
+ const latencyTotals = {
280
+ count: 0,
281
+ sum: 0,
282
+ min: Number.POSITIVE_INFINITY,
283
+ max: 0,
284
+ p95Max: 0,
285
+ };
286
+ const dailyLatencyMap = new Map();
287
+ const modelDailyMap = new Map();
288
+ const emptyTotals = () => ({
289
+ input: 0,
290
+ output: 0,
291
+ cacheRead: 0,
292
+ cacheWrite: 0,
293
+ totalTokens: 0,
294
+ totalCost: 0,
295
+ inputCost: 0,
296
+ outputCost: 0,
297
+ cacheReadCost: 0,
298
+ cacheWriteCost: 0,
299
+ missingCostEntries: 0,
300
+ });
301
+ const mergeTotals = (target, source) => {
302
+ target.input += source.input;
303
+ target.output += source.output;
304
+ target.cacheRead += source.cacheRead;
305
+ target.cacheWrite += source.cacheWrite;
306
+ target.totalTokens += source.totalTokens;
307
+ target.totalCost += source.totalCost;
308
+ target.inputCost += source.inputCost;
309
+ target.outputCost += source.outputCost;
310
+ target.cacheReadCost += source.cacheReadCost;
311
+ target.cacheWriteCost += source.cacheWriteCost;
312
+ target.missingCostEntries += source.missingCostEntries;
313
+ };
314
+ for (const merged of limitedEntries) {
315
+ const usage = await loadSessionCostSummary({
316
+ sessionId: merged.sessionId,
317
+ sessionEntry: merged.storeEntry,
318
+ sessionFile: merged.sessionFile,
319
+ config,
320
+ startMs,
321
+ endMs,
322
+ });
323
+ if (usage) {
324
+ aggregateTotals.input += usage.input;
325
+ aggregateTotals.output += usage.output;
326
+ aggregateTotals.cacheRead += usage.cacheRead;
327
+ aggregateTotals.cacheWrite += usage.cacheWrite;
328
+ aggregateTotals.totalTokens += usage.totalTokens;
329
+ aggregateTotals.totalCost += usage.totalCost;
330
+ aggregateTotals.inputCost += usage.inputCost;
331
+ aggregateTotals.outputCost += usage.outputCost;
332
+ aggregateTotals.cacheReadCost += usage.cacheReadCost;
333
+ aggregateTotals.cacheWriteCost += usage.cacheWriteCost;
334
+ aggregateTotals.missingCostEntries += usage.missingCostEntries;
335
+ }
336
+ const agentId = parseAgentSessionKey(merged.key)?.agentId;
337
+ const channel = merged.storeEntry?.channel ?? merged.storeEntry?.origin?.provider;
338
+ const chatType = merged.storeEntry?.chatType ?? merged.storeEntry?.origin?.chatType;
339
+ if (usage) {
340
+ if (usage.messageCounts) {
341
+ aggregateMessages.total += usage.messageCounts.total;
342
+ aggregateMessages.user += usage.messageCounts.user;
343
+ aggregateMessages.assistant += usage.messageCounts.assistant;
344
+ aggregateMessages.toolCalls += usage.messageCounts.toolCalls;
345
+ aggregateMessages.toolResults += usage.messageCounts.toolResults;
346
+ aggregateMessages.errors += usage.messageCounts.errors;
347
+ }
348
+ if (usage.toolUsage) {
349
+ for (const tool of usage.toolUsage.tools) {
350
+ toolAggregateMap.set(tool.name, (toolAggregateMap.get(tool.name) ?? 0) + tool.count);
351
+ }
352
+ }
353
+ if (usage.modelUsage) {
354
+ for (const entry of usage.modelUsage) {
355
+ const modelKey = `${entry.provider ?? "unknown"}::${entry.model ?? "unknown"}`;
356
+ const modelExisting = byModelMap.get(modelKey) ??
357
+ {
358
+ provider: entry.provider,
359
+ model: entry.model,
360
+ count: 0,
361
+ totals: emptyTotals(),
362
+ };
363
+ modelExisting.count += entry.count;
364
+ mergeTotals(modelExisting.totals, entry.totals);
365
+ byModelMap.set(modelKey, modelExisting);
366
+ const providerKey = entry.provider ?? "unknown";
367
+ const providerExisting = byProviderMap.get(providerKey) ??
368
+ {
369
+ provider: entry.provider,
370
+ model: undefined,
371
+ count: 0,
372
+ totals: emptyTotals(),
373
+ };
374
+ providerExisting.count += entry.count;
375
+ mergeTotals(providerExisting.totals, entry.totals);
376
+ byProviderMap.set(providerKey, providerExisting);
377
+ }
378
+ }
379
+ if (usage.latency) {
380
+ const { count, avgMs, minMs, maxMs, p95Ms } = usage.latency;
381
+ if (count > 0) {
382
+ latencyTotals.count += count;
383
+ latencyTotals.sum += avgMs * count;
384
+ latencyTotals.min = Math.min(latencyTotals.min, minMs);
385
+ latencyTotals.max = Math.max(latencyTotals.max, maxMs);
386
+ latencyTotals.p95Max = Math.max(latencyTotals.p95Max, p95Ms);
387
+ }
388
+ }
389
+ if (usage.dailyLatency) {
390
+ for (const day of usage.dailyLatency) {
391
+ const existing = dailyLatencyMap.get(day.date) ?? {
392
+ date: day.date,
393
+ count: 0,
394
+ sum: 0,
395
+ min: Number.POSITIVE_INFINITY,
396
+ max: 0,
397
+ p95Max: 0,
398
+ };
399
+ existing.count += day.count;
400
+ existing.sum += day.avgMs * day.count;
401
+ existing.min = Math.min(existing.min, day.minMs);
402
+ existing.max = Math.max(existing.max, day.maxMs);
403
+ existing.p95Max = Math.max(existing.p95Max, day.p95Ms);
404
+ dailyLatencyMap.set(day.date, existing);
405
+ }
406
+ }
407
+ if (usage.dailyModelUsage) {
408
+ for (const entry of usage.dailyModelUsage) {
409
+ const key = `${entry.date}::${entry.provider ?? "unknown"}::${entry.model ?? "unknown"}`;
410
+ const existing = modelDailyMap.get(key) ??
411
+ {
412
+ date: entry.date,
413
+ provider: entry.provider,
414
+ model: entry.model,
415
+ tokens: 0,
416
+ cost: 0,
417
+ count: 0,
418
+ };
419
+ existing.tokens += entry.tokens;
420
+ existing.cost += entry.cost;
421
+ existing.count += entry.count;
422
+ modelDailyMap.set(key, existing);
423
+ }
424
+ }
425
+ if (agentId) {
426
+ const agentTotals = byAgentMap.get(agentId) ?? emptyTotals();
427
+ mergeTotals(agentTotals, usage);
428
+ byAgentMap.set(agentId, agentTotals);
429
+ }
430
+ if (channel) {
431
+ const channelTotals = byChannelMap.get(channel) ?? emptyTotals();
432
+ mergeTotals(channelTotals, usage);
433
+ byChannelMap.set(channel, channelTotals);
434
+ }
435
+ if (usage.dailyBreakdown) {
436
+ for (const day of usage.dailyBreakdown) {
437
+ const daily = dailyAggregateMap.get(day.date) ?? {
438
+ date: day.date,
439
+ tokens: 0,
440
+ cost: 0,
441
+ messages: 0,
442
+ toolCalls: 0,
443
+ errors: 0,
444
+ };
445
+ daily.tokens += day.tokens;
446
+ daily.cost += day.cost;
447
+ dailyAggregateMap.set(day.date, daily);
448
+ }
449
+ }
450
+ if (usage.dailyMessageCounts) {
451
+ for (const day of usage.dailyMessageCounts) {
452
+ const daily = dailyAggregateMap.get(day.date) ?? {
453
+ date: day.date,
454
+ tokens: 0,
455
+ cost: 0,
456
+ messages: 0,
457
+ toolCalls: 0,
458
+ errors: 0,
459
+ };
460
+ daily.messages += day.total;
461
+ daily.toolCalls += day.toolCalls;
462
+ daily.errors += day.errors;
463
+ dailyAggregateMap.set(day.date, daily);
464
+ }
465
+ }
466
+ }
467
+ sessions.push({
468
+ key: merged.key,
469
+ label: merged.label,
470
+ sessionId: merged.sessionId,
471
+ updatedAt: merged.updatedAt,
472
+ agentId,
473
+ channel,
474
+ chatType,
475
+ origin: merged.storeEntry?.origin,
476
+ modelOverride: merged.storeEntry?.modelOverride,
477
+ providerOverride: merged.storeEntry?.providerOverride,
478
+ modelProvider: merged.storeEntry?.modelProvider,
479
+ model: merged.storeEntry?.model,
480
+ usage,
481
+ contextWeight: includeContextWeight
482
+ ? (merged.storeEntry?.systemPromptReport ?? null)
483
+ : undefined,
484
+ });
485
+ }
486
+ // Format dates back to YYYY-MM-DD strings
487
+ const formatDateStr = (ms) => {
488
+ const d = new Date(ms);
489
+ return `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, "0")}-${String(d.getUTCDate()).padStart(2, "0")}`;
490
+ };
491
+ const aggregates = {
492
+ messages: aggregateMessages,
493
+ tools: {
494
+ totalCalls: Array.from(toolAggregateMap.values()).reduce((sum, count) => sum + count, 0),
495
+ uniqueTools: toolAggregateMap.size,
496
+ tools: Array.from(toolAggregateMap.entries())
497
+ .map(([name, count]) => ({ name, count }))
498
+ .toSorted((a, b) => b.count - a.count),
499
+ },
500
+ byModel: Array.from(byModelMap.values()).toSorted((a, b) => {
501
+ const costDiff = b.totals.totalCost - a.totals.totalCost;
502
+ if (costDiff !== 0) {
503
+ return costDiff;
504
+ }
505
+ return b.totals.totalTokens - a.totals.totalTokens;
506
+ }),
507
+ byProvider: Array.from(byProviderMap.values()).toSorted((a, b) => {
508
+ const costDiff = b.totals.totalCost - a.totals.totalCost;
509
+ if (costDiff !== 0) {
510
+ return costDiff;
511
+ }
512
+ return b.totals.totalTokens - a.totals.totalTokens;
513
+ }),
514
+ byAgent: Array.from(byAgentMap.entries())
515
+ .map(([id, totals]) => ({ agentId: id, totals }))
516
+ .toSorted((a, b) => b.totals.totalCost - a.totals.totalCost),
517
+ byChannel: Array.from(byChannelMap.entries())
518
+ .map(([name, totals]) => ({ channel: name, totals }))
519
+ .toSorted((a, b) => b.totals.totalCost - a.totals.totalCost),
520
+ latency: latencyTotals.count > 0
521
+ ? {
522
+ count: latencyTotals.count,
523
+ avgMs: latencyTotals.sum / latencyTotals.count,
524
+ minMs: latencyTotals.min === Number.POSITIVE_INFINITY ? 0 : latencyTotals.min,
525
+ maxMs: latencyTotals.max,
526
+ p95Ms: latencyTotals.p95Max,
527
+ }
528
+ : undefined,
529
+ dailyLatency: Array.from(dailyLatencyMap.values())
530
+ .map((entry) => ({
531
+ date: entry.date,
532
+ count: entry.count,
533
+ avgMs: entry.count ? entry.sum / entry.count : 0,
534
+ minMs: entry.min === Number.POSITIVE_INFINITY ? 0 : entry.min,
535
+ maxMs: entry.max,
536
+ p95Ms: entry.p95Max,
537
+ }))
538
+ .toSorted((a, b) => a.date.localeCompare(b.date)),
539
+ modelDaily: Array.from(modelDailyMap.values()).toSorted((a, b) => a.date.localeCompare(b.date) || b.cost - a.cost),
540
+ daily: Array.from(dailyAggregateMap.values()).toSorted((a, b) => a.date.localeCompare(b.date)),
541
+ };
542
+ const result = {
543
+ updatedAt: now,
544
+ startDate: formatDateStr(startMs),
545
+ endDate: formatDateStr(endMs),
546
+ sessions,
547
+ totals: aggregateTotals,
548
+ aggregates,
549
+ };
550
+ respond(true, result, undefined);
551
+ },
552
+ "sessions.usage.timeseries": async ({ respond, params }) => {
553
+ const key = typeof params?.key === "string" ? params.key.trim() : null;
554
+ if (!key) {
555
+ respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, "key is required for timeseries"));
556
+ return;
557
+ }
558
+ const config = loadConfig();
559
+ const { entry } = loadSessionEntry(key);
560
+ // For discovered sessions (not in store), try using key as sessionId directly
561
+ const parsed = parseAgentSessionKey(key);
562
+ const agentId = parsed?.agentId;
563
+ const rawSessionId = parsed?.rest ?? key;
564
+ const sessionId = entry?.sessionId ?? rawSessionId;
565
+ const sessionFile = entry?.sessionFile ?? resolveSessionFilePath(rawSessionId, entry, { agentId });
566
+ const timeseries = await loadSessionUsageTimeSeries({
567
+ sessionId,
568
+ sessionEntry: entry,
569
+ sessionFile,
570
+ config,
571
+ maxPoints: 200,
572
+ });
573
+ if (!timeseries) {
574
+ respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, `No transcript found for session: ${key}`));
575
+ return;
576
+ }
577
+ respond(true, timeseries, undefined);
578
+ },
579
+ "sessions.usage.logs": async ({ respond, params }) => {
580
+ const key = typeof params?.key === "string" ? params.key.trim() : null;
581
+ if (!key) {
582
+ respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, "key is required for logs"));
583
+ return;
584
+ }
585
+ const limit = typeof params?.limit === "number" && Number.isFinite(params.limit)
586
+ ? Math.min(params.limit, 1000)
587
+ : 200;
588
+ const config = loadConfig();
589
+ const { entry } = loadSessionEntry(key);
590
+ // For discovered sessions (not in store), try using key as sessionId directly
591
+ const parsed = parseAgentSessionKey(key);
592
+ const agentId = parsed?.agentId;
593
+ const rawSessionId = parsed?.rest ?? key;
594
+ const sessionId = entry?.sessionId ?? rawSessionId;
595
+ const sessionFile = entry?.sessionFile ?? resolveSessionFilePath(rawSessionId, entry, { agentId });
596
+ const { loadSessionLogs } = await import("../../infra/session-cost-usage.js");
597
+ const logs = await loadSessionLogs({
598
+ sessionId,
599
+ sessionEntry: entry,
600
+ sessionFile,
601
+ config,
602
+ limit,
603
+ });
604
+ respond(true, { logs: logs ?? [] }, undefined);
605
+ },
63
606
  };