()
| 724 | toolMap.set(t.name, t); |
| 725 | }, |
| 726 | async start() { |
| 727 | toolDescriptors = toAgentToolDescriptors([...toolMap.values()]); |
| 728 | // Isolate per-adapter startup failures: one adapter rejecting (e.g. |
| 729 | // Telegram's setMyCommands rejecting a hyphenated command name, a revoked |
| 730 | // token, a port already in use) must NOT crash the bot or prevent the |
| 731 | // other adapters from starting. Log + degrade, never throw. |
| 732 | const startResults = await Promise.allSettled( |
| 733 | opts.adapters.map((a) => a.start(makeSink(a))), |
| 734 | ); |
| 735 | const startedPlatforms: string[] = []; |
| 736 | const failedPlatforms: string[] = []; |
| 737 | startResults.forEach((r, i) => { |
| 738 | const rawPlatform = opts.adapters[i]!.platform; |
| 739 | // Raw label for the human-facing log; normalized label for telemetry. |
| 740 | const platform = normalizePlatform(rawPlatform); |
| 741 | if (r.status === "rejected") { |
| 742 | failedPlatforms.push(platform); |
| 743 | console.error( |
| 744 | `[bot] adapter "${rawPlatform}" failed to start:`, |
| 745 | r.reason, |
| 746 | ); |
| 747 | telemetry.capture("oss.bot.start_failed", { |
| 748 | platform, |
| 749 | errorClass: errorClass(r.reason), |
| 750 | }); |
| 751 | } else { |
| 752 | startedPlatforms.push(platform); |
| 753 | } |
| 754 | }); |
| 755 | if (startedPlatforms.length > 0) { |
| 756 | telemetry.capture("oss.bot.started", { |
| 757 | platforms: startedPlatforms, |
| 758 | startedCount: startedPlatforms.length, |
| 759 | failedCount: failedPlatforms.length, |
| 760 | hasMentionHandler: mentionHandlers.length > 0, |
| 761 | hasMessageHandler: messageHandlers.length > 0, |
| 762 | interruptHandlers: interruptHandlers.size, |
| 763 | commandsCount: commandHandlers.size, |
| 764 | toolsCount: toolMap.size, |
| 765 | }); |
| 766 | } |
| 767 | // Hand declared commands to adapters that register them up front (e.g. |
| 768 | // Discord); adapters without `registerCommands` are skipped. Per-adapter |
| 769 | // failures are isolated the same way as start(). |
| 770 | const commandSpecs = [...commandHandlers.values()].map(toCommandSpec); |
| 771 | if (commandSpecs.length > 0) { |
| 772 | const registerResults = await Promise.allSettled( |
| 773 | opts.adapters.map((a) => a.registerCommands?.(commandSpecs)), |
| 774 | ); |
| 775 | registerResults.forEach((r, i) => { |
| 776 | if (r.status === "rejected") { |
| 777 | console.error( |
| 778 | `[bot] adapter "${opts.adapters[i]!.platform}" failed to register commands:`, |
| 779 | r.reason, |
| 780 | ); |
| 781 | } |
| 782 | }); |
| 783 | } |
nothing calls this directly
no test coverage detected
searching dependent graphs…