@elizaos/ui 2.0.0-alpha.526 → 2.0.0-alpha.528

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 (237) hide show
  1. package/apps/app-elizamaker/src/index.d.ts +2 -0
  2. package/apps/app-elizamaker/src/index.d.ts.map +1 -1
  3. package/apps/app-elizamaker/src/index.js +2 -0
  4. package/apps/app-elizamaker/src/init-registry-services.d.ts +18 -0
  5. package/apps/app-elizamaker/src/init-registry-services.d.ts.map +1 -0
  6. package/apps/app-elizamaker/src/init-registry-services.js +63 -0
  7. package/apps/app-elizamaker/src/plugin.d.ts.map +1 -1
  8. package/apps/app-elizamaker/src/plugin.js +7 -0
  9. package/apps/app-elizamaker/src/registry-service-registry.d.ts +4 -0
  10. package/apps/app-elizamaker/src/registry-service-registry.d.ts.map +1 -0
  11. package/apps/app-elizamaker/src/registry-service-registry.js +7 -0
  12. package/apps/app-lifeops/src/automation-node-contributor.d.ts +2 -0
  13. package/apps/app-lifeops/src/automation-node-contributor.d.ts.map +1 -0
  14. package/apps/app-lifeops/src/automation-node-contributor.js +93 -0
  15. package/apps/app-lifeops/src/public.d.ts.map +1 -1
  16. package/apps/app-lifeops/src/public.js +2 -0
  17. package/apps/app-training/src/services/training-service-registry.d.ts +4 -0
  18. package/apps/app-training/src/services/training-service-registry.d.ts.map +1 -0
  19. package/apps/app-training/src/services/training-service-registry.js +7 -0
  20. package/package.json +1 -1
  21. package/packages/agent/src/api/agent-status-routes.d.ts +3 -23
  22. package/packages/agent/src/api/agent-status-routes.d.ts.map +1 -1
  23. package/packages/agent/src/api/agent-status-routes.js +7 -40
  24. package/packages/agent/src/api/coordinator-wiring.d.ts.map +1 -0
  25. package/packages/agent/src/api/misc-routes.d.ts.map +1 -1
  26. package/packages/agent/src/api/misc-routes.js +3 -37
  27. package/packages/agent/src/api/nfa-routes.d.ts.map +1 -1
  28. package/packages/agent/src/api/nfa-routes.js +1 -9
  29. package/packages/agent/src/api/provider-switch-routes.d.ts +8 -7
  30. package/packages/agent/src/api/provider-switch-routes.d.ts.map +1 -1
  31. package/packages/agent/src/api/provider-switch-routes.js +41 -26
  32. package/packages/agent/src/api/server-types.d.ts +0 -6
  33. package/packages/agent/src/api/server-types.d.ts.map +1 -1
  34. package/packages/agent/src/api/server.d.ts.map +1 -1
  35. package/packages/agent/src/api/server.js +31 -138
  36. package/packages/agent/src/api/stream-routes.d.ts.map +1 -1
  37. package/packages/agent/src/api/stream-routes.js +6 -8
  38. package/packages/agent/src/api/wallet-trading-profile.d.ts.map +1 -1
  39. package/packages/agent/src/api/wallet-trading-profile.js +2 -23
  40. package/packages/agent/src/auth/account-storage.d.ts.map +1 -1
  41. package/packages/agent/src/auth/account-storage.js +4 -15
  42. package/packages/agent/src/runtime/eliza.d.ts.map +1 -1
  43. package/packages/agent/src/runtime/eliza.js +2 -6
  44. package/packages/agent/src/runtime/first-time-setup.d.ts.map +1 -1
  45. package/packages/agent/src/runtime/first-time-setup.js +1 -7
  46. package/packages/agent/src/runtime/operations/cold-strategy.d.ts +4 -4
  47. package/packages/agent/src/runtime/operations/cold-strategy.d.ts.map +1 -1
  48. package/packages/agent/src/runtime/operations/cold-strategy.js +13 -46
  49. package/packages/agent/src/runtime/operations/health-checks.d.ts +1 -0
  50. package/packages/agent/src/runtime/operations/health-checks.d.ts.map +1 -1
  51. package/packages/agent/src/runtime/operations/health-checks.js +1 -1
  52. package/packages/agent/src/runtime/operations/health.d.ts.map +1 -1
  53. package/packages/agent/src/runtime/operations/health.js +1 -13
  54. package/packages/agent/src/runtime/operations/index.d.ts +1 -0
  55. package/packages/agent/src/runtime/operations/index.d.ts.map +1 -1
  56. package/packages/agent/src/runtime/operations/index.js +1 -0
  57. package/packages/agent/src/runtime/operations/manager.d.ts +2 -0
  58. package/packages/agent/src/runtime/operations/manager.d.ts.map +1 -1
  59. package/packages/agent/src/runtime/operations/manager.js +27 -7
  60. package/packages/agent/src/runtime/operations/reload-hot.d.ts +4 -1
  61. package/packages/agent/src/runtime/operations/reload-hot.d.ts.map +1 -1
  62. package/packages/agent/src/runtime/operations/reload-hot.js +46 -41
  63. package/packages/agent/src/runtime/operations/repository.d.ts +30 -8
  64. package/packages/agent/src/runtime/operations/repository.d.ts.map +1 -1
  65. package/packages/agent/src/runtime/operations/repository.js +140 -54
  66. package/packages/agent/src/runtime/operations/types.d.ts +26 -24
  67. package/packages/agent/src/runtime/operations/types.d.ts.map +1 -1
  68. package/packages/agent/src/runtime/operations/types.js +8 -20
  69. package/packages/agent/src/runtime/operations/vault-bridge.d.ts +60 -0
  70. package/packages/agent/src/runtime/operations/vault-bridge.d.ts.map +1 -0
  71. package/packages/agent/src/runtime/operations/vault-bridge.js +80 -0
  72. package/packages/agent/src/runtime/plugin-resolver.d.ts.map +1 -1
  73. package/packages/agent/src/runtime/plugin-resolver.js +1 -3
  74. package/packages/agent/src/runtime/plugin-types.d.ts.map +1 -1
  75. package/packages/agent/src/runtime/plugin-types.js +1 -3
  76. package/packages/agent/src/services/app-package-modules.d.ts.map +1 -1
  77. package/packages/agent/src/services/app-package-modules.js +1 -8
  78. package/packages/agent/src/services/app-run-store.d.ts.map +1 -1
  79. package/packages/agent/src/services/app-run-store.js +2 -23
  80. package/packages/agent/src/services/registry-client-local.d.ts.map +1 -1
  81. package/packages/agent/src/services/registry-client-local.js +1 -9
  82. package/packages/agent/src/utils/atomic-json.d.ts +37 -0
  83. package/packages/agent/src/utils/atomic-json.d.ts.map +1 -0
  84. package/packages/agent/src/utils/atomic-json.js +98 -0
  85. package/packages/app-core/src/api/automation-node-contributors.d.ts +14 -0
  86. package/packages/app-core/src/api/automation-node-contributors.d.ts.map +1 -0
  87. package/packages/app-core/src/api/automation-node-contributors.js +14 -0
  88. package/packages/app-core/src/api/client-agent.d.ts +627 -0
  89. package/packages/app-core/src/api/client-agent.d.ts.map +1 -0
  90. package/packages/app-core/src/api/client-agent.js +1442 -0
  91. package/packages/app-core/src/api/client-automations.d.ts +8 -0
  92. package/packages/app-core/src/api/client-automations.d.ts.map +1 -0
  93. package/packages/app-core/src/api/client-automations.js +7 -0
  94. package/packages/app-core/src/api/client-base.d.ts +82 -0
  95. package/packages/app-core/src/api/client-base.d.ts.map +1 -0
  96. package/packages/app-core/src/api/client-base.js +729 -0
  97. package/packages/app-core/src/api/client-browser-workspace.d.ts +25 -0
  98. package/packages/app-core/src/api/client-browser-workspace.d.ts.map +1 -0
  99. package/packages/app-core/src/api/client-browser-workspace.js +98 -0
  100. package/packages/app-core/src/api/client-chat.d.ts +355 -0
  101. package/packages/app-core/src/api/client-chat.d.ts.map +1 -0
  102. package/packages/app-core/src/api/client-chat.js +582 -0
  103. package/packages/app-core/src/api/client-cloud.d.ts +286 -0
  104. package/packages/app-core/src/api/client-cloud.d.ts.map +1 -0
  105. package/packages/app-core/src/api/client-cloud.js +410 -0
  106. package/packages/app-core/src/api/client-computeruse.d.ts +32 -0
  107. package/packages/app-core/src/api/client-computeruse.d.ts.map +1 -0
  108. package/packages/app-core/src/api/client-computeruse.js +16 -0
  109. package/packages/app-core/src/api/client-imessage.d.ts +68 -0
  110. package/packages/app-core/src/api/client-imessage.d.ts.map +1 -0
  111. package/packages/app-core/src/api/client-imessage.js +74 -0
  112. package/packages/app-core/src/api/client-local-inference.d.ts +62 -0
  113. package/packages/app-core/src/api/client-local-inference.d.ts.map +1 -0
  114. package/packages/app-core/src/api/client-local-inference.js +87 -0
  115. package/packages/app-core/src/api/client-n8n.d.ts +27 -0
  116. package/packages/app-core/src/api/client-n8n.d.ts.map +1 -0
  117. package/packages/app-core/src/api/client-n8n.js +61 -0
  118. package/packages/app-core/src/api/client-skills.d.ts +475 -0
  119. package/packages/app-core/src/api/client-skills.d.ts.map +1 -0
  120. package/packages/app-core/src/api/client-skills.js +608 -0
  121. package/packages/app-core/src/api/client-types-babylon.d.ts +254 -0
  122. package/packages/app-core/src/api/client-types-babylon.d.ts.map +1 -0
  123. package/packages/app-core/src/api/client-types-babylon.js +2 -0
  124. package/packages/app-core/src/api/client-types-character.d.ts +39 -0
  125. package/packages/app-core/src/api/client-types-character.d.ts.map +1 -0
  126. package/packages/app-core/src/api/client-types-character.js +1 -0
  127. package/packages/app-core/src/api/client-types-chat.d.ts +428 -0
  128. package/packages/app-core/src/api/client-types-chat.d.ts.map +1 -0
  129. package/packages/app-core/src/api/client-types-chat.js +9 -0
  130. package/packages/app-core/src/api/client-types-config.d.ts +587 -0
  131. package/packages/app-core/src/api/client-types-config.d.ts.map +1 -0
  132. package/packages/app-core/src/api/client-types-config.js +5 -0
  133. package/packages/app-core/src/api/client-types-experience.d.ts +97 -0
  134. package/packages/app-core/src/api/client-types-experience.d.ts.map +1 -0
  135. package/packages/app-core/src/api/client-types-experience.js +1 -0
  136. package/packages/app-core/src/api/client-types-relationships.d.ts +181 -0
  137. package/packages/app-core/src/api/client-types-relationships.d.ts.map +1 -0
  138. package/packages/app-core/src/api/client-types-relationships.js +1 -0
  139. package/packages/app-core/src/api/client-types-steward.d.ts +85 -0
  140. package/packages/app-core/src/api/client-types-steward.d.ts.map +1 -0
  141. package/packages/app-core/src/api/client-types-steward.js +9 -0
  142. package/packages/app-core/src/api/client-types.d.ts +9 -0
  143. package/packages/app-core/src/api/client-types.d.ts.map +1 -0
  144. package/packages/app-core/src/api/client-types.js +12 -0
  145. package/packages/app-core/src/api/client-wallet.d.ts +130 -0
  146. package/packages/app-core/src/api/client-wallet.d.ts.map +1 -0
  147. package/packages/app-core/src/api/client-wallet.js +228 -0
  148. package/packages/app-core/src/api/client.d.ts +36 -0
  149. package/packages/app-core/src/api/client.d.ts.map +1 -0
  150. package/packages/app-core/src/api/client.js +36 -0
  151. package/packages/app-core/src/api/index.d.ts +2 -0
  152. package/packages/app-core/src/api/index.d.ts.map +1 -0
  153. package/packages/app-core/src/api/index.js +1 -0
  154. package/packages/app-core/src/bridge/electrobun-rpc.d.ts +57 -0
  155. package/packages/app-core/src/bridge/electrobun-rpc.d.ts.map +1 -0
  156. package/packages/app-core/src/bridge/electrobun-rpc.js +87 -0
  157. package/packages/app-core/src/bridge/electrobun-runtime.d.ts +3 -0
  158. package/packages/app-core/src/bridge/electrobun-runtime.d.ts.map +1 -0
  159. package/packages/app-core/src/bridge/electrobun-runtime.js +34 -0
  160. package/packages/app-core/src/bridge/native-plugins.d.ts +504 -0
  161. package/packages/app-core/src/bridge/native-plugins.d.ts.map +1 -0
  162. package/packages/app-core/src/bridge/native-plugins.js +67 -0
  163. package/packages/app-core/src/chat/coding-agent-session-state.d.ts +16 -0
  164. package/packages/app-core/src/chat/coding-agent-session-state.d.ts.map +1 -0
  165. package/packages/app-core/src/chat/coding-agent-session-state.js +27 -0
  166. package/packages/app-core/src/components/pages/browser-workspace-wallet.d.ts +80 -0
  167. package/packages/app-core/src/components/pages/browser-workspace-wallet.d.ts.map +1 -0
  168. package/packages/app-core/src/components/pages/browser-workspace-wallet.js +135 -0
  169. package/packages/app-core/src/services/account-pool.d.ts +98 -0
  170. package/packages/app-core/src/services/account-pool.d.ts.map +1 -0
  171. package/packages/app-core/src/services/account-pool.js +506 -0
  172. package/packages/app-core/src/services/account-usage.d.ts +75 -0
  173. package/packages/app-core/src/services/account-usage.d.ts.map +1 -0
  174. package/packages/app-core/src/services/account-usage.js +179 -0
  175. package/packages/app-core/src/services/local-inference/active-model.d.ts +59 -0
  176. package/packages/app-core/src/services/local-inference/active-model.d.ts.map +1 -0
  177. package/packages/app-core/src/services/local-inference/active-model.js +120 -0
  178. package/packages/app-core/src/services/local-inference/device-bridge.d.ts +131 -0
  179. package/packages/app-core/src/services/local-inference/device-bridge.d.ts.map +1 -0
  180. package/packages/app-core/src/services/local-inference/device-bridge.js +748 -0
  181. package/packages/app-core/src/services/local-inference/engine.d.ts +52 -0
  182. package/packages/app-core/src/services/local-inference/engine.d.ts.map +1 -0
  183. package/packages/app-core/src/services/local-inference/engine.js +138 -0
  184. package/packages/app-core/src/services/local-inference/external-scanner.d.ts +17 -0
  185. package/packages/app-core/src/services/local-inference/external-scanner.d.ts.map +1 -0
  186. package/packages/app-core/src/services/local-inference/external-scanner.js +261 -0
  187. package/packages/app-core/src/services/local-inference/handler-registry.d.ts +72 -0
  188. package/packages/app-core/src/services/local-inference/handler-registry.d.ts.map +1 -0
  189. package/packages/app-core/src/services/local-inference/handler-registry.js +160 -0
  190. package/packages/app-core/src/services/local-inference/paths.d.ts +24 -0
  191. package/packages/app-core/src/services/local-inference/paths.d.ts.map +1 -0
  192. package/packages/app-core/src/services/local-inference/paths.js +41 -0
  193. package/packages/app-core/src/services/local-inference/providers.d.ts +61 -0
  194. package/packages/app-core/src/services/local-inference/providers.d.ts.map +1 -0
  195. package/packages/app-core/src/services/local-inference/providers.js +277 -0
  196. package/packages/app-core/src/services/local-inference/registry.d.ts +35 -0
  197. package/packages/app-core/src/services/local-inference/registry.d.ts.map +1 -0
  198. package/packages/app-core/src/services/local-inference/registry.js +108 -0
  199. package/packages/app-core/src/services/local-inference/routing-preferences.d.ts +31 -0
  200. package/packages/app-core/src/services/local-inference/routing-preferences.d.ts.map +1 -0
  201. package/packages/app-core/src/services/local-inference/routing-preferences.js +72 -0
  202. package/packages/app-core/src/services/local-inference/types.d.ts +121 -0
  203. package/packages/app-core/src/services/local-inference/types.d.ts.map +1 -0
  204. package/packages/app-core/src/services/local-inference/types.js +14 -0
  205. package/packages/app-core/src/services/local-inference/verify.d.ts +39 -0
  206. package/packages/app-core/src/services/local-inference/verify.d.ts.map +1 -0
  207. package/packages/app-core/src/services/local-inference/verify.js +104 -0
  208. package/packages/app-core/src/types/index.d.ts +658 -0
  209. package/packages/app-core/src/types/index.d.ts.map +1 -0
  210. package/packages/app-core/src/types/index.js +4 -0
  211. package/packages/app-core/src/utils/assistant-text.d.ts +2 -0
  212. package/packages/app-core/src/utils/assistant-text.d.ts.map +1 -0
  213. package/packages/app-core/src/utils/assistant-text.js +167 -0
  214. package/packages/app-core/src/utils/eliza-globals.d.ts +15 -0
  215. package/packages/app-core/src/utils/eliza-globals.d.ts.map +1 -0
  216. package/packages/app-core/src/utils/eliza-globals.js +50 -0
  217. package/packages/app-core/src/utils/streaming-text.d.ts +9 -0
  218. package/packages/app-core/src/utils/streaming-text.d.ts.map +1 -0
  219. package/packages/app-core/src/utils/streaming-text.js +112 -0
  220. package/packages/shared/src/format-error.d.ts +14 -0
  221. package/packages/shared/src/format-error.d.ts.map +1 -0
  222. package/packages/shared/src/format-error.js +17 -0
  223. package/packages/shared/src/index.d.ts +1 -0
  224. package/packages/shared/src/index.d.ts.map +1 -1
  225. package/packages/shared/src/index.js +1 -0
  226. package/packages/typescript/src/runtime.d.ts +14 -0
  227. package/packages/typescript/src/runtime.d.ts.map +1 -1
  228. package/packages/typescript/src/runtime.js +42 -0
  229. package/packages/typescript/src/services/message.d.ts +8 -0
  230. package/packages/typescript/src/services/message.d.ts.map +1 -1
  231. package/packages/typescript/src/services/message.js +51 -0
  232. package/packages/typescript/src/services/task.d.ts +1 -0
  233. package/packages/typescript/src/services/task.d.ts.map +1 -1
  234. package/packages/typescript/src/services/task.js +26 -3
  235. package/apps/app-task-coordinator/src/api/coordinator-wiring.d.ts.map +0 -1
  236. /package/{apps/app-task-coordinator → packages/agent}/src/api/coordinator-wiring.d.ts +0 -0
  237. /package/{apps/app-task-coordinator → packages/agent}/src/api/coordinator-wiring.js +0 -0
@@ -0,0 +1,729 @@
1
+ /**
2
+ * ElizaClient class — core infrastructure only.
3
+ *
4
+ * Separated from client.ts so domain augmentation files can import the class
5
+ * without circular dependency issues.
6
+ */
7
+ import { getBootConfig, setBootConfig } from "../config/boot-config";
8
+ import { stripAssistantStageDirections } from "../utils/assistant-text";
9
+ import { clearElizaApiBase, getElizaApiBase, getElizaApiToken, setElizaApiBase, } from "../utils/eliza-globals";
10
+ import { mergeStreamingText } from "../utils/streaming-text";
11
+ import { ApiError } from "./client-types";
12
+ // ---------------------------------------------------------------------------
13
+ // Constants
14
+ // ---------------------------------------------------------------------------
15
+ const GENERIC_NO_RESPONSE_TEXT = "Sorry, I couldn't generate a response right now. Please try again.";
16
+ const DEFAULT_FETCH_TIMEOUT_MS = 10_000;
17
+ const LOCAL_STORAGE_API_BASE_KEY = "elizaos_api_base";
18
+ // ---------------------------------------------------------------------------
19
+ // Client
20
+ // ---------------------------------------------------------------------------
21
+ export class ElizaClient {
22
+ _baseUrl;
23
+ _userSetBase;
24
+ _token;
25
+ clientId;
26
+ ws = null;
27
+ wsHandlers = new Map();
28
+ wsSendQueue = [];
29
+ wsSendQueueLimit = 32;
30
+ reconnectTimer = null;
31
+ backoffMs = 500;
32
+ wsHasConnectedOnce = false;
33
+ // Connection state tracking for backend crash handling
34
+ connectionState = "disconnected";
35
+ reconnectAttempt = 0;
36
+ disconnectedAt = null;
37
+ connectionStateListeners = new Set();
38
+ maxReconnectAttempts = 15;
39
+ // UI language propagation — set by AppContext so the backend can
40
+ // localise responses when needed.
41
+ _uiLanguage = null;
42
+ /** Store the current UI language so it can be sent as a header on every request. */
43
+ setUiLanguage(lang) {
44
+ this._uiLanguage = lang || null;
45
+ }
46
+ static generateClientId() {
47
+ let random;
48
+ if (typeof globalThis.crypto?.randomUUID === "function") {
49
+ random = globalThis.crypto.randomUUID();
50
+ }
51
+ else if (typeof globalThis.crypto?.getRandomValues === "function") {
52
+ const buf = new Uint8Array(16);
53
+ globalThis.crypto.getRandomValues(buf);
54
+ random = `${Date.now().toString(36)}${Array.from(buf, (b) => b.toString(16).padStart(2, "0")).join("")}`;
55
+ }
56
+ else {
57
+ random = `${Date.now().toString(36)}${Math.random().toString(36).slice(2)}`;
58
+ }
59
+ return `ui-${random.slice(0, 256).replace(/[^a-zA-Z0-9._-]/g, "")}`;
60
+ }
61
+ constructor(baseUrl, token) {
62
+ this.clientId = ElizaClient.generateClientId();
63
+ this._token = token?.trim() || null;
64
+ const bootBase = getBootConfig().apiBase;
65
+ const injectedBase = getElizaApiBase();
66
+ const storedBase = typeof window !== "undefined" && window.localStorage
67
+ ? window.localStorage.getItem(LOCAL_STORAGE_API_BASE_KEY)
68
+ : null;
69
+ this._userSetBase = baseUrl != null;
70
+ // Priority: explicit arg > boot config > desktop injection > session storage > same origin.
71
+ // `client.setBaseUrl()` updates the boot config, so it must beat the
72
+ // shell-injected local default once the user has chosen a different
73
+ // server. Injection still beats stale session state from prior sessions.
74
+ this._baseUrl = baseUrl ?? bootBase ?? injectedBase ?? storedBase ?? "";
75
+ }
76
+ /**
77
+ * Resolve the API base URL lazily.
78
+ * In the desktop shell the main process injects the API base after the
79
+ * page loads (once the agent runtime starts). Re-checking the boot config
80
+ * on every call ensures we pick up the injected value even if it wasn't
81
+ * set at construction, or if the port changed dynamically (e.g. 2138→2139).
82
+ */
83
+ get baseUrl() {
84
+ // Always re-read boot config — the main process may push a port update
85
+ // via apiBaseUpdate RPC at any time (e.g. when the child runtime binds
86
+ // to a different port than initially injected in the HTML).
87
+ // Only skip if the user explicitly called setBaseUrl() themselves.
88
+ if (!this._userSetBase) {
89
+ const bootBase = getBootConfig().apiBase;
90
+ const injectedBase = getElizaApiBase();
91
+ const preferredBase = bootBase ?? injectedBase;
92
+ if (preferredBase && preferredBase !== this._baseUrl) {
93
+ this._baseUrl = preferredBase;
94
+ }
95
+ }
96
+ return this._baseUrl;
97
+ }
98
+ get apiToken() {
99
+ if (this._token)
100
+ return this._token;
101
+ const bootToken = getBootConfig().apiToken;
102
+ if (typeof bootToken === "string" && bootToken.trim())
103
+ return bootToken.trim();
104
+ const injectedToken = getElizaApiToken();
105
+ if (injectedToken)
106
+ return injectedToken;
107
+ return null;
108
+ }
109
+ hasToken() {
110
+ return Boolean(this.apiToken);
111
+ }
112
+ /**
113
+ * Bearer token sent on app REST requests (compat API). Used when the
114
+ * Electrobun main process relays HTTP so it can match the renderer-injected
115
+ * token in external-desktop / Vite-proxy setups.
116
+ */
117
+ getRestAuthToken() {
118
+ return this.apiToken;
119
+ }
120
+ setToken(token) {
121
+ this._token = token?.trim() || null;
122
+ // Update boot config so other consumers see the new token.
123
+ const config = getBootConfig();
124
+ setBootConfig({ ...config, apiToken: this._token ?? undefined });
125
+ }
126
+ getBaseUrl() {
127
+ return this.baseUrl;
128
+ }
129
+ setBaseUrl(baseUrl) {
130
+ const trimmed = baseUrl?.slice(0, 4096).trim() ?? "";
131
+ let end = trimmed.length;
132
+ while (end > 0 && trimmed.charCodeAt(end - 1) === 47)
133
+ end--;
134
+ const normalized = trimmed.slice(0, end);
135
+ this._userSetBase = normalized.length > 0;
136
+ this._baseUrl = normalized;
137
+ this.disconnectWs();
138
+ // Update boot config so other consumers (resolveApiUrl, etc.) see the new base.
139
+ const config = getBootConfig();
140
+ setBootConfig({ ...config, apiBase: normalized || undefined });
141
+ if (typeof window !== "undefined") {
142
+ if (normalized) {
143
+ window.localStorage.setItem(LOCAL_STORAGE_API_BASE_KEY, normalized);
144
+ }
145
+ else {
146
+ window.localStorage.removeItem(LOCAL_STORAGE_API_BASE_KEY);
147
+ }
148
+ // Clean up legacy sessionStorage entry (same key was used historically)
149
+ window.sessionStorage.removeItem(LOCAL_STORAGE_API_BASE_KEY);
150
+ }
151
+ // Mirror to window.__ELIZA_API_BASE__ so the Capacitor agent plugin's web
152
+ // fallback (native-plugins/agent/src/web.ts) and any other consumers that
153
+ // read the global directly see the same base. Electrobun's main↔renderer
154
+ // bridge also writes this; mirroring in setBaseUrl() makes mobile + dev-
155
+ // server + Electrobun behave consistently for any caller (Local Agent,
156
+ // Remote Agent, Eliza Cloud).
157
+ if (normalized) {
158
+ setElizaApiBase(normalized);
159
+ }
160
+ else {
161
+ clearElizaApiBase();
162
+ }
163
+ }
164
+ /** True when we have a usable HTTP(S) API endpoint. */
165
+ get apiAvailable() {
166
+ if (this.baseUrl)
167
+ return true;
168
+ if (typeof window !== "undefined") {
169
+ const proto = window.location.protocol;
170
+ return proto === "http:" || proto === "https:";
171
+ }
172
+ return false;
173
+ }
174
+ // --- REST API ---
175
+ async rawRequest(path, init, options) {
176
+ if (!this.apiAvailable) {
177
+ throw new ApiError({
178
+ kind: "network",
179
+ path,
180
+ message: "API not available (no HTTP origin)",
181
+ });
182
+ }
183
+ const requestUrl = (() => {
184
+ if (this.baseUrl) {
185
+ return `${this.baseUrl}${path}`;
186
+ }
187
+ if (typeof window !== "undefined") {
188
+ const proto = window.location.protocol;
189
+ if (proto === "http:" || proto === "https:") {
190
+ return new URL(path, window.location.origin).toString();
191
+ }
192
+ }
193
+ return path;
194
+ })();
195
+ const makeRequest = async (token) => {
196
+ const timeoutMs = options?.timeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS;
197
+ const abortController = new AbortController();
198
+ let timeoutId;
199
+ let timedOut = false;
200
+ let abortListener;
201
+ if (init?.signal?.aborted) {
202
+ throw new ApiError({
203
+ kind: "network",
204
+ path,
205
+ message: "Request aborted",
206
+ });
207
+ }
208
+ timeoutId = setTimeout(() => {
209
+ timedOut = true;
210
+ abortController.abort();
211
+ }, timeoutMs);
212
+ if (init?.signal) {
213
+ abortListener = () => {
214
+ abortController.abort();
215
+ };
216
+ init.signal.addEventListener("abort", abortListener, { once: true });
217
+ }
218
+ const requestInit = {
219
+ ...init,
220
+ signal: abortController.signal,
221
+ headers: {
222
+ "X-ElizaOS-Client-Id": this.clientId,
223
+ ...(token ? { Authorization: `Bearer ${token}` } : {}),
224
+ ...(this._uiLanguage
225
+ ? { "X-ElizaOS-UI-Language": this._uiLanguage }
226
+ : {}),
227
+ ...init?.headers,
228
+ },
229
+ };
230
+ try {
231
+ return await fetch(requestUrl, requestInit);
232
+ }
233
+ catch (err) {
234
+ if (timedOut) {
235
+ throw new ApiError({
236
+ kind: "timeout",
237
+ path,
238
+ message: `Request timed out after ${timeoutMs}ms`,
239
+ });
240
+ }
241
+ if (abortController.signal.aborted) {
242
+ throw new ApiError({
243
+ kind: "network",
244
+ path,
245
+ message: "Request aborted",
246
+ cause: err,
247
+ });
248
+ }
249
+ if (err instanceof ApiError) {
250
+ throw err;
251
+ }
252
+ throw new ApiError({
253
+ kind: "network",
254
+ path,
255
+ message: err instanceof Error && err.message
256
+ ? err.message
257
+ : "Network request failed",
258
+ cause: err,
259
+ });
260
+ }
261
+ finally {
262
+ if (timeoutId !== undefined) {
263
+ clearTimeout(timeoutId);
264
+ }
265
+ if (init?.signal && abortListener) {
266
+ init.signal.removeEventListener("abort", abortListener);
267
+ }
268
+ }
269
+ };
270
+ const token = this.apiToken;
271
+ let res = await makeRequest(token);
272
+ if (res.status === 401 && !token) {
273
+ const retryToken = this.apiToken;
274
+ if (retryToken) {
275
+ res = await makeRequest(retryToken);
276
+ }
277
+ }
278
+ if (!res.ok && !options?.allowNonOk) {
279
+ const body = (await res
280
+ .json()
281
+ .catch(() => ({ error: res.statusText })));
282
+ throw new ApiError({
283
+ kind: "http",
284
+ path,
285
+ status: res.status,
286
+ message: body?.error ?? `HTTP ${res.status}`,
287
+ });
288
+ }
289
+ return res;
290
+ }
291
+ async fetch(path, init, options) {
292
+ const res = await this.rawRequest(path, {
293
+ ...init,
294
+ headers: {
295
+ "Content-Type": "application/json",
296
+ ...init?.headers,
297
+ },
298
+ }, options);
299
+ if (res.status === 204) {
300
+ return undefined;
301
+ }
302
+ const text = await res.text();
303
+ if (text === "") {
304
+ return undefined;
305
+ }
306
+ try {
307
+ return JSON.parse(text);
308
+ }
309
+ catch (err) {
310
+ throw new ApiError({
311
+ kind: "parse",
312
+ path,
313
+ status: res.status,
314
+ message: err instanceof Error
315
+ ? `Invalid JSON response: ${err.message}`
316
+ : "Invalid JSON response",
317
+ cause: err,
318
+ });
319
+ }
320
+ }
321
+ // --- WebSocket ---
322
+ connectWs() {
323
+ if (this.ws?.readyState === WebSocket.OPEN ||
324
+ this.ws?.readyState === WebSocket.CONNECTING) {
325
+ return;
326
+ }
327
+ let host;
328
+ let wsProtocol;
329
+ if (this.baseUrl) {
330
+ const parsed = new URL(this.baseUrl);
331
+ host = parsed.host;
332
+ wsProtocol = parsed.protocol === "https:" ? "wss:" : "ws:";
333
+ }
334
+ else {
335
+ // In non-HTTP environments (electrobun://, file://, etc.)
336
+ // window.location.host may be empty or a non-routable placeholder like "-".
337
+ const loc = window.location;
338
+ if (loc.protocol !== "http:" && loc.protocol !== "https:")
339
+ return;
340
+ host = loc.host;
341
+ wsProtocol = loc.protocol === "https:" ? "wss:" : "ws:";
342
+ }
343
+ if (!host)
344
+ return;
345
+ // On Capacitor native (iosScheme/androidScheme = "https"), the origin host
346
+ // is a dummy bundle host (e.g. "localhost" with no server behind it).
347
+ // Skip WS if we have no explicit baseUrl and the host doesn't look like a
348
+ // real backend (no port, not an IP, not a known API domain).
349
+ if (!this.baseUrl && typeof host === "string") {
350
+ const hasPort = host.includes(":");
351
+ const isLoopback = host.startsWith("127.") || host.startsWith("localhost:");
352
+ if (!hasPort && !isLoopback)
353
+ return;
354
+ }
355
+ let url = `${wsProtocol}//${host}/ws`;
356
+ const params = new URLSearchParams({ clientId: this.clientId });
357
+ url += `?${params.toString()}`;
358
+ this.ws = new WebSocket(url);
359
+ this.ws.onopen = () => {
360
+ const token = this.apiToken;
361
+ if (token && this.ws?.readyState === WebSocket.OPEN) {
362
+ this.ws.send(JSON.stringify({ type: "auth", token }));
363
+ }
364
+ this.backoffMs = 500;
365
+ // Reset connection state on successful connection
366
+ this.reconnectAttempt = 0;
367
+ this.disconnectedAt = null;
368
+ this.connectionState = "connected";
369
+ this.emitConnectionStateChange();
370
+ // Notify listeners when the WS reconnects (not on the first connect)
371
+ // so they can re-hydrate state that may have been lost during the gap.
372
+ if (this.wsHasConnectedOnce) {
373
+ const handlers = this.wsHandlers.get("ws-reconnected");
374
+ if (handlers) {
375
+ for (const handler of handlers) {
376
+ handler({ type: "ws-reconnected" });
377
+ }
378
+ }
379
+ }
380
+ this.wsHasConnectedOnce = true;
381
+ if (this.wsSendQueue.length > 0 &&
382
+ this.ws?.readyState === WebSocket.OPEN) {
383
+ const pending = this.wsSendQueue;
384
+ this.wsSendQueue = [];
385
+ for (let i = 0; i < pending.length; i++) {
386
+ if (this.ws?.readyState !== WebSocket.OPEN) {
387
+ this.wsSendQueue = pending.slice(i).concat(this.wsSendQueue);
388
+ break;
389
+ }
390
+ try {
391
+ this.ws.send(pending[i]);
392
+ }
393
+ catch {
394
+ this.wsSendQueue = pending.slice(i).concat(this.wsSendQueue);
395
+ break;
396
+ }
397
+ }
398
+ }
399
+ };
400
+ this.ws.onmessage = (event) => {
401
+ try {
402
+ const data = JSON.parse(event.data);
403
+ const type = data.type;
404
+ const handlers = this.wsHandlers.get(type);
405
+ if (handlers) {
406
+ for (const handler of handlers) {
407
+ handler(data);
408
+ }
409
+ }
410
+ // Also fire "all" handlers
411
+ const allHandlers = this.wsHandlers.get("*");
412
+ if (allHandlers) {
413
+ for (const handler of allHandlers) {
414
+ handler(data);
415
+ }
416
+ }
417
+ }
418
+ catch {
419
+ // ignore parse errors
420
+ }
421
+ };
422
+ this.ws.onclose = () => {
423
+ this.ws = null;
424
+ // Track disconnection time if not already set
425
+ if (this.disconnectedAt === null) {
426
+ this.disconnectedAt = Date.now();
427
+ }
428
+ this.reconnectAttempt++;
429
+ // Update state based on attempt count
430
+ if (this.reconnectAttempt >= this.maxReconnectAttempts) {
431
+ this.connectionState = "failed";
432
+ }
433
+ else {
434
+ this.connectionState = "reconnecting";
435
+ }
436
+ this.emitConnectionStateChange();
437
+ this.scheduleReconnect();
438
+ };
439
+ this.ws.onerror = () => {
440
+ // close handler will fire
441
+ };
442
+ }
443
+ scheduleReconnect() {
444
+ if (this.reconnectTimer)
445
+ return;
446
+ // After the short backoff window is exhausted, keep probing at a
447
+ // low frequency so the UI can recover without a full page refresh.
448
+ if (this.reconnectAttempt >= this.maxReconnectAttempts) {
449
+ this.reconnectTimer = setTimeout(() => {
450
+ this.reconnectTimer = null;
451
+ this.connectWs();
452
+ }, 30_000);
453
+ return;
454
+ }
455
+ this.reconnectTimer = setTimeout(() => {
456
+ this.reconnectTimer = null;
457
+ this.connectWs();
458
+ }, this.backoffMs);
459
+ this.backoffMs = Math.min(this.backoffMs * 1.5, 10000);
460
+ }
461
+ emitConnectionStateChange() {
462
+ const state = this.getConnectionState();
463
+ for (const listener of this.connectionStateListeners) {
464
+ try {
465
+ listener(state);
466
+ }
467
+ catch {
468
+ // ignore listener errors
469
+ }
470
+ }
471
+ }
472
+ /** Get the current WebSocket connection state. */
473
+ getConnectionState() {
474
+ return {
475
+ state: this.connectionState,
476
+ reconnectAttempt: this.reconnectAttempt,
477
+ maxReconnectAttempts: this.maxReconnectAttempts,
478
+ disconnectedAt: this.disconnectedAt,
479
+ };
480
+ }
481
+ /** Subscribe to connection state changes. Returns an unsubscribe function. */
482
+ onConnectionStateChange(listener) {
483
+ this.connectionStateListeners.add(listener);
484
+ return () => {
485
+ this.connectionStateListeners.delete(listener);
486
+ };
487
+ }
488
+ /** Reset connection state and restart reconnection attempts. */
489
+ resetConnection() {
490
+ this.reconnectAttempt = 0;
491
+ this.disconnectedAt = null;
492
+ this.connectionState = "disconnected";
493
+ if (this.reconnectTimer) {
494
+ clearTimeout(this.reconnectTimer);
495
+ this.reconnectTimer = null;
496
+ }
497
+ this.backoffMs = 500;
498
+ this.emitConnectionStateChange();
499
+ this.connectWs();
500
+ }
501
+ /** Send an arbitrary JSON message over the WebSocket connection. */
502
+ sendWsMessage(data) {
503
+ const payload = JSON.stringify(data);
504
+ if (this.ws?.readyState === WebSocket.OPEN) {
505
+ this.ws.send(payload);
506
+ return;
507
+ }
508
+ // Keep only the newest active-conversation update while disconnected.
509
+ if (data.type === "active-conversation") {
510
+ this.wsSendQueue = this.wsSendQueue.filter((queued) => {
511
+ try {
512
+ const parsed = JSON.parse(queued);
513
+ return parsed.type !== "active-conversation";
514
+ }
515
+ catch {
516
+ return true;
517
+ }
518
+ });
519
+ }
520
+ if (this.wsSendQueue.length >= this.wsSendQueueLimit) {
521
+ const droppedType = typeof data.type === "string" ? data.type : "unknown";
522
+ console.warn("[ws] send queue full - dropping:", droppedType);
523
+ this.wsSendQueue.shift();
524
+ }
525
+ this.wsSendQueue.push(payload);
526
+ if (!this.ws || this.ws.readyState === WebSocket.CLOSED) {
527
+ this.connectWs();
528
+ }
529
+ }
530
+ onWsEvent(type, handler) {
531
+ if (!this.wsHandlers.has(type)) {
532
+ this.wsHandlers.set(type, new Set());
533
+ }
534
+ this.wsHandlers.get(type)?.add(handler);
535
+ return () => {
536
+ this.wsHandlers.get(type)?.delete(handler);
537
+ };
538
+ }
539
+ disconnectWs() {
540
+ if (this.reconnectTimer) {
541
+ clearTimeout(this.reconnectTimer);
542
+ this.reconnectTimer = null;
543
+ }
544
+ this.ws?.close();
545
+ this.ws = null;
546
+ this.wsSendQueue = [];
547
+ // Reset connection state on intentional disconnect
548
+ this.reconnectAttempt = 0;
549
+ this.disconnectedAt = null;
550
+ this.connectionState = "disconnected";
551
+ this.emitConnectionStateChange();
552
+ }
553
+ // --- Text normalization helpers (used by chat domain methods) ---
554
+ normalizeAssistantText(text) {
555
+ const stripped = stripAssistantStageDirections(text);
556
+ const trimmed = stripped.trim();
557
+ if (trimmed.length === 0) {
558
+ if (text.trim().length === 0 ||
559
+ /^\(?no response\)?$/i.test(text.trim())) {
560
+ return GENERIC_NO_RESPONSE_TEXT;
561
+ }
562
+ return "";
563
+ }
564
+ if (/^\(?no response\)?$/i.test(trimmed)) {
565
+ return GENERIC_NO_RESPONSE_TEXT;
566
+ }
567
+ return trimmed;
568
+ }
569
+ normalizeGreetingText(text) {
570
+ const stripped = stripAssistantStageDirections(text);
571
+ const trimmed = stripped.trim();
572
+ if (trimmed.length === 0 || /^\(?no response\)?$/i.test(trimmed)) {
573
+ return "";
574
+ }
575
+ return trimmed;
576
+ }
577
+ // --- Streaming chat endpoint (used by chat domain methods) ---
578
+ async streamChatEndpoint(path, text, onToken, channelType = "DM", signal, images, conversationMode, metadata) {
579
+ const res = await this.rawRequest(path, {
580
+ method: "POST",
581
+ headers: {
582
+ "Content-Type": "application/json",
583
+ Accept: "text/event-stream",
584
+ },
585
+ body: JSON.stringify({
586
+ text,
587
+ channelType,
588
+ ...(images?.length ? { images } : {}),
589
+ ...(conversationMode ? { conversationMode } : {}),
590
+ ...(metadata ? { metadata } : {}),
591
+ }),
592
+ signal,
593
+ });
594
+ if (!res.body) {
595
+ throw new Error("Streaming not supported by this browser");
596
+ }
597
+ const decoder = new TextDecoder();
598
+ const reader = res.body.getReader();
599
+ let buffer = "";
600
+ let fullText = "";
601
+ let doneText = null;
602
+ let doneAgentName = null;
603
+ let doneNoResponseReason = null;
604
+ let doneUsage;
605
+ let receivedDone = false;
606
+ const findSseEventBreak = (chunkBuffer) => {
607
+ const lfBreak = chunkBuffer.indexOf("\n\n");
608
+ const crlfBreak = chunkBuffer.indexOf("\r\n\r\n");
609
+ if (lfBreak === -1 && crlfBreak === -1)
610
+ return null;
611
+ if (lfBreak === -1)
612
+ return { index: crlfBreak, length: 4 };
613
+ if (crlfBreak === -1)
614
+ return { index: lfBreak, length: 2 };
615
+ return lfBreak < crlfBreak
616
+ ? { index: lfBreak, length: 2 }
617
+ : { index: crlfBreak, length: 4 };
618
+ };
619
+ const parseDataLine = (line) => {
620
+ const payload = line.startsWith("data:") ? line.slice(5).trim() : "";
621
+ if (!payload)
622
+ return;
623
+ let parsed;
624
+ try {
625
+ parsed = JSON.parse(payload);
626
+ }
627
+ catch {
628
+ return;
629
+ }
630
+ if (!parsed.type && typeof parsed.text === "string") {
631
+ parsed.type = "token";
632
+ }
633
+ if (parsed.type === "token") {
634
+ const chunk = parsed.text ?? "";
635
+ const nextFullText = typeof parsed.fullText === "string"
636
+ ? parsed.fullText
637
+ : chunk
638
+ ? mergeStreamingText(fullText, chunk)
639
+ : fullText;
640
+ if (nextFullText === fullText)
641
+ return;
642
+ fullText = nextFullText;
643
+ onToken(chunk, fullText);
644
+ return;
645
+ }
646
+ if (parsed.type === "done") {
647
+ receivedDone = true;
648
+ if (typeof parsed.fullText === "string")
649
+ doneText = parsed.fullText;
650
+ if (typeof parsed.agentName === "string" && parsed.agentName.trim()) {
651
+ doneAgentName = parsed.agentName;
652
+ }
653
+ if (parsed.noResponseReason === "ignored") {
654
+ doneNoResponseReason = "ignored";
655
+ }
656
+ if (parsed.usage) {
657
+ doneUsage = {
658
+ promptTokens: parsed.usage.promptTokens ?? 0,
659
+ completionTokens: parsed.usage.completionTokens ?? 0,
660
+ totalTokens: parsed.usage.totalTokens ?? 0,
661
+ model: parsed.usage.model,
662
+ };
663
+ }
664
+ // Terminal event: stop reading immediately instead of waiting for the
665
+ // server to close the body (some stacks leave the stream open briefly).
666
+ void reader.cancel("elizaos-sse-terminal-done").catch(() => { });
667
+ return;
668
+ }
669
+ if (parsed.type === "error") {
670
+ throw new Error(parsed.message ?? "generation failed");
671
+ }
672
+ };
673
+ // Contract: the API must emit `data: {"type":"done",...}` or
674
+ // `data: {"type":"error",...}` and then end the response. If the server
675
+ // stalls mid-stream (e.g. LLM provider timeout without error propagation),
676
+ // the idle timeout below aborts the read so the UI doesn't hang forever.
677
+ const SSE_IDLE_TIMEOUT_MS = 60_000;
678
+ while (true) {
679
+ let done = false;
680
+ let value;
681
+ try {
682
+ const readPromise = reader.read();
683
+ const timeoutPromise = new Promise((_, reject) => {
684
+ const id = setTimeout(() => reject(new Error("SSE idle timeout — no data for 60s")), SSE_IDLE_TIMEOUT_MS);
685
+ // Clear timeout if the read resolves first
686
+ void readPromise.finally(() => clearTimeout(id));
687
+ });
688
+ ({ done, value } = await Promise.race([readPromise, timeoutPromise]));
689
+ }
690
+ catch (streamErr) {
691
+ console.warn("[api-client] SSE stream interrupted:", streamErr);
692
+ void reader.cancel("elizaos-sse-idle-timeout").catch(() => { });
693
+ break;
694
+ }
695
+ if (done || !value)
696
+ break;
697
+ buffer += decoder.decode(value, { stream: true });
698
+ let eventBreak = findSseEventBreak(buffer);
699
+ while (eventBreak) {
700
+ const rawEvent = buffer.slice(0, eventBreak.index);
701
+ buffer = buffer.slice(eventBreak.index + eventBreak.length);
702
+ for (const line of rawEvent.split(/\r?\n/)) {
703
+ if (!line.startsWith("data:"))
704
+ continue;
705
+ parseDataLine(line);
706
+ }
707
+ eventBreak = findSseEventBreak(buffer);
708
+ }
709
+ }
710
+ if (buffer.trim()) {
711
+ for (const line of buffer.split(/\r?\n/)) {
712
+ if (line.startsWith("data:"))
713
+ parseDataLine(line);
714
+ }
715
+ }
716
+ const resolvedText = doneNoResponseReason === "ignored"
717
+ ? ""
718
+ : this.normalizeAssistantText(doneText ?? fullText);
719
+ return {
720
+ text: resolvedText,
721
+ agentName: doneAgentName ?? "Eliza",
722
+ completed: receivedDone,
723
+ ...(doneNoResponseReason
724
+ ? { noResponseReason: doneNoResponseReason }
725
+ : {}),
726
+ ...(doneUsage ? { usage: doneUsage } : {}),
727
+ };
728
+ }
729
+ }