@elizaos/plugin-elizacloud 2.0.0-beta.1 → 2.0.3-beta.3

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 (338) hide show
  1. package/README.md +20 -44
  2. package/auto-enable.ts +10 -5
  3. package/dist/browser/index.browser.js +2 -2
  4. package/dist/browser/index.browser.js.map +4 -4
  5. package/dist/cjs/index.node.cjs +2918 -5924
  6. package/dist/cjs/index.node.js.map +47 -116
  7. package/dist/cloud/auth-service-types.d.ts +8 -0
  8. package/dist/cloud/auth-service-types.d.ts.map +1 -0
  9. package/dist/cloud/auth-service-types.js +36 -0
  10. package/dist/cloud/auth-service-types.js.map +10 -0
  11. package/dist/cloud/auth.js +4 -51
  12. package/dist/cloud/auth.js.map +4 -4
  13. package/dist/cloud/backup.js +1 -1
  14. package/dist/cloud/backup.js.map +1 -1
  15. package/dist/cloud/base-url.d.ts +6 -2
  16. package/dist/cloud/base-url.d.ts.map +1 -1
  17. package/dist/cloud/base-url.js +3 -51
  18. package/dist/cloud/base-url.js.map +3 -3
  19. package/dist/cloud/bridge-client.d.ts +3 -3
  20. package/dist/cloud/bridge-client.d.ts.map +1 -1
  21. package/dist/cloud/bridge-client.js +3 -51
  22. package/dist/cloud/bridge-client.js.map +3 -3
  23. package/dist/cloud/clack-observer.d.ts +35 -0
  24. package/dist/cloud/clack-observer.d.ts.map +1 -0
  25. package/dist/cloud/clack-observer.js +143 -0
  26. package/dist/cloud/clack-observer.js.map +10 -0
  27. package/dist/cloud/cloud-api-key.js +1 -1
  28. package/dist/cloud/cloud-api-key.js.map +1 -1
  29. package/dist/cloud/cloud-manager.js +45 -92
  30. package/dist/cloud/cloud-manager.js.map +6 -6
  31. package/dist/cloud/cloud-proxy.js +1 -1
  32. package/dist/cloud/cloud-proxy.js.map +1 -1
  33. package/dist/cloud/cloud-wallet.js +2 -4835
  34. package/dist/cloud/cloud-wallet.js.map +3 -82
  35. package/dist/cloud/duffel-client.d.ts +181 -0
  36. package/dist/cloud/duffel-client.d.ts.map +1 -0
  37. package/dist/cloud/duffel-client.js +506 -0
  38. package/dist/cloud/duffel-client.js.map +11 -0
  39. package/dist/cloud/index.d.ts +6 -0
  40. package/dist/cloud/index.d.ts.map +1 -1
  41. package/dist/cloud/index.js +1782 -1
  42. package/dist/cloud/index.js.map +18 -3
  43. package/dist/cloud/lifeops-schedule-sync-client.d.ts +43 -0
  44. package/dist/cloud/lifeops-schedule-sync-client.d.ts.map +1 -0
  45. package/dist/cloud/lifeops-schedule-sync-client.js +180 -0
  46. package/dist/cloud/lifeops-schedule-sync-client.js.map +11 -0
  47. package/dist/cloud/lifeops-schedule-sync-contracts.d.ts +89 -0
  48. package/dist/cloud/lifeops-schedule-sync-contracts.d.ts.map +1 -0
  49. package/dist/cloud/lifeops-schedule-sync-contracts.js +39 -0
  50. package/dist/cloud/lifeops-schedule-sync-contracts.js.map +10 -0
  51. package/dist/cloud/managed-payment-clients.d.ts +166 -0
  52. package/dist/cloud/managed-payment-clients.d.ts.map +1 -0
  53. package/dist/cloud/managed-payment-clients.js +238 -0
  54. package/dist/cloud/managed-payment-clients.js.map +11 -0
  55. package/dist/cloud/null-observer.d.ts +35 -0
  56. package/dist/cloud/null-observer.d.ts.map +1 -0
  57. package/dist/cloud/null-observer.js +45 -0
  58. package/dist/cloud/null-observer.js.map +10 -0
  59. package/dist/cloud/reconnect.js +1 -1
  60. package/dist/cloud/reconnect.js.map +1 -1
  61. package/dist/cloud/setup-observer.d.ts +98 -0
  62. package/dist/cloud/setup-observer.d.ts.map +1 -0
  63. package/dist/cloud/setup-observer.js +2 -0
  64. package/dist/cloud/setup-observer.js.map +9 -0
  65. package/dist/cloud/validate-url.d.ts.map +1 -1
  66. package/dist/cloud/validate-url.js +2 -1
  67. package/dist/cloud/validate-url.js.map +3 -3
  68. package/dist/cloud/x402-payment-handler.d.ts +85 -0
  69. package/dist/cloud/x402-payment-handler.d.ts.map +1 -0
  70. package/dist/cloud/x402-payment-handler.js +119 -0
  71. package/dist/cloud/x402-payment-handler.js.map +10 -0
  72. package/dist/cloud-providers/cloud-status.js +1 -1
  73. package/dist/cloud-providers/cloud-status.js.map +1 -1
  74. package/dist/cloud-providers/container-health.js +1 -1
  75. package/dist/cloud-providers/container-health.js.map +1 -1
  76. package/dist/cloud-providers/credit-balance.js +1 -1
  77. package/dist/cloud-providers/credit-balance.js.map +1 -1
  78. package/dist/cloud-providers/index.js +1 -1
  79. package/dist/cloud-providers/index.js.map +1 -1
  80. package/dist/cloud-providers/model-registry.js +1 -1
  81. package/dist/cloud-providers/model-registry.js.map +1 -1
  82. package/dist/cloud-setup.d.ts +36 -0
  83. package/dist/cloud-setup.d.ts.map +1 -0
  84. package/dist/{onboarding.js → cloud-setup.js} +139 -139
  85. package/dist/cloud-setup.js.map +14 -0
  86. package/dist/cloud-voice-catalog.d.ts +65 -0
  87. package/dist/cloud-voice-catalog.d.ts.map +1 -0
  88. package/dist/cloud-voice-catalog.js +278 -0
  89. package/dist/cloud-voice-catalog.js.map +12 -0
  90. package/dist/index.browser.d.ts +11 -0
  91. package/dist/index.browser.d.ts.map +1 -1
  92. package/dist/index.d.ts +7 -1
  93. package/dist/index.d.ts.map +1 -1
  94. package/dist/index.js +5458 -8412
  95. package/dist/index.js.map +48 -116
  96. package/dist/index.node.d.ts +8 -1
  97. package/dist/index.node.d.ts.map +1 -1
  98. package/dist/init.js +17 -4
  99. package/dist/init.js.map +4 -4
  100. package/dist/lib/cloud-connection.d.ts +0 -1
  101. package/dist/lib/cloud-connection.d.ts.map +1 -1
  102. package/dist/lib/cloud-connection.js +14 -91
  103. package/dist/lib/cloud-connection.js.map +7 -7
  104. package/dist/lib/cloud-secrets.d.ts +5 -18
  105. package/dist/lib/cloud-secrets.d.ts.map +1 -1
  106. package/dist/lib/cloud-secrets.js +8 -36
  107. package/dist/lib/cloud-secrets.js.map +3 -3
  108. package/dist/lib/config-env.js +1 -1
  109. package/dist/lib/config-env.js.map +1 -1
  110. package/dist/lib/config-like.d.ts +1 -1
  111. package/dist/lib/config-like.d.ts.map +1 -1
  112. package/dist/lib/config-like.js +3 -3
  113. package/dist/lib/config-like.js.map +3 -3
  114. package/dist/lib/credential-type-map.d.ts +1 -1
  115. package/dist/lib/credential-type-map.js +1 -1
  116. package/dist/lib/credential-type-map.js.map +2 -2
  117. package/dist/lib/feature-flags.js +1 -1
  118. package/dist/lib/feature-flags.js.map +1 -1
  119. package/dist/lib/http.d.ts +0 -11
  120. package/dist/lib/http.d.ts.map +1 -1
  121. package/dist/lib/http.js +1 -1
  122. package/dist/lib/http.js.map +3 -3
  123. package/dist/lib/server-cloud-tts.d.ts +12 -25
  124. package/dist/lib/server-cloud-tts.d.ts.map +1 -1
  125. package/dist/lib/server-cloud-tts.js +31 -329
  126. package/dist/lib/server-cloud-tts.js.map +4 -7
  127. package/dist/lib/state-paths.js +1 -1
  128. package/dist/lib/state-paths.js.map +1 -1
  129. package/dist/lib/tts-debug.d.ts +5 -3
  130. package/dist/lib/tts-debug.d.ts.map +1 -1
  131. package/dist/lib/tts-debug.js +1 -34
  132. package/dist/lib/tts-debug.js.map +3 -4
  133. package/dist/models/embeddings.d.ts +7 -0
  134. package/dist/models/embeddings.d.ts.map +1 -1
  135. package/dist/models/embeddings.js +98 -73
  136. package/dist/models/embeddings.js.map +6 -6
  137. package/dist/models/image.d.ts.map +1 -1
  138. package/dist/models/image.js +42 -15
  139. package/dist/models/image.js.map +6 -6
  140. package/dist/models/index.js +719 -175
  141. package/dist/models/index.js.map +11 -12
  142. package/dist/models/research.d.ts.map +1 -1
  143. package/dist/models/research.js +24 -7
  144. package/dist/models/research.js.map +6 -6
  145. package/dist/models/speech.d.ts +61 -3
  146. package/dist/models/speech.d.ts.map +1 -1
  147. package/dist/models/speech.js +173 -17
  148. package/dist/models/speech.js.map +5 -5
  149. package/dist/models/text.d.ts +114 -1
  150. package/dist/models/text.d.ts.map +1 -1
  151. package/dist/models/text.js +481 -88
  152. package/dist/models/text.js.map +7 -8
  153. package/dist/models/tokenization.d.ts.map +1 -1
  154. package/dist/models/tokenization.js +1 -1
  155. package/dist/models/tokenization.js.map +3 -3
  156. package/dist/models/transcription.d.ts.map +1 -1
  157. package/dist/models/transcription.js +20 -6
  158. package/dist/models/transcription.js.map +5 -5
  159. package/dist/node/index.node.js +2872 -5847
  160. package/dist/node/index.node.js.map +47 -116
  161. package/dist/plugin.d.ts.map +1 -1
  162. package/dist/plugin.js +376 -5050
  163. package/dist/plugin.js.map +16 -92
  164. package/dist/providers/openai.js +11 -2
  165. package/dist/providers/openai.js.map +3 -3
  166. package/dist/register-routes.js +376 -5050
  167. package/dist/register-routes.js.map +16 -92
  168. package/dist/routes/cloud-billing-routes.d.ts.map +1 -1
  169. package/dist/routes/cloud-billing-routes.js +17 -60
  170. package/dist/routes/cloud-billing-routes.js.map +8 -7
  171. package/dist/routes/cloud-coding-container-routes.d.ts +8 -0
  172. package/dist/routes/cloud-coding-container-routes.d.ts.map +1 -0
  173. package/dist/routes/cloud-coding-container-routes.js +214 -0
  174. package/dist/routes/cloud-coding-container-routes.js.map +11 -0
  175. package/dist/routes/cloud-compat-routes.d.ts.map +1 -1
  176. package/dist/routes/cloud-compat-routes.js +17 -60
  177. package/dist/routes/cloud-compat-routes.js.map +8 -7
  178. package/dist/routes/cloud-features-routes.js +2 -2
  179. package/dist/routes/cloud-features-routes.js.map +4 -4
  180. package/dist/routes/cloud-provisioning.js +1 -1
  181. package/dist/routes/cloud-provisioning.js.map +1 -1
  182. package/dist/routes/cloud-relay-routes.d.ts +2 -1
  183. package/dist/routes/cloud-relay-routes.d.ts.map +1 -1
  184. package/dist/routes/cloud-relay-routes.js +84 -2
  185. package/dist/routes/cloud-relay-routes.js.map +5 -4
  186. package/dist/routes/cloud-routes-autonomous.d.ts +3 -4
  187. package/dist/routes/cloud-routes-autonomous.d.ts.map +1 -1
  188. package/dist/routes/cloud-routes-autonomous.js +11 -4893
  189. package/dist/routes/cloud-routes-autonomous.js.map +8 -87
  190. package/dist/routes/cloud-routes.d.ts +2 -2
  191. package/dist/routes/cloud-routes.d.ts.map +1 -1
  192. package/dist/routes/cloud-routes.js +343 -5058
  193. package/dist/routes/cloud-routes.js.map +13 -90
  194. package/dist/routes/cloud-status-routes-autonomous.d.ts +1 -2
  195. package/dist/routes/cloud-status-routes-autonomous.d.ts.map +1 -1
  196. package/dist/routes/cloud-status-routes-autonomous.js +4 -51
  197. package/dist/routes/cloud-status-routes-autonomous.js.map +5 -5
  198. package/dist/routes/cloud-status-routes.js +14 -90
  199. package/dist/routes/cloud-status-routes.js.map +7 -7
  200. package/dist/routes/home-remote-runner-access-url.d.ts +16 -0
  201. package/dist/routes/home-remote-runner-access-url.d.ts.map +1 -0
  202. package/dist/routes/home-remote-runner-access-url.js +91 -0
  203. package/dist/routes/home-remote-runner-access-url.js.map +10 -0
  204. package/dist/routes/travel-provider-relay-routes.d.ts +9 -0
  205. package/dist/routes/travel-provider-relay-routes.d.ts.map +1 -0
  206. package/dist/routes/travel-provider-relay-routes.js +358 -0
  207. package/dist/routes/travel-provider-relay-routes.js.map +14 -0
  208. package/dist/services/cloud-auth.d.ts +1 -1
  209. package/dist/services/cloud-auth.d.ts.map +1 -1
  210. package/dist/services/cloud-auth.js +7 -2
  211. package/dist/services/cloud-auth.js.map +4 -4
  212. package/dist/services/cloud-backup.js +1 -1
  213. package/dist/services/cloud-backup.js.map +3 -3
  214. package/dist/services/cloud-bootstrap.d.ts.map +1 -1
  215. package/dist/services/cloud-bootstrap.js +1 -1
  216. package/dist/services/cloud-bootstrap.js.map +3 -3
  217. package/dist/services/cloud-bridge.js +1 -1
  218. package/dist/services/cloud-bridge.js.map +4 -4
  219. package/dist/services/cloud-container.d.ts +5 -1
  220. package/dist/services/cloud-container.d.ts.map +1 -1
  221. package/dist/services/cloud-container.js +52 -1
  222. package/dist/services/cloud-container.js.map +4 -4
  223. package/dist/services/cloud-credential-provider.js +1 -1
  224. package/dist/services/cloud-credential-provider.js.map +3 -3
  225. package/dist/services/cloud-managed-gateway-relay.js +1 -1
  226. package/dist/services/cloud-managed-gateway-relay.js.map +1 -1
  227. package/dist/services/cloud-model-registry.js +1 -1
  228. package/dist/services/cloud-model-registry.js.map +3 -3
  229. package/dist/services/index.js +1 -1
  230. package/dist/services/index.js.map +1 -1
  231. package/dist/types/cloud.d.ts +1 -0
  232. package/dist/types/cloud.d.ts.map +1 -1
  233. package/dist/types/cloud.js +1 -1
  234. package/dist/types/cloud.js.map +3 -3
  235. package/dist/types/index.d.ts +1 -1
  236. package/dist/types/index.d.ts.map +1 -1
  237. package/dist/types/index.js +1 -1
  238. package/dist/types/index.js.map +1 -1
  239. package/dist/utils/cloud-api.js +1 -1
  240. package/dist/utils/cloud-api.js.map +1 -1
  241. package/dist/utils/cloud-sdk/client.d.ts.map +1 -1
  242. package/dist/utils/cloud-sdk/client.js +136 -4
  243. package/dist/utils/cloud-sdk/client.js.map +5 -5
  244. package/dist/utils/cloud-sdk/http.js +1 -1
  245. package/dist/utils/cloud-sdk/http.js.map +2 -2
  246. package/dist/utils/cloud-sdk/index.js +1 -1
  247. package/dist/utils/cloud-sdk/index.js.map +1 -1
  248. package/dist/utils/cloud-sdk/public-routes.d.ts +186 -0
  249. package/dist/utils/cloud-sdk/public-routes.d.ts.map +1 -1
  250. package/dist/utils/cloud-sdk/public-routes.js +99 -1
  251. package/dist/utils/cloud-sdk/public-routes.js.map +3 -3
  252. package/dist/utils/cloud-sdk/types.d.ts +0 -2
  253. package/dist/utils/cloud-sdk/types.d.ts.map +1 -1
  254. package/dist/utils/cloud-sdk/types.js +1 -1
  255. package/dist/utils/cloud-sdk/types.js.map +2 -2
  256. package/dist/utils/config.d.ts +10 -1
  257. package/dist/utils/config.d.ts.map +1 -1
  258. package/dist/utils/config.js +12 -2
  259. package/dist/utils/config.js.map +3 -3
  260. package/dist/utils/events.d.ts +23 -2
  261. package/dist/utils/events.d.ts.map +1 -1
  262. package/dist/utils/events.js +5 -3
  263. package/dist/utils/events.js.map +3 -3
  264. package/dist/utils/helpers.js +1 -1
  265. package/dist/utils/helpers.js.map +1 -1
  266. package/dist/utils/responses-output.js +1 -1
  267. package/dist/utils/responses-output.js.map +1 -1
  268. package/dist/utils/sdk-client.d.ts.map +1 -1
  269. package/dist/utils/sdk-client.js +17 -4
  270. package/dist/utils/sdk-client.js.map +4 -4
  271. package/dist/utils/waifu-metering.d.ts +108 -0
  272. package/dist/utils/waifu-metering.d.ts.map +1 -0
  273. package/dist/utils/waifu-metering.js +166 -0
  274. package/dist/utils/waifu-metering.js.map +10 -0
  275. package/package.json +52 -22
  276. package/registry-entry.json +208 -0
  277. package/src/cloud/auth-service-types.ts +24 -0
  278. package/src/cloud/base-url.ts +6 -62
  279. package/src/cloud/clack-observer.ts +189 -0
  280. package/src/cloud/duffel-client.ts +847 -0
  281. package/src/cloud/index.ts +10 -0
  282. package/src/cloud/lifeops-schedule-sync-client.ts +245 -0
  283. package/src/cloud/lifeops-schedule-sync-contracts.ts +124 -0
  284. package/src/cloud/managed-payment-clients.ts +374 -0
  285. package/src/cloud/null-observer.ts +45 -0
  286. package/src/cloud/setup-observer.ts +125 -0
  287. package/src/cloud/validate-url.ts +7 -1
  288. package/src/cloud/x402-payment-handler.ts +215 -0
  289. package/src/cloud-setup.ts +531 -0
  290. package/src/cloud-voice-catalog.test.ts +254 -0
  291. package/src/cloud-voice-catalog.ts +246 -0
  292. package/src/index.browser.ts +29 -0
  293. package/src/index.node.ts +31 -1
  294. package/src/index.ts +81 -4
  295. package/src/lib/cloud-connection.ts +2 -4
  296. package/src/lib/cloud-secrets.ts +10 -54
  297. package/src/lib/config-like.ts +1 -1
  298. package/src/lib/credential-type-map.ts +2 -2
  299. package/src/lib/http.ts +0 -17
  300. package/src/lib/server-cloud-tts.ts +33 -341
  301. package/src/lib/tts-debug.ts +5 -34
  302. package/src/models/embeddings.ts +187 -78
  303. package/src/models/image.ts +29 -14
  304. package/src/models/research.ts +11 -1
  305. package/src/models/speech.ts +269 -23
  306. package/src/models/text.ts +756 -114
  307. package/src/models/tokenization.ts +2 -2
  308. package/src/models/transcription.ts +7 -3
  309. package/src/plugin.ts +38 -0
  310. package/src/routes/cloud-billing-routes.ts +4 -14
  311. package/src/routes/cloud-coding-container-routes.ts +198 -0
  312. package/src/routes/cloud-compat-routes.ts +4 -14
  313. package/src/routes/cloud-features-routes.ts +1 -1
  314. package/src/routes/cloud-relay-routes.ts +47 -1
  315. package/src/routes/cloud-routes-autonomous.ts +7 -10
  316. package/src/routes/cloud-routes.ts +68 -7
  317. package/src/routes/cloud-status-routes-autonomous.ts +6 -2
  318. package/src/routes/home-remote-runner-access-url.ts +83 -0
  319. package/src/routes/travel-provider-relay-routes.ts +193 -0
  320. package/src/services/cloud-auth.ts +9 -2
  321. package/src/services/cloud-bootstrap.ts +1 -3
  322. package/src/services/cloud-bridge.ts +1 -1
  323. package/src/services/cloud-container.ts +93 -0
  324. package/src/services/cloud-credential-provider.ts +1 -1
  325. package/src/services/cloud-model-registry.ts +1 -1
  326. package/src/types/cloud.ts +22 -0
  327. package/src/types/index.ts +19 -0
  328. package/src/utils/cloud-sdk/client.ts +42 -3
  329. package/src/utils/cloud-sdk/public-routes.ts +168 -0
  330. package/src/utils/cloud-sdk/types.ts +0 -2
  331. package/src/utils/config.ts +20 -1
  332. package/src/utils/events.ts +30 -2
  333. package/src/utils/sdk-client.ts +5 -1
  334. package/src/utils/waifu-metering.ts +302 -0
  335. package/dist/onboarding.d.ts +0 -35
  336. package/dist/onboarding.d.ts.map +0 -1
  337. package/dist/onboarding.js.map +0 -14
  338. package/src/onboarding.ts +0 -396
@@ -19,7 +19,7 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
19
  // src/utils/config.ts
20
20
  import { logger } from "@elizaos/core";
21
21
  import { DEFAULT_ELIZA_CLOUD_TEXT_MODEL } from "@elizaos/core";
22
- var DEFAULT_ELIZA_CLOUD_LARGE_MODEL = "deepseek/deepseek-v4-pro";
22
+ var DEFAULT_ELIZA_CLOUD_LARGE_MODEL = "zai-glm-4.7";
23
23
  function getEnvValue(key) {
24
24
  if (typeof process === "undefined") {
25
25
  return;
@@ -109,9 +109,18 @@ function getExperimentalTelemetry(runtime) {
109
109
  const setting = getSetting(runtime, "ELIZAOS_CLOUD_EXPERIMENTAL_TELEMETRY", "false");
110
110
  return String(setting).toLowerCase() === "true";
111
111
  }
112
+ function resolveCloudTimeoutMs(envKey, defaultMs) {
113
+ const raw = typeof process !== "undefined" ? process.env[envKey] : undefined;
114
+ if (raw === undefined || raw.trim() === "")
115
+ return defaultMs;
116
+ const parsed = Number.parseInt(raw, 10);
117
+ if (!Number.isFinite(parsed))
118
+ return defaultMs;
119
+ return parsed <= 0 ? undefined : parsed;
120
+ }
112
121
 
113
122
  // src/utils/sdk-client.ts
114
- import { CloudApiClient, ElizaCloudClient } from "@elizaos/cloud-sdk";
123
+ import { ElizaCloudClient } from "@elizaos/cloud-sdk";
115
124
  function trimTrailingSlash(value) {
116
125
  return value.replace(/\/+$/, "");
117
126
  }
@@ -126,7 +135,11 @@ function apiKeyForRuntime(runtime, embedding = false) {
126
135
  }
127
136
  function createCloudApiClient(runtime, embedding = false) {
128
137
  const baseUrl = embedding ? getEmbeddingBaseURL(runtime) : getBaseURL(runtime);
129
- return new CloudApiClient(trimTrailingSlash(baseUrl), apiKeyForRuntime(runtime, embedding));
138
+ return new ElizaCloudClient({
139
+ apiBaseUrl: trimTrailingSlash(baseUrl),
140
+ baseUrl: apiBaseToSiteBaseUrl(baseUrl),
141
+ apiKey: apiKeyForRuntime(runtime, embedding)
142
+ }).v1;
130
143
  }
131
144
  function createElizaCloudClient(runtime) {
132
145
  const apiBaseUrl = trimTrailingSlash(getBaseURL(runtime));
@@ -141,7 +154,7 @@ function createElizaCloudClient(runtime) {
141
154
  import {
142
155
  EventType
143
156
  } from "@elizaos/core";
144
- function emitModelUsageEvent(runtime, type, _prompt, usage) {
157
+ function emitModelUsageEvent(runtime, type, _prompt, usage, meta = {}) {
145
158
  const inputTokens = Number(usage.inputTokens || 0);
146
159
  const outputTokens = Number(usage.outputTokens || 0);
147
160
  const totalTokens = Number(usage.totalTokens != null ? usage.totalTokens : inputTokens + outputTokens);
@@ -153,14 +166,34 @@ function emitModelUsageEvent(runtime, type, _prompt, usage) {
153
166
  prompt: inputTokens,
154
167
  completion: outputTokens,
155
168
  total: totalTokens
156
- }
169
+ },
170
+ ...meta.modelName ? { modelName: meta.modelName } : {},
171
+ ...typeof meta.costUsd === "number" && Number.isFinite(meta.costUsd) ? { costUsd: meta.costUsd } : {}
157
172
  };
158
173
  runtime.emitEvent(EventType.MODEL_USED, payload);
159
174
  }
160
175
 
161
176
  // src/models/embeddings.ts
162
- import { logger as logger2, ModelType, VECTOR_DIMS } from "@elizaos/core";
177
+ import {
178
+ logger as logger2,
179
+ ModelType,
180
+ timeInferenceSpan,
181
+ VECTOR_DIMS
182
+ } from "@elizaos/core";
163
183
  var MAX_BATCH_SIZE = 100;
184
+ var EMBED_MAX_ATTEMPTS = 2;
185
+ var EMBED_BACKOFF_BASE_MS = 1000;
186
+ var EMBED_BACKOFF_CAP_MS = 8000;
187
+ var EMBED_REQUEST_TIMEOUT_MS = 60000;
188
+ function embeddingBackoffMs(attempt, retryAfterSec) {
189
+ const exp = EMBED_BACKOFF_BASE_MS * 2 ** attempt;
190
+ const serverHint = typeof retryAfterSec === "number" && retryAfterSec > 0 ? retryAfterSec * 1000 : 0;
191
+ const base = Math.min(EMBED_BACKOFF_CAP_MS, Math.max(exp, serverHint));
192
+ return Math.round(base * (1 + Math.random() * 0.25));
193
+ }
194
+ function sleep(ms) {
195
+ return new Promise((resolve) => setTimeout(resolve, ms));
196
+ }
164
197
  function extractRateLimitInfo(response) {
165
198
  return {
166
199
  remainingRequests: parseInt(response.headers.get("x-ratelimit-remaining-requests") || "", 10) || undefined,
@@ -182,16 +215,16 @@ function getEmbeddingConfig(runtime) {
182
215
  }
183
216
  return { embeddingModelName, embeddingDimension };
184
217
  }
185
- function createErrorVector(dimension, marker) {
218
+ function createInitProbeVector(dimension) {
186
219
  const vector = Array(dimension).fill(0);
187
- vector[0] = marker;
220
+ vector[0] = 0.1;
188
221
  return vector;
189
222
  }
190
223
  async function handleTextEmbedding(runtime, params) {
191
224
  const { embeddingDimension } = getEmbeddingConfig(runtime);
192
225
  if (params === null) {
193
226
  logger2.debug("Creating test embedding for initialization");
194
- return createErrorVector(embeddingDimension, 0.1);
227
+ return createInitProbeVector(embeddingDimension);
195
228
  }
196
229
  let text;
197
230
  if (typeof params === "string") {
@@ -199,12 +232,10 @@ async function handleTextEmbedding(runtime, params) {
199
232
  } else if (typeof params === "object" && params.text) {
200
233
  text = params.text;
201
234
  } else {
202
- logger2.warn("Invalid input format for embedding");
203
- return createErrorVector(embeddingDimension, 0.2);
235
+ throw new Error("Invalid input format for embedding: expected string or { text: string }");
204
236
  }
205
237
  if (!text.trim()) {
206
- logger2.warn("Empty text for embedding");
207
- return createErrorVector(embeddingDimension, 0.3);
238
+ throw new Error("Cannot generate embedding for empty text");
208
239
  }
209
240
  const results = await handleBatchTextEmbedding(runtime, [text]);
210
241
  return results[0];
@@ -213,84 +244,78 @@ async function handleBatchTextEmbedding(runtime, texts) {
213
244
  const { embeddingModelName, embeddingDimension } = getEmbeddingConfig(runtime);
214
245
  const client = createCloudApiClient(runtime, true);
215
246
  if (!texts || texts.length === 0) {
216
- logger2.warn("[BatchEmbeddings] Empty texts array");
217
247
  return [];
218
248
  }
219
249
  const validTexts = [];
220
- const results = new Array(texts.length);
221
250
  for (let i = 0;i < texts.length; i++) {
222
251
  const text = texts[i]?.trim();
223
- if (text) {
224
- validTexts.push({ text, originalIndex: i });
225
- } else {
226
- results[i] = createErrorVector(embeddingDimension, 0.3);
252
+ if (!text) {
253
+ throw new Error(`Cannot generate embedding for empty text at index ${i}`);
227
254
  }
255
+ validTexts.push({ text, originalIndex: i });
228
256
  }
229
- if (validTexts.length === 0) {
230
- logger2.warn("[BatchEmbeddings] All texts were empty");
231
- return results;
232
- }
257
+ const results = new Array(texts.length);
233
258
  for (let batchStart = 0;batchStart < validTexts.length; batchStart += MAX_BATCH_SIZE) {
234
259
  const batchEnd = Math.min(batchStart + MAX_BATCH_SIZE, validTexts.length);
235
260
  const batch = validTexts.slice(batchStart, batchEnd);
236
261
  const batchTexts = batch.map((b) => b.text);
237
262
  logger2.info(`[BatchEmbeddings] Processing batch ${Math.floor(batchStart / MAX_BATCH_SIZE) + 1}/${Math.ceil(validTexts.length / MAX_BATCH_SIZE)}: ${batch.length} texts`);
238
263
  try {
239
- const response = await client.requestRaw("POST", "/embeddings", {
240
- json: {
241
- model: embeddingModelName,
242
- input: batchTexts
243
- }
244
- });
245
- const rateLimitInfo = extractRateLimitInfo(response);
246
- if (rateLimitInfo.remainingRequests !== undefined && rateLimitInfo.remainingRequests < 50) {
247
- logger2.warn(`[BatchEmbeddings] Rate limit: ${rateLimitInfo.remainingRequests}/${rateLimitInfo.limitRequests} requests remaining`);
248
- }
249
- if (response.status === 429) {
250
- const retryAfter = rateLimitInfo.retryAfter || 30;
251
- logger2.warn(`[BatchEmbeddings] Rate limited, waiting ${retryAfter}s...`);
252
- await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000));
253
- const retryResponse = await client.requestRaw("POST", "/embeddings", {
264
+ let response = null;
265
+ for (let attempt = 0;attempt < EMBED_MAX_ATTEMPTS; attempt++) {
266
+ const resp = await timeInferenceSpan("cloud.embedding", () => client.requestRaw("POST", "/embeddings", {
254
267
  json: {
255
268
  model: embeddingModelName,
256
- input: batchTexts
257
- }
258
- });
259
- if (!retryResponse.ok) {
260
- logger2.error(`[BatchEmbeddings] Retry failed: ${retryResponse.status}`);
261
- for (const item of batch) {
262
- results[item.originalIndex] = createErrorVector(embeddingDimension, 0.4);
263
- }
264
- continue;
269
+ input: batchTexts,
270
+ dimensions: embeddingDimension
271
+ },
272
+ timeoutMs: EMBED_REQUEST_TIMEOUT_MS
273
+ }), { batch: batchTexts.length, attempt });
274
+ const rateLimitInfo = extractRateLimitInfo(resp);
275
+ if (rateLimitInfo.remainingRequests !== undefined && rateLimitInfo.remainingRequests < 50) {
276
+ logger2.warn(`[BatchEmbeddings] Rate limit: ${rateLimitInfo.remainingRequests}/${rateLimitInfo.limitRequests} requests remaining`);
265
277
  }
266
- const retryData = await retryResponse.json();
267
- if (retryData?.data) {
268
- for (const item of retryData.data) {
269
- const originalIndex = batch[item.index].originalIndex;
270
- results[originalIndex] = item.embedding;
271
- }
272
- logger2.info(`[BatchEmbeddings] Retry successful for ${batch.length} embeddings`);
278
+ const transient = resp.status === 429 || resp.status === 502 || resp.status === 503 || resp.status === 504;
279
+ if (transient && attempt < EMBED_MAX_ATTEMPTS - 1) {
280
+ const delay = embeddingBackoffMs(attempt, rateLimitInfo.retryAfter);
281
+ logger2.warn(`[BatchEmbeddings] ${resp.status} (attempt ${attempt + 1}/${EMBED_MAX_ATTEMPTS}) — backing off ${delay}ms`);
282
+ await resp.text().catch(() => {
283
+ return;
284
+ });
285
+ await sleep(delay);
286
+ continue;
273
287
  }
274
- continue;
288
+ response = resp;
289
+ break;
290
+ }
291
+ if (!response) {
292
+ throw new Error("[BatchEmbeddings] No response after retry loop");
275
293
  }
276
294
  if (!response.ok) {
277
- logger2.error(`[BatchEmbeddings] API error: ${response.status} - ${response.statusText}`);
278
- for (const item of batch) {
279
- results[item.originalIndex] = createErrorVector(embeddingDimension, 0.4);
295
+ if (response.status === 401 || response.status === 403) {
296
+ throw new Error(`[BatchEmbeddings] Authentication failed (${response.status}). ` + `Check ELIZAOS_CLOUD_API_KEY or ELIZAOS_CLOUD_EMBEDDING_API_KEY — ` + `the current key is not authorized for the embedding endpoint.`);
280
297
  }
281
- continue;
298
+ if (response.status === 429) {
299
+ throw new Error(`[BatchEmbeddings] Rate-limit retry exhausted: API error: ${response.status} ${response.statusText}`);
300
+ }
301
+ throw new Error(`[BatchEmbeddings] API error: ${response.status} ${response.statusText}`);
282
302
  }
283
303
  const data = await response.json();
284
304
  if (!data?.data || !Array.isArray(data.data)) {
285
- logger2.error("[BatchEmbeddings] API returned invalid structure");
286
- for (const item of batch) {
287
- results[item.originalIndex] = createErrorVector(embeddingDimension, 0.5);
288
- }
289
- continue;
305
+ throw new Error("[BatchEmbeddings] API returned invalid response structure");
306
+ }
307
+ if (data.data.length !== batch.length) {
308
+ throw new Error(`[BatchEmbeddings] expected ${batch.length} embeddings, got ${data.data.length}`);
290
309
  }
291
310
  for (const item of data.data) {
292
- const originalIndex = batch[item.index].originalIndex;
293
- results[originalIndex] = item.embedding;
311
+ const slot = typeof item.index === "number" ? batch[item.index] : undefined;
312
+ if (!slot) {
313
+ throw new Error(`[BatchEmbeddings] response index out of range: ${String(item.index)} (batch size ${batch.length})`);
314
+ }
315
+ if (!Array.isArray(item.embedding) || item.embedding.length !== embeddingDimension) {
316
+ throw new Error(`[BatchEmbeddings] dimension mismatch: model returned ${Array.isArray(item.embedding) ? item.embedding.length : "non-array"}d but agent is configured for ${embeddingDimension}d`);
317
+ }
318
+ results[slot.originalIndex] = item.embedding;
294
319
  }
295
320
  if (data.usage) {
296
321
  const usage = {
@@ -300,13 +325,11 @@ async function handleBatchTextEmbedding(runtime, texts) {
300
325
  };
301
326
  emitModelUsageEvent(runtime, ModelType.TEXT_EMBEDDING, `batch:${batch.length}`, usage);
302
327
  }
303
- logger2.debug(`[BatchEmbeddings] Got ${batch.length} embeddings (${embeddingDimension}d), remaining: ${rateLimitInfo.remainingRequests ?? "unknown"}`);
328
+ logger2.debug(`[BatchEmbeddings] Got ${batch.length} embeddings (${embeddingDimension}d)`);
304
329
  } catch (error) {
305
330
  const message = error instanceof Error ? error.message : String(error);
306
- logger2.error(`[BatchEmbeddings] Error: ${message}`);
307
- for (const item of batch) {
308
- results[item.originalIndex] = createErrorVector(embeddingDimension, 0.6);
309
- }
331
+ logger2.error(`[BatchEmbeddings] Batch failed: ${message}`);
332
+ throw error instanceof Error ? error : new Error(message);
310
333
  }
311
334
  }
312
335
  return results;
@@ -424,7 +447,10 @@ async function handleImageGeneration(runtime, params) {
424
447
  }
425
448
  async function handleImageDescription(runtime, params) {
426
449
  const disableSetting = getSetting(runtime, "DISABLE_IMAGE_DESCRIPTION", "");
427
- const disabled = disableSetting === "true" || disableSetting === "1" || process.env.DISABLE_IMAGE_DESCRIPTION === "true" || process.env.DISABLE_IMAGE_DESCRIPTION === "1";
450
+ const disabled = [disableSetting, process.env.DISABLE_IMAGE_DESCRIPTION].some((value) => {
451
+ const normalized = value?.trim().toLowerCase();
452
+ return normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on";
453
+ });
428
454
  if (disabled) {
429
455
  logger4.debug("[ELIZAOS_CLOUD] IMAGE_DESCRIPTION skipped — DISABLE_IMAGE_DESCRIPTION is set");
430
456
  return {
@@ -463,16 +489,21 @@ async function handleImageDescription(runtime, params) {
463
489
  let response = null;
464
490
  let attemptedRetry = false;
465
491
  for (let attempt = 0;attempt < 2; attempt++) {
466
- response = await client.routes.postApiV1ChatCompletionsRaw({
467
- json: requestBody
492
+ const attemptResponse = await client.routes.postApiV1ChatCompletionsRaw({
493
+ json: requestBody,
494
+ timeoutMs: resolveCloudTimeoutMs("ELIZAOS_CLOUD_IMAGE_TIMEOUT_MS", 120000)
468
495
  });
469
- if (response.status !== 429 || attemptedRetry)
496
+ if (!attemptResponse) {
497
+ continue;
498
+ }
499
+ response = attemptResponse;
500
+ if (attemptResponse.status !== 429 || attemptedRetry)
470
501
  break;
471
- const headerValue = response.headers.get("retry-after");
502
+ const headerValue = attemptResponse.headers.get("retry-after");
472
503
  const headerRetryAfter = headerValue !== null && Number.isFinite(Number(headerValue)) ? Number(headerValue) : undefined;
473
504
  let bodyRetryAfter;
474
505
  try {
475
- const peek = await response.clone().json();
506
+ const peek = await attemptResponse.clone().json();
476
507
  bodyRetryAfter = typeof peek?.retryAfter === "number" && Number.isFinite(peek.retryAfter) ? peek.retryAfter : undefined;
477
508
  } catch {}
478
509
  const retryAfter = headerRetryAfter ?? bodyRetryAfter ?? 0;
@@ -485,8 +516,12 @@ async function handleImageDescription(runtime, params) {
485
516
  logger4.warn(`[ELIZAOS_CLOUD] Image analysis rate-limited (429); upstream retryAfter=${retryAfter || "unknown"}s — failing fast`);
486
517
  break;
487
518
  }
488
- if (!response?.ok) {
489
- const status = response?.status ?? 0;
519
+ if (!response) {
520
+ throw new Error("ElizaOS Cloud API did not return a response");
521
+ }
522
+ const finalResponse = response;
523
+ if (!finalResponse.ok) {
524
+ const status = finalResponse.status;
490
525
  if (status === 402) {
491
526
  throw new Error("Eliza Cloud credits exhausted — top up at https://www.elizacloud.ai/dashboard/settings?tab=billing");
492
527
  }
@@ -495,7 +530,7 @@ async function handleImageDescription(runtime, params) {
495
530
  }
496
531
  throw new Error(`ElizaOS Cloud API error: ${status}`);
497
532
  }
498
- const typedResult = await response.json();
533
+ const typedResult = await finalResponse.json();
499
534
  const content = typedResult.choices?.[0]?.message?.content;
500
535
  if (typedResult.usage) {
501
536
  emitModelUsageEvent(runtime, ModelType2.IMAGE_DESCRIPTION, typeof params === "string" ? params : params.prompt || "", {
@@ -523,6 +558,7 @@ async function handleImageDescription(runtime, params) {
523
558
 
524
559
  // src/models/research.ts
525
560
  import { logger as logger5, ModelType as ModelType3 } from "@elizaos/core";
561
+ var DEFAULT_RESEARCH_TIMEOUT_MS = 600000;
526
562
  function normalizeInput(input) {
527
563
  if (typeof input !== "string") {
528
564
  return input;
@@ -645,7 +681,8 @@ async function handleResearch(runtime, params) {
645
681
  requestBody.reasoning = { summary: params.reasoningSummary };
646
682
  }
647
683
  const response = await createCloudApiClient(runtime).requestRaw("POST", "/responses", {
648
- json: requestBody
684
+ json: requestBody,
685
+ timeoutMs: resolveCloudTimeoutMs("ELIZAOS_CLOUD_RESEARCH_TIMEOUT_MS", DEFAULT_RESEARCH_TIMEOUT_MS)
649
686
  });
650
687
  if (!response.ok) {
651
688
  const errorText = await response.text();
@@ -682,17 +719,59 @@ async function handleResearch(runtime, params) {
682
719
  }
683
720
 
684
721
  // src/models/speech.ts
685
- import { logger as logger6 } from "@elizaos/core";
722
+ import { isCloudConnected, logger as logger6, toRuntimeSettings } from "@elizaos/core";
723
+ var cloudTtsClientFactory = (runtime) => createElizaCloudClient(runtime);
724
+ function setCloudTtsClientFactoryForTesting(factory) {
725
+ if (factory === null) {
726
+ cloudTtsClientFactory = (runtime) => createElizaCloudClient(runtime);
727
+ } else {
728
+ cloudTtsClientFactory = factory;
729
+ }
730
+ }
731
+
732
+ class CloudTtsUnavailableError extends Error {
733
+ constructor(message = "Eliza Cloud is not connected") {
734
+ super(message);
735
+ this.name = "CloudTtsUnavailableError";
736
+ }
737
+ }
738
+ function normalizeTextInput(input) {
739
+ if (typeof input === "string")
740
+ return { text: input };
741
+ return input;
742
+ }
743
+ function resolveModelId(options) {
744
+ if (options.modelId && options.modelId.trim()) {
745
+ return options.modelId.trim();
746
+ }
747
+ const model = options.model?.trim();
748
+ if (!model)
749
+ return;
750
+ if (model.startsWith("elevenlabs/")) {
751
+ return model.split("/").slice(1).join("/");
752
+ }
753
+ if (model.startsWith("eleven_")) {
754
+ return model;
755
+ }
756
+ return;
757
+ }
758
+ function resolveVoiceId(options) {
759
+ if (options.voiceId && options.voiceId.trim()) {
760
+ return options.voiceId.trim();
761
+ }
762
+ const voice = options.voice?.trim();
763
+ if (!voice)
764
+ return;
765
+ if (voice === "nova")
766
+ return;
767
+ return voice;
768
+ }
686
769
  async function fetchTextToSpeech(runtime, options) {
687
- const defaultModel = getSetting(runtime, "ELIZAOS_CLOUD_TTS_MODEL", "gpt-5-mini-tts");
688
- const defaultVoice = getSetting(runtime, "ELIZAOS_CLOUD_TTS_VOICE", "nova");
689
- const model = options.model || defaultModel;
690
- const voice = options.voice || defaultVoice;
691
770
  const format = options.format || "mp3";
692
- const modelId = model.startsWith("elevenlabs/") ? model.split("/").slice(1).join("/") : model.startsWith("eleven_") ? model : undefined;
693
- const voiceId = voice && voice !== "nova" ? voice : undefined;
771
+ const modelId = resolveModelId(options);
772
+ const voiceId = resolveVoiceId(options);
694
773
  try {
695
- const res = await createElizaCloudClient(runtime).routes.postApiV1VoiceTts({
774
+ const res = await cloudTtsClientFactory(runtime).routes.postApiV1VoiceTts({
696
775
  headers: {
697
776
  ...format === "mp3" ? { Accept: "audio/mpeg" } : {}
698
777
  },
@@ -700,7 +779,8 @@ async function fetchTextToSpeech(runtime, options) {
700
779
  text: options.text,
701
780
  ...voiceId ? { voiceId } : {},
702
781
  ...modelId ? { modelId } : {}
703
- }
782
+ },
783
+ timeoutMs: resolveCloudTimeoutMs("ELIZAOS_CLOUD_TTS_TIMEOUT_MS", 60000)
704
784
  });
705
785
  if (!res.ok) {
706
786
  const err = await res.text();
@@ -718,30 +798,117 @@ async function fetchTextToSpeech(runtime, options) {
718
798
  throw new Error(`Failed to fetch speech from ElizaOS Cloud TTS: ${message}`);
719
799
  }
720
800
  }
801
+ function toUint8Array(chunk) {
802
+ if (chunk instanceof Uint8Array)
803
+ return chunk;
804
+ if (chunk instanceof ArrayBuffer)
805
+ return new Uint8Array(chunk);
806
+ if (typeof chunk === "string")
807
+ return new TextEncoder().encode(chunk);
808
+ throw new TypeError(`Unexpected TTS chunk type: ${typeof chunk}`);
809
+ }
810
+ function concatChunks(chunks) {
811
+ const total = chunks.reduce((sum, chunk) => sum + chunk.byteLength, 0);
812
+ const out = new Uint8Array(total);
813
+ let offset = 0;
814
+ for (const chunk of chunks) {
815
+ out.set(chunk, offset);
816
+ offset += chunk.byteLength;
817
+ }
818
+ return out;
819
+ }
820
+ async function webStreamToUint8Array(stream) {
821
+ const reader = stream.getReader();
822
+ const chunks = [];
823
+ try {
824
+ while (true) {
825
+ const result = await reader.read();
826
+ if (result.done)
827
+ break;
828
+ chunks.push(toUint8Array(result.value));
829
+ }
830
+ } finally {
831
+ reader.releaseLock();
832
+ }
833
+ return concatChunks(chunks);
834
+ }
835
+ async function nodeStreamToUint8Array(stream) {
836
+ const chunks = [];
837
+ for await (const chunk of stream) {
838
+ chunks.push(toUint8Array(chunk));
839
+ }
840
+ return concatChunks(chunks);
841
+ }
842
+ function isReadableStream(stream) {
843
+ return typeof stream.getReader === "function";
844
+ }
845
+ async function ttsStreamToBytes(stream) {
846
+ if (isReadableStream(stream)) {
847
+ return webStreamToUint8Array(stream);
848
+ }
849
+ return nodeStreamToUint8Array(stream);
850
+ }
851
+ function buildAudioStreamResult(stream, mimeType) {
852
+ const collected = [];
853
+ let resolveBytes;
854
+ let rejectBytes;
855
+ const bytes = new Promise((resolve, reject) => {
856
+ resolveBytes = resolve;
857
+ rejectBytes = reject;
858
+ });
859
+ async function* generate() {
860
+ try {
861
+ if (isReadableStream(stream)) {
862
+ const reader = stream.getReader();
863
+ try {
864
+ for (;; ) {
865
+ const { value, done } = await reader.read();
866
+ if (done)
867
+ break;
868
+ const chunk = toUint8Array(value);
869
+ collected.push(chunk);
870
+ yield chunk;
871
+ }
872
+ } finally {
873
+ reader.releaseLock();
874
+ }
875
+ } else {
876
+ for await (const value of stream) {
877
+ const chunk = toUint8Array(value);
878
+ collected.push(chunk);
879
+ yield chunk;
880
+ }
881
+ }
882
+ resolveBytes(concatChunks(collected));
883
+ } catch (err) {
884
+ rejectBytes(err);
885
+ throw err;
886
+ }
887
+ }
888
+ return { audioStream: generate(), bytes, mimeType };
889
+ }
721
890
  async function handleTextToSpeech(runtime, input) {
722
- const options = typeof input === "string" ? { text: input } : input;
723
- const resolvedModel = options.model || getSetting(runtime, "ELIZAOS_CLOUD_TTS_MODEL", "gpt-5-mini-tts");
891
+ if (!isCloudConnected(toRuntimeSettings(runtime))) {
892
+ throw new CloudTtsUnavailableError("Eliza Cloud is not connected — falling through to next TTS handler");
893
+ }
894
+ const options = normalizeTextInput(input);
895
+ const wantsStream = typeof input === "object" && input !== null && input.audioStream === true;
896
+ const resolvedModel = options.modelId || options.model || getSetting(runtime, "ELIZAOS_CLOUD_TTS_MODEL", "eleven_flash_v2_5");
724
897
  logger6.log(`[ELIZAOS_CLOUD] Using TEXT_TO_SPEECH model: ${resolvedModel}`);
725
898
  try {
726
899
  const speechStream = await fetchTextToSpeech(runtime, options);
727
- return speechStream;
900
+ if (wantsStream) {
901
+ const format = options.format || "mp3";
902
+ const mimeType = format === "mp3" ? "audio/mpeg" : `audio/${format}`;
903
+ return buildAudioStreamResult(speechStream, mimeType);
904
+ }
905
+ return ttsStreamToBytes(speechStream);
728
906
  } catch (error) {
729
907
  const message = error instanceof Error ? error.message : String(error);
730
908
  logger6.error(`Error in TEXT_TO_SPEECH: ${message}`);
731
909
  throw error;
732
910
  }
733
911
  }
734
- // src/providers/openai.ts
735
- import { createOpenAI } from "@ai-sdk/openai";
736
- function createOpenAIClient(runtime) {
737
- const baseURL = getBaseURL(runtime);
738
- const apiKey = getApiKey(runtime) ?? (isProxyMode(runtime) ? "eliza-proxy" : undefined);
739
- return createOpenAI({
740
- apiKey: apiKey ?? "",
741
- baseURL
742
- });
743
- }
744
-
745
912
  // src/utils/responses-output.ts
746
913
  function asRecord(value) {
747
914
  if (!value || typeof value !== "object" || Array.isArray(value)) {
@@ -827,8 +994,11 @@ import {
827
994
  buildCanonicalSystemPrompt,
828
995
  logger as logger7,
829
996
  ModelType as ModelType4,
997
+ recordInferenceSpan,
830
998
  renderChatMessagesForPrompt,
831
- resolveEffectiveSystemPrompt
999
+ resolveEffectiveSystemPrompt,
1000
+ Semaphore,
1001
+ timeInferenceSpan as timeInferenceSpan2
832
1002
  } from "@elizaos/core";
833
1003
  var TEXT_NANO_MODEL_TYPE = ModelType4.TEXT_NANO ?? "TEXT_NANO";
834
1004
  var TEXT_MEDIUM_MODEL_TYPE = ModelType4.TEXT_MEDIUM ?? "TEXT_MEDIUM";
@@ -837,6 +1007,61 @@ var TEXT_LARGE_MODEL_TYPE = ModelType4.TEXT_LARGE;
837
1007
  var TEXT_MEGA_MODEL_TYPE = ModelType4.TEXT_MEGA ?? "TEXT_MEGA";
838
1008
  var RESPONSE_HANDLER_MODEL_TYPE = ModelType4.RESPONSE_HANDLER ?? "RESPONSE_HANDLER";
839
1009
  var ACTION_PLANNER_MODEL_TYPE = ModelType4.ACTION_PLANNER ?? "ACTION_PLANNER";
1010
+ var NATIVE_CONCURRENCY_ENV = "ELIZAOS_CLOUD_NATIVE_CONCURRENCY";
1011
+ var DEFAULT_NATIVE_CONCURRENCY = 8;
1012
+ var TEXT_TIMEOUT_ENV = "ELIZAOS_CLOUD_TEXT_TIMEOUT_MS";
1013
+ var DEFAULT_TEXT_TIMEOUT_MS = 120000;
1014
+ function resolveTextTimeoutMs() {
1015
+ const raw = typeof process !== "undefined" ? process.env[TEXT_TIMEOUT_ENV] : undefined;
1016
+ if (raw === undefined || raw.trim() === "")
1017
+ return DEFAULT_TEXT_TIMEOUT_MS;
1018
+ const parsed = Number.parseInt(raw, 10);
1019
+ if (!Number.isFinite(parsed))
1020
+ return DEFAULT_TEXT_TIMEOUT_MS;
1021
+ return parsed <= 0 ? undefined : parsed;
1022
+ }
1023
+ var STREAMING_ENV = "ELIZAOS_CLOUD_STREAMING";
1024
+ function resolveStreamingEnabled() {
1025
+ const raw = typeof process !== "undefined" ? process.env[STREAMING_ENV] : undefined;
1026
+ if (raw === undefined)
1027
+ return true;
1028
+ const v = raw.trim().toLowerCase();
1029
+ return v !== "0" && v !== "false" && v !== "off";
1030
+ }
1031
+ function buildStreamAbortSignal(abortSignal, timeoutMs) {
1032
+ const timeoutSig = typeof timeoutMs === "number" && timeoutMs > 0 ? AbortSignal.timeout(timeoutMs) : undefined;
1033
+ if (abortSignal && timeoutSig)
1034
+ return AbortSignal.any([abortSignal, timeoutSig]);
1035
+ return abortSignal ?? timeoutSig;
1036
+ }
1037
+ var nativeChatLimiter = null;
1038
+ function resolveNativeConcurrency() {
1039
+ const raw = typeof process !== "undefined" ? process.env[NATIVE_CONCURRENCY_ENV] : undefined;
1040
+ const parsed = raw ? Number.parseInt(raw, 10) : Number.NaN;
1041
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_NATIVE_CONCURRENCY;
1042
+ }
1043
+ function getNativeChatLimiter() {
1044
+ if (!nativeChatLimiter) {
1045
+ nativeChatLimiter = new Semaphore(resolveNativeConcurrency());
1046
+ }
1047
+ return nativeChatLimiter;
1048
+ }
1049
+ async function withNativeChatLimit(fn, label = "native") {
1050
+ const limiter = getNativeChatLimiter();
1051
+ const waitStartedAt = Date.now();
1052
+ await limiter.acquire();
1053
+ recordInferenceSpan("cloud.semaphore-wait", Date.now() - waitStartedAt, {
1054
+ route: label
1055
+ });
1056
+ try {
1057
+ return await timeInferenceSpan2(`cloud.http:${label}`, fn, { route: label });
1058
+ } finally {
1059
+ limiter.release();
1060
+ }
1061
+ }
1062
+ function __resetNativeChatLimiterForTests() {
1063
+ nativeChatLimiter = null;
1064
+ }
840
1065
  var REASONING_MODEL_PATTERNS = [
841
1066
  "o1",
842
1067
  "o3",
@@ -847,26 +1072,53 @@ var REASONING_MODEL_PATTERNS = [
847
1072
  "claude-opus-4-7",
848
1073
  "gpt-5"
849
1074
  ];
850
- var RESPONSES_ROUTED_PREFIXES = ["openai/", "anthropic/"];
851
- function buildUserContent(params) {
852
- const content = [{ type: "text", text: params.prompt ?? "" }];
853
- for (const attachment of params.attachments ?? []) {
854
- content.push({
855
- type: "file",
856
- data: attachment.data,
857
- mediaType: attachment.mediaType,
858
- ...attachment.filename ? { filename: attachment.filename } : {}
859
- });
1075
+ var SPAN_SAMPLER_HONORING_MODEL_PREFIXES = [
1076
+ "vast/eliza-1-",
1077
+ "elizaos/eliza-1-",
1078
+ "eliza-1-"
1079
+ ];
1080
+ function isSpanSamplerHonoringModel(modelName) {
1081
+ const lower = modelName.toLowerCase();
1082
+ return SPAN_SAMPLER_HONORING_MODEL_PREFIXES.some((prefix) => lower.startsWith(prefix));
1083
+ }
1084
+ function buildSpanSamplerHeader(plan) {
1085
+ if (!plan || plan.overrides.length === 0)
1086
+ return;
1087
+ const overrides = plan.overrides.map((o) => {
1088
+ const wire = {
1089
+ span_index: o.spanIndex,
1090
+ temperature: o.temperature
1091
+ };
1092
+ if (typeof o.topK === "number")
1093
+ wire.top_k = o.topK;
1094
+ if (typeof o.topP === "number")
1095
+ wire.top_p = o.topP;
1096
+ return wire;
1097
+ });
1098
+ const body = { overrides };
1099
+ if (plan.strict === true)
1100
+ body.strict = true;
1101
+ return JSON.stringify(body);
1102
+ }
1103
+ function extractCostUsd(usage, response) {
1104
+ const fromBody = firstNumber(asRecord2(usage).cost_usd, asRecord2(usage).costUsd, asRecord2(usage).cost);
1105
+ if (typeof fromBody === "number" && Number.isFinite(fromBody)) {
1106
+ return fromBody;
1107
+ }
1108
+ const header = response?.headers?.get?.("X-Eliza-Cost-Usd");
1109
+ if (header) {
1110
+ const parsed = Number(header);
1111
+ if (Number.isFinite(parsed))
1112
+ return parsed;
860
1113
  }
861
- return content;
1114
+ return;
862
1115
  }
863
1116
  function isReasoningModel(modelName) {
864
1117
  const lower = modelName.toLowerCase();
865
1118
  return REASONING_MODEL_PATTERNS.some((pattern) => lower.includes(pattern));
866
1119
  }
867
- function supportsStopSequences(modelName) {
868
- const lower = modelName.toLowerCase();
869
- return !RESPONSES_ROUTED_PREFIXES.some((prefix) => lower.startsWith(prefix));
1120
+ function isCerebrasServedModel(modelName) {
1121
+ return modelName.toLowerCase().includes("gpt-oss");
870
1122
  }
871
1123
  function isRecord(value) {
872
1124
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -944,26 +1196,39 @@ function unwrapJsonSchema(value) {
944
1196
  const record = asRecord2(value);
945
1197
  return record.schema ?? record.jsonSchema ?? value;
946
1198
  }
1199
+ function normalizeNativeToolEntry(rawTool, fallbackName) {
1200
+ const tool = asRecord2(rawTool);
1201
+ const nested = asRecord2(tool.function);
1202
+ const name = firstString(nested.name, tool.name, fallbackName);
1203
+ if (!name) {
1204
+ return;
1205
+ }
1206
+ const description = firstString(nested.description, tool.description);
1207
+ const inputSchema = unwrapJsonSchema(nested.parameters ?? tool.inputSchema ?? tool.parameters ?? tool.schema ?? { type: "object" });
1208
+ return {
1209
+ type: "function",
1210
+ function: {
1211
+ name,
1212
+ ...description ? { description } : {},
1213
+ parameters: inputSchema
1214
+ }
1215
+ };
1216
+ }
947
1217
  function normalizeNativeTools(tools) {
948
1218
  if (!tools) {
949
1219
  return;
950
1220
  }
951
1221
  if (Array.isArray(tools)) {
952
- return tools;
1222
+ const normalized2 = tools.map((tool) => normalizeNativeToolEntry(tool)).filter((tool) => tool !== undefined);
1223
+ return normalized2.length > 0 ? normalized2 : undefined;
953
1224
  }
954
1225
  const toolSet = asRecord2(tools);
955
1226
  const normalized = [];
956
1227
  for (const [name, rawTool] of Object.entries(toolSet)) {
957
- const tool = asRecord2(rawTool);
958
- const inputSchema = unwrapJsonSchema(tool.inputSchema ?? tool.parameters ?? tool.schema ?? { type: "object" });
959
- normalized.push({
960
- type: "function",
961
- function: {
962
- name,
963
- ...typeof tool.description === "string" ? { description: tool.description } : {},
964
- parameters: inputSchema
965
- }
966
- });
1228
+ const entry = normalizeNativeToolEntry(rawTool, name);
1229
+ if (entry) {
1230
+ normalized.push(entry);
1231
+ }
967
1232
  }
968
1233
  return normalized.length > 0 ? normalized : undefined;
969
1234
  }
@@ -976,7 +1241,15 @@ function normalizeNativeToolChoice(toolChoice) {
976
1241
  }
977
1242
  const choice = asRecord2(toolChoice);
978
1243
  if (choice.type === "function") {
979
- return toolChoice;
1244
+ const functionChoice2 = recordAt(choice, "function");
1245
+ const toolName2 = firstString(functionChoice2.name, choice.name, choice.toolName);
1246
+ return toolName2 ? {
1247
+ type: "function",
1248
+ function: {
1249
+ ...functionChoice2,
1250
+ name: toolName2
1251
+ }
1252
+ } : undefined;
980
1253
  }
981
1254
  if (choice.type === "tool") {
982
1255
  const toolName2 = firstString(choice.toolName, choice.name);
@@ -986,10 +1259,13 @@ function normalizeNativeToolChoice(toolChoice) {
986
1259
  const toolName = firstString(choice.toolName, choice.name, functionChoice.name);
987
1260
  return toolName ? { type: "function", function: { name: toolName } } : toolChoice;
988
1261
  }
989
- function buildNativeResponseFormat(responseSchema) {
1262
+ function buildNativeResponseFormat(responseSchema, modelName) {
990
1263
  if (!responseSchema) {
991
1264
  return;
992
1265
  }
1266
+ if (isCerebrasServedModel(modelName)) {
1267
+ return { type: "json_object" };
1268
+ }
993
1269
  const schemaRecord = asRecord2(responseSchema);
994
1270
  if (schemaRecord.responseFormat) {
995
1271
  return schemaRecord.responseFormat;
@@ -1067,15 +1343,20 @@ function buildNativeRequestBody(params, modelName, promptText, systemPrompt) {
1067
1343
  const promptCacheKey = providerOptions ? resolvePromptCacheKey(providerOptions) : undefined;
1068
1344
  const tools = normalizeNativeTools(params.tools);
1069
1345
  const toolChoice = normalizeNativeToolChoice(params.toolChoice);
1070
- const responseFormat = buildNativeResponseFormat(params.responseSchema);
1346
+ const responseFormat = buildNativeResponseFormat(params.responseSchema, modelName);
1071
1347
  const requestBody = {
1072
1348
  model: modelName,
1073
- messages: buildNativeMessages(params, promptText, systemPrompt),
1074
- max_tokens: params.maxTokens ?? 8192
1349
+ messages: buildNativeMessages(params, promptText, systemPrompt)
1075
1350
  };
1351
+ if (!params.omitMaxTokens) {
1352
+ requestBody.max_tokens = params.maxTokens ?? 8192;
1353
+ }
1076
1354
  if (!isReasoningModel(modelName) && typeof params.temperature === "number") {
1077
1355
  requestBody.temperature = params.temperature;
1078
1356
  }
1357
+ if (isCerebrasServedModel(modelName) && recordAt(asRecord2(params.providerOptions), "eliza").thinking === "off") {
1358
+ requestBody.reasoning_effort = "low";
1359
+ }
1079
1360
  if (tools) {
1080
1361
  requestBody.tools = tools;
1081
1362
  }
@@ -1189,16 +1470,8 @@ function getModelNameForType(runtime, modelType) {
1189
1470
  }
1190
1471
  }
1191
1472
  function buildGenerateParams(runtime, modelType, params) {
1192
- const paramsWithAttachments = params;
1193
1473
  const prompt = params.prompt ?? "";
1194
- const maxTokens = params.maxTokens ?? 8192;
1195
- const openai = createOpenAIClient(runtime);
1196
1474
  const modelName = getModelNameForType(runtime, modelType);
1197
- const experimentalTelemetry = getExperimentalTelemetry(runtime);
1198
- const userContent = (paramsWithAttachments.attachments?.length ?? 0) > 0 ? buildUserContent(paramsWithAttachments) : undefined;
1199
- const model = openai.chat(modelName);
1200
- const reasoning = isReasoningModel(modelName);
1201
- const stopSequences = !reasoning && supportsStopSequences(modelName) && Array.isArray(params.stopSequences) && params.stopSequences.length > 0 ? params.stopSequences : undefined;
1202
1475
  const systemPrompt = resolveEffectiveSystemPrompt({
1203
1476
  params,
1204
1477
  fallback: buildCanonicalSystemPrompt({ character: runtime.character })
@@ -1206,28 +1479,24 @@ function buildGenerateParams(runtime, modelType, params) {
1206
1479
  const promptText = renderChatMessagesForPrompt(params.messages, {
1207
1480
  omitDuplicateSystem: systemPrompt
1208
1481
  }) ?? prompt;
1209
- const generateParams = {
1210
- model,
1211
- ...userContent ? { messages: [{ role: "user", content: userContent }] } : { prompt: promptText },
1212
- system: systemPrompt,
1213
- ...stopSequences ? { stopSequences } : {},
1214
- maxOutputTokens: maxTokens,
1215
- experimental_telemetry: {
1216
- isEnabled: experimentalTelemetry
1217
- }
1218
- };
1219
- return { generateParams, modelName, modelType, prompt: promptText, systemPrompt };
1482
+ return { modelName, modelType, prompt: promptText, systemPrompt };
1220
1483
  }
1221
1484
  async function generateTextWithModel(runtime, modelType, params) {
1222
1485
  const { modelName, prompt, systemPrompt } = buildGenerateParams(runtime, modelType, params);
1223
1486
  const paramsWithNative = params;
1224
1487
  logger7.debug(`[ELIZAOS_CLOUD] Generating text with ${modelType} model: ${modelName}`);
1225
- if (params.stream) {
1226
- logger7.debug("[ELIZAOS_CLOUD] Streaming text disabled for responses compatibility; falling back to buffered response.");
1227
- }
1488
+ const paramsStreaming = params;
1489
+ const wantsStream = Boolean(paramsStreaming.stream) && paramsStreaming.streamStructured === true && resolveStreamingEnabled();
1228
1490
  logger7.log(`[ELIZAOS_CLOUD] Using ${modelType} model: ${modelName}`);
1229
1491
  logger7.log(prompt);
1230
1492
  if (hasNativeTransportOptions(paramsWithNative)) {
1493
+ if (wantsStream) {
1494
+ return streamNativeChatCompletion(runtime, modelType, paramsWithNative, {
1495
+ modelName,
1496
+ prompt,
1497
+ systemPrompt
1498
+ });
1499
+ }
1231
1500
  const nativeResult = await generateNativeChatCompletion(runtime, modelType, paramsWithNative, {
1232
1501
  modelName,
1233
1502
  prompt,
@@ -1249,19 +1518,29 @@ async function generateTextWithModel(runtime, modelType, params) {
1249
1518
  });
1250
1519
  const requestBody = {
1251
1520
  model: modelName,
1252
- input,
1253
- max_output_tokens: params.maxTokens ?? 8192
1521
+ input
1254
1522
  };
1523
+ if (!params.omitMaxTokens) {
1524
+ requestBody.max_output_tokens = params.maxTokens ?? 8192;
1525
+ }
1255
1526
  if (!reasoning && typeof params.temperature === "number") {
1256
1527
  requestBody.temperature = params.temperature;
1257
1528
  }
1258
- const response = await createCloudApiClient(runtime).requestRaw("POST", "/responses", {
1259
- headers: {
1260
- "X-Eliza-Llm-Purpose": getPurposeForModelType(modelType),
1261
- "X-Eliza-Model-Type": modelType
1262
- },
1263
- json: requestBody
1264
- });
1529
+ const responsesHeaders = {
1530
+ "X-Eliza-Llm-Purpose": getPurposeForModelType(modelType),
1531
+ "X-Eliza-Model-Type": modelType
1532
+ };
1533
+ if (isSpanSamplerHonoringModel(modelName)) {
1534
+ const samplerHeader = buildSpanSamplerHeader(params.spanSamplerPlan);
1535
+ if (samplerHeader) {
1536
+ responsesHeaders["x-eliza-span-samplers"] = samplerHeader;
1537
+ }
1538
+ }
1539
+ const response = await withNativeChatLimit(() => createCloudApiClient(runtime).requestRaw("POST", "/responses", {
1540
+ headers: responsesHeaders,
1541
+ json: requestBody,
1542
+ timeoutMs: resolveTextTimeoutMs()
1543
+ }), "responses");
1265
1544
  const responseText = await response.text();
1266
1545
  let data = {};
1267
1546
  if (responseText) {
@@ -1286,6 +1565,12 @@ async function generateTextWithModel(runtime, modelType, params) {
1286
1565
  inputTokens: data.usage.input_tokens ?? 0,
1287
1566
  outputTokens: data.usage.output_tokens ?? 0,
1288
1567
  totalTokens: data.usage.total_tokens ?? 0
1568
+ }, {
1569
+ modelName: getModelNameForType(runtime, modelType),
1570
+ ...(() => {
1571
+ const costUsd = extractCostUsd(data.usage, response);
1572
+ return typeof costUsd === "number" ? { costUsd } : {};
1573
+ })()
1289
1574
  });
1290
1575
  }
1291
1576
  const text = extractResponsesOutputText(data);
@@ -1296,13 +1581,21 @@ async function generateTextWithModel(runtime, modelType, params) {
1296
1581
  }
1297
1582
  async function generateNativeChatCompletion(runtime, modelType, params, context) {
1298
1583
  const requestBody = buildNativeRequestBody(params, context.modelName, context.prompt, context.systemPrompt);
1299
- const response = await createCloudApiClient(runtime).requestRaw("POST", "/chat/completions", {
1300
- headers: {
1301
- "X-Eliza-Llm-Purpose": getPurposeForModelType(modelType),
1302
- "X-Eliza-Model-Type": modelType
1303
- },
1304
- json: requestBody
1305
- });
1584
+ const headers = {
1585
+ "X-Eliza-Llm-Purpose": getPurposeForModelType(modelType),
1586
+ "X-Eliza-Model-Type": modelType
1587
+ };
1588
+ if (isSpanSamplerHonoringModel(context.modelName)) {
1589
+ const samplerHeader = buildSpanSamplerHeader(params.spanSamplerPlan);
1590
+ if (samplerHeader) {
1591
+ headers["x-eliza-span-samplers"] = samplerHeader;
1592
+ }
1593
+ }
1594
+ const response = await withNativeChatLimit(() => createCloudApiClient(runtime).requestRaw("POST", "/chat/completions", {
1595
+ headers,
1596
+ json: requestBody,
1597
+ timeoutMs: resolveTextTimeoutMs()
1598
+ }), "chat/completions");
1306
1599
  const responseText = await response.text();
1307
1600
  let data = {};
1308
1601
  if (responseText) {
@@ -1324,7 +1617,13 @@ async function generateNativeChatCompletion(runtime, modelType, params, context)
1324
1617
  }
1325
1618
  const usage = convertNativeUsage(data.usage);
1326
1619
  if (usage) {
1327
- emitModelUsageEvent(runtime, modelType, context.prompt, usage);
1620
+ emitModelUsageEvent(runtime, modelType, context.prompt, usage, {
1621
+ modelName: context.modelName,
1622
+ ...(() => {
1623
+ const costUsd = extractCostUsd(data.usage, response);
1624
+ return typeof costUsd === "number" ? { costUsd } : {};
1625
+ })()
1626
+ });
1328
1627
  }
1329
1628
  const text = extractChatCompletionText(data);
1330
1629
  const toolCalls = extractNativeToolCalls(data);
@@ -1342,6 +1641,251 @@ async function generateNativeChatCompletion(runtime, modelType, params, context)
1342
1641
  }
1343
1642
  };
1344
1643
  }
1644
+ function deferred() {
1645
+ let resolve;
1646
+ const promise = new Promise((r) => {
1647
+ resolve = r;
1648
+ });
1649
+ return { promise, resolve };
1650
+ }
1651
+ async function* parseOpenAiSseStream(body) {
1652
+ const reader = body.getReader();
1653
+ const decoder = new TextDecoder;
1654
+ let buffer = "";
1655
+ const handle = (line) => {
1656
+ const trimmed = line.trimStart();
1657
+ if (!trimmed.startsWith("data:"))
1658
+ return null;
1659
+ const payload = trimmed.slice(5).trim();
1660
+ if (payload === "")
1661
+ return null;
1662
+ if (payload === "[DONE]")
1663
+ return "DONE";
1664
+ try {
1665
+ return JSON.parse(payload);
1666
+ } catch {
1667
+ return null;
1668
+ }
1669
+ };
1670
+ try {
1671
+ for (;; ) {
1672
+ const { value, done } = await reader.read();
1673
+ if (done)
1674
+ break;
1675
+ buffer += decoder.decode(value, { stream: true });
1676
+ let nl;
1677
+ while ((nl = buffer.indexOf(`
1678
+ `)) >= 0) {
1679
+ const line = buffer.slice(0, nl);
1680
+ buffer = buffer.slice(nl + 1);
1681
+ const frame = handle(line);
1682
+ if (frame === "DONE")
1683
+ return;
1684
+ if (frame)
1685
+ yield frame;
1686
+ }
1687
+ }
1688
+ const tail = handle(buffer);
1689
+ if (tail && tail !== "DONE")
1690
+ yield tail;
1691
+ } finally {
1692
+ try {
1693
+ await reader.cancel();
1694
+ } catch {}
1695
+ }
1696
+ }
1697
+ function accumulateToolCallDeltas(acc, deltas) {
1698
+ if (!Array.isArray(deltas))
1699
+ return;
1700
+ for (const raw of deltas) {
1701
+ const d = asRecord2(raw);
1702
+ const index = typeof d.index === "number" ? d.index : 0;
1703
+ const cur = acc.get(index) ?? { args: "" };
1704
+ const id = firstString(d.id);
1705
+ if (id)
1706
+ cur.id = id;
1707
+ const fn = recordAt(d, "function");
1708
+ const name = firstString(fn.name);
1709
+ if (name)
1710
+ cur.name = name;
1711
+ if (typeof fn.arguments === "string")
1712
+ cur.args += fn.arguments;
1713
+ acc.set(index, cur);
1714
+ }
1715
+ }
1716
+ function finalizeStreamedToolCalls(acc) {
1717
+ const out = [];
1718
+ for (const [index, c] of [...acc.entries()].sort((a, b) => a[0] - b[0])) {
1719
+ if (!c.name)
1720
+ continue;
1721
+ out.push({
1722
+ type: "tool-call",
1723
+ toolCallId: c.id ?? `call_${c.name}_${index}`,
1724
+ toolName: c.name,
1725
+ input: parseJsonIfPossible(c.args.trim() === "" ? "{}" : c.args)
1726
+ });
1727
+ }
1728
+ return out;
1729
+ }
1730
+ async function streamNativeChatCompletion(runtime, modelType, params, context) {
1731
+ const requestBody = buildNativeRequestBody(params, context.modelName, context.prompt, context.systemPrompt);
1732
+ requestBody.stream = true;
1733
+ requestBody.stream_options = { include_usage: true };
1734
+ const headers = {
1735
+ "X-Eliza-Llm-Purpose": getPurposeForModelType(modelType),
1736
+ "X-Eliza-Model-Type": modelType
1737
+ };
1738
+ if (isSpanSamplerHonoringModel(context.modelName)) {
1739
+ const samplerHeader = buildSpanSamplerHeader(params.spanSamplerPlan);
1740
+ if (samplerHeader) {
1741
+ headers["x-eliza-span-samplers"] = samplerHeader;
1742
+ }
1743
+ }
1744
+ const abortSignal = params.signal;
1745
+ const signal = buildStreamAbortSignal(abortSignal, resolveTextTimeoutMs());
1746
+ const limiter = getNativeChatLimiter();
1747
+ const waitStartedAt = Date.now();
1748
+ await limiter.acquire();
1749
+ recordInferenceSpan("cloud.semaphore-wait", Date.now() - waitStartedAt, {
1750
+ route: "chat/completions:stream"
1751
+ });
1752
+ let permitReleased = false;
1753
+ const releasePermit = () => {
1754
+ if (!permitReleased) {
1755
+ permitReleased = true;
1756
+ limiter.release();
1757
+ }
1758
+ };
1759
+ let response;
1760
+ try {
1761
+ response = await createCloudApiClient(runtime).requestRaw("POST", "/chat/completions", {
1762
+ headers,
1763
+ json: requestBody,
1764
+ ...signal ? { signal } : {}
1765
+ });
1766
+ } catch (err) {
1767
+ releasePermit();
1768
+ throw err;
1769
+ }
1770
+ if (!response.ok) {
1771
+ let errorBody;
1772
+ try {
1773
+ const errText = await response.text();
1774
+ if (errText) {
1775
+ errorBody = JSON.parse(errText).error;
1776
+ }
1777
+ } catch {}
1778
+ releasePermit();
1779
+ const message = typeof errorBody?.message === "string" && errorBody.message.trim() ? errorBody.message.trim() : `elizaOS Cloud error ${response.status}`;
1780
+ const requestError = new Error(message);
1781
+ requestError.status = response.status;
1782
+ if (errorBody)
1783
+ requestError.error = errorBody;
1784
+ throw requestError;
1785
+ }
1786
+ const contentType = response.headers.get("content-type") ?? "";
1787
+ const isSse = contentType.includes("text/event-stream") && response.body !== null;
1788
+ if (!isSse) {
1789
+ const bufferedText = await response.text();
1790
+ releasePermit();
1791
+ let data = {};
1792
+ if (bufferedText) {
1793
+ try {
1794
+ data = JSON.parse(bufferedText);
1795
+ } catch (parseErr) {
1796
+ logger7.error(`[ELIZAOS_CLOUD] Failed to parse buffered chat completions JSON: ${parseErr instanceof Error ? parseErr.message : String(parseErr)}`);
1797
+ }
1798
+ }
1799
+ const text = extractChatCompletionText(data);
1800
+ const toolCalls = extractNativeToolCalls(data);
1801
+ const usage = convertNativeUsage(data.usage);
1802
+ if (usage) {
1803
+ emitModelUsageEvent(runtime, modelType, context.prompt, usage, {
1804
+ modelName: context.modelName,
1805
+ ...(() => {
1806
+ const costUsd = extractCostUsd(data.usage, response);
1807
+ return typeof costUsd === "number" ? { costUsd } : {};
1808
+ })()
1809
+ });
1810
+ }
1811
+ if (!text.trim() && toolCalls.length === 0) {
1812
+ throw new Error("elizaOS Cloud returned no text or tool calls");
1813
+ }
1814
+ async function* single() {
1815
+ if (text)
1816
+ yield text;
1817
+ }
1818
+ return {
1819
+ textStream: single(),
1820
+ text: Promise.resolve(text),
1821
+ usage: Promise.resolve(usage),
1822
+ finishReason: Promise.resolve(data.choices?.[0]?.finish_reason),
1823
+ toolCalls: Promise.resolve(toolCalls),
1824
+ providerMetadata: { modelName: context.modelName, usage: data.usage }
1825
+ };
1826
+ }
1827
+ const body = response.body;
1828
+ const toolAcc = new Map;
1829
+ let accumulated = "";
1830
+ let nativeUsage;
1831
+ let rawUsage;
1832
+ let finishReason;
1833
+ const textD = deferred();
1834
+ const usageD = deferred();
1835
+ const finishD = deferred();
1836
+ const toolCallsD = deferred();
1837
+ async function* generate() {
1838
+ try {
1839
+ for await (const frame of parseOpenAiSseStream(body)) {
1840
+ if (frame.error) {
1841
+ const message = asRecord2(frame.error).message;
1842
+ throw new Error(typeof message === "string" && message.trim() ? message.trim() : "elizaOS Cloud stream error");
1843
+ }
1844
+ const choices = Array.isArray(frame.choices) ? frame.choices : [];
1845
+ const choice = asRecord2(choices[0]);
1846
+ const delta = recordAt(choice, "delta");
1847
+ if (typeof delta.content === "string" && delta.content.length > 0) {
1848
+ accumulated += delta.content;
1849
+ yield delta.content;
1850
+ }
1851
+ if (delta.tool_calls) {
1852
+ accumulateToolCallDeltas(toolAcc, delta.tool_calls);
1853
+ }
1854
+ const fr = firstString(choice.finish_reason);
1855
+ if (fr)
1856
+ finishReason = fr;
1857
+ if (frame.usage) {
1858
+ rawUsage = frame.usage;
1859
+ nativeUsage = convertNativeUsage(frame.usage);
1860
+ }
1861
+ }
1862
+ } finally {
1863
+ releasePermit();
1864
+ const toolCalls = finalizeStreamedToolCalls(toolAcc);
1865
+ textD.resolve(accumulated);
1866
+ usageD.resolve(nativeUsage);
1867
+ finishD.resolve(finishReason);
1868
+ toolCallsD.resolve(toolCalls);
1869
+ if (nativeUsage) {
1870
+ emitModelUsageEvent(runtime, modelType, context.prompt, nativeUsage, {
1871
+ modelName: context.modelName,
1872
+ ...(() => {
1873
+ const costUsd = extractCostUsd(rawUsage, response);
1874
+ return typeof costUsd === "number" ? { costUsd } : {};
1875
+ })()
1876
+ });
1877
+ }
1878
+ }
1879
+ }
1880
+ return {
1881
+ textStream: generate(),
1882
+ text: textD.promise,
1883
+ usage: usageD.promise,
1884
+ finishReason: finishD.promise,
1885
+ toolCalls: toolCallsD.promise,
1886
+ providerMetadata: { modelName: context.modelName }
1887
+ };
1888
+ }
1345
1889
  async function handleTextSmall(runtime, params) {
1346
1890
  return generateTextWithModel(runtime, TEXT_SMALL_MODEL_TYPE, params);
1347
1891
  }
@@ -1383,4 +1927,4 @@ export {
1383
1927
  fetchTextToSpeech
1384
1928
  };
1385
1929
 
1386
- //# debugId=06464BB61850EEE264756E2164756E21
1930
+ //# debugId=A300679511EB9B9464756E2164756E21