@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.
- package/README.md +20 -44
- package/auto-enable.ts +10 -5
- package/dist/browser/index.browser.js +2 -2
- package/dist/browser/index.browser.js.map +4 -4
- package/dist/cjs/index.node.cjs +2918 -5924
- package/dist/cjs/index.node.js.map +47 -116
- package/dist/cloud/auth-service-types.d.ts +8 -0
- package/dist/cloud/auth-service-types.d.ts.map +1 -0
- package/dist/cloud/auth-service-types.js +36 -0
- package/dist/cloud/auth-service-types.js.map +10 -0
- package/dist/cloud/auth.js +4 -51
- package/dist/cloud/auth.js.map +4 -4
- package/dist/cloud/backup.js +1 -1
- package/dist/cloud/backup.js.map +1 -1
- package/dist/cloud/base-url.d.ts +6 -2
- package/dist/cloud/base-url.d.ts.map +1 -1
- package/dist/cloud/base-url.js +3 -51
- package/dist/cloud/base-url.js.map +3 -3
- package/dist/cloud/bridge-client.d.ts +3 -3
- package/dist/cloud/bridge-client.d.ts.map +1 -1
- package/dist/cloud/bridge-client.js +3 -51
- package/dist/cloud/bridge-client.js.map +3 -3
- package/dist/cloud/clack-observer.d.ts +35 -0
- package/dist/cloud/clack-observer.d.ts.map +1 -0
- package/dist/cloud/clack-observer.js +143 -0
- package/dist/cloud/clack-observer.js.map +10 -0
- package/dist/cloud/cloud-api-key.js +1 -1
- package/dist/cloud/cloud-api-key.js.map +1 -1
- package/dist/cloud/cloud-manager.js +45 -92
- package/dist/cloud/cloud-manager.js.map +6 -6
- package/dist/cloud/cloud-proxy.js +1 -1
- package/dist/cloud/cloud-proxy.js.map +1 -1
- package/dist/cloud/cloud-wallet.js +2 -4835
- package/dist/cloud/cloud-wallet.js.map +3 -82
- package/dist/cloud/duffel-client.d.ts +181 -0
- package/dist/cloud/duffel-client.d.ts.map +1 -0
- package/dist/cloud/duffel-client.js +506 -0
- package/dist/cloud/duffel-client.js.map +11 -0
- package/dist/cloud/index.d.ts +6 -0
- package/dist/cloud/index.d.ts.map +1 -1
- package/dist/cloud/index.js +1782 -1
- package/dist/cloud/index.js.map +18 -3
- package/dist/cloud/lifeops-schedule-sync-client.d.ts +43 -0
- package/dist/cloud/lifeops-schedule-sync-client.d.ts.map +1 -0
- package/dist/cloud/lifeops-schedule-sync-client.js +180 -0
- package/dist/cloud/lifeops-schedule-sync-client.js.map +11 -0
- package/dist/cloud/lifeops-schedule-sync-contracts.d.ts +89 -0
- package/dist/cloud/lifeops-schedule-sync-contracts.d.ts.map +1 -0
- package/dist/cloud/lifeops-schedule-sync-contracts.js +39 -0
- package/dist/cloud/lifeops-schedule-sync-contracts.js.map +10 -0
- package/dist/cloud/managed-payment-clients.d.ts +166 -0
- package/dist/cloud/managed-payment-clients.d.ts.map +1 -0
- package/dist/cloud/managed-payment-clients.js +238 -0
- package/dist/cloud/managed-payment-clients.js.map +11 -0
- package/dist/cloud/null-observer.d.ts +35 -0
- package/dist/cloud/null-observer.d.ts.map +1 -0
- package/dist/cloud/null-observer.js +45 -0
- package/dist/cloud/null-observer.js.map +10 -0
- package/dist/cloud/reconnect.js +1 -1
- package/dist/cloud/reconnect.js.map +1 -1
- package/dist/cloud/setup-observer.d.ts +98 -0
- package/dist/cloud/setup-observer.d.ts.map +1 -0
- package/dist/cloud/setup-observer.js +2 -0
- package/dist/cloud/setup-observer.js.map +9 -0
- package/dist/cloud/validate-url.d.ts.map +1 -1
- package/dist/cloud/validate-url.js +2 -1
- package/dist/cloud/validate-url.js.map +3 -3
- package/dist/cloud/x402-payment-handler.d.ts +85 -0
- package/dist/cloud/x402-payment-handler.d.ts.map +1 -0
- package/dist/cloud/x402-payment-handler.js +119 -0
- package/dist/cloud/x402-payment-handler.js.map +10 -0
- package/dist/cloud-providers/cloud-status.js +1 -1
- package/dist/cloud-providers/cloud-status.js.map +1 -1
- package/dist/cloud-providers/container-health.js +1 -1
- package/dist/cloud-providers/container-health.js.map +1 -1
- package/dist/cloud-providers/credit-balance.js +1 -1
- package/dist/cloud-providers/credit-balance.js.map +1 -1
- package/dist/cloud-providers/index.js +1 -1
- package/dist/cloud-providers/index.js.map +1 -1
- package/dist/cloud-providers/model-registry.js +1 -1
- package/dist/cloud-providers/model-registry.js.map +1 -1
- package/dist/cloud-setup.d.ts +36 -0
- package/dist/cloud-setup.d.ts.map +1 -0
- package/dist/{onboarding.js → cloud-setup.js} +139 -139
- package/dist/cloud-setup.js.map +14 -0
- package/dist/cloud-voice-catalog.d.ts +65 -0
- package/dist/cloud-voice-catalog.d.ts.map +1 -0
- package/dist/cloud-voice-catalog.js +278 -0
- package/dist/cloud-voice-catalog.js.map +12 -0
- package/dist/index.browser.d.ts +11 -0
- package/dist/index.browser.d.ts.map +1 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5458 -8412
- package/dist/index.js.map +48 -116
- package/dist/index.node.d.ts +8 -1
- package/dist/index.node.d.ts.map +1 -1
- package/dist/init.js +17 -4
- package/dist/init.js.map +4 -4
- package/dist/lib/cloud-connection.d.ts +0 -1
- package/dist/lib/cloud-connection.d.ts.map +1 -1
- package/dist/lib/cloud-connection.js +14 -91
- package/dist/lib/cloud-connection.js.map +7 -7
- package/dist/lib/cloud-secrets.d.ts +5 -18
- package/dist/lib/cloud-secrets.d.ts.map +1 -1
- package/dist/lib/cloud-secrets.js +8 -36
- package/dist/lib/cloud-secrets.js.map +3 -3
- package/dist/lib/config-env.js +1 -1
- package/dist/lib/config-env.js.map +1 -1
- package/dist/lib/config-like.d.ts +1 -1
- package/dist/lib/config-like.d.ts.map +1 -1
- package/dist/lib/config-like.js +3 -3
- package/dist/lib/config-like.js.map +3 -3
- package/dist/lib/credential-type-map.d.ts +1 -1
- package/dist/lib/credential-type-map.js +1 -1
- package/dist/lib/credential-type-map.js.map +2 -2
- package/dist/lib/feature-flags.js +1 -1
- package/dist/lib/feature-flags.js.map +1 -1
- package/dist/lib/http.d.ts +0 -11
- package/dist/lib/http.d.ts.map +1 -1
- package/dist/lib/http.js +1 -1
- package/dist/lib/http.js.map +3 -3
- package/dist/lib/server-cloud-tts.d.ts +12 -25
- package/dist/lib/server-cloud-tts.d.ts.map +1 -1
- package/dist/lib/server-cloud-tts.js +31 -329
- package/dist/lib/server-cloud-tts.js.map +4 -7
- package/dist/lib/state-paths.js +1 -1
- package/dist/lib/state-paths.js.map +1 -1
- package/dist/lib/tts-debug.d.ts +5 -3
- package/dist/lib/tts-debug.d.ts.map +1 -1
- package/dist/lib/tts-debug.js +1 -34
- package/dist/lib/tts-debug.js.map +3 -4
- package/dist/models/embeddings.d.ts +7 -0
- package/dist/models/embeddings.d.ts.map +1 -1
- package/dist/models/embeddings.js +98 -73
- package/dist/models/embeddings.js.map +6 -6
- package/dist/models/image.d.ts.map +1 -1
- package/dist/models/image.js +42 -15
- package/dist/models/image.js.map +6 -6
- package/dist/models/index.js +719 -175
- package/dist/models/index.js.map +11 -12
- package/dist/models/research.d.ts.map +1 -1
- package/dist/models/research.js +24 -7
- package/dist/models/research.js.map +6 -6
- package/dist/models/speech.d.ts +61 -3
- package/dist/models/speech.d.ts.map +1 -1
- package/dist/models/speech.js +173 -17
- package/dist/models/speech.js.map +5 -5
- package/dist/models/text.d.ts +114 -1
- package/dist/models/text.d.ts.map +1 -1
- package/dist/models/text.js +481 -88
- package/dist/models/text.js.map +7 -8
- package/dist/models/tokenization.d.ts.map +1 -1
- package/dist/models/tokenization.js +1 -1
- package/dist/models/tokenization.js.map +3 -3
- package/dist/models/transcription.d.ts.map +1 -1
- package/dist/models/transcription.js +20 -6
- package/dist/models/transcription.js.map +5 -5
- package/dist/node/index.node.js +2872 -5847
- package/dist/node/index.node.js.map +47 -116
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +376 -5050
- package/dist/plugin.js.map +16 -92
- package/dist/providers/openai.js +11 -2
- package/dist/providers/openai.js.map +3 -3
- package/dist/register-routes.js +376 -5050
- package/dist/register-routes.js.map +16 -92
- package/dist/routes/cloud-billing-routes.d.ts.map +1 -1
- package/dist/routes/cloud-billing-routes.js +17 -60
- package/dist/routes/cloud-billing-routes.js.map +8 -7
- package/dist/routes/cloud-coding-container-routes.d.ts +8 -0
- package/dist/routes/cloud-coding-container-routes.d.ts.map +1 -0
- package/dist/routes/cloud-coding-container-routes.js +214 -0
- package/dist/routes/cloud-coding-container-routes.js.map +11 -0
- package/dist/routes/cloud-compat-routes.d.ts.map +1 -1
- package/dist/routes/cloud-compat-routes.js +17 -60
- package/dist/routes/cloud-compat-routes.js.map +8 -7
- package/dist/routes/cloud-features-routes.js +2 -2
- package/dist/routes/cloud-features-routes.js.map +4 -4
- package/dist/routes/cloud-provisioning.js +1 -1
- package/dist/routes/cloud-provisioning.js.map +1 -1
- package/dist/routes/cloud-relay-routes.d.ts +2 -1
- package/dist/routes/cloud-relay-routes.d.ts.map +1 -1
- package/dist/routes/cloud-relay-routes.js +84 -2
- package/dist/routes/cloud-relay-routes.js.map +5 -4
- package/dist/routes/cloud-routes-autonomous.d.ts +3 -4
- package/dist/routes/cloud-routes-autonomous.d.ts.map +1 -1
- package/dist/routes/cloud-routes-autonomous.js +11 -4893
- package/dist/routes/cloud-routes-autonomous.js.map +8 -87
- package/dist/routes/cloud-routes.d.ts +2 -2
- package/dist/routes/cloud-routes.d.ts.map +1 -1
- package/dist/routes/cloud-routes.js +343 -5058
- package/dist/routes/cloud-routes.js.map +13 -90
- package/dist/routes/cloud-status-routes-autonomous.d.ts +1 -2
- package/dist/routes/cloud-status-routes-autonomous.d.ts.map +1 -1
- package/dist/routes/cloud-status-routes-autonomous.js +4 -51
- package/dist/routes/cloud-status-routes-autonomous.js.map +5 -5
- package/dist/routes/cloud-status-routes.js +14 -90
- package/dist/routes/cloud-status-routes.js.map +7 -7
- package/dist/routes/home-remote-runner-access-url.d.ts +16 -0
- package/dist/routes/home-remote-runner-access-url.d.ts.map +1 -0
- package/dist/routes/home-remote-runner-access-url.js +91 -0
- package/dist/routes/home-remote-runner-access-url.js.map +10 -0
- package/dist/routes/travel-provider-relay-routes.d.ts +9 -0
- package/dist/routes/travel-provider-relay-routes.d.ts.map +1 -0
- package/dist/routes/travel-provider-relay-routes.js +358 -0
- package/dist/routes/travel-provider-relay-routes.js.map +14 -0
- package/dist/services/cloud-auth.d.ts +1 -1
- package/dist/services/cloud-auth.d.ts.map +1 -1
- package/dist/services/cloud-auth.js +7 -2
- package/dist/services/cloud-auth.js.map +4 -4
- package/dist/services/cloud-backup.js +1 -1
- package/dist/services/cloud-backup.js.map +3 -3
- package/dist/services/cloud-bootstrap.d.ts.map +1 -1
- package/dist/services/cloud-bootstrap.js +1 -1
- package/dist/services/cloud-bootstrap.js.map +3 -3
- package/dist/services/cloud-bridge.js +1 -1
- package/dist/services/cloud-bridge.js.map +4 -4
- package/dist/services/cloud-container.d.ts +5 -1
- package/dist/services/cloud-container.d.ts.map +1 -1
- package/dist/services/cloud-container.js +52 -1
- package/dist/services/cloud-container.js.map +4 -4
- package/dist/services/cloud-credential-provider.js +1 -1
- package/dist/services/cloud-credential-provider.js.map +3 -3
- package/dist/services/cloud-managed-gateway-relay.js +1 -1
- package/dist/services/cloud-managed-gateway-relay.js.map +1 -1
- package/dist/services/cloud-model-registry.js +1 -1
- package/dist/services/cloud-model-registry.js.map +3 -3
- package/dist/services/index.js +1 -1
- package/dist/services/index.js.map +1 -1
- package/dist/types/cloud.d.ts +1 -0
- package/dist/types/cloud.d.ts.map +1 -1
- package/dist/types/cloud.js +1 -1
- package/dist/types/cloud.js.map +3 -3
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/utils/cloud-api.js +1 -1
- package/dist/utils/cloud-api.js.map +1 -1
- package/dist/utils/cloud-sdk/client.d.ts.map +1 -1
- package/dist/utils/cloud-sdk/client.js +136 -4
- package/dist/utils/cloud-sdk/client.js.map +5 -5
- package/dist/utils/cloud-sdk/http.js +1 -1
- package/dist/utils/cloud-sdk/http.js.map +2 -2
- package/dist/utils/cloud-sdk/index.js +1 -1
- package/dist/utils/cloud-sdk/index.js.map +1 -1
- package/dist/utils/cloud-sdk/public-routes.d.ts +186 -0
- package/dist/utils/cloud-sdk/public-routes.d.ts.map +1 -1
- package/dist/utils/cloud-sdk/public-routes.js +99 -1
- package/dist/utils/cloud-sdk/public-routes.js.map +3 -3
- package/dist/utils/cloud-sdk/types.d.ts +0 -2
- package/dist/utils/cloud-sdk/types.d.ts.map +1 -1
- package/dist/utils/cloud-sdk/types.js +1 -1
- package/dist/utils/cloud-sdk/types.js.map +2 -2
- package/dist/utils/config.d.ts +10 -1
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +12 -2
- package/dist/utils/config.js.map +3 -3
- package/dist/utils/events.d.ts +23 -2
- package/dist/utils/events.d.ts.map +1 -1
- package/dist/utils/events.js +5 -3
- package/dist/utils/events.js.map +3 -3
- package/dist/utils/helpers.js +1 -1
- package/dist/utils/helpers.js.map +1 -1
- package/dist/utils/responses-output.js +1 -1
- package/dist/utils/responses-output.js.map +1 -1
- package/dist/utils/sdk-client.d.ts.map +1 -1
- package/dist/utils/sdk-client.js +17 -4
- package/dist/utils/sdk-client.js.map +4 -4
- package/dist/utils/waifu-metering.d.ts +108 -0
- package/dist/utils/waifu-metering.d.ts.map +1 -0
- package/dist/utils/waifu-metering.js +166 -0
- package/dist/utils/waifu-metering.js.map +10 -0
- package/package.json +52 -22
- package/registry-entry.json +208 -0
- package/src/cloud/auth-service-types.ts +24 -0
- package/src/cloud/base-url.ts +6 -62
- package/src/cloud/clack-observer.ts +189 -0
- package/src/cloud/duffel-client.ts +847 -0
- package/src/cloud/index.ts +10 -0
- package/src/cloud/lifeops-schedule-sync-client.ts +245 -0
- package/src/cloud/lifeops-schedule-sync-contracts.ts +124 -0
- package/src/cloud/managed-payment-clients.ts +374 -0
- package/src/cloud/null-observer.ts +45 -0
- package/src/cloud/setup-observer.ts +125 -0
- package/src/cloud/validate-url.ts +7 -1
- package/src/cloud/x402-payment-handler.ts +215 -0
- package/src/cloud-setup.ts +531 -0
- package/src/cloud-voice-catalog.test.ts +254 -0
- package/src/cloud-voice-catalog.ts +246 -0
- package/src/index.browser.ts +29 -0
- package/src/index.node.ts +31 -1
- package/src/index.ts +81 -4
- package/src/lib/cloud-connection.ts +2 -4
- package/src/lib/cloud-secrets.ts +10 -54
- package/src/lib/config-like.ts +1 -1
- package/src/lib/credential-type-map.ts +2 -2
- package/src/lib/http.ts +0 -17
- package/src/lib/server-cloud-tts.ts +33 -341
- package/src/lib/tts-debug.ts +5 -34
- package/src/models/embeddings.ts +187 -78
- package/src/models/image.ts +29 -14
- package/src/models/research.ts +11 -1
- package/src/models/speech.ts +269 -23
- package/src/models/text.ts +756 -114
- package/src/models/tokenization.ts +2 -2
- package/src/models/transcription.ts +7 -3
- package/src/plugin.ts +38 -0
- package/src/routes/cloud-billing-routes.ts +4 -14
- package/src/routes/cloud-coding-container-routes.ts +198 -0
- package/src/routes/cloud-compat-routes.ts +4 -14
- package/src/routes/cloud-features-routes.ts +1 -1
- package/src/routes/cloud-relay-routes.ts +47 -1
- package/src/routes/cloud-routes-autonomous.ts +7 -10
- package/src/routes/cloud-routes.ts +68 -7
- package/src/routes/cloud-status-routes-autonomous.ts +6 -2
- package/src/routes/home-remote-runner-access-url.ts +83 -0
- package/src/routes/travel-provider-relay-routes.ts +193 -0
- package/src/services/cloud-auth.ts +9 -2
- package/src/services/cloud-bootstrap.ts +1 -3
- package/src/services/cloud-bridge.ts +1 -1
- package/src/services/cloud-container.ts +93 -0
- package/src/services/cloud-credential-provider.ts +1 -1
- package/src/services/cloud-model-registry.ts +1 -1
- package/src/types/cloud.ts +22 -0
- package/src/types/index.ts +19 -0
- package/src/utils/cloud-sdk/client.ts +42 -3
- package/src/utils/cloud-sdk/public-routes.ts +168 -0
- package/src/utils/cloud-sdk/types.ts +0 -2
- package/src/utils/config.ts +20 -1
- package/src/utils/events.ts +30 -2
- package/src/utils/sdk-client.ts +5 -1
- package/src/utils/waifu-metering.ts +302 -0
- package/dist/onboarding.d.ts +0 -35
- package/dist/onboarding.d.ts.map +0 -1
- package/dist/onboarding.js.map +0 -14
- package/src/onboarding.ts +0 -396
package/dist/models/index.js
CHANGED
|
@@ -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 = "
|
|
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 {
|
|
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
|
|
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 {
|
|
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
|
|
218
|
+
function createInitProbeVector(dimension) {
|
|
186
219
|
const vector = Array(dimension).fill(0);
|
|
187
|
-
vector[0] =
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
240
|
-
|
|
241
|
-
|
|
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
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
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
|
|
267
|
-
if (
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
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
|
-
|
|
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
|
-
|
|
278
|
-
|
|
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
|
-
|
|
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
|
-
|
|
286
|
-
|
|
287
|
-
|
|
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
|
|
293
|
-
|
|
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)
|
|
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]
|
|
307
|
-
|
|
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
|
|
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
|
-
|
|
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 (
|
|
496
|
+
if (!attemptResponse) {
|
|
497
|
+
continue;
|
|
498
|
+
}
|
|
499
|
+
response = attemptResponse;
|
|
500
|
+
if (attemptResponse.status !== 429 || attemptedRetry)
|
|
470
501
|
break;
|
|
471
|
-
const headerValue =
|
|
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
|
|
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
|
|
489
|
-
|
|
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
|
|
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 =
|
|
693
|
-
const voiceId =
|
|
771
|
+
const modelId = resolveModelId(options);
|
|
772
|
+
const voiceId = resolveVoiceId(options);
|
|
694
773
|
try {
|
|
695
|
-
const res = await
|
|
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
|
-
|
|
723
|
-
|
|
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
|
-
|
|
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
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
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
|
|
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
|
|
868
|
-
|
|
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
|
-
|
|
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
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1226
|
-
|
|
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
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
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
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
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=
|
|
1930
|
+
//# debugId=A300679511EB9B9464756E2164756E21
|